|
ReadMeFirst
Read me first: an introduction to Protovis fundamentals.
IntroductionManifestoWhy does the world need another language for visualization? The inspiration for Protovis arose in part from frustrations with existing tools. On the one hand, there are a plethora of graphics libraries for rendering arbitrary shapes and manipulating pixels. These have the advantage of conceptual simplicity and are compatible with "visual thinking": they explicitly provide a way to draw curves, polygons, and other visual elements. Yet if used for visualization, such a low-level interface can be extremely tedious due to the lack of support for common abstractions such as scales for color and position. At the other end of the spectrum, there is no shortage of visualization libraries that allow the concise expression of charts and visual encodings. Some even allow fully-customizable, interactive visualizations. Yet while these tools make certain tasks easy, they often require relinquishing direct, pixel-level control over the rendered marks. Furthermore, the indirect, top-down approach can be difficult to grasp and impede visual design. Our insight was simple: find a middle ground that offers the benefits of both types of system. Protovis is a graphical toolkit, designed for visualization. It retains the conceptual simplicity and low-level control of graphical systems by dealing directly with graphical elements (shapes, lines, i.e., marks), but specifies marks declaratively as encodings of data. Additionally, we provide useful abstractions as optional tools to simplify visualization. Declarative, Data-Driven SyntaxIf you've used graphics libraries such as Java 2D or Processing before, at first glance, Protovis sounds familiar: we provide a mechanism for drawing rectangles (bars), circles (dots), lines, and polygons (areas). This is intentional: Protovis is a graphical toolkit. But there's a critical difference, which is that Protovis uses a declarative, rather than imperative, syntax. What does this mean? In Processing, you might specify a pie chart as series of arcs using a for loop and a call to arc, which immediately draws a single arc to the canvas: for (int i = 0; i < data.length; i++) {
fill(data[i] * 120);
float ang = data[i] / sum * 2 * PI;
arc(75, 75, 140, 140, lastAng, lastAng + ang);
lastAng += ang;
}In Protovis, you almost never use a for loop. A set of related graphical elements, such as the arcs in a pie chart, are specified as a single mark. The mark is associated with data, and the properties are specified as functions, encoding the data graphically: vis.add(pv.Wedge)
.data(data)
.left(75)
.bottom(75)
.outerRadius(70)
.angle(function(d) d / sum * 2 * Math.PI);Note that in Processing, you have to maintain the sum (lastAng) by hand. But in Protovis, the angle encoding is specified as a function: a linear scale (i.e., a multiple) of the datum. Furthermore, in Protovis the start angle is, by default, the previous wedge's end angle, so no bookkeeping is necessary. The declarative syntax allows for many such conveniences: Inheritance - New marks can be added to a visualization that inherit properties from existing marks. This allows encodings to be reused, and eliminates code duplication. In addition, it provides the basis for some of the more advanced tools, such as standard layouts (e.g., treemaps). Property Chaining - One mark's properties can be defined in terms of another mark's properties. For example, say you wrote a complicated function to compute a mark's fill color. If you want the stroke color to be the same, but translucent, you can define it as this.fillStyle().alpha(.4). This technique can also be used to position related marks and annotations, as with anchors. Smart Properties - Because related graphical elements are expressed as a single mark, with properties derived from data, smart defaults are possible, as shown above with the wedge start angle. Another example is default categorical colors for fill and stroke. Even better, we can write reusable property functions, such as scales. Interaction and Animation - A mark is not just a command to color some pixels, but a description of the visualization's structure. This means you can associate event handlers with marks, much like you can with parts of a web page. In addition, when the visualization is updated for animation, Protovis can redraw efficiently. In the future, we'll also support smoothly-animated transitions. MarksProtovis only has a handful of mark types, but these primitives can be combined in interesting ways to make elaborate visualizations. See our example charts and visualization gallery if you haven't already!
Consider this minimalist bar chart: var vis = new pv.Panel()
.width(150)
.height(150);
vis.add(pv.Bar)
.data([1, 1.2, 1.7, 1.5, .7])
.bottom(0)
.width(20)
.height(function(d) d * 80)
.left(function() this.index * 25);
vis.render(); The root panel, vis, is 150×150 pixels. It contains a single bar, whose data is an array of numbers. For each of these numbers, a bar is rendered to the panel. The bottom and width of the bar are fixed, but the left position is spaced by 25-pixel increments. Lastly, the height encodes the data. In effect, the specification directly reflects how the data is visualized. By specifying properties as functions, the property values can vary per datum: the height is 80 pixels for the first instance, but 96 pixels for the second. Unlike other visualization systems, Protovis does not place any constraints on the input data, other than each mark has some associated array of data objects. In the simplest case, the data is just an array of numbers; but by defining suitable property functions, any the elements can be structured objects or even nested arrays. Next: Advanced Features |
Sign in to add a comment