Skip to content

Instantly share code, notes, and snippets.

@wanyanxie
Created April 15, 2016 07:23
Show Gist options
  • Save wanyanxie/25b548b2a7ccaddaef516745cd4a13f4 to your computer and use it in GitHub Desktop.
Save wanyanxie/25b548b2a7ccaddaef516745cd4a13f4 to your computer and use it in GitHub Desktop.
National Day of Civic Hacking: Learning D3.js (part 2)

Join the chat at https://gitter.im/Jay-Oh-eN/interactive-data-viz

These are the materials for an introduction to D3.js workshop for the National day of Civic Hacking (Code for SF) attendees.

We will be using the following two tools to works through these exercises:

I would love your feedback on the materials in the Gitter forum or in the Github issues.

And please do not hesitate to reach out to me directly via email at jondinu@gmail.com or over twitter @clearspandex

Exercises

  • Part 1: Bar chart of median rent over time for the Civic Center neighborhood in SF
  • Part 2 (you are here 👇): Improving the bar chart of median rent by using a line chart instead

The Data

The data is from Zillow and is calculated according to their methodology.

The files are comma separated with headers with each column representing a given neighborhood in SF:

Month Mission Bernal Heights Excelsior ...
2014-014.211248285322362.324840764331211.50130548302872 ...
2014-024.133333333333332.547263681592041.225 ...
2014-034.549214226633582.702127659574472.25225225225225 ...
... ... ... ... ...
---

Archival event link: National Day of Civic Hacking 2015: San Francisco

<style> @import url(http://fonts.googleapis.com/css?family=Crimson+Text:700italic,400,700,400italic); div.gist-readme { font: "Helvetica Neue",Helvetica,Arial,sans-serif; color: #666; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; } .gist-readme pre { width: 200%; margin-left: -50%; overflow: hidden; } .gist-readme p.small { color: #bbb; font-size: 14px; line-height: 1.5; display: block; } .gist-readme blockquote { padding-left: 15px; border-left: 4px solid #5694f1; color: #aaa; } .gist-readme span.code { font-family: Menlo, Monaco, Courier; background-color: #EEE; font-size: 14px; } .gist-readme pre { font-family: Menlo, Monaco, Courier; white-space: pre-wrap; padding: 20px; font-size: 14px; } .gist-readme code { padding: .25em .5em; font-size: 85%; color: #bf616a; background-color: #f9f9f9; border-radius: 3px; border: 1px solid #eee; } .gist-readme table { width: 100%; margin: 40px 0; border-collapse: collapse; font-size: 13px; line-height: 1.5em; } .gist-readme th, .gist-readme td { text-align: left; padding-right: 20px; vertical-align: top; } .gist-readme table td, .gist-readme td { border-spacing: none; border-style: solid; padding: 10px 15px; border-width: 1px 0 0 0; } .gist-readme tr > td { border-top: 1px solid #eaeaea; } .gist-readme tr:nth-child(odd) > td { background: #fcfcfc; } .gist-readme thead th, .gist-readme th { text-align: left; padding: 10px 15px; height: 20px; font-size: 13px; font-weight: bold; color: #444; border-bottom: 1px solid #dadadc; cursor: default; white-space: nowrap; } </style>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.12/d3.min.js"></script>
<style>
body {
font-family: futura;
width: 960px;
}
h2.title {
color: black;
text-align: center;
}
.axis {
font-family: arial;
font-size: 0.7em;
}
text {
fill: black;
stroke: none;
}
.label {
font-size: 1.5em;
}
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: #4eb0bb;
stroke-width: 1px;
}
</style>
<script type="text/javascript">
// https://github.com/mbostock/d3/wiki/Time-Formatting
format = d3.time.format("%Y-%m");
function draw(data) {
"use strict";
debugger;
// set margins according to Mike Bostock's margin conventions
// http://bl.ocks.org/mbostock/3019563
var margin = {top: 25, right: 40, bottom: 100, left: 75};
// set height and width of chart
var width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// specify the radius of our circles and the
// column we want to plot
var radius = 3,
field = 'Van Ness - Civic Center';
// Append the title for the graph
d3.select("body")
.append("h2")
.text(field + " Median Rent")
.attr('class', 'title');
// append the SVG tag with height and width to accommodate for margins
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append('g')
.attr('class','chart')
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// remove missing values
data = data.filter(function(d) {
return d[field];
});
// bind our data to svg circles for the scatter plot
svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
// maximum price
var max_y = d3.max(data, function(d) {
return +d[field];
});
// get min/max dates
var time_extent = d3.extent(data, function(d){
return format.parse(d['month']);
});
// Create x-axis scale mapping dates -> pixels
var time_scale = d3.time.scale()
.range([0, width])
.domain(time_extent);
// Create y-axis scale mapping price -> pixels
var measure_scale = d3.scale.linear()
.range([height, 0])
.domain([0, max_y]);
// 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"));
// Create D3 axis object from measure_scale for the y-axis
var measure_axis = d3.svg.axis()
.scale(measure_scale)
.orient("left");
// Append SVG to page corresponding to the D3 x-axis
svg.append('g')
.attr('class', 'x axis')
.attr('transform', "translate(0," + height + ")")
.call(time_axis);
// Append SVG to page corresponding to the D3 y-axis
svg.append('g')
.attr('class', 'y axis')
.call(measure_axis);
// add label to y-axis
var y_label = d3.select(".y.axis")
.append("text")
.attr('class', 'label')
.text("Price (dollar/sq-ft)")
.style('font-size', '1.2em')
.attr("transform", "rotate(-90)");
// center y axis label
y_label.attr("x", -(height / 2)).attr('y', -40)
.style("text-anchor", "middle");
// based on the data bound to each svg circle,
// change its center-x (cx) and center-y (cy)
// coordinates
d3.selectAll('circle')
.attr('cx', function(d) {
return time_scale(format.parse(d['month']));
})
.attr('cy', function(d) {
return measure_scale(+d[field]);
})
.attr('r', radius);
// 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['month'])); })
.y(function(d) { return measure_scale(+d[field]); });
// append a SVG path that corresponds to the line chart
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
};
</script>
</head>
<body>
<script type="text/javascript">
// load our data file asynchronously and pass the data
// to the draw function once it is loaded.
d3.csv("http://jay-oh-en.github.io/interactive-data-viz/data/sf_rent/median_rent_pct.csv", draw);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment