Sometimes I needed to show data in HTML charts to get better insight. An example might be data from performance counters. I simply included all the stuff that generated HTML code into the script processing performance counters. That's generally bad idea.
Besides that it was needed to copy special folder with *js and *css files to the resulting HTML file. That was too annoying.

That's why I created a module that processes data and creates one single HTML file that can be displayed on its own. Look at the result and result2 or a screenshot:

Charts in HTML Charts in HTML - second

Hello chart

First let's hunt for some data to show.

$procs = 1..10 | % { Get-Process Opera; Start-Sleep -sec 5 }

The simplest example is: create one chart and show me lines for these properties: WorkingSet, VirtualMemorySize and PrivateMemorySize. Look at the result.

New-ViChart `
    -outputFile opera1.html `
    -inputObject `
        (New-ViChartInfo -data $procs -lines PrivateMemorySize,VirtualMemorySize,WorkingSet)

The -outputFile is pretty self-explanatory.

What about the inputObject param? It's collection of infos where each info describes one chart. The info object is created using New-ViChartInfo function. That's why in our case we have only one call of this function.

  • -data parameter specifies data that will be displayed on the chart. Every chart may have it's own set of data.
  • -lines parameter specifies individual lines. In this case it is array of property names. It looks the same as parameter Property of Select-Object cmdlet.

Add other chart

Adding other chart is as simple as calling function New-ViChartInfo.

New-ViChart `
    -outputFile opera2.html `
    -inputObject `
        (New-ViChartInfo -data $procs -lines PrivateMemorySize,VirtualMemorySize,WorkingSet), 
        (New-ViChartInfo -data $procs Handles)

Now, there are two charts.

What about the X-axis?

You can select values that will describe the X-axis.

$dates = 0..9 | % { [DateTime]::Now.AddSeconds($_).ToString("HH:mm:ss") }
New-ViChart `
    -outputFile opera3.html `
    -inputObject `
        (New-ViChartInfo -data $procs -lines PrivateMemorySize,VirtualMemorySize,WorkingSet -xaxis $dates ), 
        (New-ViChartInfo -data $procs Handles  -xaxis $dates)

What you can pass in as value for -xAxisValues parameter?

  • Property name – check e.g. (New-ViChartInfo ... -xaxis "Handles"). Look at the second chart and its x axis.
  • An IEnumerable, that means 'a collection'. We used this option when we passed in array of dates.
  • A Hashtable with the same keys as -lines parameter; n as Name and script block e as Expression.

Other ways how to specify values

As we saw -lines accepts property names.
However, we can supply two more types:

  • A Hashtable with keys n (that stands for "Name") and e ("Expression" – a script block using variable $_).
    Example: @{'n'='threads count'; 'e'={$_.Threads.Count}}
  • Property name with dot notation – e.g. "Threads.Count".

The options are covered here:

New-ViChart `
    -outputFile opera5.html `
    -inputObject `
        (New-ViChartInfo -data $procs -lines `
            "Threads.Count",`
            @{'n'='threads count'; 'e'={$_.Threads.Count+10}})

Process only subsets of data

Very often the items you pass in as data can not be simply processed by the above means. Example:

$procs2 = 1..10 | % { ,(@([DateTime]::now) + (Get-Process firefox,Opera)) }

$procs2 is array of items. Each item is array as well with this structure:

  1. current date
  2. info about process "Opera"
  3. info about process "Firefox"

There are several ways how to work around it.

First thought – we can convert the array into new structure. We create new array of PsObjects with the properties we are interested in: Opera-WorkingSet,Firefox-WorkingSet, …
Then we can specify lines like this: -lines 'Opera-WorkingSet','Firefox-WorkingSet'

Or – We can use script block in hashtable to get the appropriate object from array: @{'n'='ff-priv'; 'e'={$_[1].PrivateMemorySize}; }

Or – we can use slightly longer version:
@{'n'='ff-priv'; 'e'={$_.PrivateMemorySize}; 'dataconvertor'={$args[0][1]}} where $args is current item from array $procs2

This is a whole example:

New-ViChart `
    -outputFile ff-opera.html `
    -inputObject `
        (New-ViChartInfo -data $procs2 `
            -xaxis ($procs2 | % { $_[0].ToString("HH:mm:ss") }) `
            -lines `
            @{'n'='ff-priv'; 'e'={$_[1].PrivateMemorySize};},`
            @{'n'='ff-priv'; 'e'={$_[1].WorkingSet};},`
            @{'n'='op-priv'; 'e'={$_.PrivateMemorySize}; 'dataconvertor'={$args[0][2]}},`
            @{'n'='op-priv'; 'e'={$_.WorkingSet};        'dataconvertor'={$args[0][2]}}),
        (New-ViChartInfo -data $procs2 `
            -xaxis ($procs2 | % { $_[0].ToString("HH:mm:ss") }) `
            -lines `
            @{'n'='ff-handles'; 'e'={$_[1].Handles};},`
            @{'n'='op-handles'; 'e'={$_.Handles}; 'dataconvertor'={$args[0][2]}}),
        (New-ViChartInfo -data $procs2 `
            -xaxis ($procs2 | % { $_[0].ToString("HH:mm:ss") }) `
            -lines `
            @{'n'='ff-threads'; 'e'={$_[1].Threads.Count};},`
            @{'n'='op-threads'; 'e'={$_.Threads.Count}; 'dataconvertor'={$args[0][2]}})

And this is the final result.
Lines related to Firefox are specified in scriptblock and lines related to Opera use key dataconvertor – just to for demonstration purposes.

It is possible as well to use datafilter key in the hashtable. It works with variable $args[0] as well and returns $true/$false as you would expect. Example: @{'n'='only some Mins'; 'e'={$_.Minute}; 'datafilter'={$args[0] -ge 30}}

Maybe you wonder why the script blocks use $args[0] property instead of $_ I would love to work with $_, but it is from some unknown reason $null.

Credits

I use jquery plugin jQuery Visualize that does all the hard work. Thanks a lot!

Download

Download the PowerShell module:

Meta: 2009-11-19, Pepa