Autotranslation: Python to JavaScript and D3

Generate a random graph with Python, then visualize it with a D3 interactive, force-directed graph.

The first cell imports the BeakerX package and initializes the runtime.

Then we generates the graph (one made of nodes and edges, like a social network graph) and store it in the BeakerX object.

Then we load D3 and set its styles.

Finally, a JavaScript cell gets the data from the BeakerX object and renders it with D3.

This final cell was copied almost verbatim from the D3 documentation. Other D3 examples should be similarly easy to get working in BeakerX.


In [ ]:
from beakerx import beakerx

In [ ]:
from random import randrange
import math

nnodes = 100

nodes = []
links = []

for i in range(0, nnodes):
    nodes.append({"name": str(i), "group": int(i*7/nnodes)})

for i in range(0, int(nnodes*1.15)):
    source = i % nnodes
    target = int(math.log(1 + randrange(nnodes), 1.3))
    value = 10.0 / (1 + abs(source - target))
    links.append({"source": source, "target": target, "value": value * value})

beakerx.graph = {"nodes":nodes, "links":links}

In [ ]:
%%javascript
require.config({
  paths: {
      d3: '//cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.min'
  }});

In [ ]:
%%html
<style>
.node {
  stroke: #fff;
  stroke-width: 1.5px;
}

.link {
  stroke: #999;
  stroke-opacity: .6;
}
</style>

In [ ]:
%%javascript

beakerx.displayHTML(this, '<div id="fdg"></div>');

var graph = beakerx.graph

var d3 = require(['d3'], function (d3) {
    
    var width = 600,
        height = 500;

    var color = d3.scaleOrdinal(d3.schemeCategory20);

    var simulation = d3.forceSimulation()
        .force("link", d3.forceLink().distance(30))
        .force("charge", d3.forceManyBody().strength(-200))
        .force("center", d3.forceCenter(width / 2, height / 2))
        .force("y", d3.forceY(width / 2).strength(0.3))
        .force("x", d3.forceX(height / 2).strength(0.3));

    var svg = d3.select("#fdg")
                .append("svg")
                .attr("width", width)
                .attr("height", height)
                .attr("transform", "translate("+[100, 0]+")");

    simulation
          .nodes(graph.nodes)
          .force("link")
          .links(graph.links);

    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", 10)
          .style("fill", function(d) { return color(d.group); });

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

    simulation.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; });
    });
    
    node.call(d3.drag()
        .on("start", dragstarted)
        .on("drag", dragged)
        .on("end", dragended)
    );
    
    function dragstarted(d) {
        if (!d3.event.active) simulation.alphaTarget(0.3).restart();
        d.fx = d.x;
        d.fy = d.y;
    }

    function dragged(d) {
        d.fx = d3.event.x;
        d.fy = d3.event.y;
    }

    function dragended(d) {
        if (!d3.event.active) simulation.alphaTarget(0);
        d.fx = null;
        d.fy = null;
    }
});

In [ ]: