In [1]:
import ipywidgets as widgets
from traitlets import Unicode, List, Int

In [2]:
%%javascript

var s = document.createElement("style");
s.innerHTML = `
path {
  stroke: #fff;
}

path:first-child {
  fill: yellow !important;
}

circle {
  fill: #000;
  pointer-events: none;
}

.q0-9 { fill: rgb(197,27,125); }
.q1-9 { fill: rgb(222,119,174); }
.q2-9 { fill: rgb(241,182,218); }
.q3-9 { fill: rgb(253,224,239); }
.q4-9 { fill: rgb(247,247,247); }
.q5-9 { fill: rgb(230,245,208); }
.q6-9 { fill: rgb(184,225,134); }
.q7-9 { fill: rgb(127,188,65); }
.q8-9 { fill: rgb(77,146,33); }`;

document.getElementsByTagName("head")[0].appendChild(s);



In [3]:
class MyD3(widgets.DOMWidget):
    _view_name = Unicode('HelloView').tag(sync=True)
    _view_module = Unicode('myd3').tag(sync=True)
    width = Int().tag(sync=True)
    height = Int().tag(sync=True)
    vertices = List().tag(sync=True)

In [4]:
%%javascript
require.undef('myd3');

define('myd3', ["@jupyter-widgets/base",
                "https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.js"], function(widgets, d3) {
    
    var HelloView = widgets.DOMWidgetView.extend({
        
        render: function() { 
            var that = this;
            this.width = this.model.get('width');
            this.height = this.model.get('height');
            that.vertices = this.model.get('vertices');
            
            that.voronoi = d3.geom.voronoi()
                .clipExtent([[0, 0], [that.width, that.height]]);

            this.svg = d3.select(this.el).append("svg")
                .attr("width", that.width)
                .attr("height", that.height)
                .on("mousemove", function() { 
                    that.vertices[0] = d3.mouse(this);
                    that.redraw();
                });
            
            var g1 = this.svg.append("g");
            this.path = g1.selectAll("path");
            var g2 = this.svg.append("g");
            this.circle = g2.selectAll("circle");

            this.model.on('change:vertices', this.update_vertices, this);
            this.redraw();
        },
        
        update_vertices: function() {
            this.redraw();
        },
        
        redraw: function () {
          this.vertices = this.model.get('vertices');

          this.path = this.path
              .data(this.voronoi(this.vertices), this.polygon);
          this.path.exit().remove();
          this.path.enter().append("path")
              .attr("class", function(d, i) { return "q" + (i % 9) + "-9"; })
              .attr("d", this.polygon);
          this.path.order();

          this.circle = this.circle
              .data([]);
          this.circle.exit().remove();
         
          this.circle = this.circle
              .data(this.vertices.slice(1));        

          this.circle.enter().append("circle")
            .attr("transform", function(d) { 
              return "translate(" + d + ")";
            })
            .attr("r", 1.5);
        },
        
        polygon: function (d) {
          return "M" + d.join("L") + "Z";
        }
    });
    
    return {
        HelloView : HelloView
    };
});



In [5]:
import numpy as np
sample_size = 100
width = 750
height = 300

m = MyD3(vertices=(np.random.rand(sample_size, 2) * np.array([width, height])).tolist(),
     height=height, width=width)
m



In [6]:
m.vertices = (np.random.rand(sample_size, 2) * np.array([width, height])).tolist()

In [ ]: