-
Notifications
You must be signed in to change notification settings - Fork 2.2k
First draft of new custom pane functionality. #1094
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
Conversation
Hi @lpkirwin, thanks for taking this up. Good sketch you made. It is clear to me how option 1 would work out. I have a preference for option 2 because:
But I'm not sure if we can implement that in a sensible way. Leaflet has no methods to move an object to another pane, it has to be done on creation as far as I can tell. So we would have to rummage about in the templates or options of folium objects anyway. I'd be interested to hear your ideas about how we could implement option 2. If that seems not workable, option 1 is also a good option. Passing all |
- Layers now added as the child of a pane - Options and parent of child layers overridden at render time - Avoids the need to add a kwarg to other layers
Hi @Conengmo, no problem. Added a new commit with an idea for option 2. It follows the second API above, adding other layers as children to the custom pane. I've added a render argument to the CustomPane class that
and then calls super(). Works fine with TileLayers, e.g. here. I can see not all folium classes have options, so not sure how well this would extend past TileLayers (and unsure how many use-cases there are outside TileLayers...) What do you think? |
folium/map.py
Outdated
options = json.loads(element.options) | ||
options.update({'pane': self.get_name()}) | ||
element.options = json.dumps(options, sort_keys=True, indent=8) | ||
element._parent = self._parent |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When you move the element up the tree it will not get rendered, because the parent of CustomPane
has already been rendered...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah right, it's in the list of children so it will get rendered. Good one.
But then why change its parent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed the parent just so that, when render is called on the layer, the javascript ends up as
element().add_to(map_name)
rather than
element().add_to(pane_name)
which leaflet wouldn't understand
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense, thanks for explaining.
Thanks for the quick test. I added a comment about a possible problem with the child elements not being rendered. That's probably fixable by calling render manually. In general I think it best to avoid messing with the object tree. But sometimes it has to be done to get cool features :) What do you think is the best approach of these two? |
I like the API better on the second, but same as you I worry that hacking around in the object tree could have some unintended consequences, e.g. when interacting with other objects or features that might not expect this behavior. After calling render() on the pane, there's some inconsistent state (element has the map as a _parent, but is in the pane's _children and not the map's _children). But I don't have other concrete ideas at the moment. Maybe it would be possible for the tile layer to check at render time whether its parent was a map or a pane, and then use its parent/grandparent name as appropriate. |
Hmm given your exploration I now lean towards option 1. It seems less fragile than mucking around with the object tree. I'm currently working on making sure each object passes |
Sounds good, and I agree. I'll revert back to option 1 and flesh out the documentation |
Hi @Conengmo, have switched back to the earlier implementation and added a docstring and a bit more to the notebook. Couple questions for you:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking good! I added some smaller comments to put the dots on the i so to say, hope you can have a look at them.
Should I do anything about kwargs, e.g. adding 'pane' as a specific kwarg in other classes, or adding **kwargs to classes that don't accept them? You mentioned that this was being developed elsewhere, so if so I can hold off.
That PR has been merged, so most classes accept options in kwargs. We could consider adding pane
as an explicit argument to some classes, but given that this is an advanced feature I reckon we can keep it as it is now.
A straightforward test to add would be the equivalent of test_popup_show() in test_map.py. Do you think any other tests would be helpful?
Yes, something like test_popup_show()
would be fine! We want to make more functional tests later, but for now having a test that verifies stuff didn't got broken basically is already very useful.
(625) corresponds to between markers and tooltips. Default | ||
panes and z-indexes can be found at | ||
https://github.com/Leaflet/Leaflet/blob/v1.0.0/dist/leaflet.css#L87 | ||
pointer_events: bool, default False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are the consequences of setting the default here to False
?
Maybe good to add a small section in the example notebook on how this option can be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For my particular use case (labels on top of choropleth), setting this to False ensures that the new layer won't mask mouse events from lower layers, e.g. if you want a tooltip to pop up when you hover over a choropleth.
Right now I'm struggling to imagine a case where you'd want this to be True! Have googled around for how others are using custom panes, and none of them involve interactivity. I could remove the keyword from the class -- I put it in thinking it would be better to keep flexibility even if I can't anticipate how it would be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for explaining, sounds like False
is a good default. I agree on leaving it in.
… into custom-panes Pulling latest changes from master
- Cleaning up the jinja template - Changing link in the docstring - Adding a test for correct script representation - Adding a couple more tile templates to the standard set
- Changing python version to match other notebooks - Removing TOC section from nbextension
Just had a look at your changes and I think this is ready! The code looks nice, you wrote a test, the example notebook is good. We fixed the issue with the notebook tests on Travis before, so I took the liberty of updating your branch from master. When the tests are passed I'll go ahead and merge this. |
Thanks Frank! |
Great feature!! thanks a lot 👍 |
This is a rough sketch to agree the API before I flesh it out and add docs. Right now I see two options for the API:
What I have so far is the basis for 1. Happy to flip to 2 if that's preferred.
Closes #1088