Open ryanbaumann opened 6 years ago
I'll fork it and try to implement this, never done an open source contribution but see how this goes haha.
@carsnwd awesome, and thank you! This will be a great feature for data science in Jupyter, because it allows us to use different types of data visualizations and data layers based on user interaction (zoom, a layer selection dropdown, etc)
No need to fork either - please feel free to just
a) Clone this repo git clone git@github.com:mapbox/mapboxgl-jupyter.git
b) Create a new branch git branch my-branch-name
c) Check out the branch git checkout my-branch-name
d) Commit your changes
e) Push your branch git push origin my-branch-name
f) Create a pull request from your branch on this repo
[x] I'd start on this by adding the minZoom and maxZoom layer properties to the mapViz class (https://github.com/mapbox/mapboxgl-jupyter/blob/master/mapboxgl/viz.py#L14), then expose those as layer options in each template (graduatedCricle.html, heatmap.html, etc). I'd probably submit your PR after just this change.
[ ] After that, you'd want to create a method that can add/remove layers from an existing visualization. This is the part that's more work - you'll want to create a way to make a parent mapboxgl.viz
object that can accept multiple mapboxgl.viz
objects, then create a method that would take the layers and sources from each version and merge them into one style sheet.
I’ve been on and off trying to figure out this problem between classes and work, and wanted to write down what I’m thinking in case anyone else tries to take a stab or just for general thoughts. So when each viz is created, it creates the entire viz with an individual map. Initial idea I had to just create a set of child vizes to a parent...but that child viz is going to create it’s own map object and that’s no good.
My next idea so far is to abstract the map and layers/sources. So each viz starts off with the base.html and also starts off with a base map object the var map = ....
. Then, the circle.html/clustered_circle.html/etc will add in layers and sources to the base map object in Jinja. Rather than duplicating code for when each viz type is a parent and to create a map or when each viz type is a child and to just create the layers.
{% extends "main.html" %}
{% block javascript %}
var legend = document.getElementById('legend');
legend.remove();
mapboxgl.accessToken = '{{ accessToken }}';
var map = new mapboxgl.Map({
container: 'map',
style: '{{ styleUrl }}',
center: {{ center }},
zoom: {{ zoom }},
transformRequest: (url, resourceType)=> {
return {
url: [url.slice(0, url.indexOf("?")+1), "pluginName=PythonMapboxgl&", url.slice(url.indexOf("?")+1)].join('')
}
}
});
map.addControl(new mapboxgl.NavigationControl());
map.on('style.load', function() {
{% block layers %}
//Iterate through all parent and child vizes to add layer and sources
{% endblock %}
});
{% endblock %}
Then I realized that each child viz probably will also have it's own legend properties. Clustered_Circles being calcCircleColorLegend({{ colorStops }}, "Point Density");
or regular circle being calcCircleColorLegend({{ colorStops }}, "{{ colorProperty }}");
and more...supporting future viz types. So to support each legend property that's outside the map.on function...would have to iterate through them and create them.
{% extends "main.html" %}
{% block javascript %}
var legend = document.getElementById('legend');
legend.remove();
mapboxgl.accessToken = '{{ accessToken }}';
var map = new mapboxgl.Map({
container: 'map',
style: '{{ styleUrl }}',
center: {{ center }},
zoom: {{ zoom }},
transformRequest: (url, resourceType)=> {
return {
url: [url.slice(0, url.indexOf("?")+1), "pluginName=PythonMapboxgl&", url.slice(url.indexOf("?")+1)].join('')
}
}
});
map.addControl(new mapboxgl.NavigationControl());
{% block legend %}
//Iterate through each vizes legend
{% endblock %}
map.on('style.load', function() {
{% block layers %}
//Iterate through all parent and child vizes to add layer and sources
{% endblock %}
});
{% endblock %}
So seems like a lot of abstracting the individual parts of each viz (layers/sources and legend) into it's own creation that is iterated through and added for the parent viz and each child viz. Plus also extracting out the creation of the map itself from each viz type html to not duplicate maps. Then also making sure layers and sources don't have conflicting names and such...so variables aren't redefined between vizes.
Just my thoughts on the problem so far picking at it 🤔, open to suggestions and comments. Will see if I make any progress.
That's spot on with how I'd approach it too @carsnwd! I think you can just tackle the first part in an initial pull request - abstract the mapboxgl.map
variable creation from the creation of visualization layers. The main thing to ensure then is that each viz added to the map contains a unique source_id
and layer_id
schema. That should be pretty straightforward:
data-circle-1
data-circle-2
data-graduatedCircle-1
data-clusteredCircle-1
Layer names should already be unique.
After that's done, we can tackle the legend stuff 🚀
@carsnwd did you get a chance to look at adding in the next step for this issue - abstracting each viz layer to add to a base map? Looking at what to include in the next release.
I have, still haven't gotten it done yet though. Today was the first day I've made some progress in a week or so, some other things in life have gotten in the way.
I'll try to get it sorted out and make a PR before the end of the month 😬
@carsnwd no rush here, but if you have a branch that's in progress, please submit a PR - we'd love to get multiple layer functionality into the next release in March.
Let's make this a push to finish for 0.7.0, which we're targeting to release at the end of April 2018.
Hi @carsnwd - just wondering if you managed to make any progress on this since your last update? No hurries or worries if not.
If you're up for it, I'd be more than happy to take a look and see what I can do. Thanks!
@bchowTWC and @carsnwd I've been experimenting with this too though I don't have image or raster layers worked in yet. It's kind of wrapped up in generating layer styles in Python, so still needs some adjustments. I can clean up what I have and share if you're interested :)
@carsnwd thanks for opening this issue with your outline, btw!! It really got me thinking :)
@akacarlyann - Definitely interested, if you don't mind. Those are actually the two layers I need most... good timing.
Much appreciated!
Hi all, this seems definitly like a good next step as it comes closer to a more natural way of building up a map: creating a single map instance and adding layers for the stuff you want to see visualized.
Just wanted to check: the initial use-case seems to be about having one single visualisation (layer) turned on at a time:
For example, users may want to create a heatmap visualization at low zoom levels, and a graduatedCircle visualization at high zoom levels.
As well as adding only one layer of each type:
The main thing to ensure then is that each viz type contains a unique source_id and layer_id schema.
This seems imho to be unnecessary restrictive.. why not have multiple layers on at the same time (and of the same type)?
@lucasvw ah, yes, the intention for this feature is to allow a user to add multiple layers to a map at the same time, including of the same layer type (two circle layers, for example). I'll update the ticket scope to clarify.
@ryanbaumann is this still in progress?
@ryanbaumann I created some very fresh draft, where I managed to visualise two layers on same map in point-viz-categorical-example.ipynb
https://github.com/mapbox/mapboxgl-jupyter/pull/126
Any feedback is welcomed. Hopefully will have time to finalise it for merge
Excellent, thank you @emakarov! Will check your your PR.
@ryanbaumann I've checked on several my local examples, layers are working (maybe need more testing) what I need, and what is missing 1) Need to re-write the Legend for Multi-layer case. Not clear how to do it better though. 2) Need to have some menu to toggle layers visibility
@ryanbaumann Any idea when this feature will be released?
Problem
As we add more visualization types, it will be useful to pull in multiple visualization layers into the same visualization. To do this, we'll need an API to
addLayer
to an existing visualization.For example, users may want to create a
heatmap
visualization at low zoom levels, and agraduatedCircle
visualization at high zoom levels.A user may also want to add two or more layers to a map from different data sources.
Implementation
minZoom
andmaxZoom
properties to each viz typeaddLayer
function to add a layer to an existing viz object