I needed to solve this problem recently for a timeline viz. I wrote
the following routine that you may be able to just use straightaway to
address your problem. Hope this helps. Chris
/*
* pvTimelineVis
*
* syntax:
* inputs:
* panelWidth: width of the root panel
* panelHeight: height of the root panel
* minDT: starting datetime for the timeline
* maxDT: ending datetime for the timeline
* countArrays: array of arrays containing counts for each event
class
* maxEvents: maximum number of events occurring in a given time
interval
*
*/
function pvTimelineVis(panelWidth, panelHeight, minDT, maxDT,
countArrays, maxEvents) {
var numBins = countArrays[0].length, // number of time
intervals
numClasses = countArrays.length; // number of event
classes
tlDim = Math.min( panelHeight * 0.9,
panelWidth * 0.8 ), // width/height of the
timeline
xBufferDim = panelWidth * 0.1, // buffer left of the timeline
yBufferDim = panelHeight * 0.1; // buffer below the timeline
// mappings from data to pixels for x and y axes
var x = pv.Scale.ordinal(pv.range(numBins)).splitBanded(0, tlDim),
y = pv.Scale.linear(0, maxEvents).range(0, tlDim);
// create the root panel for the timeline visualization
var vis = new pv.Panel()
.width(tlDim + (2 * xBufferDim))
.height(tlDim + yBufferDim);
// add the horizontal reference lines
vis.add(pv.Rule)
.data(y.ticks())
.bottom(function(d) { return y(d) + yBufferDim })
.left(xBufferDim)
.width(tlDim)
.strokeStyle("rgba(255,255,255,.3)");
// add the y axis tick marks and numeric labels
vis.add(pv.Rule)
.data(y.ticks())
.bottom(function(d) { return y(d) + yBufferDim })
.left(xBufferDim - 5)
.width(5)
.strokeStyle("rgba(255,255,255,1)")
.anchor("left").add(pv.Label)
.textStyle("white");
// compute the time in milliseconds of the start of the first whole
day
// and the number of date labels to display on the x axis
var SECS_PER_DAY = 86400000,
dt = new Date(minDT.getFullYear(), minDT.getMonth(),
minDT.getDate(), 0, 0, 0, 0),
beginSec = dt.getTime() + SECS_PER_DAY,
numDays = Math.ceil((maxSec - beginSec) / SECS_PER_DAY);
// add the vertical reference lines
vis.add(pv.Rule)
.data(pv.range(0,numDays,1).map(function(d) { return beginSec + d *
SECS_PER_DAY }))
.bottom(yBufferDim)
.left(function(d) { return x(Math.floor((d - minSec) / binWidth)) +
xBufferDim })
.strokeStyle("rgba(255,255,255,.3)");
// add the x axis tick marks and date labels
vis.add(pv.Rule)
.data(pv.range(0,numDays,1).map(function(d) { return beginSec + d *
SECS_PER_DAY }))
.bottom(yBufferDim - 5)
.left(function(d) { return x(Math.floor((d - minSec) / binWidth)) +
xBufferDim })
.height(5)
.strokeStyle("rgba(255,255,255,1)")
.anchor("bottom").add(pv.Label)
.text(function(s) { d = new Date(s); return d.format("%m/%d/%y") })
.textStyle("white");
// add the stacked area chart to the visualization
vis.add(pv.Panel)
.bottom(yBufferDim)
.height(tlDim)
.data(countArrays)
.add(pv.Area)
.data(function(d) { return d })
.bottom(pv.Layout.stack())
// .width(tlDim / numBins) // for stacked bar (pv.Bar)
chart
.height(y)
.left(function() { return x(this.index) + xBufferDim });
return vis;