Working through the tutorials from https://d3js.org/
Note: '%%HTML' causes CORS exception. To fix this simply use '%%writefile [filename]' and then the following python code to load in an Iframe. (optionally you can load the file '.js' locally as well)
from IPython.display import IFrame
IFrame("[filename]", width=850, height=150)
In [1]:
%%writefile tutorial.bar.html
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.chart div {
font: 10px sans-serif;
background-color: steelblue;
text-align: right;
padding: 3px;
margin: 1px;
color: white;
}
</style>
<div class="chart"></div>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>
var data = [4, 8, 15, 16, 23, 42];
var x = d3.scale.linear()
.domain([0, d3.max(data)])
.range([0, 420]);
d3.select(".chart")
.selectAll("div")
.data(data)
.enter().append("div")
.style("width", function(d) { return x(d) + "px"; })
.text(function(d) { return d; });
</script>
In [5]:
from IPython.display import IFrame
IFrame("tutorial.bar.html", width=850, height=150)
Out[5]:
In [27]:
%%HTML
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.chart div {
font: 10px sans-serif;
background-color: steelblue;
text-align: right;
padding: 3px;
margin: 1px;
color: white;
}
</style>
<div class="chart"></div>
<script src="d3.v3.min.js"></script>
<script>
var data = [4, 8, 15, 16, 23, 42];
var x = d3.scale.linear()
.domain([0, d3.max(data)])
.range([0, 420]);
d3.select(".chart")
.selectAll("div")
.data(data)
.enter().append("div")
.style("width", function(d) { return x(d) + "px"; })
.text(function(d) { return d; });
</script>
from source
"To use this data in a web browser, we need to download the file from a web server and then parse it, which converts the text of the file into usable JavaScript objects. Fortunately, these two tasks can be performed by a single function, d3.tsv.
Loading data introduces a new complexity: downloads are asynchronous. When you call d3.tsv, it returns immediately while the file downloads in the background. At some point in the future when the download finishes, your callback function is invoked with the new data, or an error if the download failed. In effect your code is evaluated out of order:"
// 1. Code here runs first, before the download starts.
d3.tsv("data.tsv", function(error, data) {
// 3. Code here runs last, after the download finishes.
});
// 2. Code here runs second, while the file is downloading.
In [6]:
%%writefile tutorial.bar2.html
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.chart rect {
fill: steelblue;
}
.chart text {
fill: white;
font: 10px sans-serif;
text-anchor: end;
}
</style>
<svg class="chart"></svg>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var width = 420,
barHeight = 20;
var x = d3.scale.linear()
.range([0, width]);
var chart = d3.select(".chart")
.attr("width", width);
d3.tsv("data.tsv", type, function(error, data) {
x.domain([0, d3.max(data, function(d) { return d.value; })]);
chart.attr("height", barHeight * data.length);
var bar = chart.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", function(d, i) { return "translate(0," + i * barHeight + ")"; });
bar.append("rect")
.attr("width", function(d) { return x(d.value); })
.attr("height", barHeight - 1);
bar.append("text")
.attr("x", function(d) { return x(d.value) - 3; })
.attr("y", barHeight / 2)
.attr("dy", ".35em")
.text(function(d) { return d.value; });
});
function type(d) {
d.value = +d.value; // coerce to number
return d;
}
</script>
In [7]:
%%writefile data.tsv
name value
Locke 4
Reyes 8
Ford 15
Jarrah 16
Shephard 23
Kwon 42
In [8]:
from IPython.display import IFrame
IFrame("tutorial.bar2.html", width=850, height=150)
Out[8]:
from source
"We previously multiplied the var barHeight by the index of each data point (0, 1, 2, …) to produce fixed-height bars. The resulting chart’s height thus depended on the size of the dataset. But here the opposite behavior is desired: the chart width is fixed and the bar width variable. So rather than fix the barHeight, now we compute the barWidth by dividing the available chart width by the size of the dataset, data.length."
...
d3.tsv("data.tsv", type, function(error, data) {
y.domain([0, d3.max(data, function(d) { return d.value; })]);
var barWidth = width / data.length;
...
...
chart.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Frequency");
...
"Unit-appropriate number formatting also improves legibility by tailoring the display to your data. Since our chart displays relative frequency, percentages are more appropriate than the default behavior which shows a number between 0 and 1. A format string as the second argument to axis.ticks will customize the tick formatting, and the scale will automatically choose a precision appropriate to the tick interval."
...
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10, "%");
...
In [14]:
%%writefile tutorial.bar3.vertical.html
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.bar {
fill: steelblue;
}
.bar:hover {
fill: brown;
}
.axis--x path {
display: none;
}
</style>
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 30, left: 40},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
var x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
y = d3.scaleLinear().rangeRound([height, 0]);
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.tsv("data.tutorial3.tsv", function(d) {
d.frequency = +d.frequency;
return d;
}, function(error, data) {
if (error) throw error;
x.domain(data.map(function(d) { return d.letter; }));
y.domain([0, d3.max(data, function(d) { return d.frequency; })]);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y).ticks(10, "%"))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("text-anchor", "end")
.text("Frequency");
g.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.letter); })
.attr("y", function(d) { return y(d.frequency); })
.attr("width", x.bandwidth())
.attr("height", function(d) { return height - y(d.frequency); });
});
</script>
In [13]:
%%writefile data.tutorial3.tsv
letter frequency
A .08167
B .01492
C .02782
D .04253
E .12702
F .02288
G .02015
H .06094
I .06966
J .00153
K .00772
L .04025
M .02406
N .06749
O .07507
P .01929
Q .00095
R .05987
S .06327
T .09056
U .02758
V .00978
W .02360
X .00150
Y .01974
Z .00074
In [26]:
from IPython.display import IFrame
IFrame("tutorial.bar3.vertical.html", width=970, height=530)
Out[26]:
To size, move, etc, simply enter the
from source
"...By appending to the enter selection, we can create new circles for any missing data."
var svg = d3.select("svg");
var circle = svg.selectAll("circle")
.data([32, 57, 112, 293]);
var circleEnter = circle.enter().append("circle");
Modify attributes
circleEnter.attr("cy", 60);
circleEnter.attr("cx", function(d, i) { return i * 100 + 30; });
circleEnter.attr("r", function(d) { return Math.sqrt(d); });
from source
"... you have too many existing elements, and you want to remove some of them. Again you can select nodes and remove them manually, but the exit selection computed by a data join is more powerful."
var circle = svg.selectAll("circle")
.data([32, 57]);
...
circle.exit().remove();
In [31]:
# source: https://bost.ocks.org/mike/constancy/
from IPython.display import IFrame
IFrame("https://bost.ocks.org/mike/constancy/", width=970, height=530)
Out[31]:
In [35]:
%pwd
Out[35]:
In [40]:
from IPython.display import IFrame
IFrame("https://bost.ocks.org/mike/join/", width=970, height=530)
Out[40]:
In [39]:
%%HTML
<style>
@import url(../style.css?aea6f0a);
circle {
fill: none;
fill-opacity: .2;
stroke: black;
stroke-width: 1.5px;
}
</style>
<svg width="720" height="240">
<g transform="translate(0,128)">
<g transform="translate(300)">
<circle r="110" style="fill: rgb(49, 130, 189);"></circle>
<text y="-120" dy=".35em" text-anchor="middle" style="font-weight: bold;">Data</text>
<text x="-50" dy=".35em" text-anchor="middle">Enter</text>
</g>
<text x="360" dy=".35em" text-anchor="middle">Update</text>
<g transform="translate(420)">
<circle r="110" style="fill: rgb(230, 85, 13);"></circle>
<text y="-120" dy=".35em" text-anchor="middle" style="font-weight: bold;">Elements</text>
<text x="50" dy=".35em" text-anchor="middle">Exit</text>
</g>
</g>
</svg>
In [ ]: