block by renecnielsen 254addab2deb0e096ccf

Infant Deaths

Full Screen

A random sample of 100 infant deaths from 2009 colored by infant’s sex.

This is a work in progress.

See 2009 Cohort Linked Birth/Infant Death Data Set Guide (pdf).

Source: National Bureau of Economic Research

forked from syntagmatic‘s block: Infant Deaths

index.html

<!DOCTYPE html>
<meta charset="utf-8">
<title>Infant Death</title>
<style>
svg {
  font: 10px sans-serif;
}

.foreground path {
  fill: none;
  stroke: #222;
  stroke-opacity: 0.38;
  pointer-events: none;
  stroke-width: 1.5px;
}
 
.axis .title {
  font-size: 8px;
  font-weight: bold;
  text-transform: uppercase;
  transform: rotate(-12deg) translate(-5px,-6px);
}

.axis line,
.axis path {
  fill: none;
  stroke: #000;
  stroke-width: 1px;
}

.brush .extent {
  fill-opacity: .3;
  stroke: #fff;
  stroke-width: 1px;
}

pre {
  width: 900px;
  margin: 10px 30px;
  tab-size: 12;
  font-size: 12px;
  overflow: auto;
}
</style>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script>

var margin = {top: 50, right: 80, bottom: 20, left: 80},
    width = 960 - margin.left - margin.right,
    height = 220 - margin.top - margin.bottom;

var types = {
  "Number": {
    key: "Number",
    coerce: function(d) { return +d; },
    extent: d3.extent,
    within: function(d, extent) { return extent[0] <= d && d <= extent[1]; },
    defaultScale: d3.scale.linear().range([height, 0])
  },
  "String": {
    key: "String",
    coerce: String,
    extent: function (data) { return data.sort(); },
    within: function(d, extent, dim) { return extent[0] <= dim.scale(d) && dim.scale(d) <= extent[1]; },
    defaultScale: d3.scale.ordinal().rangePoints([0, height])
  }
};

var dimensions = [
  {
    key: "mager14",
    description: "Mother's Age",
    scale: d3.scale.ordinal().rangePoints([0, height]),
    type: types["String"],
    axis: d3.svg.axis().orient("left")
      .tickFormat(function(d) {
        return {
          1: "Under 15",
          3: "15",
          4: "16",
          5: "17",
          6: "18",
          7: "19",
          8: "20-24",
          9: "25-29",
          10: "30-34",
          11: "35-39",
          12: "40-44",
          13: "45-49",
          14: "50-54"
        }[d]
      }),
    domain: [1,3,4,5,6,7,8,9,10,11,12,13,14]
  },
  {
    key: "fagerec11",
    description: "Father's Age",
    type: types["String"],
    domain: [1,2,3,4,5,6,7,8,9,10,11],
    axis: d3.svg.axis().orient("left")
      .tickFormat(function(d) {
        return {
          1: "Under 15",
          2: "15-19",
          3: "20-24",
          4: "25-29",
          5: "30-34",
          6: "35-39",
          7: "40-44",
          8: "45-49",
          9: "50-54",
          10: "55-98",
          11: "Not stated"
        }[d]
      })
  },
  {
    key: "sex",
    description: "Sex",
    type: types["String"]
  },
  {
    key: "dob_yy",
    description: "Birth Year",
    type: types["String"]
  },
  {
    key: "dob_mm",
    description: "Birth Month",
    type: types["String"],
    domain: d3.range(1,13),
    axis: d3.svg.axis().orient("left")
      .tickFormat(function(d) {
        return {
          1: "Jan",
          2: "Feb",
          3: "Mar",
          4: "Apr",
          5: "May",
          6: "Jun",
          7: "Jul",
          8: "Aug",
          9: "Sep",
          10: "Oct",
          11: "Nov",
          12: "Dec"
        }[d]
      })
  },
  {
    key: "mar",
    description: "Mother's Marital Status",
    type: types["String"],
    axis: d3.svg.axis().orient("left")
      .tickFormat(function(d) {
        return {
          1: "Yes",
          2: "No",
          9: "Unknown"
        }[d]
      })
  },
  {
    key: "meduc_rec",
    description: "Mother's Education",
    type: types["String"],
    axis: d3.svg.axis().orient("left")
      .tickFormat(function(d) {
        return {
          1: "0-8 years",
          2: "9-11 years",
          3: "12 years",
          4: "13-15 years",
          5: "16+ years",
          6: "Not stated"
        }[d]
      })
  },
  {
    key: "mpcb",
    description: "Month Prenatal Care Began",
    type: types["String"],
    axis: d3.svg.axis().orient("left")
      .tickFormat(function(d) {
        if (d == 0) return "No care";
        if (d <= 10) return d + " months";
        if (d == 99) return "Unknown";
      })
  },
  {
    key: "wtgain_rec",
    description: "Weight Gain",
    type: types["String"],
    axis: d3.svg.axis().orient("left")
      .tickFormat(function(d) {
        if (d < 98) return d + " lbs";
        if (d = 98) return "98+ lbs";
        if (d = 99) return "Unknown";
        return "null"
      })

  },
  {
    key: "cig_rec6",
    description: "Cigarettes Per Day",
    type: types["String"],
    axis: d3.svg.axis().orient("left")
      .tickFormat(function(d) {
        return {
          0: "Non-smoker",
          1: "1-5",
          2: "6-10",
          3: "11-20",
          4: "21-40",
          5: "41+",
          6: "Unknown"
        }[d]
      })
  },
  {
    key: "uop_induc",
    description: "Induction of Labor",
    type: types["String"],
    axis: d3.svg.axis().orient("left")
      .tickFormat(function(d) {
        return {
          1: "Yes",
          2: "No",
          9: "Unknown"
        }[d]
      })
  },
  {
    key: "ume_vag",
    description: "Vaginal Delivery",
    type: types["String"],
    axis: d3.svg.axis().orient("left")
      .tickFormat(function(d) {
        return {
          1: "Yes",
          2: "No",
          9: "Unknown"
        }[d]
      })
  },
  {
    key: "gestrec10",
    description: "Gestation (weeks)",
    type: types["String"],
    axis: d3.svg.axis().orient("left")
      .tickFormat(function(d) {
        return {
          1: "Under 20",
          2: "20-27",
          3: "28-31",
          4: "32-33",
          5: "34-36",
          6: "37-38",
          7: "39",
          8: "40",
          9: "41",
          10: "42+",
          99: "Unknown"
        }[d]

      })
  },
];

