Callysto.ca Banner

Open in Callysto

Animations in D3

from IPython.core.display import display, HTML

html_text = '''
<div id="myDisplay"></div>
<script> 
    require.config({paths: {d3: "https://d3js.org/d3.v5.min"}});
    require(["d3"], function(d3) {
        var mySVG = d3.select("#myDisplay") 
          .append("svg")
          .attr("width", 300)
          .attr("height", 300);    
       mySVG.append("circle")
          .style("fill", "red")
          .attr("r", 130)
          .attr("cx", 150)
          .attr("cy", 150)
          .transition()
             .delay(100)
             .duration(20000)  
             .attr("r", 10)
             .attr("cx", 290)
             .style("fill", "blue");             
    });
</script>
'''

display(HTML(html_text))

Reload the page

to restart the animation. It only runs for 20 seconds.

Notes on the above animation

This is a very simple D3 animation, which should work in any Jupyter hub as well as on a Jupyter book. We kept is as simple as possible, to show the main feature of how to use D3 in a Jupyter noteboo.

In the above code, we create some html text which includes a place (div) to display some material, then some javascript code (script) to create an svg canvas to draw in, then draw a circle and animate it.

Notes on D3

D3 is an amazing collection of tools for creating Data Driven Documents (DDD = D3). It is also a great tool for creating animations. You can read about it here: https://d3js.org/

Several issues arise in using D3. First, it is written in Javascript so you need to learn Javascript to do this well. Second, your Jupyter notebook has security measures in place to avoid what it suspects might be malicious (dangerous) code. Third, the D3 libraries and the Jupyter security keeps changing, so code you write today may become inoperative in a just a few months. So be carefu!

To learn Javascript you can search online for tutorials.

To get your notebook to bypass security, we write the Javascript code in into a text file, then use the display and HTML functions from module IPython.core.display This is what works in Summer 2020. Last year, we did it a different way, which no longer works. We then use some Python code to load in this .html code.

Fancier code

Often we like to split up our HTML code into portions for CSS commansd (Cascading Style Sheets), Javascipt code, and then the body of the HTML document.

Here is an example we found at: https://www.bogotobogo.com/python/IPython/iPython_Jupyter_Notebook_with_Embedded_D3.php

First step is to load in the a few Python modules to help us out.

from IPython.core.display import display, HTML
from string import Template
import json

Next, we create an HTML template, some CSS text (empty) and a Javascript template. We will pass variables and text to the templates using the substitute command.

html_template = Template('''
<style> $css_text </style>
<div id="animation"></div>
<script> $js_text </script>
''')

css_text = '''
'''

js_text_template = Template('''
    require.config({paths: {d3: "https://d3js.org/d3.v5.min"}});
    require(["d3"], function(d3) {
        console.log("in require");
        console.log(d3.version)
        console.log(d3)
        var bogoSVG = d3.select("#$bogoanimation") 
          .append("svg")
          .attr("width", 300)
          .attr("height", 300);    

        var data = $python_data ;
        bogoSVG.append("circle")
          .style("stroke", "gray")
          .style("fill", "cyan")
          .attr("r", data[0]['r'])
          .attr("cx", data[0]['cx'])
          .attr("cy", data[0]['cy'])
          .transition()
             .delay(100)
             .duration(20000)  
             .attr("r", 10)
             .attr("cx", data[0]['cx'])
             .style("fill", "blue"); 
            
       });
       
''')

At this point, we use the substitute command to fill in the various data into the open variables in the templates. Then we call display(HTML(…)) as in the first example.

js_text = js_text_template.substitute({'python_data': json.dumps([{'r': 130, 'cx': 150, 'cy': 150}]),
                                       'bogoanimation': 'animation'})


display(HTML(html_template.substitute({'css_text': css_text, 'js_text': js_text})))

Reload the page

to restart the animation. It only runs for 20 seconds.

And that’s it.

Some things to look out for:

  • we need the require and require.config commands to load in the D3 files properly.

  • it is possible to use the ##javascipt magic command directly. But it does not work with Jupyter Book.

  • you will need to read the D3 documentation and learn the Javascript programming language to make good use of this tool.

Callysto.ca License