Protovis
A graphical toolkit for visualization
Overview
Examples
Documentation
Paper
Download
Protovis is a visualization toolkit for JavaScript using the canvas element. It takes a graphical approach to data visualization, composing custom views of data with simple graphical primitives like bars and dots. These primitives are called marks, and each mark encodes data visually through dynamic properties such as color and position. For example, this simple bar chart visually encodes an array of numbers with height:
new pv.Panel().width(150).height(150)
    .add(pv.Bar)
      .data([1, 1.2, 1.7, 1.5, .7, .3])
      .bottom(0)
      .width(20)
      .height(function(d) d * 80)
      .left(function() this.index * 25)
    .root.render();

Although marks are simple by themselves, you can combine them in interesting ways to make rich, interactive visualizations. To facilitate this, Protovis supports panels and inheritance. A panel is a container for marks; the contained marks are replicated for each data point on the panel. You can vary the panel position to create small multiple displays, or you can overlay panels, such as in this stacked area chart of sine waves:

new pv.Panel().width(150).height(150)
    .add(pv.Panel)
      .data([[Math.sin(x / y)
             for (x in pv.range(50))]
             for (y in pv.range(3, 9))])
    .add(pv.Area)
      .data(function(d) d)
      .fillStyle(pv.Colors.category19.unique)
      .bottom(function() let (c = this.cousin())
          c ? (c.bottom + c.height) : 0)
      .height(function(d) (d + 1) * 13)
      .left(function() this.index * 3)
    .root.render();

Inheritance lets you derive new marks from existing ones, while sharing some or all of the same properties. This is the same principle as cascading in CSS, or prototypal inheritance in JavaScript. For example, here we derive labels for a rule and a bar:

new pv.Panel().width(150).height(150)
    .bottom(9.5).left(20)
  .add(pv.Rule)
    .data(function() pv.range(0, 2, .5))
    .bottom(function(d) d * 70)
    .anchor("left").add(pv.Label)
  .root.add(pv.Bar)
    .data([1, 1.2, 1.7, 1.5, .7])
    .height(function(d) d * 70).width(20)
    .bottom(0).left(function() this.index * 25 + 4)
    .anchor("bottom").add(pv.Label)
  .root.render();

And that's the basic idea. If you're interested in learning more about Protovis, you can read the research paper, browse the API documentation, or play with the examples we've implemented. Or download protovis.js and start making your own visualizations! This is very much a work in progress, so we're eager for your feedback. Try it out and let us know what you think.

Please note: Protovis is in its early stages of development. At the moment, we support Firefox 3, Chrome and Safari 4. (We have a little hack to allow JavaScript 1.8 function expressions in browsers that don't support them.) We are also working on interaction and animation.

Protovis is a project led by Mike Bostock and Jeff Heer. We are with the Stanford Visualization Group, a joint program with the Stanford Graphics Lab and Stanford HCI Group. Protovis is provided under the BSD License.

Copyright 2009 Stanford Visualization Group