Last active
June 26, 2020 15:32
-
-
Save ursulams/85916753803ea938ee1bc07a8214f373 to your computer and use it in GitHub Desktop.
bar chart and responsive nyc choropleth
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
<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> | |
<title>NYC Cuisines Mapped - Ursula Kaczmarek</title> | |
<style id="jsbin-css"> | |
.zipcode { | |
stroke: grey; | |
stroke-width: 1px; | |
fill: none; | |
} | |
.bar { | |
fill: lightsteelblue; | |
stroke: grey; | |
} | |
.bar:hover { | |
fill: steelBlue; | |
} | |
.axis--y path { | |
display: none; | |
} | |
.label { | |
fill: black; | |
font-family: Helvetica; | |
font-size: 12px; | |
} | |
.axislabel { | |
fill: black; | |
font-family: Helvetica; | |
font-size: 12px; | |
} | |
.axis--x path { | |
opacity: 0.0; | |
} | |
.axis--x line { | |
stroke: lightgrey; | |
opacity: 0.5; | |
} | |
.axis--map--caption { | |
fill: black; | |
font-family: Helvetica; | |
font-size: 12px; | |
text-anchor: start; | |
font-weight: bold; | |
} | |
.tooltip { | |
position: absolute; | |
z-index: 10; | |
visibility: hidden; | |
background: lightgrey; | |
padding: 10px; | |
border: 1px solid grey; | |
font-family: Helvetica; | |
font-size: 12px; | |
} | |
.scale { | |
font-family: Helvetica; | |
font-size: 8px; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="chart"> | |
<svg width="1000" height="850"></svg> | |
</div> | |
<script id="jsbin-javascript"> | |
var zip_url = "https://raw.githubusercontent.com/hvo/datasets/master/nyc_zip.geojson"; | |
var cuisines_url = "https://raw.githubusercontent.com/hvo/datasets/master/nyc_restaurants_by_cuisine.json"; | |
Promise.all([d3.json(zip_url), d3.json(cuisines_url)]) | |
.then(ready); | |
function ready(bothSets) { | |
var zipcodes = bothSets[0]; | |
var cuisines = bothSets[1]; | |
var data = cuisines.map(function(d) { | |
return [d.cuisine, d.total]; | |
}) | |
.slice(0, 25) | |
var svg = d3.select("svg"); | |
var gMap = svg.append("g") | |
.attr("transform", "translate(0, 0)"); | |
var totalValues = d3.max(data, function(d) { | |
return d[1]; | |
}); | |
var g = svg.append("g"); | |
var x = d3.scaleLinear() | |
.domain([0, totalValues]) | |
.rangeRound([00, 250]); | |
var ybar = d3.scaleBand() | |
.domain(data.map(function(d) { | |
return d[0]; | |
})) | |
.rangeRound([55, 525]); | |
var tooltip = d3.select("body") | |
.append("div") | |
.attr("class", "tooltip"); | |
//add cuisine names to barchart | |
g.append("g") | |
.attr("class", "axis axis--y") | |
.attr("transform", "translate(100,0)") | |
.call(d3.axisLeft(ybar)) | |
.append("text") | |
.attr("class", "label") | |
.attr("transform", "rotate(-90)") | |
.attr("x", -ybar.range()[1] * 0.2) | |
.attr("y", -35); | |
//creating x axis and ticks | |
g.append("g") | |
.attr("class", "axis axis--x") | |
.attr("transform", "translate(100, 45)") | |
.call(d3.axisBottom(x) | |
.ticks(7) | |
.tickSize(490) | |
.tickSizeOuter(0) | |
.tickFormat(d3.format(".0s"))) | |
.append("text") | |
.attr("class", "axislabel") | |
.attr("x", (x.range()[0] + x.range()[1]) * 0.5) | |
.attr("y", -18) | |
.text("Number of restaurants"); | |
//adding x ticks below | |
g.append("g") | |
.attr("class", "axis axis--x") | |
.attr("transform", "translate(100,40)") | |
.call(d3.axisBottom(x) | |
.ticks(7) | |
.tickSize(0) | |
.tickSizeOuter(0) | |
.tickFormat(d3.format(".0s"))) | |
// create barchart | |
g.selectAll(".bar") | |
.data(data) | |
.enter().append("rect") | |
.attr("class", "bar") | |
.attr("x", x(0) + 100) | |
.attr("y", function(d, i) { | |
return ybar(d[0]); | |
}) | |
.attr("width", function(d, i) { | |
return x(d[1]); | |
}) | |
.attr("height", ybar.bandwidth() - 2) | |
.on("mouseover", function(d, i) { | |
cuisinemap(cuisines[i], gMap, data[i]); | |
d3.select(this) | |
.transition().duration(500) | |
.attr("x", x(0) - 1 + 100) | |
.attr("y", ybar(d[0]) - 1) | |
.attr("width", x(d[1]) + 20) | |
.attr("height", ybar.bandwidth() - 2); | |
tooltip.text("Number of " + d[0] + " restaurants citywide: " + d[1]); | |
return tooltip.style("visibility", "visible"); // show tooltip on hover | |
}) | |
.on("mousemove", function() { | |
return tooltip | |
.style("top", (d3.event.pageY + 1) + "px") | |
.style("left", (d3.event.pageX + 1) + "px"); | |
}) | |
.on("mouseout", function(d) { | |
d3.select(this) | |
.transition().duration(500) | |
.attr("x", x(0) + 100) | |
.attr("y", ybar(d[0])) | |
.attr("width", x(d[1])) | |
.attr("height", ybar.bandwidth() - 2); | |
return tooltip.style("visibility", "hidden"); | |
}); | |
// create map using function defined below | |
cuisinemap(cuisines[0], gMap, data[0]); | |
function cuisinemap(cuisineName, gMap, cuisineLegend) { | |
var canvasSize = [1200, 850]; | |
var counts = cuisineName.perZip; | |
var countData = Object.entries(counts); | |
var maxCount = d3.max(countData, function(d) { | |
return d[1]; | |
}); | |
var color = d3.scaleThreshold() | |
.domain(d3.range(0, maxCount, maxCount / 5)) | |
.range(["#f1eef6", "#bdc9e1", "#74a9cf", "#2b8cbe", "#045a8d"]); | |
var projection = d3.geoMercator() | |
.scale(Math.pow(2, 10.35 + 5.34)) | |
.center([-73.975, 40.7]) | |
.translate([canvasSize[0] / 2, canvasSize[1] / 3]); | |
var path = d3.geoPath() | |
.projection(projection); | |
var scale = d3.scaleLinear() | |
.domain([0, 0]) | |
.rangeRound([350, 490]); | |
gMap.selectAll(".zipcode") | |
.data(zipcodes.features) | |
.enter().append("path") | |
.attr("class", "zipcode") | |
.attr("d", path); | |
// update all elements of zipcode class | |
gMap.selectAll(".zipcode") | |
.data(countData, function(d) { | |
return (d[0] ? d[0] : d.properties.zipcode); | |
}) | |
.style("fill", function(d) { | |
return color(d[1]); | |
}) | |
.on("mouseover", function(d, i) { | |
tooltip.transition() | |
.duration(500) | |
.text("Restaurants in zipcode " + d[0] + ": " + d[1]); | |
return tooltip.style("visibility", "visible"); // show tooltip on hover | |
}) | |
.on("mousemove", function() { | |
return tooltip | |
.style("top", (d3.event.pageY + 1) + "px") | |
.style("left", (d3.event.pageX + 1) + "px"); | |
}) | |
.on("mouseout", function(d) { | |
d3.select(this) | |
.transition().duration(500) | |
.attr("x", x(0) + 100) | |
.attr("y", ybar(d[0])) | |
.attr("width", x(d[1])) | |
.attr("height", ybar.bandwidth() - 2); | |
return tooltip.style("visibility", "hidden"); | |
}) | |
.exit().style("fill", color(-1)); | |
g.append("g") | |
.attr("class", "legend") | |
.attr("transform", "translate(1,1)") | |
.append("text") | |
.attr("class", "axis--map--caption") | |
.attr("y", -6); | |
g.append("g") | |
.attr("class", "grid axis--x") | |
.attr("transform", "translate(0, 50)") | |
.call(d3.axisTop(scale).ticks(5).tickSize(-15).tickFormat("")) | |
g.selectAll(".scale").remove(); | |
g.selectAll(".label").remove(); | |
g.append("text") | |
.data(cuisineLegend) | |
.attr("class", "label") | |
.attr("x", 370) | |
.attr("y", 45) | |
.text(function(d) { | |
return "Number of " + d + " Restaurants"; | |
}); | |
for (i = 0; i < 4; ++i) { | |
g.append("rect") | |
.attr("class", "scale") | |
.attr("x", 370 + i * 35) | |
.attr("y", 50) | |
.attr('width', 35) | |
.attr("height", 7) | |
.style("fill", color(i / 4 * maxCount)); | |
} | |
for (i = 0; i < 4; ++i) { | |
g.append("text") | |
.attr("class", "scale") | |
.attr("x", 435 + 33 * (i - 2)) | |
.attr("y", 70) | |
.text(Math.round(i / 5 * maxCount).toString()); | |
} | |
} | |
} | |
</script> | |
</body> | |
</html> |
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
.zipcode { | |
stroke: grey; | |
stroke-width: 1px; | |
fill: none; | |
} | |
.bar { | |
fill: lightsteelblue; | |
stroke: grey; | |
} | |
.bar:hover { | |
fill: steelBlue; | |
} | |
.axis--y path { | |
display: none; | |
} | |
.label { | |
fill: black; | |
font-family: Helvetica; | |
font-size: 12px; | |
} | |
.axislabel { | |
fill: black; | |
font-family: Helvetica; | |
font-size: 12px; | |
} | |
.axis--x path { | |
opacity: 0.0; | |
} | |
.axis--x line { | |
stroke: lightgrey; | |
opacity: 0.5; | |
} | |
.axis--map--caption { | |
fill: black; | |
font-family: Helvetica; | |
font-size: 12px; | |
text-anchor: start; | |
font-weight: bold; | |
} | |
.tooltip { | |
position: absolute; | |
z-index: 10; | |
visibility: hidden; | |
background: lightgrey; | |
padding: 10px; | |
border: 1px solid grey; | |
font-family: Helvetica; | |
font-size: 12px; | |
} | |
.scale { | |
font-family: Helvetica; | |
font-size: 8px; | |
} |
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
var zip_url = "https://raw.githubusercontent.com/hvo/datasets/master/nyc_zip.geojson"; | |
var cuisines_url = "https://raw.githubusercontent.com/hvo/datasets/master/nyc_restaurants_by_cuisine.json"; | |
Promise.all([d3.json(zip_url), d3.json(cuisines_url)]) | |
.then(ready); | |
function ready(bothSets) { | |
var zipcodes = bothSets[0]; | |
var cuisines = bothSets[1]; | |
var data = cuisines.map(function(d) { | |
return [d.cuisine, d.total]; | |
}) | |
.slice(0, 25) | |
var svg = d3.select("svg"); | |
var gMap = svg.append("g") | |
.attr("transform", "translate(0, 0)"); | |
var totalValues = d3.max(data, function(d) { | |
return d[1]; | |
}); | |
var g = svg.append("g"); | |
var x = d3.scaleLinear() | |
.domain([0, totalValues]) | |
.rangeRound([00, 250]); | |
var ybar = d3.scaleBand() | |
.domain(data.map(function(d) { | |
return d[0]; | |
})) | |
.rangeRound([55, 525]); | |
var tooltip = d3.select("body") | |
.append("div") | |
.attr("class", "tooltip"); | |
//add cuisine names to barchart | |
g.append("g") | |
.attr("class", "axis axis--y") | |
.attr("transform", "translate(100,0)") | |
.call(d3.axisLeft(ybar)) | |
.append("text") | |
.attr("class", "label") | |
.attr("transform", "rotate(-90)") | |
.attr("x", -ybar.range()[1] * 0.2) | |
.attr("y", -35); | |
//creating x axis and ticks | |
g.append("g") | |
.attr("class", "axis axis--x") | |
.attr("transform", "translate(100, 45)") | |
.call(d3.axisBottom(x) | |
.ticks(7) | |
.tickSize(490) | |
.tickSizeOuter(0) | |
.tickFormat(d3.format(".0s"))) | |
.append("text") | |
.attr("class", "axislabel") | |
.attr("x", (x.range()[0] + x.range()[1]) * 0.5) | |
.attr("y", -18) | |
.text("Number of restaurants"); | |
//adding x ticks below | |
g.append("g") | |
.attr("class", "axis axis--x") | |
.attr("transform", "translate(100,40)") | |
.call(d3.axisBottom(x) | |
.ticks(7) | |
.tickSize(0) | |
.tickSizeOuter(0) | |
.tickFormat(d3.format(".0s"))) | |
// create barchart | |
g.selectAll(".bar") | |
.data(data) | |
.enter().append("rect") | |
.attr("class", "bar") | |
.attr("x", x(0) + 100) | |
.attr("y", function(d, i) { | |
return ybar(d[0]); | |
}) | |
.attr("width", function(d, i) { | |
return x(d[1]); | |
}) | |
.attr("height", ybar.bandwidth() - 2) | |
.on("mouseover", function(d, i) { | |
cuisinemap(cuisines[i], gMap, data[i]); | |
d3.select(this) | |
.transition().duration(500) | |
.attr("x", x(0) - 1 + 100) | |
.attr("y", ybar(d[0]) - 1) | |
.attr("width", x(d[1]) + 20) | |
.attr("height", ybar.bandwidth() - 2); | |
tooltip.text("Number of " + d[0] + " restaurants citywide: " + d[1]); | |
return tooltip.style("visibility", "visible"); // show tooltip on hover | |
}) | |
.on("mousemove", function() { | |
return tooltip | |
.style("top", (d3.event.pageY + 1) + "px") | |
.style("left", (d3.event.pageX + 1) + "px"); | |
}) | |
.on("mouseout", function(d) { | |
d3.select(this) | |
.transition().duration(500) | |
.attr("x", x(0) + 100) | |
.attr("y", ybar(d[0])) | |
.attr("width", x(d[1])) | |
.attr("height", ybar.bandwidth() - 2); | |
return tooltip.style("visibility", "hidden"); | |
}); | |
// create map using function defined below | |
cuisinemap(cuisines[0], gMap, data[0]); | |
function cuisinemap(cuisineName, gMap, cuisineLegend) { | |
var canvasSize = [1200, 850]; | |
var counts = cuisineName.perZip; | |
var countData = Object.entries(counts); | |
var maxCount = d3.max(countData, function(d) { | |
return d[1]; | |
}); | |
var color = d3.scaleThreshold() | |
.domain(d3.range(0, maxCount, maxCount / 5)) | |
.range(["#f1eef6", "#bdc9e1", "#74a9cf", "#2b8cbe", "#045a8d"]); | |
var projection = d3.geoMercator() | |
.scale(Math.pow(2, 10.35 + 5.34)) | |
.center([-73.975, 40.7]) | |
.translate([canvasSize[0] / 2, canvasSize[1] / 3]); | |
var path = d3.geoPath() | |
.projection(projection); | |
var scale = d3.scaleLinear() | |
.domain([0, 0]) | |
.rangeRound([350, 490]); | |
gMap.selectAll(".zipcode") | |
.data(zipcodes.features) | |
.enter().append("path") | |
.attr("class", "zipcode") | |
.attr("d", path); | |
// update all elements of zipcode class | |
gMap.selectAll(".zipcode") | |
.data(countData, function(d) { | |
return (d[0] ? d[0] : d.properties.zipcode); | |
}) | |
.style("fill", function(d) { | |
return color(d[1]); | |
}) | |
.on("mouseover", function(d, i) { | |
tooltip.transition() | |
.duration(500) | |
.text("Restaurants in zipcode " + d[0] + ": " + d[1]); | |
return tooltip.style("visibility", "visible"); // show tooltip on hover | |
}) | |
.on("mousemove", function() { | |
return tooltip | |
.style("top", (d3.event.pageY + 1) + "px") | |
.style("left", (d3.event.pageX + 1) + "px"); | |
}) | |
.on("mouseout", function(d) { | |
d3.select(this) | |
.transition().duration(500) | |
.attr("x", x(0) + 100) | |
.attr("y", ybar(d[0])) | |
.attr("width", x(d[1])) | |
.attr("height", ybar.bandwidth() - 2); | |
return tooltip.style("visibility", "hidden"); | |
}) | |
.exit().style("fill", color(-1)); | |
g.append("g") | |
.attr("class", "legend") | |
.attr("transform", "translate(1,1)") | |
.append("text") | |
.attr("class", "axis--map--caption") | |
.attr("y", -6); | |
g.append("g") | |
.attr("class", "grid axis--x") | |
.attr("transform", "translate(0, 50)") | |
.call(d3.axisTop(scale).ticks(5).tickSize(-15).tickFormat("")) | |
g.selectAll(".scale").remove(); | |
g.selectAll(".label").remove(); | |
g.append("text") | |
.data(cuisineLegend) | |
.attr("class", "label") | |
.attr("x", 370) | |
.attr("y", 45) | |
.text(function(d) { | |
return "Number of " + d + " Restaurants"; | |
}); | |
for (i = 0; i < 4; ++i) { | |
g.append("rect") | |
.attr("class", "scale") | |
.attr("x", 370 + i * 35) | |
.attr("y", 50) | |
.attr('width', 35) | |
.attr("height", 7) | |
.style("fill", color(i / 4 * maxCount)); | |
} | |
for (i = 0; i < 4; ++i) { | |
g.append("text") | |
.attr("class", "scale") | |
.attr("x", 435 + 33 * (i - 2)) | |
.attr("y", 70) | |
.text(Math.round(i / 5 * maxCount).toString()); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment