Skip to content

Instantly share code, notes, and snippets.

@llimllib
Last active September 6, 2018 18:12
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save llimllib/841dd138e429bb0545df to your computer and use it in GitHub Desktop.
Save llimllib/841dd138e429bb0545df to your computer and use it in GitHub Desktop.
Table With Embedded Line Chart

Given a CSV, generate a table from the data, then append a chart to the final column.

I'd like to be able to put the chart in other columns, but I haven't yet figured out a neat way to do so.

In this case, we're showing the results for Borussia Dortmund so far this season, and how their rating has changed as a result. Check out the code to generate the ratings if that interests you.

mu sigma opp result date
1662.30921255 290.31746003 FC Augsburg 1 2013-08-10T00:00:00
1720.31516965 260.486532706 TSV Eintracht Braunschweig 1 2013-08-18T00:00:00
1833.29188401 225.673906004 Werder Bremen 1 2013-08-23T00:00:00
1857.5300504 214.245325191 Eintracht Frankfurt 1 2013-09-01T00:00:00
1875.73400724 205.674370682 Hamburg SV 1 2013-09-14T00:00:00
1784.18071145 185.716271567 Napoli 0 2013-09-18T00:00:00
1718.35291449 179.834040342 Nurnberg 0.5 2013-09-21T00:00:00
1740.98858679 171.270511287 SC Freiburg 1 2013-09-28T00:00:00
1786.58260116 157.720707589 Marseille 1 2013-10-01T00:00:00
1693.24904256 150.534136974 Borussia Monchengladbach 0 2013-10-05T00:00:00
1730.8689396 141.113609063 Hannover 96 1 2013-10-19T00:00:00
1796.86111973 134.157129861 Arsenal 1 2013-10-22T00:00:00
1815.9808198 129.14679898 Schalke 04 1 2013-10-26T00:00:00
1827.35641274 126.152133747 VfB Stuttgart 1 2013-11-01T00:00:00
1792.11402645 120.045882423 Arsenal 0 2013-11-06T00:00:00
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<head>
<title>Table With Embedded Line Chart</title>
<script src="http://d3js.org/d3.v3.min.js"></script>
<link rel="stylesheet" href="http://billmill.org/css/style.css" />
<style>
table {
border-collapse: collapse;
}
th {
border-bottom: 2px solid #ddd;
padding: 8px;
font-weight: bold;
}
td {
padding: 8px;
border-top: 1px solid #ddd;
}
#chart {
padding: 0px;
}
.xaxislabel {
font-size: 9px;
}
</style>
</head>
<body>
<div id="datatable"></div>
<script>
var rows = []
var formatdate = d3.time.format("%b %d %Y");
d3.csv("dortmund.csv", function(error, csv) {
csv.forEach(function(row) {
row.mu = parseFloat(row.mu).toFixed(1);
row.sigma = parseFloat(row.sigma).toFixed(1);
row.dt = formatdate(new Date(Date.parse(row.date)));
var res = parseFloat(row.result);
if (res < .5) {
row.result = "loss";
} else if (res > .5) {
row.result = "win";
} else {
row.result = "draw";
}
rows.push(row);
});
var table = d3.select("#datatable").append("table");
thead = table.append("thead");
tbody = table.append("tbody");
thead.append("th").text("Date");
thead.append("th").text("Opponent");
thead.append("th").text("Result");
thead.append("th").text("Rating");
thead.append("th").text("");
var tr = tbody.selectAll("tr")
.data(rows)
.enter().append("tr");
var td = tr.selectAll("td")
.data(function(d) { return [d.dt, d.opp, d.result, d.mu]; })
.enter().append("td")
.text(function(d) { return d; });
var width = 80,
height = d3.select("table")[0][0].clientHeight,
mx = 10,
radius = 2;
// Now add the chart column
d3.select("#datatable tbody tr").append("td")
.attr("id", "chart")
.attr("width", width + "px")
.attr("rowspan", rows.length);
var chart = d3.select("#chart").append("svg")
.attr("class", "chart")
.attr("width", width)
.attr("height", height);
var maxMu = 0;
var minMu = Number.MAX_VALUE;
for (i=0; i < rows.length; i++) {
if (rows[i].mu > maxMu) { maxMu = rows[i].mu; }
if (rows[i].mu < minMu) { minMu = rows[i].mu; }
}
var dates = rows.map(function(t) { return t.dt; });
var xscale = d3.scale.linear()
.domain([minMu, maxMu])
.range([mx, width-mx])
.nice();
var yscale = d3.scale.ordinal()
.domain(dates)
.rangeBands([0, height]);
chart.selectAll(".xaxislabel")
.data(xscale.ticks(2))
.enter().append("text")
.attr("class", "xaxislabel")
.attr("x", function(d) { return xscale(d); })
.attr("y", 10)
.attr("text-anchor", "middle")
.text(String)
chart.selectAll(".xaxistick")
.data(xscale.ticks(2))
.enter().append("line")
.attr("x1", function(d) { return xscale(d); })
.attr("x2", function(d) { return xscale(d); })
.attr("y1", 10)
.attr("y2", height)
.attr("stroke", "#eee")
.attr("stroke-width", 1);
chart.selectAll(".line")
.data(rows)
.enter().append("line")
.attr("x1", function(d) { return xscale(d.mu); })
.attr("y1", function(d) { return yscale(d.dt) + yscale.rangeBand()/2; })
.attr("x2", function(d,i) { return rows[i+1] ? xscale(rows[i+1].mu) : xscale(d.mu); })
.attr("y2", function(d,i) { return rows[i+1] ? yscale(rows[i+1].dt) + yscale.rangeBand()/2 : yscale(d.dt) + yscale.rangeBand()/2; })
.attr("stroke", "#777")
.attr("stroke-width", 1);
var pt = chart.selectAll(".pt")
.data(rows)
.enter().append("g")
.attr("class", "pt")
.attr("transform", function(d) { return "translate(" + xscale(d.mu) + "," + (yscale(d.dt) + yscale.rangeBand()/2) + ")"; });
pt.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", radius)
.attr("opacity", .5)
.attr("fill", "#ff0000");
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment