While reflecting on the state of my GitHub repos yesterday, I was thinking how cool things would be if I used D3.

Previously I came across Mike Irvine's personal website and I really like how he made the dynamic D3 visual, showcasing the spread of disease in a community (ie. related to his work), as the first thing one notices when they come across his page.

I want to do something similar for my personal website.

Editor for D3

Before I begin, I want an interactive development environment (IDE) for D3. In my search I came across the following:

IDE Rating
D3.js playground
Tributary
JSFiddle

Embedding D3 in Jupyter Notebooks

I also came across embedding D3 in Jupyter Notebooks with py_d3.

  1. Install py_d3 with pip install py_d3
  2. Run %load_ext py_d3 in Jupyter Notebook for Jupyter notebook D3 block magic

In [1]:
%load_ext py_d3

Include D3 script:


In [2]:
%%d3
<script src="https://d3js.org/d3.v3.js"></script>


Example 01: Hello world


In [4]:
%%d3

<div></div>

<script>
d3.select("div").text("Hello world")
</script>


Example 02: Simple rectangle


In [5]:
%%d3

<g></g>

<script>
    d3.select("g").append("svg").append("rect")
      .attr("x", 150)
      .attr("y", 50)
      .attr("width", 50)
      .attr("height", 140);
</script>


Example 03: Functions, style, and polygons


In [6]:
%%d3

<g></g>

<script>
function CalculateStarPoints(centerX, centerY, arms, outerRadius, innerRadius) {
  var results = "";
  var angle = Math.PI / arms * 2;

  for (var i = 0; i < 2 * arms; i++) {
    var r = (i & 1) == 0 ? outerRadius : innerRadius;
    var pointX = centerX + Math.cos(i * angle) * r;
    var pointY = centerY + Math.sin(i * angle) * r;
    // Our first time we simply append the coordinates, subsequet times
    // we append a ", " to distinguish each coordinate pair.
    if (i == 0) {
      results = pointX + "," + pointY;
    } else {
      results += ", " + pointX + "," + pointY;
    }
  }
  return results;
}

d3.select("g").append("svg")
  .append("polygon")
  .attr("visibility", "visible")
  .attr("points", CalculateStarPoints(100, 100, 5, 30, 15));

d3.select("g").append("svg")
  .append("polygon")
  .attr("visibility", "visible")
  .attr("points", CalculateStarPoints(100, 100, 5, 30, 15))
  .style("fill", "lime")
  .style("stroke", "purple")
  .style("stroke-width", "5")
  .style("fill-rule","evenodd");
</script>


Kink with using Jupyter Notebook

When I load the Collision Detection example by Mike Bostock in the Jupyter Notebook, it doesn't work. Nothing is rendered (see following). However, this is not an issue with JSFiddle.


In [7]:
%%d3

<script src="https://d3js.org/d3.v3.js"></script>

This example is modified from <a href="https://bl.ocks.org/mbostock/3231298">https://bl.ocks.org/mbostock/3231298</a>

<body></body>

<script>
var width = 500,
  height = 500;

var nodes = d3.range(200).map(function() {
    return {
      radius: Math.random() * 12 + 4
    };
  }),
  root = nodes[0],
  color = d3.scale.category10();

root.radius = 0;
root.fixed = true;

var force = d3.layout.force()
  .gravity(0.05)
  .charge(function(d, i) {
    return i ? 0 : -1500;
  })
  .nodes(nodes)
  .size([width, height]);

force.start();

var svg = d3.select("body").append("svg")
  .attr("width", width)
  .attr("height", height);

svg.selectAll("circle")
  .data(nodes.slice(1))
  .enter().append("circle")
  .attr("r", function(d) {
    return d.radius;
  })
  .style("fill", function(d, i) {
    return color(i % 3);
  });

force.on("tick", function(e) {
  var q = d3.geom.quadtree(nodes),
    i = 0,
    n = nodes.length;

  while (++i < n) q.visit(collide(nodes[i]));

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

svg.on("mousemove", function() {
  var p1 = d3.mouse(this);
  root.px = p1[0];
  root.py = p1[1];
  force.resume();
});

function collide(node) {
  var r = node.radius + 16,
    nx1 = node.x - r,
    nx2 = node.x + r,
    ny1 = node.y - r,
    ny2 = node.y + r;
  return function(quad, x1, y1, x2, y2) {
    if (quad.point && (quad.point !== node)) {
      var x = node.x - quad.point.x,
        y = node.y - quad.point.y,
        l = Math.sqrt(x * x + y * y),
        r = node.radius + quad.point.radius;
      if (l < r) {
        l = (l - r) / l * .5;
        node.x -= x *= l;
        node.y -= y *= l;
        quad.point.x += x;
        quad.point.y += y;
      }
    }
    return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
  };
}
</script>


This example is modified from https://bl.ocks.org/mbostock/3231298