mapbox-gl-js icon indicating copy to clipboard operation
mapbox-gl-js copied to clipboard

Aggregate function for the property heatmap-color

Open fifiDesPlaines opened this issue 4 years ago • 13 comments

Hi,

mapbox-gl-js version: 1.10.1

Question

I would like to construct a kind of temperature-like map. I would like to fill the map depending on the value of my dots and not their densities. The closest kind of layer that I can use is the Heatmap... Is there a way to display a heatmap whose color depends on an aggregation of the point's properties composing it instead of their densities?

Something like that : https://github.com/optimisme/javascript-temperatureMap where dots will be kind of cluster's centers of other points.

Links to related documentation

https://docs.mapbox.com/mapbox-gl-js/style-spec/layers/#heatmap The doc says : "Defines the color of each pixel based on its density value in a heatmap. Should be an expression that uses ["heatmap-density"] as input."

https://docs.mapbox.com/help/tutorials/make-a-heatmap-with-mapbox-gl-js/ Here, you've constructed the heatmap from the density, Is it possible to construct an expression based on an average of property of the geojson ?

fifiDesPlaines avatar Jun 05 '20 14:06 fifiDesPlaines

Currently this is not possible with the heatmap layer — the way it is technically implemented makes the rendering dependent on the density of points. We might want to explore adding an option for an alternative rendering. For now, you could try e.g. using blurred circles to represent the temperatures, kind of like a scatterplot.

mourner avatar Jun 06 '20 13:06 mourner

It would be perfect to show temperature or internet speed from user doesn't matter the amount or density of users that we have.

Using the explained heatmap it doesn't make any sense as "temperature" can't be added depending on the amount of dots.

From the docs:

It is even mentioned the second kind of heatmap, in which the value is the average of the points, instead of the density. However, only one is explained.

https://docs.mapbox.com/help/tutorials/make-a-heatmap-with-mapbox-gl-js/#what-is-the-purpose-of-a-heatmap

Among maps you'll find on the web, there are two common categories of heatmaps: those that encourage the user to explore dense point data, and those that interpolate discrete values over a continuous surface, creating a smooth gradient between those points. The latter is less common and most often used in scientific publications or when a phenomenon is distributed over an area in a predictable way. For example, your town may only have a few weather stations, but your favorite weather app displays a smooth gradient of temperatures across the entire area of your town. For your local weather service, it is reasonable to assume that, if two adjacent stations report different temperatures, the temperature between them will transition gradually from one to the next.

More info about these kind of maps:

https://mgimond.github.io/Spatial/spatial-interpolation.html

Sample:

image

Possible result: image

jdelga avatar Jun 07 '20 15:06 jdelga

Currently this is not possible with the heatmap layer — the way it is technically implemented makes the rendering dependent on the density of points. We might want to explore adding an option for an alternative rendering. For now, you could try e.g. using blurred circles to represent the temperatures, kind of like a scatterplot.

@mourner , I tried this approach, but the result is not satisfying for the moment. I'm trying to cut the map in tiles with their size depending on the zoom, and to calculate the fill color from an aggregation function.

fifiDesPlaines avatar Jun 08 '20 13:06 fifiDesPlaines

Hi, if anyone still needs this feature I used a custom Mapbox layer to create what you're describing, take a look here: https://github.com/Rylern/InterpolateHeatmapLayer

Rylern avatar Oct 06 '21 15:10 Rylern

@Rylern We tried your approach, but the rendering is not customizable (no custom colors) and rendering fast enough for our use case. We currently went for the approach suggested by @mourner (blurred circles to represent the temperatures), but we keep our eyes open for something better in the future!

royyeah avatar Mar 21 '22 13:03 royyeah

Any update on this? The heatmap layer looks amazing! It's a shame we can't use it for this other common use case as well. :)

dson avatar Mar 24 '22 14:03 dson

@Rylern We tried your approach, but the rendering is not customizable (no custom colors) and rendering fast enough for our use case. We currently went for the approach suggested by @mourner (blurred circles to represent the temperatures), but we keep our eyes open for something better in the future!

Actually you can customize the colors, take a look at the valueToColor parameter. It allows you to define the function that maps a value to a color. Tell me the color scale you want, and I can help you define this parameter. When you say it's not rendering fast enough, what do you mean exactly? Is it when you first load the map, or after when you change the map location?

Rylern avatar Mar 24 '22 16:03 Rylern

@Rylern Oh, you’re right, my bad. I confused it with another approach we tried. I think your solution works pretty well for visualizing value distribution on a global scale. For our use case however we ran into some issues we couldn’t solve:

  • It covers the entire map. There is an option to limit it to a specific area, but we would prefer something more like the Mapbox heatmap, where the effect only applies where the points are.
  • The points have to be passed at layer creation, which means we’ll have to recreate the layer every time we want to update the values. It would be nice if we could use a datasource for the points.
Screenshot 2022-03-25 at 13 30 46

royyeah avatar Mar 25 '22 15:03 royyeah

* It covers the entire map. There is an option to limit it to a specific area, but we would prefer something more like the Mapbox heatmap, where the effect only applies where the points are.

* The points have to be passed at layer creation, which means we’ll have to recreate the layer every time we want to update the values. It would be nice if we could use a datasource for the points.
  • You could try the averageThreshold parameter. It's not optimal and somebody already mentioned the same issue, but I'm not sure I can make the effect only applies where the points are. I'll give it a look when I have time.
  • I'm using a custom layer from the Mapbox library and I don't think it can work with the Mapbox sources. However, I could create a function that update the points.

Rylern avatar Apr 01 '22 14:04 Rylern

@Rylern Oh, you’re right, my bad. I confused it with another approach we tried. I think your solution works pretty well for visualizing value distribution on a global scale. For our use case however we ran into some issues we couldn’t solve:

* It covers the entire map. There is an option to limit it to a specific area, but we would prefer something more like the Mapbox heatmap, where the effect only applies where the points are.

* The points have to be passed at layer creation, which means we’ll have to recreate the layer every time we want to update the values. It would be nice if we could use a datasource for the points.
Screenshot 2022-03-25 at 13 30 46

For future use, features addressing these two comments have been added in version 1.3.0 of the InterpolateHeatmapLayer.

Rylern avatar Oct 17 '22 17:10 Rylern