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

Batch property updates fail #657

Closed
wxd opened this issue Jul 23, 2020 · 10 comments
Closed

Batch property updates fail #657

wxd opened this issue Jul 23, 2020 · 10 comments

Comments

@wxd
Copy link

wxd commented Jul 23, 2020

Python version: 3.8
ipyleaflet version: 0.13.1 used in a vanilla Jupyter notebook

A question, not a bug: I have a layer group of ~3000 polylines, which I need to re-style in response to user input. I'm only learning ipyleaflet, so I do it naïvely in a loop:

for obj_id, obj_data in data:  # len(data) > 3000
    line: ipyleaflet.Polyline = self._obj_lines[obj_id]

    if obj_data["x"] > user_input:
    	line.color = 'red'
    	line.weight = 10
    else:
    	line.color = 'black'
    	line.weight = 1

Sometimes (not always) these updates get stuck half-way (see the GIF; no line is supposed to stay blue) and nothing short of recreating the whole map object helps, certainly not re-executing the update code.

My guess is that this approach generates too many individual update messages between the kernel and the front-end which leads to some communication breakdown or state discrepancy. If that is correct, what are the better options from the Python side?

  • is it possible to manually trigger "state synchronization" to ensure update completion?
  • can/should I manually batch updates?
  • should I switch to a GeoJSON layer? (GeoData doesn't seem to support dynamic styling, if I'm correct)

ipyleaflet

@martinRenou
Copy link
Member

martinRenou commented Jul 23, 2020

My guess is that this approach generates too many individual update messages between the kernel and the front-end which leads to some communication breakdown

That sounds very much correct. That would have been my first guess as well. There is a message rate limit in Jupyter comms, which is something like 1000 msgs/second I think.

You can change this rate limit using the following argument to Jupyter Notebook: https://stackoverflow.com/questions/43490495/how-to-set-notebookapp-iopub-data-rate-limit-and-others-notebookapp-settings-in

I am not sure I would recommend doing it though, but I have no best idea for this (apart from putting a time.sleep call somewhere in your code in order to reduce the rate manually, but that is no better solution).

Another solution might be to represent all your data as a single GeoJSON widget. Each feature would have its own style in the JSON structure. Then you only send one single message to update the entire JSON which contains all the lines. Not only that would fix your issue, but it might as well be faster in terms of performances (you send only one update message instead of 3000).

Edit: Sorry, I did not see you were mentioning GeoJSON. Actually I think that would be the best approach for fixing this. GeoData should support dynamic styling as it inherits from GeoJSON, but to be confirmed.

@wxd
Copy link
Author

wxd commented Jul 24, 2020

Thank you for a quick reply!

Is changing style_callback supposed to have any effect on the existing map layer? It doesn't seem to do anything in my case: layer.style_callback = new_cb does update layer.data but the new style does not get applied.

Does it mean that I should update the style properties in the data and do layer.data = updated_data?

@martinRenou
Copy link
Member

The fact that it does not update itself when you assign the style_callback might be a bug. Could you provide some code that I could easily run to reproduce your issue?

@wxd
Copy link
Author

wxd commented Jul 24, 2020

https://gist.github.com/wxd/8142eb1fb21a07d91073499263e06e0a

After [5] the blue lines are drawn; after [6] no visual changes.

Versions (all latest versions I got from pip install two weeks ago or so):

  • Python 3.8.3
  • ipykernel==5.3.2
  • ipyleaflet==0.13.1
  • ipython==7.16.1
  • traitlets==4.3.3
  • Chrome 83.0.4103.116
  • macOS Catalina 10.5.5

@martinRenou
Copy link
Member

This piece of code should work indeed. The following PR should fix it: #658. I tried locally and could see it working but if you have time to try it out too that would be greatly appreciated :)

@wxd
Copy link
Author

wxd commented Jul 24, 2020

I can confirm that it works. Thank you!

@wxd wxd closed this as completed Jul 24, 2020
@martinRenou
Copy link
Member

Sure! Let's merge this PR and include it in the next release then :)

@martinRenou
Copy link
Member

ipyleaflet 0.13.2 is out with the fix. You should be able to install it with pip now. If you are using conda you will need to wait a little bit.

@wxd
Copy link
Author

wxd commented Jul 31, 2020

Re-opening the issue: in 0.13.2 as well as 0.13.2, updating the style callback does something weird; see the GIF. It appears that a "new layer" with the new style gets drawn on the map, while the "old layer" gets hidden. However, the "new layer" seems to exist only in the JavaScript world, not in Python.

ipyleaflet

I don't think that just applying #658 on top of 0.13.1 had the same effect, but I'm not 100% sure.

@wxd wxd reopened this Jul 31, 2020
@martinRenou
Copy link
Member

This looks like a different issue. Would you mind opening another issue and provide some code to reproduce?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants