Search code examples
pythonplotlyradio-buttonplotly-dashplotly-python

Why does my dash app not update with RadioItems


In the dash app below, my figure legend only updates when I change the values of 'points_category' - if I click a button on the 'legend_display' object then the legend does not appear or disappear until I change a value in the 'points_category' object.

Can someone explain why, and how to make the app update when I change either value?

Thanks! Tim

import sys
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output


app = dash.Dash(__name__)
tab_names = ['KnownClusterBlast', 'ClusterBlast']

                       
app.layout = html.Div([
    dcc.Tabs(id='choose_clusterblast', 
             value='ClusterBlast', 
             children=[
                 dcc.Tab(label='ClusterBlast', value='ClusterBlast'),
                 dcc.Tab(label='KnownClusterBlast', value='KnownClusterBlast')]),
    dcc.RadioItems(options=[{'label': 'homolog_bgc_type', 
                                                  'value': 'homolog_bgc_type'},
                                                 {'label': 'genus', 
                                                  'value': 'genus'},
                                                 {'label': 'species', 
                                                  'value': 'species'},
                                                 {'label': 'strain', 
                                                  'value': 'strain'}],
                   value = 'genus',
                   id = 'points_category'),
    dcc.RadioItems(options=[{'label': 'show_legend', 
                             'value': 'show_legend'},
                            {'label': 'dont_show_legend', 
                             'value': 'dont_show_legend'}],
                   value = 'dont_show_legend',
                   id = 'legend_display'),
    dcc.Graph(id = 'scatter_graph')])
     




@app.callback(
    [Output('scatter_graph', 'figure')],
    [Input('choose_clusterblast', 'value'),
    Input('points_category', 'value'),
    Input('legend_display', 'value')]
    )
def update_figure(type_clusterblast, category_colour, legend_display):
    if type_clusterblast == 'KnownClusterBlast': 
        df = known_clusterblast_df
    elif type_clusterblast == 'ClusterBlast':
        df = clusterblast_df
    else:
        sys.exit('error')
    fig = px.scatter(df, 
                     x="homolog_percent", 
                     y="multigeneblast_score", 
                     color = category_colour,
                     range_x = [0, 100],
                     range_y = [0, max(df['multigeneblast_score']) * 1.1],
                     height = 750,
                     width = 2000)
    if legend_display == 'dont_show_legend':
        fig.update_layout(showlegend=False)
    elif legend_display == 'show_legend':
        fig.update_layout(showlegend=True)
    else:
        sys.exit()
    fig.update_layout(transition_duration=500)
    
    return [fig]



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

Solution

  • To solve this problem remove the transition, the following line:

    fig.update_layout(transition_duration=500)
    

    It seems that there is a problem of synchronization between updating the layout and the speed of callback. Callback cannot wait for the update of layout to update of the legend, and it only returns the figure without updating.