block by dhoboy 4c8f05129838a63ec90930f8c46262f0

Beijing Air Quality

Full Screen

Readings of the amount of PM2.5 (particulate matter less than 2.5 micrometers in diameter) in the air in Beijing for every hour over the past 8 years. Readings reported in micrograms per cubic meter.

Data is not fully validated or verified, collected unofficially from the U.S. Embassy in Beijing, and provided by the U.S. Department of State

index.html

<!DOCTYPE html>
<meta charset="utf-8">
<style>
body { font: 10px sans-serif; }

.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

.x.axis path { display: none; }

.line {
  fill: none;
  stroke-width: 1.5px;
  stroke-linecap: round;
}

.line.yr_2008 { stroke: #a6cee3; }
.line.yr_2009 { stroke: #1f78b4; }
.line.yr_2010 { stroke: #b2df8a; }
.line.yr_2011 { stroke: #33a02c; }
.line.yr_2012 { stroke: #fb9a99; }
.line.yr_2013 { stroke: #e31a1c; }
.line.yr_2014 { stroke: #fdbf6f; }
.line.yr_2015 { stroke: #ff7f00; }

#years_form {
  width: 36%;
  margin: auto;
}

</style>
<body>
<form name="example" id="years_form">
  <input type="checkbox" class="years" name="year" value="yr_2008" checked onchange="toggle()">2008
  <input type="checkbox" class="years" name="year" value="yr_2009" onchange="toggle()">2009
  <input type="checkbox" class="years" name="year" value="yr_2010" onchange="toggle()">2010
  <input type="checkbox" class="years" name="year" value="yr_2011" onchange="toggle()">2011
  <input type="checkbox" class="years" name="year" value="yr_2012" onchange="toggle()">2012
  <input type="checkbox" class="years" name="year" value="yr_2013" onchange="toggle()">2013
  <input type="checkbox" class="years" name="year" value="yr_2014" onchange="toggle()">2014
  <input type="checkbox" class="years" name="year" value="yr_2015" onchange="toggle()">2015
</form>
<script src="//d3js.org/d3.v3.js"></script>
<script>
var margin = {top: 10, right: 50, left: 50, bottom: 40},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

var x = {}; // x is time

var y = d3.scale.linear() // y is value
  .domain([0, 1000])
  .range([height, 0]);

var line = {}; // path generators

var svg = d3.select("body").append("svg")
  .attr("width", width + margin.right + margin.left)
  .attr("height", height + margin.top + margin.bottom)
  .append("g")
  .attr("transform", "translate(" + margin.left + "," + margin.top + ")")

var data = {}, remaining = 8; // parallel loading csv code from here: https://groups.google.com/forum/#!msg/d3-js/3Y9VHkOOdCM/YnmOPopWUxQJ
d3.csv("//dhoboy.github.io/china-air-files/beijing2008.csv", function(data_2008) {
  data.yr_2008 = data_2008;
  if (!--remaining) draw();
})

d3.csv("//dhoboy.github.io/china-air-files/beijing2009.csv", function(data_2009) {
  data.yr_2009 = data_2009;
  if (!--remaining) draw();
})

d3.csv("//dhoboy.github.io/china-air-files/beijing2010.csv", function(data_2010) {
  data.yr_2010 = data_2010;
  if (!--remaining) draw();
})

d3.csv("//dhoboy.github.io/china-air-files/beijing2011.csv", function(data_2011) {
  data.yr_2011 = data_2011;
  if (!--remaining) draw();
})

d3.csv("//dhoboy.github.io/china-air-files/beijing2012.csv", function(data_2012) {
  data.yr_2012 = data_2012;
  if (!--remaining) draw();
})

d3.csv("//dhoboy.github.io/china-air-files/beijing2013.csv", function(data_2013) {
  data.yr_2013 = data_2013;
  if (!--remaining) draw();
})

d3.csv("//dhoboy.github.io/china-air-files/beijing2014.csv", function(data_2014) {
  data.yr_2014 = data_2014;
  if (!--remaining) draw();
})

d3.csv("//dhoboy.github.io/china-air-files/beijing2015.csv", function(data_2015) {
  data.yr_2015 = data_2015;
  if (!--remaining) draw();
})

function draw() {
  var data_keys = d3.keys(data);

  data_keys.forEach(function(year) { // set x scale's domain
    x[year] = d3.time.scale()
      .range([0, width]);
  })

  var default_x_scale = d3.time.scale() // for the axis
    .domain([new Date(2015, 0, 1, 0), new Date(2015, 11, 31, 23)])
    .range([0, width]);

  data = d3.entries(data);

  data.forEach(function(dataset) {
    dataset.value = dataset.value.filter(function(d) { // only want valid readings
      return d["QC Name"] == "Valid" && d["Value"] != "-999";
    }).map(function(d) { // form datasets to be date and value
      return {date: new Date(d["Year"], d["Month"]-1, d["Day"], d["Hour"]), value: +d["Value"]};
    });

    x[dataset.key]
      .domain(d3.extent(dataset.value, function(d) { return d.date; }))

    line[dataset.key] = d3.svg.line()
        .x(function(d) { return x[dataset.key](d.date); })
        .y(function(d) { return y(d.value); })
        .interpolate("linear");
  });

  var xAxis = d3.svg.axis()
    .scale(default_x_scale)
    .orient("bottom")
    .tickFormat(d3.time.format("%B"));

  var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left")
    .ticks(10)

  /* axes */
  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", ".71em")
      .style("text-anchor", "end")
      .text("PM2.5/micrograms per cubic meter")

  /* lines */
  data.forEach(function(dataset) {
    svg.append("path")
      .datum(dataset.value)
      .attr("class", "line " + dataset.key)
      .attr("d", line[dataset.key])
  });

  svg.selectAll(".line")
    .style("display", "none");

  toggle();
}

function toggle() {
  for (var i = 0; i < document.example.year.length; i++) {
    var year = document.example.year[i];
    if (year.checked) {
      svg.select("." + year.value)
        .style("display", "block")
    } else {
      svg.select("." + year.value)
        .style("display", "none")
    }
  }
}
</script>