Hello reviz!

3 reads

This post comes originally from a notebook of mine on Observable. Head over there to view it in its original context with interactive editing.

reviz is a new, open-source library for automatically reverse engineering data visualizations from the DOM. You can think of it almost like a compiler that transforms svg subtrees into partial programs written using Observable Plot. reviz applies a set of deductive heuristics over attributes of an svg subtree to infer a matching visualization type. From there it generates a partial Plot program that, applied to a new dataset, renders a visualization that matches the appearance of the original but targeted at new data. This is a process we and others in the community call visualization retargeting.

To see how reviz works, let’s apply it to a working example with the Penguins dataset used by @Fil in his Plot Exploration notebook.

Choosing an input visualization

First, we need to find an input visualization we want to use as the basis for the one reviz will generate. Let’s use this one from the New York Times. We’ve replicated just the DOM tree here by copying it directly using Firefox’s DOM inspector. In addition, we’ve manually copied over the minimal CSS used by the visualization.

The reviz process

To get started, we’ll need to get a reference to the svg Node containing our input visualization. In Observable we have direct access to the Node via the variable we bound to the cell (nytViz in this case), but you could also use document.querySelector, document.getElementById, or React refs — whatever API is appropriate for accessing the DOM in your specific case!

With a reference to the root svg Node in hand, we now call the analyzeVisualization function from reviz. This single function is the entirety of the reviz API!

You can see that the call to analyzeVisualization returns an Object containing two properties — spec and program.

spec is itself an Object that captures information of interest about the input svg subtree. This includes both geometric attributes, such as the radii of circle elements, and presentational attributes, such as the set of unique fills and strokes encountered in the subtree. spec also includes a top-level type property, which refers to the visualization type reviz has determined the input svg subtree to correspond to. As an early disclaimer, reviz only supports a finite set of visualization types.

program is a string representing the (partial) Observable Plot program reviz generates from the spec. A partial program is one in which small pieces are left empty; these pieces are called “holes” and are denoted in the generated program by the string '??'. By filling in holes with the names of columns from your input dataset, you get a fully working data visualization with the accompanying source code!

Targeting a reviz-generated program at new data

To target the reviz-generated program at new data, all we need to do is fill in the holes! reviz has given us the entirety of this program already — we just need to apply the following diff:

This program generates the following visualization:

We could just as easily use a different set of column names to fill in the holes. Let’s instead compare our penguins’ bill lengths and bill depths to see if there is a correlation between these variables across islands.

Et voilà! We’ve used reviz to automatically visualize our data (multiple times!) using the appearance and chart type of a visualization we found in the wild, all with a single call to analyzeVisualization!

Going further

To make reviz even easier to use in Observable, we include an example function here, revizify, that will automatically fill in holes and render the output visualization for you! It also renders a pretty-printed view of both spec and program so you can more closely examine the inferences reviz is making to reverse engineer a data visualization. Many more examples are available on our example site.

Below, we generate our earlier example using a single call to revizify! You can also see the pretty-printed spec and generated program.

We can even use revizify to see our data using a different input visualization type, like a strip plot. Let’s use Mike Bostock’s D3 Dot Strip Plot as an example. We’ll lift the style of this visualization to look at the distribution of flipper lengths of our penguins across different islands.

With just four lines of code we have a fully functional data visualization and its source code, all thanks to reviz’s automated reverse engineering! With the beauty of Observable imports, this will work with any supported visualization you can find on Observable. Happy charting!

Learn more about reviz!

To learn more about reviz, check out the repo on GitHub. You can also read the short paper to get much more detail into how reviz works under the hood. While you’re there, consider contributing by adding tests, sharing examples, or just giving it a star 🌟. You can also download reviz for use in your own projects from NPM.

Appendix