Wednesday, August 1, 2012

Introducing Custom Plotters

Once you get your chart displaying with dygraphs, you'll want to customize its appearance.

dygraphs includes a plethora of options for doing simple customization, e.g. colors, strokeWidth, drawPoints, stackedGraph and fillGraph. You can see examples of all of these in use from the links off the options reference, or you can play around with them yourself using the experimental palette.

But what if you want to do something really crazy? To fundamentally change the way that data series are displayed? We've recently added a new plotter option which lets you customize to your heart's content.

The standard plotter just draws lines from point to point. While it's a bit more complex in reality, in essence, it's just this:

g = new Dygraph(div, data, {
  plotter: function(e) {
    var ctx = e.drawingContext;
    ctx.beginPath();
    ctx.moveTo(e.points[0].canvasx, e.points[0].canvasy);
    for (var i = 1; i < e.points.length; i++) {
      var p = e.points[i];
      ctx.lineTo(p.canvasx, p.canvasy);
    }
    ctx.stroke();
  }
});
(View/Edit in jsFiddle)

The plotter is called once for each series that needs to be drawn. Its one parameter is a dictionary of useful data about the series and the dygraph. The essential properties are the ones which we use here, namely:

  • drawingContext: a <canvas> drawing context on which you should render this series.
  • points: an array containing the individual points to draw. Each entry has a canvasx and canvasy attribute which tells you where to draw the point.

dygraphs will set up the drawing context for you as best it can. There's no need for you to set the stoke width or color for each series unless you want to do something unusual.

Other properties passed to the plotter include:

  • setName: the name of the series being drawn, e.g. "Y2"
  • color: the color of the series being drawn (you won't normally need this, see above)
  • strokeWidth: the width of the line being drawn (again, you won't normally need this, see above)
  • dygraph: A reference to current dygraph object (useful for calling getOption() and friends)
  • plotArea: Contains x, y, w and h properties which define the plotting rectangle.

As a simple example of what a custom plotter can do, let's make dygraphs draw bar charts instead of line charts.

Here's a bar chart plotter:

function barChartPlotter(e) {
  var ctx = e.drawingContext;
  var points = e.points;
  var y_bottom = e.dygraph.toDomYCoord(0);  // see http://dygraphs.com/jsdoc/symbols/Dygraph.html#toDomYCoord

  // This should really be based on the minimum gap
  var bar_width = 2/3 * (points[1].canvasx - points[0].canvasx);
  ctx.fillStyle = e.color;

  // Do the actual plotting.
  for (var i = 0; i < points.length; i++) {
    var p = points[i];
    var center_x = p.canvasx;  // center of the bar

    ctx.fillRect(center_x - bar_width / 2, p.canvasy,
        bar_width, y_bottom - p.canvasy);
    ctx.strokeRect(center_x - bar_width / 2, p.canvasy,
        bar_width, y_bottom - p.canvasy);
  }
}

And a dygraph that uses it:

g = new Dygraph(div, data, {
  plotter: barChartPlotter,
  dateWindow: [0, 9]  // avoid clipping first and last bars
});

and here's what the output looks like:

(View/Edit in jsFiddle)

Pretty easy! And since this is dygraphs, you get nice things like (animated) zooming, panning and hover labels for free. Try it out by clicking and dragging to zoom, or holding down shift and dragging to pan.

You can mix and match different plotters by setting the plotter option on a per-series basis. Here's how you might combine a line and bar chart (aka a Pareto chart):

g = new Dygraph(div, data, {
  "Late Arrivals": {
    plotter: barChartPlotter
  },
});
(View/Edit in jsFiddle)

This is admittedly a bit simplified: a real Pareto chart would list causes on the x-axis (instead of numbers) and would use two y-axes. In a future post, we'll try to recreate this Wikipedia Pareto chart more precisely using a valueFormatter and a secondary y-axis.

In the mean time, check out the plotters demo for some examples of how to use this exciting new tool.

11 comments:

  1. I have created a plotter function that takes three data columns as input.
    How do I specify those?
    I tried:
    "data1": {
    plotter: multiPlotter(data1,data2,data3)
    }

    But then it does not display the graph at all.

    ReplyDelete
  2. differenxe, would you mind please asking your question on the Dygraphs mailing list at groups.google.com/group/dygraphs-users ?

    ReplyDelete
    Replies
    1. Done. https://groups.google.com/forum/?fromgroups=#!topic/dygraphs-users/UrlFnAJTNcU

      Delete
  3. This comment has been removed by the author.

    ReplyDelete
  4. Karthik, it depends on what you mean. If you just want the bar charts to have a 3d effect, then, sure, but we don't provide them.

    ReplyDelete
  5. This comment has been removed by the author.

    ReplyDelete
  6. How could I plot two lines using dygraphs: one with fillGraph=true and one with fillGraph=false?

    ReplyDelete
  7. Shikher, I suggest using stackoverflow or the mailing list for such questions. Good luck!

    ReplyDelete
  8. Thank you for sharing the code, it is very interesting for me. I am a beginner programmer. I began studying Javascript. Recently I learned to make beautiful pie charts, making them to these examples http://charts.poweredtemplate.com/powerpoint-diagrams-charts/ppt-graph-charts/0/index.html. You can use them as templates, who are interested.

    ReplyDelete
  9. Can you color the bars by a third factor? Similar to group and fill functions in in ggplot?

    ReplyDelete