Select area of BYOC image using bbox/geometry in iypleaflet

Hello, I am writing with a request similar to a previous one using OpenLayers, which is figuring out how to select just a portion of a BYOC image. In this case, I am using leafmap (which is built on ipyleaflet) and its add_wms_layer function to do the display, which is calling ipyleaflet.WMSLayer (which builds on ipyleaflet.TileLayer).

I can get the entire image to display in leafmap, but it will not show up when I try to confine it to the desired bounds, either using a WKT polygon passed in through keyword argument “geometry”, or with “bounds”, structured as [(xmin, ymin), (xmax, ymax)], or with “bbox” (which I don’t think is a valid argument) in conventional [xmin, ymin, xmax, ymax], or as ", ".join([xmin, ymin, xmax, ymax]).

The relevant snippet is below, with hard-coded values for location:

import leafmap.leafmap as leafmap
import localtileserver

url = "https://services.sentinel-hub.com/ogc/wms/<instance>"
p = "POLYGON ((38.193 12.236, 38.193 12.249, 38.180 12.249, 38.180 12.236, 38.193 12.236))"
bb = [38.180, 12.236, 38.193, 12.249]
kwargs = {
    "time": "2022-05-15/2022-05-15",
    "geometry": p
    # "bounds": [(bb[1], bb[0]), (bb[3], bb[2])],
    # "extent": ",".join(bb),
    # "crs": {"crs": "EPSG:4326"}
}

m = leafmap.Map(zoom=16, center=[12.2425, 38.1865])
m.add_basemap("SATELLITE")
m.add_wms_layer(url, layers="TRUE-COLOR", name="TRUE-COLOR", format='image/png', 
                transparent=False, opacity=1.0, shown=True, **kwargs)                
m

Note with some permutations of the keyword arguments, the underlying image shows up, but it is not constrained to the desired boundaries.

Thanks for any pointers you can provide on this.

Hey, sorry for a bit late answer.

The problem is that using m.add_wms_layer() directly, the additional params are not used by the underlying ipyleaflet’s WMSLayer class.
The solution is to create a custom class which extends ipyleaflet’s WMSLayer class with additional params needed for Sentinel Hub WMS request.
Then we can create a layer from that class and add it to the map.

I followed an example in ipyleaflet’s documentation for WMS layer and added time and geometry. I also added maxcc (max cloud coverage) parameter, so it overrides the value that is set in the dashboard for the layer in case you would want to do that.

There is no need to set the bounding box manually because it gets set automatically and changes when you interact with the map (zoom / move).

There is no need to extend the default ipyleaflet’s WMSLayer with the crs parameter because it already accepts it - it just needs to be of correct type. (I followed this clue in the ipyleaflet’s documentation)

The code

import leafmap.leafmap as leafmap
import localtileserver
from ipyleaflet import WMSLayer, projections
from traitlets import Unicode

url = "https://services.sentinel-hub.com/ogc/wms/<instance>"
p = "POLYGON ((38.193 12.236, 38.193 12.249, 38.180 12.249, 38.180 12.236, 38.193 12.236))"

# custom class which extends ipyleaflet's WMSLayer class with
# additional params needed for Sentinel Hub WMS request
class SHWMSLayer(WMSLayer):
    time = Unicode('').tag(sync=True, o=True)
    geometry = Unicode('').tag(sync=True, o=True)
    maxcc=Unicode('').tag(sync=True, o=True)

sh_wms = SHWMSLayer(
    url=url,
    layers="1_TRUE_COLOR",
    format='image/png',
    transparent=True,
    geometry=p,
    time="2022-05-15/2022-05-20",
    crs=projections.EPSG4326,
    maxcc="100"
)

m = leafmap.Map(zoom=16, center=[12.2425, 38.1865])
m.add_basemap("SATELLITE")
m.add_layer(sh_wms)
m

Hope this helps. If you have any additional questions, don’t be afraid to ask.

Cheers

1 Like

Thanks very much, that works perfectly!

In case of interest for others, I have deployed the solution here:

1 Like

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.