jupyter-widgets / ipyleaflet

A Jupyter - Leaflet.js bridge
https://ipyleaflet.readthedocs.io
MIT License
1.47k stars 359 forks source link

Update styles without slow js-py-js roundtrip? #1169

Open NickCrews opened 6 months ago

NickCrews commented 6 months ago

Thanks for the help!

I have some GeoJSON features. I want to be able to toggle select them on the map, and when this happens

  1. the style of the feature changes to highlighted, so you can see it is selected
  2. python is notified of this

This is currently possible, but as far as I can tell, only via a very slow js-py-js roundtrip:

  1. I set a .on_click callback in python
  2. When a click happens in JS, that is passed to python. This is for a single geo feature and is fast, no problem yet.
  3. On the python side, I am keeping track of a selected: set[str] of geometries. In the callback, I either add or remove the feature from this set.
  4. Now I have to re-update the style in JS-land. so I make a new style_callback that references the selected set. Then I set the style_callback on the GeoJSON object to trigger an update.
  5. Now this has to deepcopy the entire GeoJSON, traverse the whole thing to compute the style, and then serde this over the JS side.

This takes ~4 seconds on every click for 400 geometries. If I cut it down to 10 geometries, it is only .1 sec, which is totally workable, but of course I need all 400 (and in the future I think I may need up to 1k)

Is there a way to avoid the deepcopy? even better, is there way to hack in there and do all the style logic in JS, and just callback to python letting me know what geometries were selected? Any other thoughts on how to achieve my needs? I'm not positive this is where the slowness is coming from, I'm not that familiar with how to profile ipywidgets, but I used %prun cell magic and the deepcopy calls look to be the cause.

Attached is a working notebook and the data I'm working with (voting precinct geojson from the Alaska department of elections)

slow_style.zip