A d3 experiment on my Tinkerer blog
Mar 15, 2016
warning
This post is more than 5 years old. While math doesn't age, code and operating systems do. Please use the code/ideas with caution and expect some issues due to the age of the content. I am keeping these posts up for archival purposes because I still find them useful for reference, even when they are out of date!
This blog uses Tinkerer (at the time this post was written; now it's actually 11ty), which is based on the Sphinx documentation framework, to create static html pages from rest (rst) markup. If you are familiar with the Python world you've probably created documentation using Sphinx, or at the very least, you have read documenation created in Sphinx. Because the setup is Python-focused, it is not straightforward to write posts that employ javascript libraries like d3js . This post describes my method for doing javascript examples in Tinkerer blog posts or Sphinx docs, as well as how to do some d3js.
Raw javascript
First, let's consider a simple javascript example without using d3js. I will create an html-div as well as two buttons that use javascript to insert some text. In the rst markup the div and buttons are created using
.. raw:: html
<div id="js_ex"
style="padding: 20px 0px;">
<p id="js_ex_text"
style="padding: 10px; background: #111; color: #eee;">
-- click write and clear ---
</p>
<button id="js_ex_write">
write
</button>
<button id="js_ex_clear">
clear
</button>
</div>
The result of the above code is shown below:
-- click write and clear ---
The raw:: html
tag in the rst markup
makes Tinkerer/Sphinx insert the
html into the document. Next, we can use javascript to change the text using
some click events. In the rst document I have:
.. raw:: html
<script type='text/javascript'>
p = document.getElementById('js_ex_text');
buttonWrite = document.getElementById('js_ex_write');
buttonWrite.onclick = function() {
p.innerHTML = 'Hello <strong>js</strong> world!';
};
buttonClear = document.getElementById('js_ex_clear');
buttonClear.onclick = function() {
p.innerHTML = ' -- nothing here, click write --';
};
</script>
Notice that the .. raw:: html
tag is used
again and the javascript is surrounded by the
script
tags
-- just as you would have to do in normal, inline html markup.
Okay, now let's integrate some d3js into a Tinkerer post or Sphinx document.
Using d3
Linking d3
The first step in using d3js is to link to the library. I'm sure there are a variety of ways to do this, but I chose to link to the library on all pages.
Given this choice, there is a standard way to add external javascript files --
see
Enabling Google Analytics
for an example of adding
google analytics js to a Tinkerer blog. In my case, I added
d3.min.js
(you can get the latest
version here:
d3 at github
to the _static
directory and
modified the page.html
template in my
theme -- see
page template example
-- to include the following:
{% raw %}
{%- extends "layout.html" -%}
{% set script_files = script_files + ["_static/d3.min.js"] %}
{% endraw %}
This tells Tinkerer to link the d3.min.js
in the header of each page. If
you are not working with a theme, create a directory
_templates
and add the file
page.html
with the above content. The
organization would be something like this (where
conf.py
and master.rst
are in the base directory
of the blog):
├── conf.py
├── master.rst
├── _static
│ ├── d3.min.js
├── _templates
├── page.html
That should work as well.
Using d3 in a post
Finally, here's a little experiment using d3js that is motivated by the classic {% sbUrl refs["3 circles"] %} three little circles example. As with the simple javascript example we have to setup an html-div that will be used:
.. raw:: html
<div id='vizdiv' style="padding: 20px 0px;">
</div>
Let's put it here:
Next, we use the following d3 code to draw some circles using data:
var data = [{r: 5, cy: 100, cx: 100},
{r: 10, cy: 100, cx: 200},
{r: 15, cy: 100, cx: 300}];
var root = d3.select('#vizdiv').append('svg')
.attr('width', 400)
.attr('height', 200);
root.selectAll('circle')
.data(data).enter()
.append('circle')
.attr('r', function(d) {return d.r;})
.attr('cx', function(d) {return d.cx;})
.attr('cy', function(d) {return d.cy;})
.attr('fill', 'steelblue');
In the rst markup for the post, this actually has to look like this:
.. raw:: html
<script type='text/javascript'>
var data = [{r: 5, cy: 100, cx: 100},
{r: 10, cy: 100, cx: 200},
{r: 15, cy: 100, cx: 300}];
var root = d3.select('#vizdiv').append('svg')
.attr('width', 400)
.attr('height', 200);
root.selectAll('circle')
.data(data).enter()
.append('circle')
.attr('r', function(d) {return d.r;})
.attr('cx', function(d) {return d.cx;})
.attr('cy', function(d) {return d.cy;})
.attr('fill', 'steelblue');
</script>
Again, notice that we have to use
.. raw:: html
and the
script
tags!
Okay, that's it. Now I'm setup to talk more about javascript and d3 on the blog -- very nice! If you have other ways to do this, again, please leave a comment!