Stable release | 3.3.1 / September 17, 2010 |
---|---|
Development status | Protovis is no longer under active development. |
Written in | JavaScript |
License | BSD |
Website | http://protovis.org/ |
Protovis is a visualization toolkit for JavaScript that takes a graphical approach to data visualization by allowing the user to specify how the data should be encoded in the marks representing it on the screen. The project is led by Mike Bostock and Jeff Heer of the Stanford Visualization Group, with help from Vadim Ogievetsky. Protovis uses SVG image for rendering, allowing visualizations to be seamlessly inserted into pages.
Contents |
Protovis is a single JavaScript file, containing all its declarations and functions. It can be included within a web page using the following mark-up:
<script type="text/javascript" src="protovis-r3.2.js"></script>
The Protovis code to build the visualization is added to the body of the page using a script tag.
<script type="text/javascript+protovis"> // Protovis code goes here... </script>
Due to its declarative style, Protovis code typically makes very extensive use of small anonymous functions; to allow for more concise code and increase readability Protovis provides the javascript+protovis script tag type which adds the shorthand function declaration:
function(x) 5*x
which is equivalent to writing:
function(x) { return 5*x; }
The following example demonstrates the ability to create three different network visualizations using the same dataset. The visualizations show content co-creation trends in a fictitious organization.
var w = document.body.clientWidth, h = document.body.clientHeight, colors = pv.Colors.category20(); var vis = new pv.Panel() .width(w) .height(h) .fillStyle("white") .event("mousedown", pv.Behavior.pan()) .event("mousewheel", pv.Behavior.zoom(3)); var force = vis.add(pv.Layout.Force) .nodes(departments.nodes) .links(departments.links); force.link.add(pv.Line); force.node.add(pv.Dot) .size(function(d) (d.linkDegree + 104) * Math.pow(this.scale, -1.5)) .fillStyle(function(d) d.fix ? "red" : colors(d.group)) .strokeStyle(function() this.fillStyle().darker()) .lineWidth(0) .title(function(d) d.nodeName) .event("mousedown", pv.Behavior.drag()) .event("drag", force); force.label.add(pv.Label) vis.render();
var vis = new pv.Panel() .width(880) .height(410) .bottom(90); var colors = pv.Colors.category20(); var arc = vis.add(pv.Layout.Arc) .nodes(departments.nodes) .links(departments.links) .sort(function(a, b) a.group == b.group ? b.linkDegree - a.linkDegree : b.group - a.group); arc.link.add(pv.Line); arc.node.add(pv.Dot) .size(function(d) (d.linkDegree + 104) * Math.pow(this.scale, -1.5)) .fillStyle(function(d) d.fix ? "brown" : colors(d.group)) .strokeStyle(function() this.fillStyle().darker()); arc.label.add(pv.Label) vis.render();
var color = pv.Colors.category20().by(function(d) d.group); var vis = new pv.Panel() .width(400) .height(400) .top(90) .left(90); var layout = vis.add(pv.Layout.Matrix) .nodes(departments.nodes) .links(departments.links) .sort(function(a, b) b.group - a.group); layout.link.add(pv.Bar) .fillStyle(function(l) l.linkValue ? ((l.targetNode.group == l.sourceNode.group) ? color(l.sourceNode) : "rgb("+ (80-(l.linkValue)) + "%, " + (80-(l.linkValue)) + "%, "+ (80-(l.linkValue)) +"%)") : "#EEEEEE") .antialias(false) .lineWidth(1) .anchor("center").add(pv.Label).text(function(l) l.linkValue) .textStyle("#FFFFFF") .font(function(l) l.linkValue + "px sans-serif") layout.label.add(pv.Label) .textStyle(color); vis.render();
var departments = { nodes:[ {nodeName:"Marketing", group:0}, {nodeName:"IT", group:1}, {nodeName:"Engineering", group:2}, {nodeName:"Quality", group:3}, {nodeName:"BI", group:4}, {nodeName:"RND", group:5}, {nodeName:"Administrative", group:6}, {nodeName:"Sales", group:7}, {nodeName:"Legal", group:8}, ], links:[ {source:1, target:0, value:4}, {source:1, target:2, value:3}, {source:1, target:3, value:5}, {source:1, target:4, value:15}, {source:1, target:6, value:2}, {source:1, target:7, value:13}, {source:6, target:0, value:1}, {source:6, target:2, value:1}, {source:6, target:3, value:1}, {source:6, target:4, value:1}, {source:6, target:7, value:1}, {source:0, target:7, value:17}, {source:2, target:3, value:15}, {source:2, target:4, value:9}, {source:2, target:5, value:1}, {source:3, target:5, value:1}, {source:8, target:0, value:9}, {source:8, target:1, value:2}, {source:8, target:7, value:1}, ] };
Here is an example of code needed to draw a bar chart in Protovis:
// Create the root panel and set the visualization's size to 150x150 var vis = new pv.Panel() .width(150) .height(150); // Add the horizontal rules (grid lines), we add them first so they go in the back. vis.add(pv.Rule) .data(pv.range(0, 2, .5)) .bottom(function(d) d * 80 + 1) .add(pv.Label); // Add the bars with the height corresponding to the values in the data property vis.add(pv.Bar) .data([1, 1.2, 1.7, 1.5, .7]) .width(20) .height(function(d) 80 * d) .bottom(0) .left(function() this.index * 25 + 25) // this.index is the position of the datum in the array .anchor("bottom").add(pv.Label); // Add a label to the bottom of each bar // Render everything. vis.render();
Protovis makes extensive use of property chaining allowing the example above to be written in four statements.