Skip to content

Instantly share code, notes, and snippets.

@ctufts
Last active December 13, 2016 20:35
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 ctufts/a7acd0ba3d8dfd72bd2773a855184784 to your computer and use it in GitHub Desktop.
Save ctufts/a7acd0ba3d8dfd72bd2773a855184784 to your computer and use it in GitHub Desktop.
Philadelphia Air Quality Index Days - Multi-Series Path, Point, and Tooltip
license: gpl-3.0
height: 500
Year Good Moderate Unhealthy
1990 71 214 80
1991 110 179 76
1992 106 197 63
1993 94 175 96
1994 72 184 109
1995 114 171 80
1996 111 147 107
1997 132 159 74
1998 150 178 37
1999 132 203 30
2000 142 198 26
2001 103 223 39
2002 127 188 50
2003 146 188 31
2004 138 204 24
2005 150 187 28
2006 154 178 33
2007 140 193 32
2008 128 217 21
2009 185 175 5
2010 175 165 25
2011 159 192 14
2012 147 198 21
2013 174 185 6
2014 131 228 6
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Philadelphia Air Quality</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<link rel="stylesheet" type="text/css" href="main.css">
</head>
<body>
<script>
// Define margins as per convention:
//http://bl.ocks.org/mbostock/3019563
var margin = {
top: 20,
right: 60,
bottom: 20,
left: 30
};
var width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// chart title
svg.append("text")
.attr("x", width / 2)
.attr("y", 0)
.attr("text-anchor", "middle")
.attr("font-family", "sans-serif")
.attr("font-size", "16px")
.attr("font-weight", "bold")
.attr("fill", "black")
.text("Air Quality Index Days");
// set up date parsing and scale ranges
var parseTime = d3.timeParse("%Y");
var x = d3.scaleTime().range([0, width]),
y = d3.scaleLinear()
.domain([0, 365])
.range([height, 0]),
z = d3.scaleOrdinal(d3.schemeCategory10);
// function for generation of path
var line = d3.line()
.curve(d3.curveLinear)
.x(function(d) {
return x(d.date);
})
.y(function(d) {
return y(d.days);
});
d3.csv('Air_Quality_Index_Days.csv', type, function(error, data) {
if (error) throw error;
var airData = data.columns.slice(1).map(function(id) {
// creates an array of objects:
// One object for each column name (id)
// Contains an id field and a values field
// the values field is an object containing
// two arrays : date and temperature
return {
id: id,
values: data.map(function(d) {
return {
date: d.Year,
days: d[id]
};
})
};
});
console.log(airData);
// set x domain
x.domain([
d3.min(airData, function(c) {
return d3.min(c.values, function(d) {
return d.date;
});
}),
d3.max(airData, function(c) {
return d3.max(c.values, function(d) {
return d.date;
});
})
]);
// set up z (fill) domain
z.domain(airData.map(function(c) {
return c.id;
}));
// create axis
var xAxis = d3.axisBottom()
.scale(x);
var yAxis = d3.axisLeft()
.scale(y);
// create paths for each outcome
var airQuality = svg.selectAll(".airQuality")
.data(airData)
.enter().append("g")
.attr("class", "airQuality");
airQuality.append("path")
.attr("class", "line")
.attr("d", function(d) {
return line(d.values);
})
.style("stroke", function(d) {
return z(d.id);
});
// Add individual data points
svg.selectAll(".aqpoints")
.data(airData)
.enter().append("g")
.attr("class", "aqpoints")
.style("fill", function(d) {
return z(d.id);
})
.selectAll(".point")
.data(function(d) {
return d.values;
})
.enter().append("circle")
.attr("class", "point")
.attr("r", 4.5)
.attr("cx", function(d) {
return x(d.date);
})
.attr("cy", function(d) {
return y(d.days);
})
.on("mouseover", function(d) {
//calculate position of tooltip
var xPosition = parseFloat(d3.select(this).attr("cx"));
var yPosition = parseFloat(d3.select(this).attr("cy")) - 20;
//Create the tooltip label
svg.append("text")
.attr("id", "tooltip")
.attr("x", xPosition)
.attr("y", yPosition)
.attr("text-anchor", "middle")
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("font-weight", "bold")
.attr("fill", "black")
.text(d.days);
})
.on("mouseout", function() {
//Remove the tooltip
d3.select("#tooltip").remove();
});
// append axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("fill", "#000")
.text("Days per Year");
//label each series
airQuality.append("text")
.datum(function(d) {
return {
id: d.id,
value: d.values[d.values.length - 1]
};
})
.attr("transform", function(d) {
return "translate(" + (x(d.value.date) - 5) + "," + (y(d.value.days) - 20) + ")";
})
.attr("x", 3)
.attr("dy", "0.35em")
.style("font", "12px sans-serif")
.attr("font-weight", "bold")
.attr("fill", function(d) {
return z(d.id)
})
.text(function(d) {
return d.id;
});
});
// row data format function
function type(d, _, columns) {
d.Year = parseTime(d.Year);
for (var i = 1, n = columns.length, c; i < n; ++i) d[c = columns[i]] = +d[c];
return d;
}
</script>
<p></p>
<a href="https://www.opendataphilly.org/dataset/air-quality-index-days">Source: Open Data Philly</a>
</body>
</html>
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
.point {
stroke: #000;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment