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))
to restart the animation. It only runs for 20 seconds.
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.
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.
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})))
to restart the animation. It only runs for 20 seconds.
Some things to look out for: