Last active
July 9, 2020 19:26
-
-
Save ursulams/7f4d93b0944c7c7d29ef3cc6060b808d to your computer and use it in GitHub Desktop.
small multiples mapping nyc trash tonnage
This file contains 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 characters
license:mit |
This file contains 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 characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width"> | |
<!-- <script src="d3.min.js"></script> --> | |
<script src="https://d3js.org/d3.v5.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/chroma-js/2.1.0/chroma.min.js"></script> | |
<title></title> | |
<style id="jsbin-css"> | |
svg { | |
margin: 5px; | |
} | |
.cd { | |
stroke: #ada7b3; | |
stroke-width: 0.5; | |
fill: none; | |
} | |
.tooltip { | |
color: grey; | |
position: absolute; | |
text-align: left; | |
width: 150px; | |
height: 55px; | |
padding: 2px; | |
font-family: "Montserrat", sans-serif; | |
font-size: 12px; | |
background: white; | |
} | |
h3, .label | |
{ | |
top: 30px; | |
font-family: "Montserrat", sans-serif; | |
font-size: 0.9em; | |
font-weight: 100; | |
color: grey; | |
} | |
</style> | |
</head> | |
<body> | |
<h3>2020 nyc total residential & school trash tonnage year over year change</h3> | |
<div id="chart"></div> | |
<script id="jsbin-source-javascript" type="text/javascript"> | |
//each map svg size | |
var width = 270, | |
height = 320; | |
//map parameters | |
var projection = d3.geoMercator() | |
.scale(Math.pow(2, 14.66)) | |
.translate([width / 1.8, height / 1.2]) | |
.center([-73.94, 40.50]); | |
//community district outlines | |
var path = d3.geoPath() | |
.projection(projection); | |
var cd_url = "https://raw.githubusercontent.com/ursulakaczmarek/open.trash.lab/master/dsny.tonnage/nyccd.geojson"; | |
var trash_url = "https://data.cityofnewyork.us/resource/ebb7-mvp5.json?$where=month IN('2019 / 03','2019 / 04', '2019 / 05', '2019 / 06', '2020 / 03','2020 / 04', '2020 / 05', '2020 / 06')"; | |
Promise.all([d3.json(cd_url), d3.json(trash_url)]) | |
.then(function(bothSets) { | |
var districts = bothSets[0]; | |
var tonnage = bothSets[1]; | |
var trashData = tonnage.filter( | |
row => new Date(row.month.split(" / ")[0] + "/" + row.month.split(" / ")[1] + "/01") > new Date("2019-02-28")).map( | |
row => [{ | |
boroCD: row.borough_id.concat(row.communitydistrict), | |
date: new Date(row.month.split(" / ")[0] + "/" + row.month.split(" / ")[1] + "/01").toDateString().split(" ").slice(1).join(" "), | |
total: Object.entries(row).reduce( | |
(totals, type) => { | |
if (type[0].includes("tons")) | |
return totals + Number(type[1]); | |
else return +Number(totals).toFixed(3); | |
}, 0)}]).reduce( | |
(a, b) => a.concat(b)); | |
console.log(trashData); | |
var yoy = trashData.reduce( | |
(a, b) => { | |
function diff(a, b) { | |
return +Number(100 * ((a - b) / Math.abs(b))).toFixed(3); | |
} | |
var idx = a.findIndex( | |
elem => elem.boroCD === b.boroCD && | |
elem.date.substring(0, 3) === b.date.substring(0, 3)); | |
if (~idx) { | |
a[idx].totalDiff = diff(b.total, a[idx].total); | |
a[idx].total2020 = b.total; | |
} else { | |
a.push(JSON.parse(JSON.stringify(b))); | |
} | |
return a | |
}, []); | |
var months = d3.nest() | |
.key(d => d.date) | |
.entries(yoy); | |
var totalDomain = [d3.min(months, month => d3.min(month.values, d => d.totalDiff)), | |
d3.max(months, month => d3.max(month.values, d => d.totalDiff)) | |
]; | |
var colorTotal = chroma.scale(["#5d537c", "#f28454"]) | |
.domain(totalDomain); | |
var svgs = d3.select("#chart") | |
.selectAll("svg") | |
.data(months, d => d.key) | |
.enter() | |
.append("svg") | |
.attr("width", width) | |
.attr("height", height); | |
svgs.append("text") | |
.attr("class", "label") | |
.attr("x", 5) | |
.attr("y", 45) | |
.text(d => d.key.substring(0, 3)); | |
//grouping element for drawing nyc in each svg | |
var gMaps = svgs.append("g"); | |
//define legend | |
var legend = d3.select("#chart") | |
.append("svg") | |
.attr("class", "label"); | |
//define tooltip | |
var tooltip = d3.select("body") | |
.append("div") | |
.attr("class", "tooltip"); | |
//draw nyc choropleths | |
gMaps.selectAll(".cd") | |
.data(districts.features) | |
.enter() | |
.append("path") | |
.attr("class", "cd") | |
.attr("d", path); | |
gMaps.selectAll(".cd") | |
.data(d => d.values, d => (d.boroCD ? d.boroCD : d.properties.boro_cd)) | |
.style("fill", d => colorTotal(d.totalDiff)) | |
.on("mouseover", (d, i) => { | |
tooltip.transition().duration(750).style("visibility", "visible") | |
tooltip.html("community district: " + d.boroCD + "<br/> " + "2019 tons: " + d.total + "<br/> " + "2020 tons: " + d.total2020 + "<br/> " + "change: " + d.totalDiff + "%") | |
tooltip.style("top", (d3.event.pageY + 1) + "px") | |
tooltip.style("left", (d3.event.pageX + 1) + "px") | |
}) | |
.on("click", d => { | |
lines(trashData, d[0], g, d); | |
}) | |
.on("mouseout", (d, i) => { | |
tooltip.transition().duration(500).style("visibility", "hidden") | |
}); | |
//map legend | |
legend.append("text") | |
.attr("class", "label") | |
.attr("x", 85) | |
.attr("y", 20) | |
.text("% change year over year"); | |
legend.append("text") | |
.attr("class", "label") | |
.attr("x", 60) | |
.attr("y", 50) | |
.text(totalDomain[0] + "%"); | |
legend.append("text") | |
.attr("class", "label") | |
.attr("x", 200) | |
.attr("y", 50) | |
.text(totalDomain[1] + "%"); | |
var defs = legend.append("defs"); | |
// append linearGradient element | |
var linearGradient = defs.append("linearGradient") | |
.attr("id", "linear-gradient"); | |
linearGradient.selectAll("stop") | |
.data([{ | |
offset: "0%", | |
color: "#5d537c" | |
}, { | |
offset: "25%", | |
color: "#875f73" | |
}, | |
{ | |
offset: "50%", | |
color: "#ac6b6a" | |
}, { | |
offset: "75%", | |
color: "#cf7760" | |
}, | |
{ | |
offset: "100%", | |
color: "#f28454" | |
} | |
]) | |
.enter().append("stop") | |
.attr("offset", d => d.offset) | |
.attr("stop-color", d => d.color); | |
legend.append("rect") | |
.attr("width", 75) | |
.attr("height", 20) | |
.attr("x", 120) | |
.attr("y", 30) | |
.style("fill", "url(#linear-gradient)"); | |
}); | |
</script></body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment