Ok, it’s been a few days since I last blogged on this topic. One thing you might notice is that I no longer call this D3JS Reusable Charting Patterns. There is good reason for this; I realized that there is no reason that this pattern could not easily integrate D3JS with other powerful visualization facilities such as WebGL or even Processing scripts. So why limit yourself? I will demonstrate this later.
At the core of every charting component is a single prototype called DexComponent. This component provides core capabilities and a base contract that each and every charting component will honor.
The nice thing is that DexComponent is the man behind the curtain. You never have to worry about it.
What Mike Bostock has achieved with D3JS is amazing. I can not understate my admiration for what Mike has achieved with D3JS. It’s an immensely flexible and powerful visualization framework. However, it has a steep learning curve which will limit it’s userbase.
After all, why should users struggle with such mundane issues as:
- Canvas coordinates: My data is cartesian, how do i translate that to a canvas?
- Data Transformation: The data I have is in format X, but this visualization needs format Y. This other visual needs yet anothe format.
- Math: I didn’t listen well enough in Geometry, Triginometry or Linear Algebra. Turns out this is very useful stuff in D3.
Why should users have to worry about all this when all they really want to do is chuck some data into a visualization and share it with others? Let’s abstract these concerns away through flexible and reusable components and provide them with the tools they need in order to simply focus on the task at hand; visualizing, understanding their data and communicating this understanding to others in an efficient and pain-free manner.
This is key. In order to really take off, users must contribute their work back into the reusable charting library. In turn, these reusable components should evolve in a vibrant ecosystem where great replaces good replaces poor. A meritocracy of visual components where everyone works together and contributes. Good components deprecate poor ones and great components deprecating the good ones.
Currently, DexComponent provides only a handful of services:
- Configuration : Univeral access to the chart’s configuration.
- Debugging : (dump and debug flags)
- A base contract for rendering and updating components: (update and render)
- An eventing system: (addListener and notify)
Since DexComponent implements these services centrally, this takes the burden off of each derived component. It also provides a central place to implement central functionality we might need later as new requirements emerge.
While it goes against my nature, I am starting with a small set of commonly used components.
- Line Charts
- Bar Charts
- Pie Charts
- Status Windows
This will keep the framework agile as the architecture gets refactored. Also, you can achieve an amazing amount of effective visualization with these basic components.
A ScatterPlot is a very simple and very basic component which simply graphs X versus Y. It should be simple to achieve and easy to integrate into other composite views.
Here is a simple reusable code for a ScatterPlot, currently implemented with very few frills.
This example creates an SVG to hold our chart, then instantiates and renders a scatterplot.
An interactive version can be found here:
Nothing too spectacular, but pretty simple to use. Here is where it gets interesting. Typically you will find one example for a scatterplot, another for a scatterplot matrix, yet another for a scatterplot configured differently. Let’s implement the scatterplot matrix with our reusable code.
Scatter Plot Matrix
SPLOM is a fairly complicated visualization component as found in Mike Bostock’s examples. However we are able to get this component virtually for free. Better still, it will evolve capabilities as our base ScatterPlot evolves.
Essentially, all we do differently is create 1 scatterplot per x/y combination and tell the scatterplot that we are interested in viewing the x column specified in xi (x index) versus the y column in yi (y index).
The resulting view is surprisingly powerful. I was surprised to see that I didn’t even have to worry about coding listeners to coordinate the views.
Please note that this component isn’t ready. My intention is to present the power of this concept only.
Deriving responsive chart interactivity is also pretty simple. I’ve covered it before, but it’s evolved over the past week so I’ll cover it again.
Consider this code which implements a scatterplot and a linechart. The linechart responds to the brushed selections of the scatterplot.
And a live version can be found here:
Last, but not least, here is beginnings of a reusable BarChart. Here is a code sample:
This code illustrates a couple of important points.
- We can instantiate a base chart then reuse this base to create other charts.
- We can reconfigure the pieces that need to be different in these derivative charts and render them all in a single line.
- The “yi” attribute specifies which group of data columns to chart. Effectively removing the need for one bar chart for single series and another for grouped series. This kind of refactoring makes life easier.
Here is the live sample:
I hope that you are as excited about the possibility of easy to use and highly configurable charts as I am. I am hoping to foster a movement that brings previously high expertise technologies such as WebGL, Processing and D3 into the hands of the masses. The ultimate goal being the creation of data visualizations that help us better understand our world.
Also, while I have not talked much about it yet, I hope to marry these generic visualizations together with Machine Learning analytic algorithms such as Genetic Programming, SVG, Logistic Regression, etc… so that we can truly interact and explore the data we are given. However, this part of the vision is further down the road (6 months or more).
While postive feedback is motivational, suggestions and criticism are even more welcome. Feedback will help in the evolution of these concepts.
Thanks for listening…
Since you made it this far, here are a few more examples which I did not talk about in depth: