block by curran efe359877d85ddd1e225

Crime by Race Dataset (Normalized)

Full Screen

This is a dataset on crime in 2014, subdivided by race and offense. Originally found in table 43 in the FBI Web Site “2014 Crime in the United States”. This is the same data as in a previous block, but normalized such that “Race” is now a single column rather than a collection of different columns. This allows the data to be easily used with d3.nest and other utilities/

This example page provides the basic code required to load the data and display it on the page (as JSON) using D3.js.

Built with blockbuilder.org

forked from curran‘s block: Crime by Race Dataset

web counter

forked from curran‘s block: Crime by Race Dataset (Normalized)

index.html

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.9/d3.min.js"></script>
  <script src="//curran.github.io/dsv-dataset/dsv-dataset-v0.2.1.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/d3-legend/1.1.0/d3-legend.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/d3-tip/0.6.3/d3-tip.min.js"></script>
  <link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
  <style>

    .axis text {
      font-family: 'Open Sans', sans-serif;
      font-size: 19pt;
    }
    .axis .label {
      font-size: 20pt;
    }

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

    .color-legend text {
      font-family: 'Open Sans', sans-serif;
      font-size: 10pt;
    }

    .d3-tip {
      font-family: 'Open Sans', sans-serif;
      font-size: 19pt;
      line-height: 1;
      padding: 7px;
      background: black;
      color: lightgray;
      border-radius: 20px;
    }

  </style>
</head>

<body>
  <script>
    
    var outerWidth = 960;
    var outerHeight = 500;
    var margin = { left: 130, top: 44, right: 30, bottom: 47 };
    var barPadding = 0.2;

    var xColumn = "Offense charged";
    var yColumn = "count";
    var colorColumn = "Race";
    var layerColumn = colorColumn;

    var hoveredColorValue;
    var hoveredStrokeColor = "black";

    var innerWidth  = outerWidth  - margin.left - margin.right;
    var innerHeight = outerHeight - margin.top  - margin.bottom;

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

    // This is the layer where the bars are drawn.
    var baseBarLayer = g.append("g");

    // This layer contains a semi-transparent overlay
    // that fades out the base bars.
    var overlayRect = g.append("g")
      .append("rect")
      .attr("width", innerWidth)
      .attr("height", innerHeight)
      .style("pointer-events", "none");

    // This contains the subset of bars rendered on top
    // when you hover over the entries in the color legend.
    var foregroundBarLayer = g.append("g");

    var xAxisG = g.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + innerHeight + ")");
    var yAxisG = g.append("g")
      .attr("class", "y axis");
    var colorLegendG = g.append("g")
      .attr("class", "color-legend")
      .attr("transform", "translate(596, 0)");

    var xScale = d3.scale.ordinal().rangeBands([0, innerWidth], barPadding);
    var yScale = d3.scale.linear().range([innerHeight, 0]);
    var colorScale = d3.scale.category10();

    var tipNumberFormat = d3.format(",");
    var tip = d3.tip()
      .attr("class", "d3-tip")
      .offset([-10, 0])
      .html(function(d) {
        return [
          d[colorColumn],
          " in ",
          d[xColumn],
          ": ",
          tipNumberFormat(d[yColumn])
        ].join("");
      });
    g.call(tip);

    // Use a modified SI formatter that uses "B" for Billion.
    var siFormat = d3.format("s");
    var customTickFormat = function (d){
      return siFormat(d).replace("G", "B");
    };

    var xAxis = d3.svg.axis().scale(xScale).orient("bottom")
      .outerTickSize(0);
    var yAxis = d3.svg.axis().scale(yScale).orient("left")
      .ticks(5)
      .tickFormat(customTickFormat)
      .outerTickSize(0);

    var colorLegend = d3.legend.color()
      .scale(colorScale)
      .shapePadding(6.24)
      .shapeWidth(25)
      .shapeHeight(6)
      .labelOffset(5);

    function render(data){
      console.log(data);

      var nested = d3.nest()
        .key(function (d){ return d[layerColumn]; })
        .entries(data);

      var stack = d3.layout.stack()
        .y(function (d){ return d[yColumn]; })
        .values(function (d){ return d.values; });

      var layers = stack(nested.reverse()).reverse();

      xScale.domain(layers[0].values.map(function (d){
        return d[xColumn];
      }));

      yScale.domain([
        0,
        d3.max(layers, function (layer){
          return d3.max(layer.values, function (d){
            return d.y0 + d.y;
          });
        })
      ]);

      colorScale.domain(layers.map(function (layer){
        return layer.key;
      }));

      xAxisG.call(xAxis); 
      yAxisG.call(yAxis);

      renderBars(baseBarLayer, layers);

      if(hoveredColorValue){
        setOverlayTransparency(0.7);
        renderBars(foregroundBarLayer, layers.filter(function (layer){
          return layer.key === hoveredColorValue;
        }));
      } else {
        setOverlayTransparency(0.0);
        renderBars(foregroundBarLayer, []);
      }

      colorLegendG.call(colorLegend);

      // Move the text down a bit.
      colorLegendG.selectAll("text").attr("y", 4);

      listenForHover(colorLegendG.selectAll("rect"), data);
      listenForHover(colorLegendG.selectAll("text"), data);
    }

    function setOverlayTransparency(alpha){
      overlayRect
        .transition().duration(400)
        .attr("fill", "rgba(255, 255, 255, " + alpha + ")");
    }

    function renderBars(g, layers){
      var layerGs = g.selectAll(".layer").data(layers);
      layerGs.enter().append("g").attr("class", "layer");
      layerGs.exit().remove();
      layerGs.style("fill", function (d){
        return colorScale(d.key);
      });

      var bars = layerGs.selectAll("rect").data(function (d){
        return d.values;
      });
      bars.enter().append("rect")
        .on("mouseover", tip.show)
        .on("mouseout", tip.hide);
      bars.exit().remove();
      bars
        .attr("x", function (d){ return xScale(d[xColumn]); })
        .attr("y", function (d){ return yScale(d.y0 + d.y); })
        .attr("width", xScale.rangeBand())
        .attr("height", function (d){ return innerHeight - yScale(d.y); });
    }

    function listenForHover(selection, data){
      selection
        .on("mouseover", function (d){
          hoveredColorValue = d;
          render(data);
        })
        .on("mouseout", function (d){
          hoveredColorValue = null;
          render(data);
        })
        .style("cursor", "pointer");
    }
 
    d3.csv("data.csv", function(data){
      d3.json("data.json", function(metadata){
        
        var dataset = dsvDataset.parse({
          data: data,
          metadata: metadata
        });
        
        // Transform the table so "Race" is a single column.
        data = normalize(dataset.data, "Race", "count", [
          "White",
          "Black or African American",
          "American Indian or Alaska Native",
          "Asian",
          "Native Hawaiian or Other Pacific Islander"
        ]);
        
        // Remove the "TOTAL" values.
        data = data.filter(function (d){
          return d["Offense charged"] !== "TOTAL";
        });
        
        data.forEach(function (d){
          delete d["Total"];
        });
        
        render(data);
      });
    });
    
    function normalize(dataIn, dimension, measure, values){
      
      var data = []; 
      
      // All the columns not in "values".
      var columns = Object.keys(dataIn[0]).filter(function (column){
        return !values.some(function (value){
          return column === value;
        });
      });
      
      dataIn.forEach(function (d){
        values.forEach(function (value){
          var row = {};
          
          // Pivot the given value columns into rows.
          row[dimension] = value;
          row[measure] = d[value];
          
          // Copy over values from other columns.
          columns.forEach(function (column){
            row[column] = d[column];
          });
          
          data.push(row);
        });
      });
      
      return data;
    }
    
  </script>
</body>

data.csv

Offense charged,Total,White,"Black or African American","American Indian or Alaska Native",Asian,"Native Hawaiian or Other Pacific Islander"
TOTAL,8730665,6056687,2427683,135599,100067,10629
Murder and nonnegligent manslaughter,8230,3807,4224,83,107,9
Rape,16326,10977,4888,212,222,27
Robbery,74077,31354,41379,616,617,111
Aggravated assault,291600,185612,96511,4372,4507,598
Burglary,186794,126242,56504,1703,1999,346
Larceny-theft,971199,671260,271788,15869,11355,927
Motor vehicle theft,53456,35551,16391,668,677,169
Arson,7298,5338,1709,142,98,11
Violent crime,390233,231750,147002,5283,5453,745
Property crime,1218747,838391,346392,18382,14129,1453
Other assaults,853887,558181,272068,13618,9173,847
Forgery and counterfeiting,44336,28272,15095,279,646,44
Fraud,109576,72424,34853,1116,1124,59
Embezzlement,12678,7851,4518,87,210,12
"Stolen property; buying, receiving, possessing",69912,45816,22538,662,812,84
Vandalism,154755,108531,41723,2761,1556,184
"Weapons; carrying, possessing, etc.",109891,62920,44705,803,1307,156
Prostitution and commercialized vice,37030,19867,15483,199,1434,47
Sex offenses (except rape and prostitution),43125,31279,10462,640,688,56
Drug abuse violations,1216225,837851,353862,10071,12893,1548
Gambling,4363,1560,2568,16,192,27
Offenses against the family and children,79075,50912,26048,1521,574,20
Driving under the influence,863598,722451,112107,12048,15938,1054
Liquor laws,246304,197559,35727,9539,3302,177
Drunkenness,327325,264906,51485,6952,3552,430
Disorderly conduct,338636,213342,114802,7734,2493,265
Vagrancy,21577,14819,6116,443,182,17
All other offenses (except traffic),2546822,1726091,750488,42980,23946,3317
Suspicion,1057,557,472,15,13,0
Curfew and loitering law violations,41513,21357,19169,450,450,87

data.json

{
  "columns":[
    { "name": "Offense charged", "type": "string" },
    { "name": "Total", "type": "number" },
    { "name": "White", "type": "number" },
    { "name": "Black or African American", "type": "number" },
    { "name": "American Indian or Alaska Native", "type": "number" },
    { "name": "Asian", "type": "number" },
    { "name": "Native Hawaiian or Other Pacific Islander", "type": "number" }
  ] 
}