jupyter-widgets / ipyleaflet

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

[Question / Feature] Adding multiple basemaps as leaflet base layers? #970

Closed whudson closed 2 years ago

whudson commented 2 years ago

In leaflet.js it is possible to have multiple basemaps that show up in radio boxes at the top of LayerControl by adding them as control layers:

http://bl.ocks.org/cccruzr/2be38431f91ff2adb9ded7c0e0950382

Is there any way to do this in IPyLeaflet?

whudson commented 2 years ago

Passing a dict of TileLayers into the Map() constructor results in no basemap being shown.

whudson commented 2 years ago

Adding TileLayers by Map.add_layer() is not ideal because they all load visible on the map.

giswqs commented 2 years ago

Leafmap has some similar functionality. Not sure if it suits your needs.

Notebook: https://leafmap.org/notebooks/02_using_basemaps Demo: https://www.youtube.com/watch?v=-lOo-vxjrDM

whudson commented 2 years ago

Thanks. There sure are a lot of different options for mapping in Jupyter!

martinRenou commented 2 years ago

There is a LayerControl in ipyleaflet, if that's the question: https://ipyleaflet.readthedocs.io/en/latest/controls/layers_control.html

whudson commented 2 years ago

That was not my question. IPyLeaflet does not appear to support using multiple basemaps as shown in the linked leaflet.js example.

martinRenou commented 2 years ago

IIRC it does, if you add multiple tile layers to the map, giving a name to each tile layer

whudson commented 2 years ago

IIRC it does, if you add multiple tile layers to the map, giving a name to each tile layer

Not sure if you mean to just do map.add_layer(tile_layer), but that is not the same as the leaflet example as it does not show up as basemap layers in the LayerControl, and every basemap added this way will be loaded into the map and visible at the same time.

I did try doing something like this, however I did not create TileLayers before passing them in. (The docs seem to say that these objects in basemaps are already TileLayers)

Map(basemap={'Layer 1': basemaps.OpenStreetMap.Mapnik, 'Layer 2': basemaps.Gaode.Satellite})
whudson commented 2 years ago

Capture

In the leaflet example. the basemaps are grouped at the top of the later control and selectable using radio buttons. Only one is loaded at a time.

whudson commented 2 years ago

Example:

from ipyleaflet import Map, basemaps, basemap_to_tiles, LayersControl

m = Map(
    basemap=basemap_to_tiles(basemaps.OpenStreetMap.Mapnik),
    center=(48.204793, 350.121558),
    zoom=3
    )

layer = basemap_to_tiles(basemaps.OpenStreetMap.Mapnik)
layer.name = "Test Layer"
m.add_layer(layer)
m.add_control(LayersControl())
m

Capture

martinRenou commented 2 years ago

You apparently need to set the base property to True as well:

from ipyleaflet import *

mapnik = basemap_to_tiles(basemaps.OpenStreetMap.Mapnik)
mapnik.base = True
mapnik.name = 'Mapnik Layer'

toner = basemap_to_tiles(basemaps.Stamen.Toner)
toner.base = True
toner.name = 'Toner Layer'

bzh = basemap_to_tiles(basemaps.OpenStreetMap.BZH)
bzh.base = True
bzh.name = 'BZH layer'

m = Map(center=(52, 10), zoom=8, layers=[mapnik, toner, bzh])

m.add_control(LayersControl())

m

We could probably provide some APIs to make this simpler

whudson commented 2 years ago

Just to note- setting the name is not necessary for them to show up as base layers, only the base property needs to be set True.