Dash Leaflet - hide colorbar while allowing click events on GeoJSON behind it

Hi, I’m hoping for some advice, and will put together a minimal example if it will help.

I have on a Dash Leaflet map:

  • a GeoJSON layer with shading
  • a ColorBar (in front of it)

The GeoJSON shading can flip between a choropleth and showing selected countries (in response to radio buttons), and I’d like to hide the ColorBar when showing selected countries.

At the moment I do this by setting its opacity=0.0, but this has the problem that the invisible ColorBar still appears to mask hover and click events - if the mouse is over the ColorBar position the GeoJSON tooltip doesn’t show and the GeoJSON doesn’t respond to click events. (Both work perfectly when the mouse cursor is away from the ColorBar location).

Is there a good way of solving this? I think my next step is probably to find a way of changing the z-index of the ColorBar (setting style={“z-index”:“0”} seems to have no effect). I’m a bit reluctant to remove/replace map layers in response to a callback, but I think I may be missing some more straightforward solution.

Did you try setting display none?

Yeah, id agree with emil on this one. I setup a ledger within my map at https://dash.geomapindex.com

Thats connected to dl.Eastbutton

And put a blank div within the page.

When the dl.Easybutton is clicked

It updates the blank div’s children and style which are both outputs in the callback connected to all this.

Setup with style of position absolute and z-index of 1000

Also from my experiences you can set a map to a z-index of -1 and it will function just fine, for my design i prefer that over 0 but any more of a negitive z-index it will break the map.

Setting display none seems to have no effect, unless I’m making an error somewhere - see self-contained example below:

from dash import Dash, html, Input, Output, State, dcc
import dash_leaflet as dl

app = Dash(__name__) 
app.layout = [
    dcc.Checklist(["Show colorbar"], ["Show colorbar"], id='checkbox-show'),
    html.Div("Not clicked",id="messages"),
    dl.Map(
        children=[
            dl.GeoJSON(
                url="https://unpkg.com/geojson-resources@1.1.0/world.json",
                id="geojson",
            ),
            dl.Colorbar(min=0, max=2, classes=[0,1,2], colorscale=['#0000FF','#FF0000'],
                tickValues=[0.5, 1.5], tickText=["A", "B"],
                width=300, height=30, position="bottomleft",
                id=f"cbar"
            )
        ],
        center=[56,10], zoom=3,
        style={'width': '100%', 'height': '50vh'},
        id="dlmap"
    )
]

@app.callback(
    Output("messages","children"),
    Input("geojson","n_clicks"),
    State("geojson","clickData"),
    prevent_initial_call=True
)
def cb1(nclicks, clickdata):
    return f'{nclicks} clicks, clicked on: {clickdata["properties"]["FID"]}'

@app.callback(
    Output("cbar","opacity"),
    Output("cbar","tickText"),
    Output("cbar","style"),
    Input("checkbox-show","value"),
    prevent_initial_call=False
)
def show_cbar(values):
    if values:
        opacity, ticktext, style = 1.0,  ["A","B"], {"display":"block"} 
    else: 
        opacity, ticktext, style = 0.0,  ["",""], {"display":"none"} 
    return opacity, ticktext, style

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

Thanks - I can see your app not only looks amazing, but also solves this issue :slight_smile:

I think I see what you mean - the basic idea I’m taking from this is that there’s no reason why my ColorBar has to be a layer in the same dl.Map as my GeoJSON layer, and if it isn’t then the solution should be straightforward.

1 Like