Skip to main content

Visualize data as a heatmap

Add earthquake frequency data to a style from a GeoJSON file and render it on a map using a HeatmapLayer.
Android Examples App Available

This example code is part of the Maps SDK for Android Examples App, a working Android project available on GitHub. Android developers are encouraged to run the examples app locally to interact with this example in an emulator and explore other features of the Maps SDK.

See our Run the Maps SDK for Android Examples App tutorial for step-by-step instructions.

HeatmapLayerGlobeActivity.kt
package com.mapbox.maps.testapp.examples.globe

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.mapbox.maps.MapboxMap
import com.mapbox.maps.Style
import com.mapbox.maps.extension.style.expressions.dsl.generated.interpolate
import com.mapbox.maps.extension.style.layers.addLayerAbove
import com.mapbox.maps.extension.style.layers.addLayerBelow
import com.mapbox.maps.extension.style.layers.generated.CircleLayer
import com.mapbox.maps.extension.style.layers.generated.HeatmapLayer
import com.mapbox.maps.extension.style.layers.generated.circleLayer
import com.mapbox.maps.extension.style.layers.generated.heatmapLayer
import com.mapbox.maps.extension.style.layers.properties.generated.ProjectionName
import com.mapbox.maps.extension.style.projection.generated.projection
import com.mapbox.maps.extension.style.sources.addSource
import com.mapbox.maps.extension.style.sources.generated.GeoJsonSource
import com.mapbox.maps.extension.style.sources.generated.geoJsonSource
import com.mapbox.maps.extension.style.style
import com.mapbox.maps.testapp.databinding.ActivityHeatmapLayerBinding

/**
* Add earthquake frequency data to a style from a GeoJSON file and render
* it on a map in globe projection using a HeatmapLayer.
*/
class HeatmapLayerGlobeActivity : AppCompatActivity() {

private lateinit var mapboxMap: MapboxMap

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityHeatmapLayerBinding.inflate(layoutInflater)
setContentView(binding.root)

mapboxMap = binding.mapView.mapboxMap.apply {
loadStyle(
style(Style.DARK) {
+projection(ProjectionName.GLOBE)
}
) { style ->
addRuntimeLayers(style)
}
}
}

private fun addRuntimeLayers(style: Style) {
style.addSource(createEarthquakeSource())
style.addLayerAbove(createHeatmapLayer(), "waterway-label")
style.addLayerBelow(createCircleLayer(), HEATMAP_LAYER_ID)
}

private fun createEarthquakeSource(): GeoJsonSource {
return geoJsonSource(EARTHQUAKE_SOURCE_ID) {
data(EARTHQUAKE_SOURCE_URL)
}
}

private fun createHeatmapLayer(): HeatmapLayer {
return heatmapLayer(
HEATMAP_LAYER_ID,
EARTHQUAKE_SOURCE_ID
) {
maxZoom(9.0)
sourceLayer(HEATMAP_LAYER_SOURCE)
// Begin color ramp at 0-stop with a 0-transparancy color
// to create a blur-like effect.
heatmapColor(
interpolate {
linear()
heatmapDensity()
stop {
literal(0)
rgba(33.0, 102.0, 172.0, 0.0)
}
stop {
literal(0.2)
rgb(103.0, 169.0, 207.0)
}
stop {
literal(0.4)
rgb(209.0, 229.0, 240.0)
}
stop {
literal(0.6)
rgb(253.0, 219.0, 240.0)
}
stop {
literal(0.8)
rgb(239.0, 138.0, 98.0)
}
stop {
literal(1)
rgb(178.0, 24.0, 43.0)
}
}
)
// Increase the heatmap weight based on frequency and property magnitude
heatmapWeight(
interpolate {
linear()
get { literal("mag") }
stop {
literal(0)
literal(0)
}
stop {
literal(6)
literal(1)
}
}
)
// Increase the heatmap color weight weight by zoom level
// heatmap-intensity is a multiplier on top of heatmap-weight
heatmapIntensity(
interpolate {
linear()
zoom()
stop {
literal(0)
literal(1)
}
stop {
literal(9)
literal(3)
}
}
)
// Adjust the heatmap radius by zoom level
heatmapRadius(
interpolate {
linear()
zoom()
stop {
literal(0)
literal(2)
}
stop {
literal(9)
literal(20)
}
}
)
// Transition from heatmap to circle layer by zoom level
heatmapOpacity(
interpolate {
linear()
zoom()
stop {
literal(7)
literal(1)
}
stop {
literal(9)
literal(0)
}
}
)
}
}

private fun createCircleLayer(): CircleLayer {
return circleLayer(
CIRCLE_LAYER_ID,
EARTHQUAKE_SOURCE_ID
) {
circleRadius(
interpolate {
linear()
zoom()
stop {
literal(7)
interpolate {
linear()
get { literal("mag") }
stop {
literal(1)
literal(1)
}
stop {
literal(6)
literal(4)
}
}
}
stop {
literal(16)
interpolate {
linear()
get { literal("mag") }
stop {
literal(1)
literal(5)
}
stop {
literal(6)
literal(50)
}
}
}
}
)
circleColor(
interpolate {
linear()
get { literal("mag") }
stop {
literal(1)
rgba(33.0, 102.0, 172.0, 0.0)
}
stop {
literal(2)
rgb(102.0, 169.0, 207.0)
}
stop {
literal(3)
rgb(209.0, 229.0, 240.0)
}
stop {
literal(4)
rgb(253.0, 219.0, 199.0)
}
stop {
literal(5)
rgb(239.0, 138.0, 98.0)
}
stop {
literal(6)
rgb(178.0, 24.0, 43.0)
}
}
)
circleOpacity(
interpolate {
linear()
zoom()
stop {
literal(7)
literal(0)
}
stop {
literal(8)
literal(1)
}
}
)
circleStrokeColor("white")
circleStrokeWidth(0.1)
}
}

companion object {
private const val EARTHQUAKE_SOURCE_URL =
"https://www.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson"
private const val EARTHQUAKE_SOURCE_ID = "earthquakes"
private const val HEATMAP_LAYER_ID = "earthquakes-heat"
private const val HEATMAP_LAYER_SOURCE = "earthquakes"
private const val CIRCLE_LAYER_ID = "earthquakes-circle"
}
}
Was this example helpful?