How to leverage d3.js in the noteboook

Because IPython supports HTML and JavaScript representations of Python objects, it is possible to leverage the power of d3.js, even without using the new Widget architecture. These examples help to clarify the differences between regular HTML/JavaScript output and the new Widgets:

Regular HTML/JavaScript output in the notebook is put on the page a single time and subsequently cannot communicate with the backend kernel

Widgets can communicate with the backend kernel bidirectionally at any time after being rendered on the page.

One of the central benefits of using regular HTML/JavaScript output is that the resulting visualizations will work on http://nbviewer.ipython.org for IPython 2.0.

We are working on enabling Widgets on http://nbviewer.ipython.org, but it will probably be another 6 months.

A basic d3.js example

Here is a simple example from the d3 website, which shows how we can use d3 directly in the Notebook.

First, let's create a div for a d3 visualization and define some CSS styles:

In [1]:
%%html

<div id="d3-example"></div>

<style>
.node {stroke: #fff; stroke-width: 1.5px;}
.link {stroke: #999; stroke-opacity: .6;}
</style>

Now let's run the JavaScript code for a d3 example using the %%javascript magic. Note, this is pulling the data (miserables.json) from a local file sitting in the data directory next to this notebook and using the above defined div and CSS.

In [2]:
%%javascript

require.config({paths: {d3: "http://d3js.org/d3.v3.min"}});

require(["d3"], function(d3) {
  var width = 600,
      height = 400;

  var color = d3.scale.category20();

  var force = d3.layout.force()
    .charge(-120)
    .linkDistance(30)
    .size([width, height]);

  var svg = d3.select("#d3-example").append("svg")
    .attr("width", width)
    .attr("height", height);

  d3.json("data/miserables.json", function(error, graph) {
    force.nodes(graph.nodes)
         .links(graph.links)
         .start();

    var link = svg.selectAll(".link")
        .data(graph.links)
        .enter().append("line")
        .attr("class", "link")
        .style("stroke-width", function(d) { return Math.sqrt(d.value); });

    var node = svg.selectAll(".node")
        .data(graph.nodes)
        .enter().append("circle")
        .attr("class", "node")
        .attr("r", 5)
        .style("fill", function(d) { return color(d.group); })
        .call(force.drag);

    node.append("title")
        .text(function(d) { return d.name; });

    force.on("tick", function() {
      link.attr("x1", function(d) { return d.source.x; })
          .attr("y1", function(d) { return d.source.y; })
          .attr("x2", function(d) { return d.target.x; })
          .attr("y2", function(d) { return d.target.y; });

      node.attr("cx", function(d) { return d.x; })
          .attr("cy", function(d) { return d.y; });
    });
  });
});

Vincent/Vega

Vega is a declarative, JSON-based grammar for specifying SVG/Canvas visualizations.

Vincent is a Python plotting library that produces Vega JSON that is automatically rendered as output in the Notebook.

mpld3

Matplotlib is a mature visualization library for Python. When using matplotlib in the notebook it usually produces PNG, JPEG or PDF output.

mpld3 is a recently created Python library that converts matplotlib Figure objects to d3 based visualizations that the notebook can display.

In [3]:
%matplotlib inline
import numpy as np
from matplotlib import pyplot as plt
from mpld3 import enable_notebook, plugins
enable_notebook()
In [7]:
from sklearn.datasets import load_iris

data = load_iris()
X = data.data
y = data.target

# dither the data for clearer plotting
X += 0.1 * np.random.random(X.shape)

fig, ax = plt.subplots(4, 4, sharex="col", sharey="row", figsize=(8, 8))
fig.subplots_adjust(left=0.05, right=0.95, bottom=0.05, top=0.95,
                    hspace=0.1, wspace=0.1)

for i in range(4):
    for j in range(4):
        ax[3 - i, j].scatter(X[:, j], X[:, i],
                             c=y, s=40, alpha=0.3)

# remove tick labels
for axi in ax.flat:
    for axis in [axi.xaxis, axi.yaxis]:
        axis.set_major_formatter(plt.NullFormatter())

# add a reset() button
plugins.connect(fig, plugins.ResetButton())
plt.show()

Plotly

Plotly is a web-based data analysis and plotting tool that has IPython integration and uses d3 for its visualizations.

In [5]:
import plotly
py = plotly.plotly('IPython.Demo', '1fw3zw2o13')
nr = np.random
In [6]:
distributions = [nr.uniform, nr.normal , lambda size: nr.normal(0, 0.2, size=size),
                 lambda size: nr.beta(a=0.5, b=0.5, size=size),
                 lambda size: nr.beta(a=0.5, b=2, size=size)]

names = ['Uniform(0,1)', 'Normal(0,1)', 'Normal(0, 0.2)', 'beta(a=0.5, b=0.5)', 'beta(a=0.5, b=2)']

boxes = [{'y': dist(size=50), 'type': 'box', 'boxpoints': 'all', 'jitter': 0.5, 'pointpos': -1.8,
        'name': name} for dist, name in zip(distributions, names)]

layout = {'title': 'A few distributions',
          'showlegend': False,
          'xaxis': {'ticks': '', 'showgrid': False, 'showline': False},
          'yaxis': {'zeroline': False, 'ticks': '', 'showline': False},
          }

py.iplot(boxes, layout = layout, filename='Distributions', fileopt='overwrite', width=1000, height=650)
Out[6]:
In [ ]: