AngularJS + D3.js = Radian
UPDATE: Radian is now open source. Read about it on the BayesHive website here.
Courtesy of Hideharu Sakai, this article is also available in Japanese.
I’d just been working on another part of the software, a tool for constructing algebraic representations of dynamical systems (defined by systems of ordinary or stochastic differential equations), and I’d been using the AngularJS framework. It took a while to get used to, but it seemed as though it might, in conjunction with D3.js, provide a way to produce a declarative plotting API that would be really easy to use and could take advantage of the clever data binding features of Angular.
Thus was Radian born: a declarative extension to HTML for rendering data and functional plots as SVG graphics. You can go straight to a gallery of examples here. Details and some more examples below the fold. (Note that, since Radian uses SVG graphics, you’ll need a fairly recent browser to see anything...)
The basic idea
<plot> directive. Within a
<plot> directive, you can place multiple directives specifying different kinds of plots. For example:
<plot height=300 aspect=3 stroke-width=2 x="[[seq(0,4*PI,101)]]" axis-x-label="Time" axis-y-label="sin(x) / cos(x)"> <lines y="[[sin(x)]]" stroke="red"/> <lines y="[[cos(x)]]" stroke="blue"/> </plot>
seq function produces an array of regularly spaced values, and the
cos functions are implicitly vectorised over arrays so that the
y values are calculated as you might expect. (The Radian plotting library includes a bunch of useful functions, all of which exhibit this useful vectorised behaviour, as do arithmetic operators in Radian expressions.) The above code results in the following plot:
Plotting functions is all very well, but we more often need to generate plots based on data–either data uploaded by users or the results of statistical analyses. Radian makes this easy with a directive called
<plot-data>. We can specify data in-line within our HTML page or cause it to be loaded from a URL as required. Here’s an example:
<plot-data name="fam" src="familyr.csv" format="csv" cols="name,age,height,sex,salaryhr"> </plot-data>
We can then use this data in a plot as:
<palette name="mfpal" type="discrete"> female #FF7F7F; male #7F7FFF </palette> <plot height=600 aspect=1 stroke="none" marker="circle" axis-x-label="Age" axis-y-label="Height"> <points x="[[fam.age]]" y="[[fam.height]]" fill="[[mfpal(fam.sex)]]" marker-size="[[30*sqrt(fam.salaryhr)]]"> </points> </plot>
yielding the following figure:
Note how we’ve used a palette here to specify the mapping from gender values to colours–the
Binding to Angular
The relationship between the variable names used in Radian directives and Angular scope variables is designed to make using Angular’s data binding capabilities easy. All attribute names in Radian plotting directives generate Angular scope variables (with nested scopes being created as appropriate), and all free variables in Radian expressions are treated as referring to Angular variables in the enclosing scope. (It helps to understand how Angular scopes work here, of course...)
The upshot of all this is that you can do things like this:
<div class="form-inline"> <label>Mean</label> <input type="range" min=0 max=10 step=0.01 ng-model="mu" ng-init="mu=5"> <label style="margin-left: 20px;">Standard deviation</label> <input type="range" min=0 max=10 step=0.01 ng-model="sigma" ng-init="sigma=1"> </div> <plot height=300 aspect=3 stroke-width=2 stroke="red"> <lines x="[[seq(0,10,200)]]" y="[[normal(x,mu,sigma)]]"/> </plot>
to get the following:
Manipulating the UI elements (bound to Angular variables using
ng-model) leads to immediate changes in the plot.
Radian is very much a work-in-progress. I’m adding new functionality (and fixing bugs) nearly every day. I’m learning a lot as Tom and I use Radian in the BayesHive web app: the examples here and in the gallery are standalone, and don’t really get into the gritty corners of the interactions between Radian and other Angular code. Those gritty corners are being exercised by the integration of Radian into BayesHive, which is essentially a document authoring system oriented towards Bayesian data analysis. The functionality of the system is completely open-ended and every data analysis example we come up with stresses Radian in a different way.
Radian is currently proprietary. There are some contractual encumbrances that prevent us from open-sourcing it right now, but that may change at some point in the future. In the meantime, if you’re interested in learning more, contact me or Tom.