Skip to content

Instantly share code, notes, and snippets.

@dhoboy
Last active April 17, 2016 04:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dhoboy/19d5d6dda01690e314e9a14a3cc3118e to your computer and use it in GitHub Desktop.
Save dhoboy/19d5d6dda01690e314e9a14a3cc3118e to your computer and use it in GitHub Desktop.
Beijing Air Quality 2
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 18px sans-serif;
shape-rendering: crispEdges;
}
.day {
fill: #f0f0f0;
stroke: #ccc;
}
.month {
fill: none;
stroke: #000;
stroke-width: 2px;
}
.tooltip {
background-color: #fff;
padding: 0px 10px;
font-family: sans-serif;
width: 800px;
}
.tooltip_body {
margin: 5px 0;
font-size: 18px;
}
h5 {
font-size: 18px;
margin-left: 10px;
}
</style>
<body>
<h5>Concentration of Particluate Matter less than 2.5 micrometers in diameter</h5>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var width = 960,
height = 136,
cellSize = 17,
margin = 14;
var format = d3.time.format("%x");
var color = d3.scale.threshold()
.domain([51, 101, 151, 201, 301])
.range(["#1a9850", "#fee08b", "#f46d43", "#d73027", "#a50026", "#67001f"]);
var tooltip = d3.select("body")
.append("div")
.attr("class", "tooltip")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden");
var svg = d3.select("body").selectAll("svg")
.data(d3.range(2008, 2016))
.enter().append("svg")
.attr("width", width)
.attr("height", height + margin)
.append("g")
.attr("transform", "translate(" + ((width - cellSize * 53) / 2) + "," + (height - cellSize * 7 - 1) + ")");
svg.append("text")
.attr("transform", "translate(-6," + cellSize * 3.5 + ")rotate(-90)")
.style("text-anchor", "middle")
.text(function(d) { return d; });
var rect = svg.selectAll(".day")
.data(function(d) { return d3.time.days(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter().append("rect")
.attr("class", "day")
.attr("width", cellSize)
.attr("height", cellSize)
.attr("x", function(d) { return d3.time.weekOfYear(d) * cellSize; })
.attr("y", function(d) { return d.getDay() * cellSize; })
.datum(format);
svg.selectAll(".month")
.data(function(d) { return d3.time.months(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter().append("path")
.attr("class", "month")
.attr("d", monthPath);
var data = {}, remaining = 8; // parallel loading csv code from here: https://groups.google.com/forum/#!msg/d3-js/3Y9VHkOOdCM/YnmOPopWUxQJ
d3.csv("/d/4c8f05129838a63ec90930f8c46262f0/Beijing_2008_HourlyPM2.5_created20140325.csv", function(data_2008) {
data.yr_2008 = data_2008;
if (!--remaining) draw();
})
d3.csv("/d/4c8f05129838a63ec90930f8c46262f0/Beijing_2009_HourlyPM25_created20140709.csv", function(data_2009) {
data.yr_2009 = data_2009;
if (!--remaining) draw();
})
d3.csv("/d/4c8f05129838a63ec90930f8c46262f0/Beijing_2010_HourlyPM25_created20140709.csv", function(data_2010) {
data.yr_2010 = data_2010;
if (!--remaining) draw();
})
d3.csv("/d/4c8f05129838a63ec90930f8c46262f0/Beijing_2011_HourlyPM25_created20140709.csv", function(data_2011) {
data.yr_2011 = data_2011;
if (!--remaining) draw();
})
d3.csv("/d/4c8f05129838a63ec90930f8c46262f0/Beijing_2012_HourlyPM2.5_created20140325.csv", function(data_2012) {
data.yr_2012 = data_2012;
if (!--remaining) draw();
})
d3.csv("/d/4c8f05129838a63ec90930f8c46262f0/Beijing_2013_HourlyPM2.5_created20140325.csv", function(data_2013) {
data.yr_2013 = data_2013;
if (!--remaining) draw();
})
d3.csv("/d/4c8f05129838a63ec90930f8c46262f0/Beijing_2014_HourlyPM25_created20150203.csv", function(data_2014) {
data.yr_2014 = data_2014;
if (!--remaining) draw();
})
d3.csv("/d/4c8f05129838a63ec90930f8c46262f0/Beijing_2015_HourlyPM25_created20160201.csv", function(data_2015) {
data.yr_2015 = data_2015;
if (!--remaining) draw();
})
function draw() {
data = d3.entries(data);
data.forEach(function(dataset) {
dataset.value = dataset.value.filter(function(d) { // only want valid readings
return d["QC Name"] == "Valid" && d["Value"] != "-999";
});
});
var flatData = d3.merge(data.map(function(d) { return d.value; }));
var dailyAvg = d3.nest()
.key(function(d) {
return format(new Date(d.Year, d.Month - 1, d.Day));
})
.rollup(function(hourlyReadings) {
if (hourlyReadings.length != 24) {
return "N/A";
}
return d3.sum(hourlyReadings, function(d) { return +d.Value; }) / 24
})
.map(flatData)
var key = { "#1a9850": "Good", "#fee08b": "Moderate", "#f46d43": "Unhealthy for sensitive groups",
"#d73027": "Unhealthy", "#a50026": "Very Unhealthy", "#67001f": "Hazardous" };
var calBounds = { "cal2008": { top: 150 }, "cal2009": { top: 255 }, "cal2010" : { top: 409 },
"cal2011": { top: 563 }, "cal2012": { top: 718 }, "cal2013" : { top: 870 },
"cal2014" : { top: 1024 }, "cal2015": { top: 1179 } };
var calTooltipTop = { "cal2008": 60, "cal2009": 217, "cal2010": 372, "cal2011": 525,
"cal2012": 679, "cal2013": 833, "cal2014": 987, "cal2015": 1142 };
d3.keys(calBounds).forEach(function(cal) {
calBounds[cal].bottom = calBounds[cal].top + 114;
});
rect
.style("fill", function(d) { // d here is the date sring for each day
if (dailyAvg[d] && dailyAvg[d] !== "N/A") {
return color(dailyAvg[d]);
}
})
.on("mouseover", function(d) {
tooltip.html("");
tooltip.append("pre").attr("class", "tooltip_body");
tooltip.select(".tooltip_body")
.text(
"Date: " + d + "\t Reading: " + (dailyAvg[d] && dailyAvg[d] !== "N/A" ? d3.round(dailyAvg[d], 2) + " µg/cu PM2.5 \t" + "Air Quality: " + key[color(dailyAvg[d])] : "No Data")
);
return tooltip.style("visibility", "visible");
})
.on("mousemove", function() {
var y = d3.event.pageY;
var currentCal = "";
d3.keys(calBounds).forEach(function(cal) {
if (y >= calBounds[cal].top && y <= calBounds[cal].bottom) {
currentCal = cal;
}
});
return tooltip.style("top", calTooltipTop[currentCal] + "px").style("left", "45px");
})
}
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment