Skip to content

Instantly share code, notes, and snippets.

@espinielli
Last active July 5, 2016 15:05
Show Gist options
  • Save espinielli/26ab95770e41008e240b84e799ba088b to your computer and use it in GitHub Desktop.
Save espinielli/26ab95770e41008e240b84e799ba088b to your computer and use it in GitHub Desktop.
Civic Impact through Data Visualization: Final
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.8/d3.min.js"></script>
<style>
body, html {
width: 100%;
height: 100%;
}
svg {
width:50%;
height:100%;
float: left;
}
circle.airbnb {
fill: #e00007;
opacity: 0.6;
}
.axis {
font-family: arial;
font-size: 0.7em;
}
text {
fill: black;
}
.label {
font-size: 2em;
}
path {
fill: none;
stroke: black;
stroke-width: 2px;
}
.tick {
fill: none;
stroke: black;
}
circle {
opacity: 0.9;
stroke: none;
fill: red;
}
.line {
fill: none;
stroke: #e00007;
stroke-width: 1px;
}
</style>
<script>
function draw(geo_data) {
"use strict";
/*
D3.js setup code
*/
var margin = 75,
width = 750 - margin,
height = 780 - margin;
// https://github.com/mbostock/d3/wiki/Time-Formatting
var format = d3.time.format("%Y-%m-%d");
var projection = d3.geo.mercator()
.center([-122.433701, 37.767683])
.scale(230000)
.translate([width / 1.95, height / 1.74]);
var path = d3.geo.path()
.projection(projection);
var map = d3.select('#map').selectAll('path')
.data(geo_data.features)
.enter()
.append('path')
.attr('d', path)
.style('fill', '#eee')
.style('stroke', 'black')
.style('stroke-width', 1);
map.datum(function(d) {
var normalized = d.properties.neighbourhood
.replace(/ /g, '_')
.replace(/\//g, '_');
d.properties.neighbourhood = normalized;
return d;
});
map.attr('class', function(d) {
return d.properties.neighbourhood;
});
d3.json("http://cdn.rawgit.com/hopelessoptimism/interactive-data-viz/master/data/airbnb/listing_count.json", function(data) {
var listings_extent = d3.extent(d3.values(data));
var bubbles = d3.select('#map').append("g")
.attr("class", "bubble")
.selectAll("circle")
.data(geo_data.features)
.enter()
.append("circle")
.attr('class', 'airbnb');
bubbles.datum(function(d) {
d.count = data[d.properties.neighbourhood];
return d;
});
var radius = d3.scale.pow().exponent(1.2)
.domain(listings_extent)
.range([3, 25]);
bubbles
.attr("cx", function(d) { return path.centroid(d.geometry)[0]; })
.attr("cy", function(d) { return path.centroid(d.geometry)[1]; })
.attr("r", function(d) { return radius(d.count); });
d3.csv('http://cdn.rawgit.com/hopelessoptimism/interactive-data-viz/master/data/airbnb/neighborhood_reviews_timeseries.csv',
function(timeseries) {
var field = "Mission";
// maximum reviews
var max_y = d3.max(timeseries, function(d) {
var max = 0;
d3.values(d).forEach(function(i) {
if (+i && (+i > max)) {
max = +i;
}
});
return max;
});
// Create y-axis scale mapping price -> pixels
var measure_scale = d3.scale.linear()
.range([height, 100])
.domain([0, max_y]);
// Create D3 axis object from measure_scale for the y-axis
var measure_axis = d3.svg.axis()
.scale(measure_scale)
.orient("right");
// Append SVG to page corresponding to the D3 y-axis
d3.select('#chart').append('g')
.attr('class', 'y axis')
.attr("transform", "translate(" + (width - 40) + " ,0)")
.call(measure_axis);
// add label to y-axis
d3.select(".y.axis")
.append("text")
.attr('class', 'label')
.text("Reviews per week")
.attr("transform", "translate(45,300) rotate(90)");
var drawChart = function(field) {
d3.select('#chart').select('.x.axis').remove();
d3.select('#chart').select('#chart path').remove();
d3.select('#heading')
.text(field);
// remove missing values
timeseries = timeseries.filter(function(d) {
return d[field];
});
// get min/max dates
var time_extent = d3.extent(timeseries, function(d){
return format.parse(d['timestamp']);
});
// Create x-axis scale mapping dates -> pixels
var time_scale = d3.time.scale()
.range([0, width - 50])
.domain(time_extent);
// Create D3 axis object from time_scale for the x-axis
var time_axis = d3.svg.axis()
.scale(time_scale)
.tickFormat(d3.time.format("%b '%y"));
// Append SVG to page corresponding to the D3 x-axis
d3.select('#chart').append('g')
.attr('class', 'x axis')
.attr('transform', "translate(0," + height + ")")
.call(time_axis);
// define the values to map for x and y position of the line
var line = d3.svg.line()
.x(function(d) { return time_scale(format.parse(d['timestamp'])); })
.y(function(d) { return measure_scale(+d[field]); });
// append a SVG path that corresponds to the line chart
d3.select('#chart').append("path")
.datum(timeseries)
.attr("class", "line")
.attr("d", line);
};
drawChart(field);
var mover = function(d) {
var neigh = d.properties.neighbourhood;
d3.select('#map path.' + neigh).style('fill', 'black');
drawChart(neigh);
};
var mout = function(d) {
var neigh = d.properties.neighbourhood;
d3.select('path.' + neigh).style('fill', '#eee');
}
map.on("mouseover", mover);
map.on("mouseout", mout);
bubbles.on('mouseover', mover);
bubbles.on('mouseout', mout);
});
});
}
</script>
</head>
<body>
<svg id="map"></svg>
<svg id="chart">
<text x="50%" y="50" id="heading" font-size="2em" text-anchor="middle" font-family="futura">SF</text>
</svg>
<script>
d3.json("http://cdn.rawgit.com/hopelessoptimism/interactive-data-viz/master/data/airbnb/neighbourhoods.geojson", draw);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment