ipyleaflet icon indicating copy to clipboard operation
ipyleaflet copied to clipboard

dynamically update Map CRS

Open epifanio opened this issue 4 years ago • 1 comments

Hi,

attempting to add a widget to switch between a list of map projections, I wasn't able to find a method to interact with the map.crs attribute.

I tried to manually set the crs option, but it doesn't seem to have any effect on the active map widget, e.g.:

from ipyleaflet import (
    Map,
    WMSLayer,
    projections,
)

prj1 = projections.EPSG4326

prj2 = {'name': 'EPSG:32661',
 'custom': True,
 'proj4def': '+proj=stere +lat_0=90 +lon_0=0 +k=0.994 +x_0=2000000 +y_0=2000000 +datum=WGS84 +units=m +no_defs +type=crs',
 'origin': [1999999.9999999998, 3702940.358685655],
 'bounds': [[1999999.9999999995, 5405880.71737131], [2000000.0, 2000000.0]],
 'resolutions': [16384.0, 8192.0, 4096.0, 2048.0, 1024.0, 512.0, 256.0]}

I then use two WMS layers, for which I know both prj1 and prj2 are available

wms_urls = [
    "http://nbswms.met.no/thredds/wms_ql/NBS/S1A/2021/05/18/EW/S1A_EW_GRDM_1SDH_20210518T070428_20210518T070534_037939_047A42_65CD.nc?SERVICE=WMS&REQUEST=GetCapabilities",
    "http://nbswms.met.no/thredds/wms_ql/NBS/S1A/2021/04/22/IW/S1A_IW_GRDM_1SDV_20210422T152707_20210422T152740_037565_046E1E_0EF5.nc?SERVICE=WMS&REQUEST=GetCapabilities",
]

wms_layer1 = WMSLayer(
    url=wms_urls[0],
    layers="amplitude_hh",
    format="image/png",
    transparent=True,
    min_zoom=1,
    crs=prj2,  
)

wms_layer2 = WMSLayer(
    url=wms_urls[1],
    layers="amplitude_vh",
    format="image/png",
    transparent=True,
    min_zoom=1,
    crs=prj2,  
)

The resulting ipyleaflet.Map renders correctly:

m = Map(center=(70, 15), zoom=0, max_zoom=6, layers=(wms_layer1, wms_layer2), crs=crs_32661)

Unfortunately, if I try to change the Map.crs option, I can see it get set correctly in the map object attributes, but the widget doesn't sync with the applied changes, e,g,

m.crs = projections.EPSG4326
for i in m.layers:
    i.crs = projections.EPSG4326

I tried to manually expose the crs attributes as a "trait", by subclassing the Map object with:

from traitlets import Dict, Unicode

class MapCRS(Map):
    crs = Dict().tag(sync=True, o=True)

# and define the new widget with:

m = MapCRS(center=(70, 15), zoom=0, max_zoom=6, layers=(wms_layer1, wms_layer2), crs=crs_32661)

But the behavior didn't change.

I also tried a different syntax:

m.set_trait("crs", projections.EPSG4326)
for i in m.layers:
    i.crs = projections.EPSG4326

But that didn't work ... do you have any clue on what I am doing wrong?

epifanio avatar May 31 '21 13:05 epifanio

I was thinking about this lately, having a map control widget to switch between different predefined projections. Since recreating the map is a pain, which is what I was doing. I hope to have some time next week to take a look and see if we can implement it.

betolink avatar Aug 12 '21 15:08 betolink