Skip to content

Instantly share code, notes, and snippets.

@micahstubbs
Last active June 14, 2016 22:16
Show Gist options
  • Save micahstubbs/a2f0fbb9b4da06b34b94fdffc2290327 to your computer and use it in GitHub Desktop.
Save micahstubbs/a2f0fbb9b4da06b34b94fdffc2290327 to your computer and use it in GitHub Desktop.
Air Quality Calendars II
license: CC0-1.0
height: 500
border: no
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
overflow: hidden;
margin: 24px 12px;
font-size: 14px;
font-family: "Futura", "Helvetica Neue", Helvetica, Arial, sans-serif;
}
#container {
display: flex;
}
.section {
display: flex;
flex-direction: column;
margin-right: 10px;
}
.title {
width: 100%;
margin: 12px auto;
text-align: center;
font-size: 18px;
}
.yearLabel {
margin-right: 10px;
color: #666;
}
.beijingYear, .chengduYear, .guangzhouYear, .shanghaiYear, .shenyangYear {
display: flex;
}
#beijing .title {
margin-left: 20px;
}
#key {
display: flex;
min-width: 745px;
max-width: 850px;
justify-content: space-between;
margin: 32px;
}
.keyEntry span {
margin: 0 0 0 26px;
color: #666;
}
.keyEntry canvas {
position: absolute;
margin-top: -1px;
}
</style>
<body>
<div id="container">
<div id="beijing" class="section"></div>
<div id="chengdu" class="section"></div>
<div id="guangzhou" class="section"></div>
<div id="shanghai" class="section"></div>
<div id="shenyang" class="section"></div>
</div>
<div id="key"></div>
<script src="https://d3js.org/d3.v3.js"></script>
<script>
var cellSize = 3;
var canvasWidth = 160;
var canvasHeight = 34;
var format = d3.time.format("%x");
var color = d3.scale.linear()
.domain([18, 45, 91, 141, 191, 291, Infinity])
.range(["#1a9850", "#d9ef8b", "#fee08b", "#fc8d59", "#d73027", "#a50026", "#a50026"]);
var colorMap = d3.scale.ordinal()
.range(["#1a9850", "#d9ef8b", "#fee08b", "#fc8d59", "#d73027", "#a50026"]);
var cities = ['beijing', 'chengdu', 'guangzhou', 'shanghai', 'shenyang'];
var data = {};
var remaining = 30;
var datasets = ["beijing2008", "beijing2009", "beijing2010", "beijing2011", "beijing2012",
"beijing2013", "beijing2014", "beijing2015", "beijing2016", "chengdu2012",
"chengdu2013", "chengdu2014", "chengdu2015", "chengdu2016", "guangzhou2011",
"guangzhou2012", "guangzhou2013", "guangzhou2014", "guangzhou2015", "guangzhou2016", "shanghai2011", "shanghai2012", "shanghai2013", "shanghai2014", "shanghai2015", "shanghai2016", "shenyang2013", "shenyang2014", "shenyang2015", "shenyang2016"];
(function loadData() {
datasets.forEach(function(dataset) {
d3.csv("https://gist.githubusercontent.com/dhoboy/499741034a2edb844ba3171aa73298d2/raw/b486c6fbd63747fccc7b492741fc0b775f855d16/" + dataset + ".csv", function(err, d) {
if (!err) {
data[dataset] = d;
--remaining;
}
if (!remaining) draw();
});
});
})();
function draw() {
// turn into array to filter out invalid readings
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";
});
});
// turn back into object for daily averages
data = data.reduce(function(prev, next) {
prev[next.key] = next.value;
return prev;
}, {});
var dailyAvg = {};
cities.forEach(function(city) {
d3.range(2008,2017).forEach(function(year) {
if (data[city + year]) {
dailyAvg[city + year] = 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(data[city + year])
} else {
dailyAvg[city + year] = "No Data";
}
});
});
d3.select("div#beijing").append("div").attr("class", "title").text("beijing");
var beijingDivs = d3.select("div#beijing").selectAll(".beijingYear")
.data(d3.keys(dailyAvg).filter(function(d) { return /beijing/.test(d)}))
.enter()
.append("div")
.attr("class", "beijingYear");
beijingDivs.append("div")
.attr("class", "yearLabel")
.text(function(d) {
return /\d{4}/.exec(d)[0];
})
beijingDivs.append("canvas")
.attr("width", canvasWidth)
.attr("height", canvasHeight)
.attr("id", function(d) { return d; });
d3.select("div#chengdu").append("div").attr("class", "title").text("chengdu");
var chengduDivs = d3.select("div#chengdu").selectAll(".chengduYear")
.data(d3.keys(dailyAvg).filter(function(d) { return /chengdu/.test(d)}))
.enter()
.append("div")
.attr("class", "chengduYear")
.append("canvas")
.attr("width", canvasWidth)
.attr("height", canvasHeight)
.attr("id", function(d) { return d; });
d3.select("div#guangzhou").append("div").attr("class", "title").text("guangzhou");
var guangzhouDivs = d3.select("div#guangzhou").selectAll(".guangzhouYear")
.data(d3.keys(dailyAvg).filter(function(d) { return /guangzhou/.test(d)}))
.enter()
.append("div")
.attr("class", "guangzhouYear")
.append("canvas")
.attr("width", canvasWidth)
.attr("height", canvasHeight)
.attr("id", function(d) { return d; });
d3.select("div#shanghai").append("div").attr("class", "title").attr("class", "title").text("shanghai");
var shanghaiDivs = d3.select("div#shanghai").selectAll(".shanghaiYear")
.data(d3.keys(dailyAvg).filter(function(d) { return /shanghai/.test(d)}))
.enter()
.append("div")
.attr("class", "shanghaiYear")
.append("canvas")
.attr("width", canvasWidth)
.attr("height", canvasHeight)
.attr("id", function(d) { return d; });
d3.select("div#shenyang").append("div").attr("class", "title").text("shenyang");
var shenyangDivs = d3.select("div#shenyang").selectAll(".shenyangYear")
.data(d3.keys(dailyAvg).filter(function(d) { return /shenyang/.test(d)}))
.enter()
.append("div")
.attr("class", "shenyangYear")
.append("canvas")
.attr("width", canvasWidth)
.attr("height", canvasHeight)
.attr("id", function(d) { return d; });
var categoryMap = { "good": "good", "moderate": "moderate", "sensitive": "unhealthy for sensitive groups", "unhealthy": "unhealthy", "very": "very unhealthy", "hazardous": "hazardous" };
["good", "moderate", "sensitive", "unhealthy", "very", "hazardous"].forEach(colorMap);
var keyEntries = d3.select("#key").selectAll(".keyEntry")
.data(["good", "moderate", "sensitive", "unhealthy", "very", "hazardous"])
.enter()
.append("div")
.attr("class", "keyEntry");
keyEntries.append("canvas")
.attr("width", 20)
.attr("height", 20)
.attr("id", function(d) { return d; });
keyEntries.append("span")
.text(function(d) { return categoryMap[d]; });
var keyCtx = {};
d3.keys(categoryMap).forEach(function(k) {
keyCtx[k] = document.getElementById(k).getContext("2d");
drawKey(k, keyCtx[k]);
});
var ctx = {};
d3.keys(dailyAvg).forEach(function(k) {
ctx[k] = document.getElementById(k).getContext("2d");
});
cities.forEach(function(city) {
d3.range(2008,2017).forEach(function(year) {
var monthsInYear = d3.time.months((new Date(year, 0, 1)), new Date(year+1, 0, 1));
var daysInYear = d3.time.days((new Date(year, 0, 1)), new Date(year+1, 0, 1));
daysInYear.forEach(function(day) {
drawDay((d3.time.weekOfYear(day)*cellSize), (day.getDay() * cellSize), city + year, format(day), ctx[city + year]);
});
});
});
function drawDay(x, y, key, day, ctx) {
if (dailyAvg[key] == "No Data") {
ctx.fillStyle = "#ffffff";
} else {
console.log(dailyAvg[key][day]);
if (+dailyAvg[key][day] > -1) {
ctx.fillStyle = color(dailyAvg[key][day]);
} else {
ctx.fillStyle = "#e6e6e6";
}
}
ctx.fillRect(x,y,cellSize,cellSize);
}
function drawKey(key, ctx) {
ctx.fillStyle = colorMap(key);
ctx.fillRect(0,0,20,20);
}
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment