Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support HeatMap #1

Closed
bhaskarvk opened this issue Oct 4, 2016 · 30 comments
Closed

Support HeatMap #1

bhaskarvk opened this issue Oct 4, 2016 · 30 comments
Assignees
Milestone

Comments

@bhaskarvk
Copy link
Contributor

Options

I'm leaning towards #3 as it has performance benefits over the other two.

@bhaskarvk
Copy link
Contributor Author

closed in 488de06

@bhaskarvk bhaskarvk self-assigned this Oct 5, 2016
@bhaskarvk bhaskarvk added this to the v1.1 milestone Oct 5, 2016
@RCura
Copy link
Contributor

RCura commented Jan 3, 2017

After trying a lot to use this library, I'm now convinced that it's not satisfying enough for a real use:

  • The original library hasn't evolved in years ;
  • some of the functions that probably worked years ago do not anymore, for example gradientTextures that doesn't work (heatmap remains black, check the original example), and thus doesn't allow to change the default colors ;
  • heatmap.blur() and heatmap.multiply() can't be applied live : layer has to be removed, changed and added again.

In comparison, Leaflet.heat is way more reliable, considering it's developed by Leaflet authors and more actively maintained.

As for the perfomances, I did some benchmark using the feature/heatmap branch of rstudio/leaflet and comparing it to this WebGLHeatmap binding, for different size datasets :

  • small : 10k random points
  • medium : 100k random points
  • big : 500k random points
Benchmark files

Benchmark results
Framework Size Time (s)
Leaflet.heat Small 1.14
Leaflet.heat Small 1.14
Leaflet.heat Small 1.16
Leaflet.heat Small 1.20
Leaflet.heat Small 1.13
----------- ------ ------
WebGLHeatmap Small 1.32
WebGLHeatmap Small 1.35
WebGLHeatmap Small 1.41
WebGLHeatmap Small 1.38
WebGLHeatmap Small 1.32
----------- ------ ------
Leaflet.heat Medium 1.60
Leaflet.heat Medium 1.63
Leaflet.heat Medium 1.65
Leaflet.heat Medium 1.61
Leaflet.heat Medium 1.68
----------- ------ ------
WebGLHeatmap Medium 1.70
WebGLHeatmap Medium 1.83
WebGLHeatmap Medium 1.83
WebGLHeatmap Medium 2.23
WebGLHeatmap Medium 2.19
----------- ------ ------
Leaflet.heat Big 3.23
Leaflet.heat Big 3.17
Leaflet.heat Big 3.22
Leaflet.heat Big 3.29
Leaflet.heat Big 3.23
----------- ------ ------
WebGLHeatmap Big 3.29
WebGLHeatmap Big 3.17
WebGLHeatmap Big 3.29
WebGLHeatmap Big 3.21
WebGLHeatmap Big 3.14

This shows that for such datasets, there is no significant differences in load time. I also checked memory use (js heap), and the result is also approximately the same.

For all those reasons, I'd like Leaflet.heat to be considered worthy of being added to leaflet.extras, as I think it would be a big asset for this package, and for R spatial analysts in general.

@bhaskarvk
Copy link
Contributor Author

@RCura Thanks for the detailed comparison. I'll integrate leaflet.heat soon.

@bhaskarvk
Copy link
Contributor Author

@RCura Some more comments
Recently I fixed some performance issues in the WebGL heatmap code (see #42), have you tried with the revised code for your benchmarking ?
I know why gradientTextures doesn't work (CORS issue) and in theory should be fixable.

I will integrate Leaflet.heat but just wanted to make sure your benchmarking is done against the latest code base.

@RCura
Copy link
Contributor

RCura commented Jan 4, 2017

@bhaskarvk : I ran those tests like 2-3 days ago, and used the github version of leaflet.extras, so, this commit was taken into account :)
The performance boost probably affects larger datasets, that I haven't been testing here as I'm looking for "real-time" exploration :)

As for the gradientTextures, I'm glad you found :)
It seems to have been bugging for years (see that issue : pyalot/webgl-heatmap#7), and the author seems to have abandonned this repo (this PR hasn't been answered in 1 year), so, I don't know how/if you want to correct it, but a fresh fork might be a good option :)

Thanks for your work 😀

@bhaskarvk
Copy link
Contributor Author

Cool thanks for the confirmation. You've certainly made a solid case for Leaflet.heat :)

@Vishan07
Copy link

Great to read that Leaflet.heat will be integrated. Do you have an expectation as to when this will be available?

@dutchminator
Copy link

I'd like to add my vote for integrating leaflet.heat.
@bhaskarvk Do you have an ETA more specific than "soon" on when you will be able to implement it? Is there any way we can assist you with this?

@bhaskarvk
Copy link
Contributor Author

I'll start working on this today, so hopefully before the start of next week.

@timelyportfolio
Copy link
Contributor

timelyportfolio commented Feb 2, 2017

@bhaskarvk, we were nearly finished integrating leaflet.heat https://github.com/rstudio/leaflet/tree/feature/heatmap a while back but ran into some problems with the underlying library, most specifically Leaflet/Leaflet.heat#32. We were unwilling to run with a fork, so ultimately abandoned.

@bhaskarvk
Copy link
Contributor Author

I know, hence my initial hesitation in integrating leaflet.heat. However I feel comfortable working off a fork for leaflet.extras. I have had to fork and fix quite a few of the plugins that have been integrated in this repo. Many times original authors abandon their projects but fixing small issues is no big deal.
I'll start my work based of the leaflet.heat branch and make sure to integrate that PR too.

@timelyportfolio
Copy link
Contributor

timelyportfolio commented Feb 2, 2017

Big difference here is the author of leaflet.heat is also the author of leaflet :) I will say I like leaflet.heat the best though especially this ability rstudio/leaflet#174 (comment).

@bhaskarvk
Copy link
Contributor Author

bhaskarvk commented Feb 2, 2017

Oh man you guys are killing me. That Leaflet.heat hasn't been touched by the owner in a while too and has a lot of pending PRs. So my first task is to fork it and merge the pending PRs (coz they contain some important fixes). This is going to take me a while (approx 1 or 2 weeks).

@bhaskarvk
Copy link
Contributor Author

bhaskarvk commented Feb 3, 2017

@timelyportfolio / @jcheng5 , Does this Leaflet/Leaflet.heat#78 look like a better alternative to Leaflet/Leaflet.heat#32, they kind of look like addressing the same problem, but 43 looks more exhaustive.

@jcheng5
Copy link

jcheng5 commented Feb 3, 2017

I'd be surprised if 78 strictly dominates 32--it makes the same mistake that master does, of adding together the altitudes instead of alpha blending them.

@bhaskarvk
Copy link
Contributor Author

Yes I saw that, but w/o max I've no way to alpha blend. I need to see how to alpha blend on top of 78. Coz 78 is imp. too. There is a valid use case to support intensity using altitude.

@bhaskarvk
Copy link
Contributor Author

never mind I think I know what to do.

@jcheng5
Copy link

jcheng5 commented Feb 3, 2017

78 removes the option for max intensity by auto assigning max intensity based on the data, is that right? Is that desirable behavior? I'd think you'd want the ability to be explicit.

@jcheng5
Copy link

jcheng5 commented Feb 3, 2017

By the way, IIRC by far the best results were by alpha blending and not performing clustering at all, and was still plenty fast for 10K data points (I don't think I tested larger).

@bhaskarvk
Copy link
Contributor Author

For the max intensity, looks to me, if only Lat/Lng are supplied, it defaults to 1, and should be only provided if in addition to Lat/Lag you supply the actual intensity in the alt field. And 78 calculates appropriate max based on the intensity if provided. So I don't see a need for max, unless I am missing something obvious.

@bhaskarvk
Copy link
Contributor Author

bhaskarvk commented Feb 3, 2017

I don't understand not performing clustering at all. Are you talking about marker clustering, or something else ?

@bhaskarvk
Copy link
Contributor Author

FWIW , here's my merged changes so far
https://github.com/Leaflet/Leaflet.heat/compare/gh-pages...bhaskarvk:up2date?expand=1

I've added your alpha blended code but commented it out for now, will test with and w/o it. From where I see I don't think alpha blending is required as the max is changed during the calculation. But we'll see.

@jcheng5
Copy link

jcheng5 commented Feb 3, 2017

I'm saying what if the max is not the max intensity of the data, but some other higher value. Like picture you have two data sets that are being plotted side by side (or two layers in the same map) that reflect the same type of data, and one of them has no points that reach the max?

(My PR used the intensity too btw, in case that wasn't clear. It just does a better job of combining multiple data points in the same cell IIRC.)

@bhaskarvk
Copy link
Contributor Author

OK cool, I have my task cut out, I'll play with just your PR, just 78 and may be a combo of them.

@jcheng5
Copy link

jcheng5 commented Feb 3, 2017

Sorry to preface everything with IIRC but it's been a long time and I'm on my phone. So clustering refers to (IIRC) Leaflet.heat works pretty hard to reduce the number of points it sends to the underlying heatmap. This should just be a performance optimization as far as I could tell but the end result is the heatmap looks radically different depending on the factor (I think it's v?).

@bhaskarvk
Copy link
Contributor Author

@RCura I have a small question, the timings that you mentioned in #1 (comment).
How did you calculate them ? was it using sys.time or proc.time ? Coz if so then you're measuring only the R function execution time, and not the JS execution time. In that case the slight slowness in the R code of webglheatmap is expected because it builds the points in R so as to avoid an expensive computational for loop on the JS side.
If you have profiled only R code, please also profile JS part using chrome dev tools. I am very much interested in seeing how that compares.
I want to have both the libs available as options but want to make proper recommendations based on overall performance of the two.

Thanks

@RCura
Copy link
Contributor

RCura commented Feb 3, 2017

The benchmarks I gave are the js benchmarks, using chrome dev tools profiling :)
I didn't write any R benchmarks for the reasons you say, that I also noticed when first wanting to do this ^^

@bhaskarvk
Copy link
Contributor Author

All done.
@RCura Some more notes....

  • I've fixed the gradientTexture part in webgl-heatmap but it needs a weird hack of zooming-in zooming-out on map load to work. The hack is part of the binding JS so you don't have to do anything special. Just a small zoom-in zoom-out when the map loads initially will occur if you were to use the two available gradientTextures.

  • You can work on both the webgl and the regular heatmap maps using leafletProxy() + htmlwidgets::onRender(), w/o needing to rebuild the whole heatmap.

So something like

leaflet() %>% addHeatMap(..., layerId="ABC")  
# OR
leaflet() %>% addWebGLHeatMap(..., layerId="ABC")  

And later on 
leafletproxy() %>%
  htmlwidgets::onRender(JS("
    function(el, x, data) {
      var map = this;
      var layer = map.layerManager.getLayer("heatmap", "ABC");
      // OR
      var layer = map.layerManager.getLayer("webGLHeatmap", "ABC");

      // Work on layer using whatever JS operations it permits.
    }
  "))
  • Finally for my satisfaction, could you run the same benchmarks again on the addHeatmap and addWebGLHeatMap functions in this package again? Please provide R function times, and JS load times. Also please run the tests for up to 2M points so 10K, 100K, 250K, 500K, 1M, 2M.
    That would be really helpful to me.

@RCura
Copy link
Contributor

RCura commented Feb 6, 2017

Did all those benchmarks : the result is no good for WebGLHeatmap ;)

Here's the gist with all infos.
addHeatmap and addWebGLHeatmap have similar performances while creating the htmlwidget :

Code
heat_benchs <- microbenchmark(
    heat_10k = leaflet() %>% addHeatmap(data = coords_10k, layerId = "ABC"),
    webgl_10k = leaflet() %>% addWebGLHeatmap(data = coords_10k, layerId = "ABC"),
    heat_100k = leaflet() %>% addHeatmap(data = coords_100k, layerId = "ABC"),
    webgl_100k = leaflet() %>% addWebGLHeatmap(data = coords_100k, layerId = "ABC"),
    heat_250k = leaflet() %>% addHeatmap(data = coords_250k, layerId = "ABC"),
    webgl_250k = leaflet() %>% addWebGLHeatmap(data = coords_250k, layerId = "ABC"),
    heat_500k = leaflet() %>% addHeatmap(data = coords_500k, layerId = "ABC"),
    webgl_500k = leaflet() %>% addWebGLHeatmap(data = coords_500k, layerId = "ABC"),
    heat_1M = leaflet() %>% addHeatmap(data = coords_1M, layerId = "ABC"),
    webgl_1M = leaflet() %>% addWebGLHeatmap(data = coords_1M, layerId = "ABC"),
    heat_2M = leaflet() %>% addHeatmap(data = coords_2M, layerId = "ABC"),
    webgl_2M = leaflet() %>% addWebGLHeatmap(data = coords_2M, layerId = "ABC"),
    times = 100
)

(Run 100 times with microbenchmark the lesser the better)

bench_r

But page load shows some very different performances, webgl becoming massively slow as points number is increased :

wbench Code
http-server -p 8080 &
wbench http://localhost:8080/heat_10k.html -nc >> benchs.txt &&
wbench http://localhost:8080/webgl_10k.html -nc >> benchs.txt &&
wbench http://localhost:8080/heat_100k.html -nc >> benchs.txt &&
wbench http://localhost:8080/webgl_100k.html -nc >> benchs.txt &&
wbench http://localhost:8080/heat_250k.html -nc >> benchs.txt &&
wbench http://localhost:8080/webgl_250k.html -nc >> benchs.txt &&
wbench http://localhost:8080/heat_500k.html -nc >> benchs.txt &&
wbench http://localhost:8080/webgl_500k.html -nc >> benchs.txt &&
wbench http://localhost:8080/heat_1M.html -nc >> benchs.txt &&
wbench http://localhost:8080/webgl_1M.html -nc >> benchs.txt &&
wbench http://localhost:8080/heat_2M.html -nc >> benchs.txt &&
wbench http://localhost:8080/webgl_2M.html -nc >> benchs.txt &&
pkill node

(the lesser the better)
bench_js

File size are quite the same, so, this can't be a file loading difference.
Please note that the 1M and 2M benchmarks were'nt done as the smaller ones : htmlwidgets::saveWidget fails at saving those, so, I had to knit the pages. The size and load time is increased, but this has been done both for addHeatmap and addWebGLHeatmap.

So, seems there's a clear winner ;)

BTW, thanks a lot for adding leaflet.heat, I can now use a stable and durable package instead of my ugly/dangerously unstable fork of rstudio/leaflet.

@bhaskarvk
Copy link
Contributor Author

Wow I would never have guessed webGL plugin would be this bad. Thanks for all your hard work on this btw.

schloerke added a commit that referenced this issue Mar 29, 2018
npm + webpack all plugins
trafficonese pushed a commit that referenced this issue Apr 2, 2024
Improve handling of gradients in addHeatmap
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants