[PYTHON] Drawing a tree structure with D3.js in Jupyter Notebook

Thing you want to do

I want to draw beautiful tree structure data with Jupyter Notebook or a web application! That is my motivation. I use Python for the convenience of analyzing the original data, and I wanted to repeat the analysis and visualization interactively.

Python There seem to be many ways to draw a tree structure in Python, and the first one that comes to mind is networkx or [graphviz]. I use a graph library such as (https://graphviz.readthedocs.io/en/stable/), but since the purpose is to analyze the graph structure in the first place, I think that elaborate expressions are difficult.

On the other hand, there is ETE Toolkit as a dedicated analysis and visualization tool for tree structures. The model is represented using The Newick format, which seems to be a well-known representation of the tree structure. This also looks pretty good, but considering its affinity on the web, I wanted to use something a little more versatile, such as JSON, to describe the model.

Javascript For drawing graph structure in Javascript, there is a good summary here [https://qiita.com/d0nchaaan/items/c47dc74cfefd92516e28). There are various things, but in terms of versatility and the amount of information, I think it is D3.js. There is also a library for drawing trees.

So, I will try to draw a tree structure with D3.js using Jupyter Notebook. Jupyter Notebook has a good affinity from the beginning because it can execute Javascript and draw HTML while using the Python kernel by using cell magic (%% javascript).

Using D3.js with Jupyter Notebook

As a method, you can use Javascript cell magic or py_d3. Well, the former is difficult to understand intuitively using RequireJS (see here). The latter seems to wrap Javascript's cell magic nicely. Here, I will explain drawing using py_d3.

Preparation

Anyway, install py_d3. Use pip. pip install py_d3 First, load the module as follows:

import py_d3
py_d3.load_ipython_extension(get_ipython())

The following is a sample quote from the home page. The first %% d3 5.12.0 specifies the version of d3.js. You can find out which version is available by typing % d3 version.


%%d3 5.12.0

<g></g>

<style>
element {
    height: 25px;
}
div.bar {
    display: inline-block;
    width: 20px;
    height: 75px;
    margin-right: 2px;
    background-color: teal;
}
</style>

<script>
var dataset = [ 5, 10, 13, 19, 21, 25, 22, 18, 15, 13,
                11, 12, 15, 20, 18, 17, 16, 18, 23, 25 ];

d3.select("g").selectAll("div")
    .data(dataset)
    .enter()
    .append("div")
    .attr("class", "bar")
    .style("height", function(d) {
        var barHeight = d * 5;
        return barHeight + "px";
    });
</script>

You can check the output of the graph as shown below. image.png

Data linkage with Python

By making full use of RequireJS, it is possible to input objects and variables calculated in Python into the defined Javascript function. However, it is not much different from outputting as JSON and reading with d3.js, so if the data is not very large, it is easy to go through the intermediate file. For example, prepare a JSON file with a tree structure as shown below.

import json
data = {
    "name": "A",
    "children": [
      { "name": "B" },
      {
        "name": "C",
        "children": [{ "name": "D" }, { "name": "E" }, { "name": "F" }]
      },
      { "name": "G" },
      {
        "name": "H",
        "children": [{ "name": "I" }, { "name": "J" }]
      },
      { "name": "K" }
    ]
  };
json_file = open('test.json', 'w')
json.dump(data, json_file)

Drawing of tree structure

Use the tree layout of d3 hierarchy to draw the tree structure. After loading the JSON data structure and creating a tree based on that data, all you have to do is adjust the SVG drawing. Please refer to the d3.js and SVG documents for fine adjustment of drawing.

%%d3 5.12.0

<style>
.link {
fill: none;
stroke: #555;
stroke-opacity: 0.4;
stroke-width: 1.5px;
}
</style>

<svg width="800" height="600"></svg>

<script>
var width = 800;
var height = 600;

var g = d3.select("svg").append("g")
    .attr("transform", "translate(80,0)");
     console.log("data");


d3.json("test.json")
    .then((data) => {
        console.log(data);
        var root = d3.hierarchy(data);
        var tree = d3.tree(root).size([height, width - 160]);
        tree(root);

        var link = g.selectAll(".link")
            .data(root.descendants().slice(1))
            .enter()
            .append("path")
            .attr("class", "link")
            .attr("d", (d) => {
                return "M" + d.y + "," + d.x +
                    "C" + (d.parent.y + 100) + "," + d.x +
                    " " + (d.parent.y + 100) + "," + d.parent.x +
                    " " + d.parent.y + "," + d.parent.x;
            });

        var node = g.selectAll(".node")
            .data(root.descendants())
            .enter()
            .append("g")
            .attr("class", "node")
            .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })

        node.append("circle")
            .attr("r", 8)
            .attr("fill", "#999");

        node.append("text")
            .attr("dy", 3)
            .attr("x", function(d) { return d.children ? -12 : 12; })
            .style("text-anchor", function(d) { return d.children ? "end" : "start"; })
            .attr("font-size", "200%")
            .text(function(d) { return d.data.name; });
        })
   .catch((error)=>{
    
   }
)
</script>

image.png

reference

  1. Summary of 7 network graph drawing libraries
  2. How to use D3.js v4 / v5 tree-Sample
  3. Rich data visualization with Jupyter Notebook x d3.js
  4. Custom D3.js Visualization in a Jupyter Notebook

Recommended Posts

Drawing a tree structure with D3.js in Jupyter Notebook
Make a sound with Jupyter notebook
Draw a graph with Japanese labels in Jupyter
Graph drawing with jupyter (ipython notebook) + matplotlib + vagrant
To output a value even in the middle of a cell with Jupyter Notebook
Using Graphviz with Jupyter Notebook
Display HTML in Jupyter notebook
Use pip with Jupyter Notebook
Multiprocessing error in Jupyter Notebook
Use Cython with Jupyter Notebook
Play with Jupyter Notebook (IPython Notebook)
Graph drawing with IPython Notebook
Machine learning with Jupyter Notebook in OCI Always Free environment (2019/12/17)
Reflect the virtual environment created with Miniconda in Jupyter notebook
Opens in a new window when launching Jupyter Notebook (Windows)
I want to use a virtual environment with jupyter notebook!
The usual way to add a Kernel with Jupyter Notebook
Write charts in real time with Matplotlib on Jupyter notebook
View dynamic graphs in Jupyter notebook. (Inline display of D3.js)
How to import NoteBook as a module in Jupyter (IPython)
Try clustering with a mixed Gaussian model on a Jupyter Notebook
Automatically opens in a new window when launching Jupyter Notebook
Allow external connections with jupyter notebook
How to batch start a python program created with Jupyter notebook
Formatting with autopep8 on Jupyter notebook
Git management of Jupyter notebook (ipynb) differences in easy-to-read with JupyterLab
Post a Jupyter Notebook as a blog post
Creating a decision tree with scikit-learn
Visualize decision trees with jupyter notebook
I wanted to create a smart presentation with Jupyter Notebook + nbpresent
Generate Jupyter notebook ".ipynb" in Python
Build a comfortable psychological experiment / analysis environment with PsychoPy + Jupyter Notebook
Use markdown with jupyter notebook (with shortcut)
Add more kernels with Jupyter Notebook
View graphs inline in Jupyter Notebook
Convenient analysis with Pandas + Jupyter notebook
3D drawing with SceneKit in Pythonista
Take a look at the built-in exception tree structure in Python 3.8.2
[Small story] How to save matplotlib graphs in a batch with Jupyter
I wanted to use jupyter notebook with docker in pip environment (opticspy)
Make a decision tree from 0 with Python and understand it (4. Data structure)
Spiral book in Python! Python with a spiral book! (Chapter 14 ~)
Use nb extensions with Anaconda's Jupyter notebook
Use apache Spark with jupyter notebook (IPython notebook)
Output tree structure of files in Python
Try drawing a simple animation in Python
Try drawing a normal distribution with matplotlib
[Python] Drawing a swirl pattern with turtle
Draw a heart in Ruby with PyCall
Use Jupyter Lab and Jupyter Notebook with EC2
Make Jupyter Notebook a service on CentOS
Try SVM with scikit-learn on Jupyter Notebook
Make a Notebook Pipeline with Kedro + Papermill
How to execute commands in jupyter notebook
Make a drawing quiz with kivy + PyTorch
How to use jupyter notebook with ABCI
Linking python and JavaScript with jupyter notebook
Draw a tree in Python 3 using graphviz
Try drawing a map with python + cartopy 0.18.0
[Jupyter Notebook memo] Display kanji with matplotlib
Run Jupyter notebook on a remote server