Style_handling from dash-leaflet docu breaks choropleth-map polygons

Hello everyone

I am trying to build a Dash app with an interactive dash-leaflet map as the core element. To start out, I am trying to recreate the map shown n the official tutorial as seen here. I can’t get this to work, despite not changing anything about the code from the linked docu.

Here’s my attempt using dash 2.16.0 and dash-leaflet 1.0.15.

import dash_leaflet as dl
from dash import Dash, Input, Output, State
from dash_extensions.javascript import assign

# Color selected state(s) red.
style_handle = assign("""function(feature, context){
    const {selected} = context.hideout;
    if(selected.includes(feature.properties.name)){
        return {fillColor: 'red', color: 'grey'}
    }
    return {fillColor: 'grey', color: 'grey'}
}""")

url = "https://raw.githubusercontent.com/PublicaMundi/MappingAPI/master/data/geojson/us-states.json"

# Create small example app.
app = Dash()
app.layout = dl.Map(
    [
        dl.TileLayer(),
        dl.GeoJSON(
            url=url,
            zoomToBounds=True,
            id="geojson",
            hideout=dict(selected=[]),
            style=style_handle,
        ),
    ],
    style={"height": "50vh"},
    center=[56, 10],
    zoom=6,
)


@app.callback(
    Output("geojson", "hideout"),
    Input("geojson", "n_clicks"),
    State("geojson", "clickData"),
    State("geojson", "hideout"),
    prevent_initial_call=True,
)
def toggle_select(_, feature, hideout):
    selected = hideout["selected"]
    name = feature["properties"]["name"]
    if name in selected:
        selected.remove(name)
    else:
        selected.append(name)
    return hideout


if __name__ == "__main__":
    app.run_server()

This is the exact same code from the tutorial, except for the explicit loading of the geojson dataset off of github. The polygons, however, are not displayed. This changes if I deactivate the style_handler like so:

import dash_leaflet as dl
from dash import Dash, Input, Output, State
from dash_extensions.javascript import assign

# Color selected state(s) red.
style_handle = assign("""function(feature, context){
    const {selected} = context.hideout;
    if(selected.includes(feature.properties.name)){
        return {fillColor: 'red', color: 'grey'}
    }
    return {fillColor: 'grey', color: 'grey'}
}""")

url = "https://raw.githubusercontent.com/PublicaMundi/MappingAPI/master/data/geojson/us-states.json"

# Create small example app.
app = Dash()
app.layout = dl.Map(
    [
        dl.TileLayer(),
        dl.GeoJSON(
            url=url,
            zoomToBounds=True,
            id="geojson",
            hideout=dict(selected=[]),
            # style=style_handle,
        ),
    ],
    style={"height": "50vh"},
    center=[56, 10],
    zoom=6,
)


@app.callback(
    Output("geojson", "hideout"),
    Input("geojson", "n_clicks"),
    State("geojson", "clickData"),
    State("geojson", "hideout"),
    prevent_initial_call=True,
)
def toggle_select(_, feature, hideout):
    selected = hideout["selected"]
    name = feature["properties"]["name"]
    if name in selected:
        selected.remove(name)
    else:
        selected.append(name)
    return hideout


if __name__ == "__main__":
    app.run_server()

Now the map loads properly, but obviously without the desired styling feature.
What am I missing? The code appears to work fine on the docu page, but not when recreating locally.

I am quite certain that dash-extensions.javascript does not work as intended, although I have installed the newest published version 1.0.14.

Thanks a lot in advance.

Hi @stargazer Welcome to the forums.

Try updating dash to 2.16.1

I wish it was that simple. That changed nothing, unfortunately. But thanks for the response.

Yeah, I just mentioned it because there are some known issues with 2.16.0.

Hey @stargazer. I copied your second code block, and I’m actually not sure what is the issue you face. That is what I see.

Yes, this is ecpected because the styling is commented out in the second bodeblock, so the polygons render normally. But they reactive styling does not work now, which is the point of this demo app. I would like to apply JS-styling as shown in the documentation linked above, but it breaks the app when copied straight over.

Basically, the second codeblock confirms that the JS-styling is the issue, even if it’s taken straight from the docu - so I assume there must be an error with dash-leaflet.

So commenting in the style=style_handle ?

exactly. the only difference between codeblock 1 and 2 is that I commented out style=style_handle which allows the polygons to be rendered again. but commenting it in seems to break the app, which is not at all in line with the docu app here.

Here the line commented in:

leaf

Isn’t that what is shown in the example?

I… wait, this works on your machine? I cannot reproduce this. The map renders empty for me, without any polygons, if I comment in style=style_handle.

yes.

dash 2.15.0
dash-extensions 1.0.8
dash-leaflet 1.0.13

I will test downgrading to these versions immediately.
Just for my own sanity, does this also work for you with the following geojson? https://raw.githubusercontent.com/johan/world.geo.json/master/countries.geo.json

Yes

leaf2

1 Like

I have downgraded my libraries to your specified versions but that did not change anything unfortunately. What else could this be? I work on an M1 mac, which sometimes causes issues, could that be a problem? Or do I need to set up JS to work like this?

I just tested with the following config, works on my side on Firefox and Chrome.

dash 2.16.1
dash-leaflet 1.0.16rc2
dash-extensions 1.0.14

Ubuntu 22.04
python 3.10.12

I will try and get to the bottom of this later, maybe test in a container if all else fails. thank you for your insights already!

1 Like

@AIMPED After containerizing the app everything works as expected. I am not sure how to explain this behavior, but digging into the logs led me to some errors with JS.
Not sure how this can be fixed, but I am content with working in a container-environment as a workaround.

Thank you for your help, without you I would not have figured this out as I thought it was a problem with dash-leaflet.

1 Like