I recently saw HalifaxCrime, a hackathon project that animates crime data. I hoped to use the same technique to make a lightweight heatmap that I could feed with data from any Socrata dataset with a location column and a date & time column.
HalifaxCrime uses Heatmap.js an open source JavaScript library for making heatmaps. Most of the examples involve tracking user mouse movements and clicks on websites, but it’s also quite useful for mapping. (So useful that there are existing plugins for Google Maps, Leaflet, and OpenLayers. I started with this non-animated example from the heatmap-leaflet.js plugin page.
Basically, you feed heatmap.js an array of objects, each with x/y values and some sort of weight. The code below gets you a leaflet map with a static heatmap layer drawn in canvas. (One important config variable is useLocalExtrema, which adjusts the heatmap based on the points that are in the current view… I think this could be pretty misleading for an interactive map, so I chose to turn it off.)
To make an animated heatmap with time series data, we just need to re-draw the layer over and over again, and modify each “frame” of the animation with new data, and/or some modification of the existing data. The workflow goes like this:
Obviously, there are a lot of variables to tweak here, and you can yield different results. But first, let’s use jQuery’s $getJSON()
method to get some time-series vehicle collisions data from data.cityofnewyork.us.
After cleaning up the results a bit to filter out null
lat/lon fields, I’m left with an array of goodData
that I can start mapping.
For my heatmap experiment, I am using setInterval()
to iterate every 100ms. My data is only accurate to 1 day, so I am adding 1 day’s worth of data every 10 iterations, or one day per second. Here’s the interval function minus the chart bits:
New points start with a value(weight)
of 0, and I use a boolean to determine whether they are heating up or cooling down. On each interval, points that are heating up have their value incremented by .8, while those that are cooling down have their value decremented by .1. (Points arrive quickly, but fade out slowly). Once a point’s value is greater than or equal to 10, we toggle the boolean and start cooling it off.
Doing the math, a point will heat-up over 12 intervals (1.2 seconds), then cool down over 100 intervals (10 seconds). Since we are adding new data every second, there will be plenty of overlap, allowing the map to emphasize those areas where there are many events happening over a several-day period.
You can fork my repo here and tweak the config values to see what kind of results you get.