Build a map of NYC’s police precincts with React & D3, Part 2

3 min readMay 12, 2021

In Part 2 of this tutorial, we are going to turn our basic map into a heat map that visualizes the amount of total allegations filed against each precinct. If you missed Part 1, I recommend reading that first.

Now that we have a basic working map, let’s use it to show some data! The data we are going to be using comes from ProPublica’s release of over 33,300 records of misconduct against the NYPD, dating back to 1985. The actual data parsing is outside the scope of this article — instead, we’ll be using a .json file that I made from the data and can be downloaded in this project’s GitHub repo.

First let’s work on adding to our App component, since that is where we pass down props to our Map component, and we’ll need to pass it some new data. We can import the .json file at the top our file with the following line of code:

import { default as allegationsPerPrecinct } from './data/allegationsByPrecinct.json'

Then we’ll update how we render our Map component, by passing it the allegationsPerPrecinct object we just imported as a new prop.

<Map geoJson={data} allegationsPerPrecinct={allegationsPerPrecinct}/>

Here’s what the finished App component looks like:

Now we need to update our Map component in order to read the data and reflect it in our map. In our new heat map, we will be representing the amount of allegations associated with each precinct through a spectrum of colors. The more allegations a precinct has, the darker it will appear on the map. To do this, we need a scale function: a function that takes in a value in our input domain and returns a ‘scaled’ value within our output range. Once again, D3 provides a number of scale functions, all of which have specific use cases. We will be using scaleSequential, which is a good choice for generating color scales. We will be giving it two arguments: the input domain, and an interpolator that it will use to generate output in the form of an RGB value.

Let’s cover the input first. For our purposes, the domain will be all the possible numbers of allegations that a precinct can have, so it will include all numbers from 0 to the maximum amount of allegations that any precinct has. In order to get this value, we’ll use the map() iterator and ES6’s spread operator :

const maxAllegations = Math.max( => obj.allegations))

Now we can write our scale function. For its second argument, we’ll be using one of D3’s built-in interpolators, interpolateBlues, to generate RGB values in a spectrum of blue colors. The completed function will look like this:

const scale = d3.scaleSequential([0, maxAllegations], d3.interpolateBlues)

The next part is a lot of fun, and is a great example of D3’s data-driven philosophy at work. In the earlier iteration of Map, our renderMap() function gave each path element a ‘fill’ attribute with the value of ‘transparent’. Obviously we need to change that if we want color, and D3 gives us a powerful way to do that dynamically. This time, ‘fill’ will be given a function instead of a string value, and inside that function we will generate a color for each path element. Remember, each of these elements corresponds to a precinct, so we can use the number of allegations associated with that precinct with our previously-defined scale function to get the correct value for ‘fill’. Here’s what that part of the code will look like:

.attr('fill', function(d) {
const precinct = allegationsPerPrecinct.filter(item => item.precinct ===['Precinct'])[0]
return scale(precinct.allegations)

We are using D3 to iterate over the features of our GeoJSON object and ‘draw’ the path string for each feature, which corresponds to a precinct. For the fill attribute, we’ll access the current feature’s ‘Precinct’ property in order to filter our allegationsPerPrecinct array and find the corresponding precinct. Then we just pass the precincts ‘allegations’ property into scale, and it will return an RGB value. Reload your browser and look at the results. You should be rendering a colorized heat map now! Here’s what the finished Map component will look like:

And here’s the colorized heat map!

A heat map of NYC’s police precincts by allegations of misconduct

You can look at the original code and download it here: