Skip to content

Instantly share code, notes, and snippets.

@lingyielia
Last active April 29, 2018 20:50
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 lingyielia/ea6ad33ef89176dc9566eac049975ae5 to your computer and use it in GitHub Desktop.
Save lingyielia/ea6ad33ef89176dc9566eac049975ae5 to your computer and use it in GitHub Desktop.
NYC Cuisine Map
license: gpl-3.0
height: 1700
scrolling: no
border: yes
<!DOCTYPE html>
<meta name="robots" content="noindex">
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Cuisine Map</title>
<style id="jsbin-css">
.zipcode {
stroke: black;
stroke-width: 1px;
fill: none;
}
.mark {
stroke: black;
}
.tooltip {
position: absolute;
z-index: 10;
visibility: hidden;
background: beige;
padding: 5px;
border: 1px solid black;
}
.x-axis path {
display: none;
}
.y-axis path {
display: none;
}
.grid path {
stroke-width: 0;
}
.grid line {
stroke: lightgrey;
stroke-opacity: 0.7;
shape-rendering: crispEdges;
}
.label {
fill: black;
font-size: 14px;
}
</style>
</head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.3/d3.min.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.25.5/d3-legend.min.js"></script>
<body>
<div id="chart">
<svg width="400" height="800" id="svg1"></svg>
<svg width="650" height="800" id="svg2"></svg>
</div>
<script id="jsbin-javascript">
var ZIPCODE_URL =
"https://raw.githubusercontent.com/lingyielia/D3-visual/master/data/nyc_zip.geojson";
var RES_BY_CUISINE_URL =
"https://raw.githubusercontent.com/lingyielia/D3-visual/master/data/nyc_restaurants_by_cuisine.json";
d3.queue()
.defer(d3.json, ZIPCODE_URL)
.defer(d3.json, RES_BY_CUISINE_URL)
.await(createChart);
function createChart(error, zipcodes, byCuisine) {
////////////////////////////////////////////////////////
///////////////// map plot /////////////////////////////
////////////////////////////////////////////////////////
var svg2 = d3.select("#svg2"),
gMap = svg2.append("g"),
canvasSize = [650,800],
projection = d3.geoMercator()
.scale(Math.pow(2, 10.66 + 5.34))
.center([-73.975, 40.7])
.translate([canvasSize[0]/2, canvasSize[1]/2]),
path = d3.geoPath()
.projection(projection);
gMap.selectAll(".zipcode")
.data(zipcodes.features)
.enter()
.append("path")
.attr("class", "zipcode")
.attr("d", path);
var index = 0;
function mapUpdate(index) {
var counts = byCuisine[index].perZip,
data = Object.entries(counts),
maxCount = d3.max(data, d => d[1]),
color = d3.scaleThreshold()
.domain(d3.range(0, maxCount, maxCount/5))
.range(d3.schemeBlues[5])
zc = gMap.selectAll(".zipcode")
.data(data, myKey);
zc.merge(zc)
.transition().duration(1000)
.style("fill", d => color(d[1]));
zc.exit()
.transition().duration(1000)
.style("fill", "transparent");
var linear = d3.scaleLinear()
.domain([0,maxCount])
.range(["#BFD9E5", "#0758A2"]);
gMap.append("g")
.attr("class", "legendLinear")
.attr("transform", "translate(15,100)");
var legendLinear = d3.legendColor()
.title("Number of " + cuisine[index] + " Restauants")
.labelAlign("start")
.labelFormat(".2s")
.shapeHeight(5)
.shapeWidth(60)
.cells(4)
.orient('horizontal')
.scale(linear);
gMap.select(".legendLinear")
.call(legendLinear);
}
////////////////////////////////////////////////////////
///////////////// bar plot /////////////////////////////
////////////////////////////////////////////////////////
var svg1 = d3.select("#svg1"),
g = svg1.append("g"),
cuisine = byCuisine.slice(0,25).map(function(d) {return d.cuisine;}),
total = byCuisine.slice(0,25).map(function(d) {return d.total;}),
maxValue = d3.max(total);
var w = d3.scaleLinear()
.domain([0, maxValue])
.rangeRound([0, 200]);
// gridlines
var make_x_gridlines = d3.axisBottom()
.tickFormat("")
.tickSize(600)
.scale(w)
.ticks(5);
// add the x gridlines
g.append("g")
.attr("class", "grid")
.attr("transform", "translate(150,100)")
.call(make_x_gridlines);
g.selectAll(".mark")
.data(total)
.enter()
.append('rect')
.attr('class', 'mark')
.attr('x', 150)
.attr('y', function(d,i) {return 100+i*24;})
.attr('width', function(d,i) {return w(d);})
.attr('height', 22)
.attr('fill','lightgrey')
.on("mouseover", function(d) {
d3.select(this)
.transition().ease(d3.easeSin).duration(500)
.attr("fill", "SteelBlue")
.attr('x', 150)
.attr('width', function(d,i) {return w(d)+20;})
.attr('height', 22+2);
var index = mapUpdate(total.indexOf(d));
mapUpdate(index);
})
.on("mouseout", function(d) {
d3.select(this)
.transition().duration(500)
.attr("fill", "lightgrey")
.attr('x', 150)
.attr('width', function(d,i) {return w(d);})
.attr('height', 22);
});
var xAxis = d3.axisBottom()
.scale(w)
.ticks(5);
var xAxisTop = d3.axisTop()
.scale(w)
.ticks(5);
g.append("g")
.attr("class", "x-axis")
.attr("transform", "translate(150,700)")
.call(xAxis)
.append("text")
.attr("class", "label")
.style("text-anchor", "middle")
.attr("transform","translate(100,40)")
.text("Number of Restaurants");
g.append("g")
.attr("class", "x-axis")
.attr("transform", "translate(150,100)")
.call(xAxisTop);
var y = d3.scalePoint().domain(cuisine).range([0,577]);
var yAxis = d3.axisLeft()
.scale(y);
g.append("g")
.attr("class", "y-axis")
.attr("transform", "translate(146,110)")
.call(yAxis);
}
function myKey(d) {
return (d[0]?d[0]:d.properties.zipcode);
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment