-
Notifications
You must be signed in to change notification settings - Fork 137
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
Pull Request for multi-layer support #129
base: master
Are you sure you want to change the base?
Conversation
Hi @ryanbaumann, I have seen there are multiple pull-requests for this issue so its probably a good idea to continue with only one of them. I still have time next week to put in some work but to prevent 'double-work' its perhaps best to decide which multi-layer extension has your/mapbox's preference. Would be great to have some feedback! |
@lucasvw I like the idea of a layer-based api. Overall cleaner. Mine was definitely more of an experiment from a few months back. Curious to see how you handle layer ordering. Looking forward to checking it out! |
Agreed, I also think its the right approach. I also kind of like the "json specs" approach although I have my doubts: (1) i guess the python api will never be as complete as the Javascript lib, its more a quick way to create visualizatios based on data that you wrangled in python.. if you need full control over the visualization, youll always need to get down to mapboxgl-js. (2) you probably cant get rid of javascript code snippets in this repo, I am not totally familiar with the expressiveness of the json spec but I guess you ll always need some JS glue to make everything work (can you declare legends for example in the spec?) Currently havent done anything extra related to layer ordering, e.g. the belowLayer functionality is copied over to the Layer level. Ill make an example with multilayers as soon as possible, probably sunday or monday. |
I think the JSON layer specification is still important to develop (#23) but I don't think it is mutually exclusive with using a layer-based API :) And yup, agree it would be great to reduce JavaScript snippets in this particular project. |
Great, sounds good. I might also just have to dive a little bit deeper into these style-sheets to understand it better and how it could be used.
|
Agree with @akacarlyann @lucasvw, this is a great implementation. Let's move forward with this approach for multi-layer management. |
Great! I just added a new example: It shows the Map and Layer API as well as a multi-layer example. Feedback is welcome =) |
Nice! I'll check it out later this week. Thanks @lucasvw ! |
Cool. To summarize:
Some interactive layer control (turn on/off layers) would perhaps be a good next step..? |
Thanks for the architecture overview.
Agree, that would be a great addition in a new PR! |
@ryanbaumann any updates on checking this? |
thanks @lucasvw, can't wait to see it live, @ryanbaumann let me know if you need help here |
@vincentsarago added you to contributors - yes, please take this PR review if you have time. Thank you! |
Just merged in #120 to master, which will cause a few conflicts on this branch. Excited to get this branch merged in - and it will be high time for a relase after that! Next steps:
|
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.
Nice work! left some comments for your reference.
def create_html(self): | ||
options = dict( | ||
opacity=self.opacity, | ||
belowLayer=self.below_layer, |
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.
I understand this is artefact from previous code, but CamelCase in python looks like an anti-pattern. Would be great if this can be avoided
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.
I guess this is done because the variables end up in HTMl/JS files where camelCase is quite common. But actually the variables don't enter into JS, since they are just used as placeholder in the templating, so I guess you are right! It will take some time changing all the variable names though.. :)
def get_layer_specific_variables(self, options): | ||
"""Update map template variables specific to heatmap visual""" | ||
options.update(dict( | ||
geojson_data=json.dumps(self.data, ensure_ascii=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.
here and in some other places, json.dumps
potentially can raise Exception that some objects are not JSON serializable. So, I think it would be useful to pass a custom serializer
class into Layer's init somehow.
And in some corresponding/or similar situations be able to assign custom serializer
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.
Hmm interesting, Ill see if I can figure something out. Any suggestions are welcome!
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.
Some suggestion
maybe, AbstractLayer
can receive two types of data
in __init__
- dict
- str (in this case, user is responsible for serialization as he wants)
__init__
can receive additional kwargdata_serializator_class
which (if notNone
) will be used injson.dumps(data, cls=data_serializator_class)
json.dumps
can be moved to separate function of base class, likedef serialize_data
which will check whether data has typestr
ordict
and make serialization accordingly
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 approach will also give user ability to override def serialize_data
for example, to use another serialization library (for ex. nssjson
or ultrajson
) if he wants to..
legend_key_shape='circle', | ||
*args, | ||
**kwargs): | ||
"""Construct a Mapviz object |
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.
Docstring seems to be misleading. Why not Construct ClusteredCircleLayer object
?
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.
Good catch, I still need to go to all the docstrings and update them.
|
||
<style type='text/css'> |
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.
probably it makes sense to separate CSS and JS code at least to different {% include %}
tags
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.
Yes, agreed
@emakarov Thanks a lot for your review and comments, much appreciated! |
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.
Few general comments for now.
Also we should update the tests
@@ -0,0 +1,165 @@ | |||
import codecs |
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.
I wonder if we could name this sub-module differently.
I'm afraid some people could do from mapboxgl import map
which will override map
function. That's said I don't have a better name.
maybe @perrygeo has some thought on that
|
||
from mapboxgl.utils import color_map, height_map | ||
from mapboxgl import templates | ||
from mapboxgl.utils import img_encode, numeric_map |
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.
I think we can merge all the .utils
import in one line
|
||
GL_JS_VERSION = 'v0.49.0' | ||
|
||
|
||
class MapViz(object): |
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 something I'm not sure to understand, to me MapViz should inherit from Map
class because from what I understood, Viz
are just a Map + Layer
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.
and also I think there might be a better way to reduce code duplication
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.
Well the more I think about the more I think we should maybe deprecate the Viz
, for now it works but it also means there will be a lot of code duplication and it might result in a bit of a nightmare when we either update the Map
or Layers
classes.
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.
The Viz classes are just wrappers around certain Map
+ Layer
combinations to offer backwards compatibility. MapViz doesn't inherit from Map
but contains a Map
legend_text_numeric_precision=None, | ||
legend_key_shape='square', | ||
min_zoom=0, | ||
max_zoom=24, |
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.
Also noting, we should maybe rename min_zoom
and max_zoom
because it can be confusing between min_zoom
/max_zoom
for the map instance. layer_min_zoom
might be better
Hi everyone, thanks for all the feedback! I just started a new position and Iam kind of busy with that.. so I am afraid it will take a little until I have spare-time to spend on this. Feel free to fork and continue if somebody has earlier availability! |
This is a huge feature and very close @lucasvw - do you have time to finish off for the coming release at the end of December 2019? If not, no worries - let's transfer ownership. |
Sorry man, no time. As stated before, feel free to fork and continue from where I left off. |
so, what is the current status for this PR? seems like the desired feature is not going forward... |
We'll need to find a new owner for this PR @emakarov to finish off. It is the top-requested feature at the moment for mapboxgl-jupyter. |
For those who interested in alternative (simple, yet flexible) multi-layer lib: |
@emakarov Nice! I especially like the way you formulated a Layout class. |
Agreed @emakarov your implementation is an excellent approach. I'd love to see if we can adopt a similar approach in I will cut a few tickets to capture this issue and link back to this PR. Let's continue the discussion on the issues. |
Hi there,
I just finished some refactoring for multi-layer support. I basically implemented a lower level Map class and all appropriate Layer classes. This was needed because the current *Viz classes are a combination of setting up the main Map instance as well as adding the (Source and) and Layers with the actual data. I am not a big fan of the Viz-collection-approach because each Viz instance can have its own specification of the actual Map (for example the "size" or "base-layer" etc). I think its more appropriate to get closer to the actual JS implementation and have Python classes for Map and Layers as well.
Most of the logic now happens in these lower Map and Layer classes, the *Viz classes just pass the logic onto these lower-level classes (Map and a single Layer). I didnt want to remove them for backwards compatibility but the idea for the future is that people start using the Map and Layer API's. I will try to add an example as soon as possible.
I have tested locally an example with multiple choroplethlayers and have run the examples contained in the project. I think some of the tests are broken so that has to be checked as well.