The following post is a portion of the Leaflet Tips and Tricks book which is free to download. To use this post in context, consider it with the others in this blog or just download the the book as a pdf / epub or mobi .
----------------------------------------------------------
----------------------------------------------------------
Generate a heatmap with Leaflet.heat
A heatmap is a two dimensional representation of values encodes as colours. In our case these colours are superimposed over a map generated using leaflet.js.
The example here represents seismic activity in July / August of 2013 in central New Zealand, when they were unfortunate enough to experience a series of earthquakes.
Leaflet.heat representation of earthquakes in central New Zealand |
In areas of greater intensity and density, the heatmap produces a gradient that varies from blue to red. This example shows a definite region of increased activity over the time in question.
There are several variations on heatmap plugins for Leaflet. The one we are going to examine is called Leaflet.heat. It is fairly new (at time of writing), and it builds on a separate JavaScript library called simpleheat. Both of these have been developed by Vladimir Agafonkin (yes, the developer of Leaflet), so they come with a considerable pedigree.
Leaflet.heat code description
The following is a code listing that we will use to describe the required changes from our simple-map.html example to enable Leaflet.heat. There is also an online version on bl.ocks.org, GitHub and can be downloaded along with the data file (in a zip file) when you download the book from Leanpub.
<!DOCTYPE html>
<html>
<head>
<title>
Simple Leaflet Map with Heatmap </title>
<meta
charset=
"utf-8"
/>
<link
rel=
"stylesheet"
href=
"http://cdn.leafletjs.com/leaflet-0.7/leaflet.css"
/>
</head>
<body>
<div
id=
"map"
style=
"width: 600px; height: 400px"
></div>
<script
src=
"http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"
>
</script>
<script
src=
"http://leaflet.github.io/Leaflet.heat/dist/leaflet-heat.js"
>
</script>
<script
src=
"2013-earthquake.js"
></script>
<script>
var
map
=
L
.
map
(
'map'
).
setView
([
-
41.5546
,
174.146
],
10
);
mapLink
=
'<a href="http://openstreetmap.org">OpenStreetMap</a>'
;
L
.
tileLayer
(
'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
,
{
attribution
:
'© '
+
mapLink
+
' Contributors'
,
maxZoom
:
18
,
}).
addTo
(
map
);
var
heat
=
L
.
heatLayer
(
quakePoints
,{
radius
:
20
,
blur
:
15
,
maxZoom
:
17
,
}).
addTo
(
map
);
</script>
</body>
</html>
We will be loading our data from a separate JavaScript file called 2013-earthquake.js
. The data has been sourced from New Zealand’s Geonet site over a date range that covers a period of reasonable seismic activity in July / August 2013.
Loading the file from a separate JavaScript file is purely for conveniences sake and the format of the data is as follows;
var quakePoints = [
[-41.5396,174.1242,1.7345],
[-38.8725,175.9561,2.6901],
[-41.8992,174.3117,4.6968],
[-41.7495,174.02,1.8642],
[-41.7008,174.0876,2.1629],
[-41.7371,174.0682,2.0408],
[-41.372,173.3502,2.7565],
[-41.7511,174.0623,2.4531],
[-41.7557,174.3391,2.1871],
[-41.6881,174.2726,3.1336],
[-41.7463,174.1194,2.7113],
[-41.6966,174.1238,2.4168],
...
];
There are only two ‘blocks’ that have changed in the code from our simple map example.
The first is an additional two links to external JavaScript files;
<script
src=
"http://leaflet.github.io/Leaflet.heat/dist/leaflet-heat.js"
>
</script>
<script
src=
"2013-earthquake.js"
></script>
The first link loads the Leaflet.heat plugin and the second loads our data from 2013-earthquake.js
.
The second change from our simple map example adds and configures our heatmap layer;
var heat = L.heatLayer(quakePoints,{
radius: 20,
blur: 15,
maxZoom: 17,
}).addTo(map);
In this block we load the data as the variable quakePoints
then set our radius, blur and maxZoom values for the plugin.
<!DOCTYPE html>
<html>
<head>
<title>
Simple Leaflet Map with Heatmap </title>
<meta
charset=
"utf-8"
/>
<link
rel=
"stylesheet"
href=
"http://cdn.leafletjs.com/leaflet-0.7/leaflet.css"
/>
</head>
<body>
<div
id=
"map"
style=
"width: 600px; height: 400px"
></div>
<script
src=
"http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"
>
</script>
<script
src=
"http://leaflet.github.io/Leaflet.heat/dist/leaflet-heat.js"
>
</script>
<script
src=
"2013-earthquake.js"
></script>
<script>
var
map
=
L
.
map
(
'map'
).
setView
([
-
41.5546
,
174.146
],
10
);
mapLink
=
'<a href="http://openstreetmap.org">OpenStreetMap</a>'
;
L
.
tileLayer
(
'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
,
{
attribution
:
'© '
+
mapLink
+
' Contributors'
,
maxZoom
:
18
,
}).
addTo
(
map
);
var
heat
=
L
.
heatLayer
(
quakePoints
,{
radius
:
20
,
blur
:
15
,
maxZoom
:
17
,
}).
addTo
(
map
);
</script>
</body>
</html>
2013-earthquake.js
. The data has been sourced from New Zealand’s Geonet site over a date range that covers a period of reasonable seismic activity in July / August 2013.var quakePoints = [
[-41.5396,174.1242,1.7345],
[-38.8725,175.9561,2.6901],
[-41.8992,174.3117,4.6968],
[-41.7495,174.02,1.8642],
[-41.7008,174.0876,2.1629],
[-41.7371,174.0682,2.0408],
[-41.372,173.3502,2.7565],
[-41.7511,174.0623,2.4531],
[-41.7557,174.3391,2.1871],
[-41.6881,174.2726,3.1336],
[-41.7463,174.1194,2.7113],
[-41.6966,174.1238,2.4168],
...
];
<script
src=
"http://leaflet.github.io/Leaflet.heat/dist/leaflet-heat.js"
>
</script>
<script
src=
"2013-earthquake.js"
></script>
2013-earthquake.js
. var heat = L.heatLayer(quakePoints,{
radius: 20,
blur: 15,
maxZoom: 17,
}).addTo(map);
quakePoints
then set our radius, blur and maxZoom values for the plugin.
radius
configuration option
The radius option sets the radius (duh) of the circles that correspond to a single data point on the map. If we remove the blur effect we can clearly see the effect on the map.
Radii of points |
As we zoom in and out of the map, the radii of the points remains constant on the screen, but the representation that they create on the screen changes as there are subsequently more or less points to generate an effect.
Radii of points zoomed in |
blur
configuration option
Blurring the points results in a smoothing and dispersing of the data. The previous section demonstrated the effect of removing the blurring (set to 1), but it can also be increased to the point where they can run the risk of fading away a bit too much. For example this is the effect when blurring is set to 50;
Points with blur set to 50 |
maxZoom
configuration option
The maxZoom
configuration option designates the level where the points reach their maximum intensity. Therefore if we were to set the maxZoom
value to the initial zoom level (10) of our map, we should expect to see each point represented by a full spectrum of blue to green;
maxZoom
configuration option designates the level where the points reach their maximum intensity. Therefore if we were to set the maxZoom
value to the initial zoom level (10) of our map, we should expect to see each point represented by a full spectrum of blue to green;Zoom level and maxZoom both on 10 |
Obviously this is something that you will want to consider as you plan how to set the configuration options on your maps :-).
A copy of this file and a copy of all the files that appear in the book can be downloaded (in a zip file) when you download the book from Leanpub
Great maps! Cheers.
ReplyDeleteWow, Heat map is so spectacular. It makes any "boring data" look like a Piet Mondrian art piece !
ReplyDeleteThanks for your post!
ReplyDeleteIs there any method to clear existing data inside of a map? For instance, I would simply like to show and clear the data every time I click a button.
Thanks
Sorry for the delay in replying. Thinking off the top of my head I would associate the javascript with an html button such that on a click it loaded a null set of data. Similar to the process here https://leanpub.com/D3-Tips-and-Tricks/read#leanpub-auto-update-data-dynamically---on-click
DeleteHi, any idea how to update the L.heatLayer (e.g. i want to add a slider for radius size)...? Many thanks for a great page!
ReplyDeleteSorry for the late reply. I've never experimented with that myself, but I recommend that you try a couple of things that might get you closer and if you're still struggling use these experiments to ask a question on Stack Overflow. Best of luck.
DeleteHi, All heatmap and leaflet examples do have a map in them where they plot data accordingly. I have a data where there are x,y,z position co ordinates given, how do I create a heat map for that data(because I do not have a definite map defining the total area, just by the x,y,z and the time spent, I have to visualize a heatmap for a person
ReplyDeleteInteresting question. I'm not sure that I know the answer, but try looking for examples using d3 hexagons http://www.visualcinnamon.com/2013/07/self-organizing-maps-creating-hexagonal.html type of thing
Deletethank you for the reference. Still looking for a detailed example where they read data from file(say ".csv") and visualize a heat map. Couldnt fine one though.
DeleteHmm... could you possible consider that the hexagons (if small enough) could form the heatmap?
Delete