The R/horizon package is an htmlwidgets-based R package for making horizon plots with the cubism.js library. Cubism.js is aimed towards "real time" dashboards, fetching time series data incrementally. R/horizon focuses just on making horizon plot of a static data set.
Here, I'll describe briefly how I created the package.
I started with this gist: https://gist.github.com/bae25/10797393, which itself is based on this demo.
The first thing to do was to tear apart the HTML, CSS, and Javascript into three separate files.
Next, I want to turn the thing into a function that takes some data. The main task, in doing so, is to pull out the code that reads data from files, which in the original gist and demo were deep inside things, and have that be way on the outside.
My first successful attempt is at https://github.com/kbroman/cubism_test/blob/master/script.js.
The next thing that was confusing was the x-axis scale. It turns out the cubism expects evenly-spaced data, with a single pixel per time point.
The code
cubism.context()
is the main initializer of everything, and
.size()
is going to be the number of data points. I don't completely
understand .serverDelay()
and .step()
, but note that
.stop()
is used to stop trying to grab data externally.
The next confusing bit was that Cubism doesn't make a single graphic,
but rather each horizontal segment (that is, each separate time
series) exists in a separate <canvas>
within a separate <div>
.
The horizontal rules bordering each is controlled in the CSS.
These things are created by calls to
context.horizon()
The upper and lower axes are separate SVGs, and their placement at the
very top and bottom was controlled in the CSS. These are created by
calls to context.axis()
context.horizon()
and context.axis()
each return a function that,
when called, will create the actual objects. These can be done both at
once, as I've done for
.horizon()
,
or in separate pieces, as I've done for
.axis()
.
To make the horizon plots accessible from R, we need to create a separate R package.
You can use the htmlwidgets::scaffoldWidget
function to create the
basic "scaffolding", or you can just do it by hand.
Create a directory /inst/htmlwidgets/lib
.
Put D3.js code in inst/htmlwidgets/lib/d3
Put Cubism.js code in inst/htmlwidgets/lib/cubism
.
I put the basic function to make the horizon plot, plus related CSS
code, within
inst/htmlwidgets/lib/cubism_horizon
.
Within inst/htmlwidgets
, create a
horizon.yaml
file that indicates the dependencies (on D3, Cubism, and the special
cubism_horizon.js
and cubism_horizon.css
.
Also within inst/htmlwidgets
, create a
horizon.js
file that contains a call to HTMLWidgets.widget()
. This defines
three separate function: initialize
, renderValue
(which calls the
main function to make the plot), and resize
(which you can use to
re-size the plot).
The functions pass around a <div>
in which you'll place the actual plot.
I futz around a bit here to try to pass the height of the widget to
my cubism_plot()
function.
Within R
, create an R function that reorganizes the data and any
other plotting options and passes them to
htmlwidgets::createWidget
.
You can use sizingPolicy
to control the default sizes (and
padding) of the chart in different contexts.
You can also define Shiny bindings, for creating the chart within a Shiny app.
I had a whole bunch of messing around with sizes of things. Mostly, I'm taken the height of the plot as given, and I'm not trying to control the width at all, but rather leaving at the Cubism default of 1 pixel per time point.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.