Skip to content

Instantly share code, notes, and snippets.

@SHewitt95
Created February 29, 2016 20:46
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 SHewitt95/269f3cf71e8cb71369ad to your computer and use it in GitHub Desktop.
Save SHewitt95/269f3cf71e8cb71369ad to your computer and use it in GitHub Desktop.
Dots on Lines
<!DOCTYPE html>
<!-- Modification of an example by Scott Murray from Knight D3 course -->
<html lang="en">
<head>
<meta charset="utf-8">
<title>College Enrollment Percentages</title>
<style type="text/css">
body {
background-color: white;
font-family: Helvetica, Arial, sans-serif;
}
h1 {
font-size: 24px;
margin: 0;
}
p {
font-size: 14px;
margin: 10px 0 0 0;
}
svg {
background-color: white;
}
.axis path,
.axis line {
fill: none;
stroke: black;
stroke-width: 1px;
}
.line {
fill: none;
/*stroke: gray;*/
stroke-width: 2px;
stroke-opacity: 80%;
}
.line.unfocused{
stroke-opacity: 30%;
}
.line.focused {
stroke-width: 4px;
stroke-opacity: 100%;
/*stroke: black;*/
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
.tooltip {
position: absolute;
z-index: 10;
background-color: white;
}
.tooltip p {
background-color: white;
border: none;
padding: 2px;
}
.container {
display: block;
width: 50%;
margin: 1em auto;
}
.ylabel {
transform: rotate(-90deg);
}
</style>
</head>
<body>
<div class="container">
<h1>College Enrollment Percentages, from 2000 to 2012</h1>
<p>Source: Data.gov, U.S. Department of Commerce, Census Bureau, Current Population Survey</p>
<p>The data portrays the changing percentages of 18 to 24-year-olds per race/ethnicity who attend 2 or 4-year colleges. For example, in 2000, 21.7 percent of all Hispanics between age 18 and 24 attended college. By 2012, that percentage increased by about 16 percent to 37.5 percent.</p>
<p>Hover over the lines to display data points associated with the line. Lines with labels indicate races or ethnicities with the highest and lowest percentage in 2012.</p>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<script type="text/javascript">
//Dimensions and padding
var fullwidth = window.innerWidth; // Allows SVG wo be size of current window upon load.
var fullheight = 600;
var margin = { top: 20, right: 350, bottom: 40, left: 100};
var width = fullwidth - margin.left - margin.right;
var height = fullheight - margin.top - margin.bottom;
//Set up date formatting and years
var dateFormat = d3.time.format("%Y");
var xScale = d3.time.scale()
.range([ 0, width]);
var yScale = d3.scale.linear()
.range([0, height]);
//Configure axis generators
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(15)
.tickFormat(function(d) {
return dateFormat(d);
})
.innerTickSize([5]);
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.innerTickSize([5]);
//Configure line generator
// each line dataset must have a d.year and a d.amount for this to work.
var line = d3.svg.line()
.x(function(d) {
console.log(d);
return xScale(dateFormat.parse(d.year));
})
.y(function(d) {
return yScale(+d.percent);
});
// add a tooltip to the page - not to the svg itself!
var tooltip = d3.select("body")
.append("div")
.attr("class", "tooltip");
//Create the empty SVG image
var svg = d3.select("body")
.append("svg")
.attr("width", fullwidth)
.attr("height", fullheight)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//Load data
d3.csv("Race_Education_Data.csv", function(data) {
//Data is loaded in, but we need to restructure it.
//Remember, each line requires an array of x/y pairs;
//that is, an array of arrays, like so:
//
// [ [x: 1, y: 1], [x: 2, y: 2], [x: 3, y: 3] ]
//
//We, however, are using 'year' as x and 'amount' as y.
//We also need to know which country belongs to each
//line, so we will build an array of objects that is
//structured like this:
/*
[
{
country: "Australia",
emissions: [
{ year: 1961, amount: 90589.568 },
{ year: 1962, amount: 94912.961 },
{ year: 1963, amount: 101029.517 },
]
},
{
country: "Bermuda",
emissions: [
{ year: 1961, amount: 176.016 },
{ year: 1962, amount: 157.681 },
{ year: 1963, amount: 150.347 },
]
},
]
**** My Data structure ****
Stats = [
{
race: "Hispanic",
data: [
year: "2000",
percent: 15
]
}
]
*/
//Note that this is an array of objects. Each object
//contains two values, 'country' and 'emissions'.
//The 'emissions' value is itself an array, containing
//more objects, each one holding 'year' and 'amount' values.
//New array with all the years, for referencing later
//var years = ["1961", "1962", "1963", "1964", "1965", "1966", "1967", "1968", "1969", "1970", "1971", "1972", "1973", "1974", "1975", "1976", "1977", "1978", "1979", "1980", "1981", "1982", "1983", "1984", "1985", "1986", "1987", "1988", "1989", "1990", "1991", "1992", "1993", "1994", "1995", "1996", "1997", "1998", "1999", "2000", "2001", "2002", "2003", "2004", "2005", "2006", "2007", "2008", "2009", "2010"];
// or you could get this by doing:
var years = d3.keys(data[0]).slice(0, 13);
//Create a new, empty array to hold our restructured dataset
var dataset = [];
//Loop once for each row in data
data.forEach(function(d, i) {
var eduPerYear = [];
//Loop through all the years
years.forEach(function(y) {
if (d[y]) {
//Add a new object to the new eduPerYear data array - for year, percent
eduPerYear.push({
race: d["Race or Ethnicity"],
year: y,
percent: d[y]
});
}
})
//Create new object with this race's name and empty array
// d is the current data row... from data.forEach above.
dataset.push({
race: d["Race or Ethnicity"],
data: eduPerYear
});
}) // End of data.forEach loop.
//Set scale domains - max and min of the years
xScale.domain(
d3.extent(years, function(d) {
return dateFormat.parse(d);
}));
// max of emissions to 0 (reversed, remember) - [max, 0] for y scale
yScale.domain([
d3.max(dataset, function(d) {
return d3.max(d.data, function(d) {
return +d.percent;
});
}),
0
]);
// Adds labels to end of lines
svg
.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
if (d.race == "Asian, non-Hispanic" || d.race == "American Indian/Alaska Native, non-Hispanic") {
return d.race;
} else {
return "";
}
})
.attr("transform", function(d,i) {
return "translate(" + (width+3) + "," + yScale(d.data[data.length-1].percent) + ")";
})
.attr("dy", "-5");
//Make a group for each country - just for the data binding
var groups = svg.selectAll("g.lines")
.data(dataset)
.enter()
.append("g")
.attr("class", "lines");
var circles = groups.selectAll("circle")
.data(function(d) {
//console.log(d);
return d.data;
})
.enter()
.append("circle")
.style("opacity", 0);
//console.log(dataset);
circles.attr("cx", function(d, i) {
//console.log(d);
return xScale(dateFormat.parse(d.year))
})
.attr("cy", function(d, i) {
return yScale(d.percent);
})
.attr("r", 6)
.attr("fill", "green");
//Within each group, create a new line/path,
//binding just the emissions data to each one
//var colors = d3.scale.category10();
groups.selectAll("path")
.data(function(d) { // because there's a group with data per race already...
return [ d.data ]; // it has to be an array for the line function
})
.enter()
.append("path")
.attr("class", "line")
.attr("d", line); // calls the line function you defined above, using that array
// Adds color to the lines.
d3.selectAll("path.line").attr("stroke", function(d,i) {
return "green";
});
//Axes
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
// here we add the mouseover and mouseout effect, and use the id we created to style it.
// this is on the g elements, because the country name is in the data there.
// the line itself has data of an array of x,y values.
d3.selectAll("g circle")
.on("mouseover", mouseoverFunc)
.on("mouseout", mouseoutFunc)
.on("mousemove", mousemoveFunc); // this version calls a named function.
}); // end of data csv
function mouseoverFunc(d) {
d3.select(this)
.transition()
.duration(500)
.style("opacity", 1);
tooltip.style("display", null)
.html("<p>Year: " + d.year + "</p>"
+ "<p>Race: " + d.race + "</p>"
+ "<p>Percent: " + d.percent + "%</p>"
);
}
function mouseoutFunc() {
d3.select(this)
.transition()
.duration(500)
.style("opacity", 0);
tooltip.style("display", "none"); // this sets it to invisible!
}
function mousemoveFunc(d) {
//console.log("events", window.event, d3.event);
tooltip
.style("top", (d3.event.pageY - 10) + "px" )
.style("left", (d3.event.pageX + 10) + "px");
}
// X-axis label
svg.append("text")
.attr("class", "xlabel")
.attr("transform", "translate(" + width/2 + " ," +
height + ")")
.style("text-anchor", "middle")
.attr("dy", "35")
.text("Year");
</script>
</div> <!-- End container -->
</body>
</html>
Race or Ethnicity 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012
White, non-Hispanic 38.7 39.5 40.9 41.6 41.7 42.8 41 42.6 44.2 45 43.3 44.7 42.1
Black, non-Hispanic 30.5 31.4 31.9 32.3 31.8 33.1 32.6 33.1 32.1 37.7 38.4 37.1 36.4
Hispanic 21.7 21.7 19.9 23.5 24.7 24.8 23.6 26.6 25.8 27.5 31.9 34.8 37.5
Asian, non-Hispanic 55.9 61.3 60.9 61.2 60.6 61 58.3 57.2 59.3 65.2 63.6 60.1 59.8
Pacific Islander, non-Hispanic 43.3 55.8 50.6 39.1 37.1 27.3 33.4 36 37.8 50.3
American Indian/Alaska Native, non-Hispanic 15.9 23.3 23.6 17.7 24.4 27.8 26.2 24.7 21.9 29.8 41.4 23.5 27.8
Two or more races, non-Hispanic 41.6 36.8 41.8 38.5 39.2 45.7 39.3 38.3 38.8 39.4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment