Last active
March 15, 2019 15:53
-
-
Save alansmithy/6fd2625d3ba2b6c9ad48 to your computer and use it in GitHub Desktop.
Revisions
-
alansmithy revised this gist
Sep 11, 2015 . No changes.There are no files selected for viewing
-
alansmithy created this gist
Sep 11, 2015 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,5 @@ ###Calendar heatmap A calendar heatmap using a simple csv file structure of date and value. These kinds of displays are good for highlighting patterns in time series data where there might be multiple time patterns present - i.e. daily/weekly/monthly/seasonal. A great implementation of this kind of graphic is the [Wisconsin crash calendar](http://www.coolinfographics.com/blog/2012/9/4/2011-wisconsin-crash-calendar-interview.html). This particular implementation produces just one svg element with a discrete group element for every year referenced in the data set. This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,53 @@ date,value 16/01/15,45 18/01/15,1 22/01/15,21 30/01/15,10 07/02/15,9 08/02/15,29 09/02/15,317 03/03/15,10 08/03/15,4 17/03/15,6 19/03/15,1 06/04/15,11 10/04/15,2 13/04/15,400 16/04/15,53 17/04/15,1 19/04/15,794 20/04/15,3 02/05/15,3 21/05/15,1 23/05/15,5 25/05/15,5 30/05/15,25 17/06/15,3 23/06/15,7 06/07/15,8 07/07/15,18 09/07/15,12 10/07/15,30 15/07/15,1 16/07/15,6 27/07/15,13 02/08/15,4 03/08/15,6 06/08/15,225 11/08/15,60 15/08/15,49 16/08/15,1 17/08/15,9 18/08/15,6 21/08/15,1 23/08/15,1 24/08/15,6 25/08/15,1 26/08/15,50 27/08/15,9 28/08/15,204 30/08/15,37 31/08/15,8 01/09/15,4 02/09/15,2 04/09/15,70 This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,262 @@ <!DOCTYPE html> <meta charset="utf-8"> <head> <title>Data Calendar</title> <style> .month { fill: none; stroke: #000; stroke-width: 2px; } .day { fill: #fff; stroke: #ccc; } text { font-family:sans-serif; font-size:1.5em; } .dayLabel { fill:#aaa; font-size:0.8em; } .monthLabel { text-anchor:middle; font-size:0.8em; fill:#aaa; } .yearLabel { fill:#aaa; font-size:1.2em; } .key {font-size:0.5em;} </style> </head> <body> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script> <script> var title="Migrant deaths in the Mediterranean"; var units=" dead or missing"; var breaks=[10,25,50,100]; var colours=["#ffffd4","#fed98e","#fe9929","#d95f0e","#993404"]; //general layout information var cellSize = 17; var xOffset=20; var yOffset=60; var calY=50;//offset of calendar in each group var calX=25; var width = 960; var height = 163; var parseDate = d3.time.format("%d/%m/%y").parse; format = d3.time.format("%d-%m-%Y"); toolDate = d3.time.format("%d/%b/%y"); d3.csv("data.csv", function(error, data) { //set up an array of all the dates in the data which we need to work out the range of the data var dates = new Array(); var values = new Array(); //parse the data data.forEach(function(d) { dates.push(parseDate(d.date)); values.push(d.value); d.date=parseDate(d.date); d.value=d.value; d.year=d.date.getFullYear();//extract the year from the data }); var yearlyData = d3.nest() .key(function(d){return d.year;}) .entries(data); var svg = d3.select("body").append("svg") .attr("width","90%") .attr("viewBox","0 0 "+(xOffset+width)+" 540") //title svg.append("text") .attr("x",xOffset) .attr("y",20) .text(title); //create an SVG group for each year var cals = svg.selectAll("g") .data(yearlyData) .enter() .append("g") .attr("id",function(d){ return d.key; }) .attr("transform",function(d,i){ return "translate(0,"+(yOffset+(i*(height+calY)))+")"; }) var labels = cals.append("text") .attr("class","yearLabel") .attr("x",xOffset) .attr("y",15) .text(function(d){return d.key}); //create a daily rectangle for each year var rects = cals.append("g") .attr("id","alldays") .selectAll(".day") .data(function(d) { return d3.time.days(new Date(parseInt(d.key), 0, 1), new Date(parseInt(d.key) + 1, 0, 1)); }) .enter().append("rect") .attr("id",function(d) { return "_"+format(d); //return toolDate(d.date)+":\n"+d.value+" dead or missing"; }) .attr("class", "day") .attr("width", cellSize) .attr("height", cellSize) .attr("x", function(d) { return xOffset+calX+(d3.time.weekOfYear(d) * cellSize); }) .attr("y", function(d) { return calY+(d.getDay() * cellSize); }) .datum(format); //create day labels var days = ['Su','Mo','Tu','We','Th','Fr','Sa']; var dayLabels=cals.append("g").attr("id","dayLabels") days.forEach(function(d,i) { dayLabels.append("text") .attr("class","dayLabel") .attr("x",xOffset) .attr("y",function(d) { return calY+(i * cellSize); }) .attr("dy","0.9em") .text(d); }) //let's draw the data on var dataRects = cals.append("g") .attr("id","dataDays") .selectAll(".dataday") .data(function(d){ return d.values; }) .enter() .append("rect") .attr("id",function(d) { return format(d.date)+":"+d.value; }) .attr("stroke","#ccc") .attr("width",cellSize) .attr("height",cellSize) .attr("x", function(d){return xOffset+calX+(d3.time.weekOfYear(d.date) * cellSize);}) .attr("y", function(d) { return calY+(d.date.getDay() * cellSize); }) .attr("fill", function(d) { if (d.value<breaks[0]) { return colours[0]; } for (i=0;i<breaks.length+1;i++){ if (d.value>=breaks[i]&&d.value<breaks[i+1]){ return colours[i]; } } if (d.value>breaks.length-1){ return colours[breaks.length] } }) //append a title element to give basic mouseover info dataRects.append("title") .text(function(d) { return toolDate(d.date)+":\n"+d.value+units; }); //add montly outlines for calendar cals.append("g") .attr("id","monthOutlines") .selectAll(".month") .data(function(d) { return d3.time.months(new Date(parseInt(d.key), 0, 1), new Date(parseInt(d.key) + 1, 0, 1)); }) .enter().append("path") .attr("class", "month") .attr("transform","translate("+(xOffset+calX)+","+calY+")") .attr("d", monthPath); //retreive the bounding boxes of the outlines var BB = new Array(); var mp = document.getElementById("monthOutlines").childNodes; for (var i=0;i<mp.length;i++){ BB.push(mp[i].getBBox()); } var monthX = new Array(); BB.forEach(function(d,i){ boxCentre = d.width/2; monthX.push(xOffset+calX+d.x+boxCentre); }) //create centred month labels around the bounding box of each month path //create day labels var months = ['JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC']; var monthLabels=cals.append("g").attr("id","monthLabels") months.forEach(function(d,i) { monthLabels.append("text") .attr("class","monthLabel") .attr("x",monthX[i]) .attr("y",calY/1.2) .text(d); }) //create key var key = svg.append("g") .attr("id","key") .attr("class","key") .attr("transform",function(d){ return "translate("+xOffset+","+(yOffset-(cellSize*1.5))+")"; }); key.selectAll("rect") .data(colours) .enter() .append("rect") .attr("width",cellSize) .attr("height",cellSize) .attr("x",function(d,i){ return i*130; }) .attr("fill",function(d){ return d; }); key.selectAll("text") .data(colours) .enter() .append("text") .attr("x",function(d,i){ return cellSize+5+(i*130); }) .attr("y","1em") .text(function(d,i){ if (i<colours.length-1){ return "up to "+breaks[i]; } else { return "over "+breaks[i-1]; } }); });//end data load //pure Bostock - compute and return monthly path data for any year function monthPath(t0) { var t1 = new Date(t0.getFullYear(), t0.getMonth() + 1, 0), d0 = t0.getDay(), w0 = d3.time.weekOfYear(t0), d1 = t1.getDay(), w1 = d3.time.weekOfYear(t1); return "M" + (w0 + 1) * cellSize + "," + d0 * cellSize + "H" + w0 * cellSize + "V" + 7 * cellSize + "H" + w1 * cellSize + "V" + (d1 + 1) * cellSize + "H" + (w1 + 1) * cellSize + "V" + 0 + "H" + (w0 + 1) * cellSize + "Z"; } </script> </body> </html> LoadingSorry, something went wrong. Reload?Sorry, we cannot display this file.Sorry, this file is invalid so it cannot be displayed.