emilhe / dash-leaflet

MIT License
204 stars 33 forks source link

Updating layers or styles in WMSTileLayer does not have any effect #237

Closed jajberni closed 1 month ago

jajberni commented 1 month ago

I've been trying to implement a simple dash script where a select control will change the displayed layer in a WMSTileLayer. However, changing layers or styles in the callback doesn't seem to have any effect.

Here is a sample code of my attemp. This code only changes the layers property for sample puporses, but the same behaviour is observed when trying to change styles.

from dash import Dash, html, dcc, callback, Output, Input, State

import dash_bootstrap_components as dbc
import dash_leaflet as dl

# Initialize the app with a Dash Bootstrap theme
external_stylesheets = [dbc.themes.CERULEAN]
app = Dash(__name__, external_stylesheets=external_stylesheets)

# App layout
app.layout = dbc.Container([
    dbc.Navbar(  # Header
        dbc.Container(
            [
                dbc.Row(
                    [
                        dbc.Col(dbc.NavbarBrand("WMS Test", href="#")),
                    ],
                    align="center",
                    className="g-0",  # Remove gutters between columns
                ),
                dbc.NavbarToggler(id="navbar-toggler"),
                dbc.Nav(
                    [
                        dbc.NavItem(dbc.NavLink("Home", href="#")),
                        dbc.NavItem(dbc.NavLink("Help", href="#")),
                    ],
                    className="ms-auto",  # Move navigation links to the right
                    navbar=True,
                ),
            ]
        ),
        color="primary",
        dark=True,
        style={'margin-bottom': '10px'}
    ),

    dbc.Row([
        dbc.Col([
            dbc.Accordion(
                [
                    dbc.AccordionItem(
                        [

                            dbc.Label("Layer"),
                            dbc.Select(
                                id="layerId",
                                options=[
                                    {"label": "Fondo", "value": "fondo"},
                                    {"label": "Mosaico", "value": "Mosaico"},
                                    {"label": "OI.OrthoimageCoverage", "value": "OI.OrthoimageCoverage"},
                                    {"label": "OI.MosaicElement", "value": "OI.MosaicElement"},
                                ],
                                value="fondo",
                                style={'margin-bottom': '10px'}
                            ),
                        ],
                        title="Enter data"
                    ),
                ],
                start_collapsed=False,
            ),
        ], width=3),

        dbc.Col([
            dl.Map([
                dl.TileLayer(),
                dl.WMSTileLayer(
                    url="https://www.ign.es/wms-inspire/pnoa-ma",
                    layers="fondo",
                    format="image/png",
                    transparent=True,
                    id='wms_map'
                ),

            ], center=[37.5, -4], zoom=14, style={'height': '94vh'})
        ], width=9),
    ]),

], fluid=True)

# Callback to update the selected layer in WMSTileLayer 
@callback(
    Output('wms_map', 'layers'),
    Input('layerId', 'value'),
    State("wms_map", "layers"),
    #prevent_initial_call=True
)
def changeLayer(selected_layer, current_layer):
    print("new: ", selected_layer)
    print("current: ", current_layer)

    return selected_layer

# Run the app
if __name__ == '__main__':
    app.run(debug=True)
prl900 commented 1 month ago

Hey @jajberni, the documentation is a bit obscure on how to change the layers prop but you should be able to use params to do it:

# Callback to update the selected layer in WMSTileLayer 
@callback(
    Output('wms_map', 'params'),
    Input('layerId', 'value'),
    State('wms_map', 'params'),
    #prevent_initial_call=True
)
def changeLayer(selected_layer, current_layer):
    print("new: ", selected_layer)
    print("current: ", current_layer)

    return dict(layers=selected_layer)
jajberni commented 1 month ago

Thank you @prl900! You are completely right. Using the params instead of the property worked perfectly. It would be good to fix the documentation as it's very confusing now.

Closing the issue.