This page describes the heatmap utility that's available in the utility library for the Maps SDK for iOS. Heatmaps are useful for representing the distribution and density of data points on a map.
This video discusses the use of heatmaps as an alternative to markers, when your data requires a large number of data points on the map.
Heatmaps make it easy for viewers to understand the distribution and relative intensity of data points on a map. Rather than placing a marker at each location, heatmaps use color to represent the distribution of the data.
In the example below, red represents areas of high concentration of police stations in Victoria, Australia.
If you haven't yet set up the library, follow the setup guide before reading the rest of this page.
Adding a simple heatmap
To add a heatmap to your map, you will need a dataset consisting of the
coordinates for each location of interest. First, create a
GMUHeatmapTileLayer
instance, setting the map
property to a GMSMapView
.
Do this in your app's viewDidLoad()
function, to ensure that the base map is
loaded before working with the heatmap. Then pass a collection of
GMUWeightedLatLng
objects to the GMUHeatmapTileLayer
instance.
The utility supplies the GMUHeatmapTileLayer
class, which accepts a
collection of GMUWeightedLatLng
objects. It creates the tile images for
various zoom levels, based on the radius, gradient and opacity options
supplied.
Looking at the steps in more detail:
- Create a
GMUHeatmapTileLayer
instance, setting themap
property to aGMSMapView
(do this in your app'sviewDidLoad()
function). - Pass a collection of
GMUWeightedLatLng
objects to theGMUHeatmapTileLayer
instance. - Call
GMUHeatmapTileLayer.map
, passing the map view.Swift
class Heatmap: UIViewController { private var mapView: GMSMapView! private var heatmapLayer: GMUHeatmapTileLayer! override func viewDidLoad() { super.viewDidLoad() heatmapLayer = GMUHeatmapTileLayer() heatmapLayer.map = mapView } // ... func addHeatmap() { // Get the data: latitude/longitude positions of police stations. guard let path = Bundle.main.url(forResource: "police_stations", withExtension: "json") else { return } guard let data = try? Data(contentsOf: path) else { return } guard let json = try? JSONSerialization.jsonObject(with: data, options: []) else { return } guard let object = json as? [[String: Any]] else { print("Could not read the JSON.") return } var list = [GMUWeightedLatLng]() for item in object { let lat = item["lat"] as! CLLocationDegrees let lng = item["lng"] as! CLLocationDegrees let coords = GMUWeightedLatLng( coordinate: CLLocationCoordinate2DMake(lat, lng), intensity: 1.0 ) list.append(coords) } // Add the latlngs to the heatmap layer. heatmapLayer.weightedData = list } }
Objective-C
@implementation Heatmap { GMSMapView *_mapView; GMUHeatmapTileLayer *_heatmapLayer; } - (void)viewDidLoad { [super viewDidLoad]; _heatmapLayer = [[GMUHeatmapTileLayer alloc] init]; _heatmapLayer.map = _mapView; } // ... - (void) addHeatmap { // Get the data: latitude/longitude positions of police stations. NSURL *path = [NSBundle.mainBundle URLForResource:@"police_stations" withExtension:@"json"]; NSData *data = [NSData dataWithContentsOfURL:path]; NSArray *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; NSMutableArray<GMUWeightedLatLng *> *list = [[NSMutableArray alloc] init]; [json enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { NSDictionary *item = (NSDictionary *)obj; CLLocationDegrees lat = [(NSNumber *) [item valueForKey:@"lat"] doubleValue]; CLLocationDegrees lng = [(NSNumber *) [item valueForKey:@"lng"] doubleValue]; GMUWeightedLatLng *coords = [[GMUWeightedLatLng alloc] initWithCoordinate:CLLocationCoordinate2DMake(lat, lng) intensity:1.0]; [list addObject:coords]; }]; // Add the latlngs to the heatmap layer. _heatmapLayer.weightedData = list; } @end
For this example, the data is stored in a JSON file, police_stations.json
.
Here is an extract from the file:
[
{"lat" : -37.1886, "lng" : 145.708 } ,
{"lat" : -37.8361, "lng" : 144.845 } ,
{"lat" : -38.4034, "lng" : 144.192 } ,
{"lat" : -38.7597, "lng" : 143.67 } ,
{"lat" : -36.9672, "lng" : 141.083 }
]
Customizing the heatmap
The heatmap has several customizable properties. You can set the options when
initially creating the GMUHeatmapTileLayer
instance, or at any time by
setting a new value for the option.
The following options are available:
Radius: The size of the Gaussian blur applied to the heatmap, expressed in pixels. The default is 20. Must be between 10 and 50. Use
GMUHeatmapTileLayer.radius
to set the radius.Gradient: A range of colors that the heatmap uses to generate its color map, ranging from lowest to highest intensity. A
GMUGradient
is created using an integer array containing the colors, and a float array indicating the starting point for each color, given as a percentage of the maximum intensity, and expressed as a fraction from 0 to 1. You need to specify only one color for a single-colored gradient, or a minimum of two colors for a multi-colored gradient. The color map is generated using interpolation between those colors. The default gradient has two colors. ThecolorMapSize
parameter defines the number of steps in the gradient. Larger numbers will result in a smoother gradient, while smaller numbers will give sharper transitions similar to a contour graph. UseGMUHeatmapTileLayer.gradient
to set the gradient.Opacity: This is the opacity of the entire heatmap layer, and ranges from 0 to 1. The default is 0.7. Use
GMUHeatmapTileLayer.opacity
to set the opacity value.
For example, create a Gradient
:
Swift
let gradientColors: [UIColor] = [.green, .red] let gradientStartPoints: [NSNumber] = [0.2, 1.0] heatmapLayer.gradient = GMUGradient( colors: gradientColors, startPoints: gradientStartPoints, colorMapSize: 256 )
Objective-C
NSArray<UIColor *> *gradientColors = @[UIColor.greenColor, UIColor.redColor]; NSArray<NSNumber *> *gradientStartPoints = @[@0.2, @1.0]; _heatmapLayer.gradient = [[GMUGradient alloc] initWithColors:gradientColors startPoints:gradientStartPoints colorMapSize:256];
To change the opacity of an existing heatmap:
Swift
heatmapLayer.opacity = 0.7
Objective-C
_heatmapLayer.opacity = 0.7;
Update an existing option
To update an option that has already been set, take these steps:
- Update the option to the desired value.
- Call
GMUHeatmapTileLayer.clearTileCache()
.
Changing the dataset
To change the dataset upon which a heatmap is built:
- Update your data collection. Use
GMUHeatmapTileLayer.weightedData
, passing an array ofGMUWeightedLatLng
. - Call
GMUHeatmapTileLayer.clearTileCache()
.
Removing a heatmap
To remove a heatmap, call GMUHeatmapTileLayer.map
, passing nil
.
Swift
heatmapLayer.map = nil
Objective-C
_heatmapLayer.map = nil;
See the demo app
For another example of a heatmap implementation, take a look at the
HeatmapViewController
in the demo app that ships with the utility library.
The setup guide shows you how to
run the demo app.