Figure does not update in (dynamic) callback

Hi,

I’m doing a callback on my mapbox figure. However it does not succeed completely. The reason is a bit unclear to me. The dashboard works as following.

  1. you can click on a theme
  2. you can click on a dataset
  3. the figure updates according to the dataset

These number are also indicated in the figure below

The first issue is that step 2 does not exist at the start but only when a theme is selected. Therefore, the callback between step 2 and 3 gives an error which can also be seen in the figure. Moreover, when I click on either of the datasets nothing happens.

Below is my code:

from dash import Dash, html, dcc, Input, Output
from dash.exceptions import PreventUpdate
import dash_bootstrap_components as dbc
import plotly.express as px
import pandas as pd
import dask.dataframe as dd
import os
import base64
# initialize dash app
app = Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])

# load shoreline monitor dataframe
path_shorelineNL = r'P:\1000545-054-globalbeaches\15_GlobalCoastalAtlas\datasets\ShorelineMonitor\shoreline_NL.csv'
df = pd.read_csv(path_shorelineNL)

# Icons
test_png = 'dash/assets/deltares.png'
test_base64 = base64.b64encode(open(test_png, 'rb').read()).decode('ascii')


# initialize figure
fig = px.scatter_mapbox(zoom= 7, height=1000, center = {'lat': 52.6, 'lon':5})
fig.update_layout(mapbox_style="open-street-map", margin=dict(l=0,r=0,b=0,t=0), paper_bgcolor="Black")

# create theme buttons
button_style = {'color': 'white', 'font-size': 20, 'width': '100%', 'border-color': 'dark', 'textAlign': 'left'}
button_group = dcc.RadioItems(
            [ 
                {"label": html.Div(["Shoreline Development"], style= button_style), "value": 1},
                {"label": html.Div(["Beach State"], style= button_style), "value": 2},
                {"label": html.Div(["Sea Conditions"], style= button_style),"value": 3},
            ], 
            value= 0,
            id="choose_theme",
            style= {'width': '100%'},
            className="btn-group-vertical",
            inputClassName="btn-check",
            labelClassName="btn",
)

# Make initial app layout
app.layout = html.Div(children=[
                      dbc.Card(
                        dbc.CardBody([
                                dbc.Row([
    
                                        dbc.Row([
                                                dbc.Col(html.Div(id = 'Theme_container',
                                                                 children = [   dbc.Row([
                                                                                        dbc.Row([
                                                                                                    html.Div([html.Img(src = 'data:image/png;base64,{}'.format(test_base64), style = {'width': '30%'}),
                                                                                                            html.Div(children='Dutch Coastal Atlas', style = {'color': 'white', 'textAlign': 'left', 'font-size': 15})], style = {'display': 'inline-block'})
                                                                                                ]),
                                                                                        ]),
                                                                                html.Br(),
                                                                                html.H2(children = 'Themes', style = {'color': 'white', 'textAlign': 'left'}),
                                                                                html.Br(),
                                                                                button_group
                                                                            ]), width = 2, style = {'background-color': 'dark'}),
                                                dbc.Col(html.Div(children =  dcc.Graph(id='mapbox',figure= fig)), width = 6, style = {'background-color' : 'dark'}),
                                                dbc.Col(html.Div(id = 'Data_container',
                                                                 children = []), width = 4, style = {'background-color': 'dark'})
                                                ])
                                        ])
                                    ])
                                , color = 'dark') 
                            ])       
                     

@app.callback(
    [Output(component_id = 'Data_container', component_property = 'children')],
    [Input(component_id = 'choose_theme', component_property = 'value')]
)
def update_data_container(value):
    if value == 1:
        container = [
                     dbc.Col([
                                html.Br(), 
                                html.H2('Shoreline Development', style = {'color': 'white', 'textAlign': 'center'}),
                                html.Br(), 
                                html.Br(), 
                                dcc.RadioItems(
                                                [
                                                    {
                                                        "label": html.Div(['Transects'], style = {'color' : 'white'}), "value": 1,
                                                    },
                                                    {
                                                        "label": html.Div(['Continious'], style = {'color' : 'white'}),"value": 2,
                                                    },
                                                ],
                                                labelStyle={'display': 'block'},
                                                value = 0,
                                                inline= False,
                                                id= 'data_shorelinedevelop'
                                                #style= {'width': '100%'}
                                            )
                            ])
                    ]
        return container
    if value == 2:
        container = [
                     dbc.Col([
                                html.Br(), 
                                dbc.Row(html.H2('Beach State', style = {'color': 'white', 'textAlign': 'center'}))
                            ])
                    ]
        return container
    if value == 3:
        container = [
                     dbc.Col([
                                html.Br(), 
                                dbc.Row(html.H2('Sea Conditions', style = {'color': 'white', 'textAlign': 'center'}))
                            ])
                    ]
        return container
    else:
        raise PreventUpdate

@app.callback(
    Output(component_id = 'mapbox', component_property = 'figure'),
    Input(component_id = 'data_shorelinedevelop', component_property = 'value')
)
def update_figure(value):
    print(value)
    if value == 1:
        fig_new = px.scatter_mapbox(
                        df, lat="Intersect_lat", 
                        lon="Intersect_lon", 
                        hover_name="transect_id", 
                        hover_data=["country_name", "changerate"],
                        labels = {'country_name' : 'Country', 'Intersect_lat': 'Latitude', 'Intersect_lon': 'Longitude'},
                        color_discrete_sequence=["black"], zoom= 7, height=1000, center = {'lat': 52.6, 'lon':5})
        fig_new.update_layout(mapbox_style="open-street-map", margin=dict(l=0,r=0,b=0,t=0), paper_bgcolor="Black")
        fig_new.update_traces(marker={'size': 15})
        return fig_new
    
    if value == 2:
        fig_new = px.scatter_mapbox(zoom= 7, height=1000, center = {'lat': 40, 'lon':5})
        fig_new.update_layout(mapbox_style="open-street-map", margin=dict(l=0,r=0,b=0,t=0), paper_bgcolor="Black")
        return fig_new
    
    else:
        raise PreventUpdate

if __name__ == '__main__':
    app.run_server(debug=True)

Also if anyone knows how to fix the following:

  1. Aline the pictogram and the text in the upper left horizontally
  2. Align the label and selection box of the radio buttons horizontally.

Thanks in advance,

Dante

Hi @DantevdH,

I think that is because you create this component dynamically in a callback.

Since there might be constellations where this ID is not found in the layout and the callbacks referring to this ID throw the error you see in the upper right corner of your screenshot.

Hi,

Thanks for your response. I already thought so. How can I create a callback on this dynamically generated element?

Regards,

Dante