var colordimension = dimensions.filter(function(d) { return d.key == "sex"; })[0];

var color = d3.scale.ordinal()
  .range(["#1b9e77","#d95f02","#7570b3","#e7298a","#66a61e","#e6ab02","#a6761d","#666666"]);

var x = d3.scale.ordinal()
    .domain(dimensions.map(function(dim) { return dim.key; }))
    .rangePoints([0, width]);

var line = d3.svg.line()
    .defined(function(d) { return !isNaN(d[1]); });

var yAxis = d3.svg.axis()
    .orient("left");

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 + ")");

var output = d3.select("body").append("pre");

var foreground = svg.append("g")
  .attr("class", "foreground");

var axes = svg.selectAll(".axis")
    .data(dimensions)
  .enter().append("g")
    .attr("class", "axis")
    .attr("transform", function(d) { return "translate(" + x(d.key) + ")"; });

d3.csv("linkco2009us_num.csv", function(error, rawdata) {
  if (error) throw error;

  // take subset of data
  data = d3.shuffle(rawdata).slice(0,100);

  data.forEach(function(d) {
    dimensions.forEach(function(p) {
      d[p.key] = p.type.coerce(d[p.key]);
    });
  });

  // type/dimension default setting happens here
  dimensions.forEach(function(dim) {
    if (!("domain" in dim)) {
      // detect domain using dimension type's extent function
      dim.domain = d3.functor(dim.type.extent)(data.map(function(d) { return d[dim.key]; }));

      // TODO - this line only works because the data encodes data with integers
      // Sorting/comparing should be defined at the type/dimension level
      dim.domain.sort(function(a,b) {
        return a - b;
      });
    }
    if (!("scale" in dim)) {
      // use type's default scale for dimension
      dim.scale = dim.type.defaultScale.copy();
    }
    dim.scale.domain(dim.domain);
  });

  color.domain(colordimension.scale.domain());

  foreground.selectAll("path")
      .data(data)
    .enter().append("path")
      .attr("d", draw)
      .style("stroke", function(d) { return color(d[colordimension.key]); });

  axes.append("g")
      .attr("class", "axis")
      .each(function(d) {
        var renderAxis = "axis" in d
          ? d.axis.scale(d.scale)  // custom axis
          : yAxis.scale(d.scale);  // default axis
        d3.select(this).call(renderAxis);
      })
    .append("text")
      .attr("class", "title")
      .attr("text-anchor", "start")
      .text(function(d) { return "description" in d ? d.description : d.key; });

  // Add and store a brush for each axis.
  axes.append("g")
      .attr("class", "brush")
      .each(function(d) {
        d3.select(this).call(d.brush = d3.svg.brush()
          .y(d.scale)
          .on("brushstart", brushstart)
          .on("brush", brush));
      })
    .selectAll("rect")
      .attr("x", -8)
      .attr("width", 16);

  output.text(d3.tsv.format(data));

  function draw(d) {
    return line(dimensions.map(function(dim) {
      return [x(dim.key), dim.scale(d[dim.key])];
    }));
  }

  function brushstart() {
    d3.event.sourceEvent.stopPropagation();
  }

  // Handles a brush event, toggling the display of foreground lines.
  function brush() {
    var actives = dimensions.filter(function(p) { return !p.brush.empty(); }),
        extents = actives.map(function(p) { return p.brush.extent(); });

    var selected = [];

    d3.selectAll(".foreground path").style("display", function(d) {
      if (actives.every(function(dim, i) {
          // test if point is within extents for each active brush
          return dim.type.within(d[dim.key], extents[i], dim);
        })) {
        selected.push(d);
        return null;
      }
      return "none";
    });

    output.text(d3.tsv.format(selected));
  }
});

</script>