heatmap.js icon indicating copy to clipboard operation
heatmap.js copied to clipboard

Smart adjustment for gradient configuration

Open jocooler opened this issue 7 years ago • 4 comments

I'm trying to find some way to adjusting the heatmap configuration based on the data so that it is meaningful in more cases. I'm using this for a mapping application. I've gotten part of the way by nudging the color stops depending on zoom level, but it's still not as useful as I'd like.

I have a map showing crash data. Depending on the query, there could be anywhere from 0 - 5000 locations on the map with widely varying density. Here are some pictures:

Useful, hand tweaked color stops: image

Less useful, automatic zoom-based color stops (use local maximum is on): image

Automatic doing a better job with fewer points: image

Certainly I could refine my zoom-based color stop adjustment, but it would be better if I could get the maximum density and curve the gradient based on that number, even if that had to be an iterative process. This would allow the heatmap to be meaningful no matter the data put in. The heatmap configuration would be data aware. Is there a way to get the maximum density or maximum color for a heatmap? Has anyone successfully made a data-aware heatmap configurator?

Just for reference, my current color stop scaling formula is:

                var stops = [0, 0.4, 0.5, 0.6, 0.7, 0.8, 0.89, 0.99],
		   colors = ["rgba(0,0,0,0)",
		         "rgba(50,200,100,0.01)",
		         "rgba(50,200,200, 0.5)",
		         "rgba(0,255,0, 0.55)",
		         "rgba(155,255,0, 0.6)",
		         "rgba(255,255,0, 0.65)",
		          "rgba(255,155,0, 0.7)",
		          "rgba(255,0,0,0.7)"];
    
                var f = zoom - 7; // 8 is my "default" zoom level
		
		$.each(stops, function (i, v) {			
			var s = Math.max(Math.min(v - f*(-4 * Math.pow(v-0.5, 2) + 1)/10, 1), 0);
			config.gradient[s] = colors[i];
		}); 

Thanks!

jocooler avatar Mar 01 '17 13:03 jocooler

Hi. Do you use a different radius for each point of your dataset? (ie: [lat, lng, value, radius])

LePew avatar Mar 14 '17 09:03 LePew

@LePew No, they are all the same.

jocooler avatar Mar 14 '17 12:03 jocooler

@jocooler It's just a hint, but you could try adjusting minOpacity to 0.1 (for low values) ? For my own needs (using leaflet-heatmap), I modified the "scaleRadius" from scale = Math.pow(2, zoom); to scale=zoom; because I need to scaleRadius when I zoom in, but the default value wasn't really useful to me.

If your dataset's values are something else than 0 or 1, you could also index the radius of each point to the value, so the gradient would be smaller for small values.

Here's a sample with minOpacity set to 0.8, same radius for each point, point value=1: minopacity80 And another one with minOpacity set to 0.01, same radius for each point, point value=1: minopacity1

LePew avatar Mar 14 '17 13:03 LePew

@jocooler have you tried using the onExtremaChange callback configuration? It will be called whenever min or max changes, simply pass the callback to your instance config:

var cfg = {
   ..
   onExtremaChange: function(extremaData) {
      // extremaData contains 
      // { min: <number>, max: <number>, gradient: <current gradient cfg> }
   }
};

pa7 avatar Mar 15 '17 17:03 pa7