Callback reset using callback_context

Hello Community…
I’m trying to reset the output, after updating the bar graph using clickData property of callback input.

Initial output is displayed from the IF block of code. After updating the graph via the clickData input the ELSE block of code is activated and displays the output. when we clicked on the Reset button it moves again to the IF block of code. till then all going well. but, after that, when we try to change the input date it triggers the callback and again moves to the ELSE block of code, how can I prevent this last move.
Any guidance is super helpful Thanks in advance.

from jupyter_dash import JupyterDash
import dash
from dash import dcc, html
from dash import html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
import plotly.graph_objects as go
import pandas as pd
import numpy as np
import math
from datetime import datetime as dt

def load_data(path):
    data = pd.read_csv(path)
    lowercase = lambda x: str(x).lower()
    data.rename(lowercase, axis='columns', inplace=True)
    data['bedate'] = pd.to_datetime(data['bedate'])
    return data

df = load_data('https://docs.google.com/spreadsheets/d/e/2PACX-1vTOMUYStiCsAQkEJwP0NPsasTzyH17jVJQcsSKlLSpuYDuDE1OACWfebeiYUy_CJdL9d7L8YI3MOdIT/pub?gid=636681119&single=true&output=csv')

app = JupyterDash(__name__, external_stylesheets=[dbc.themes.CYBORG])


date_picker =  dcc.DatePickerRange(id='date range picker'
                                   ,min_date_allowed=df.bedate.min()
                                   ,max_date_allowed=df.bedate.max()
                                   ,start_date=df.bedate.max()-pd.offsets.MonthBegin(1, normalize=True)
                                   ,end_date=df.bedate.max()
                                   ,display_format='D-MMM-YY')


@app.callback(
    Output('top 10 importer', 'figure')
    ,Input('date range picker', 'start_date')
    ,Input('date range picker', 'end_date')
    ,Input('top 10 supplier','clickData')
    ,Input('reset', 'n_clicks'))
             
def update_period(start_date, end_date, clicked_supplier, n_clicks):
    changed_id = dash.callback_context.triggered[0]['prop_id'].split('.')[0]
    dfx = df[(df.bedate>= start_date) & (df.bedate <= end_date)]
    
    if (clicked_supplier is None) | (changed_id == 'reset'):
        dfxx = dfx.groupby(['importer_name','supplier_name'])[['quantity(kg)']].sum().reset_index()
        
        df_bar_impo = dfxx.groupby('importer_name')['quantity(kg)'].sum().reset_index().sort_values(by='quantity(kg)')
        df_bar_impo['market_share']= round(df_bar_impo['quantity(kg)']/df_bar_impo['quantity(kg)'].sum()*100,2)

        fig_impo = go.Figure(data=[
            go.Bar(
            y=[i for i in df_bar_impo['importer_name']][-10:]

            ,x=df_bar_impo['quantity(kg)'][-10:]/1000
            ,orientation='h'
            # ,marker=dict(color='#636efa')
            ,textfont=dict(family="sans serif"
                            ,size=12)
            ,text= [i for i in df_bar_impo['quantity(kg)'][-10:]/1000]
            ,textposition="auto"
            ,hovertemplate ='<b> %{x:,.0f} MT</b>' #<extra></extra>'
            ,name='Imported Qty')

            ,go.Bar(
            y=[i for i in df_bar_impo['importer_name']][-10:]
            ,x=df_bar_impo['market_share'][-10:]
            ,orientation='h'
            ,marker=dict(color='#636efa')
            ,text= [str(round(i))+'%' for i in df_bar_impo['market_share'][-10:]]
            ,textposition="auto"
            ,textfont=dict(family="sans serif"
                            ,size=12)
            ,hovertemplate ='<b> %{x:,.2f}%</b>'#<extra></extra>' # extra HTML tag is used to remove default trace name
            ,name='Market Share')
        ])

        fig_impo.update_xaxes(showgrid=False, zeroline=False)
        fig_impo.update_yaxes(showgrid=False, zeroline=False)

        fig_impo.update_layout(
            title_text='Top 10 Importer'
            ,title_x=0.5
            ,barmode='stack'
            ,template='plotly_dark'
            ,showlegend=False
            ,hovermode='y'
            # ,margin=dict(b=30, t=60)
            ,height=450
            # ,width=400
            ,yaxis= dict(tickfont= dict(size=10))
            ,xaxis= dict(tickfont= dict(size=10))
        )
        return fig_impo
    
    else:
        selected_supplier =  clicked_supplier['points'][0]['y']
        dfx= dfx[dfx['supplier_name'] == selected_supplier]
        
        dfxx = dfx.groupby(['importer_name','supplier_name'])[['quantity(kg)']].sum().reset_index()
    
        df_bar_impo = dfxx.groupby('importer_name')['quantity(kg)'].sum().reset_index().sort_values(by='quantity(kg)')
        df_bar_impo['market_share']= round(df_bar_impo['quantity(kg)']/df_bar_impo['quantity(kg)'].sum()*100,2)

        fig_impo = go.Figure(data=[
            go.Bar(
            y=[i for i in df_bar_impo['importer_name']][-10:]
            ,x=df_bar_impo['quantity(kg)'][-10:]/1000
            ,orientation='h'
            # ,marker=dict(color='#636efa')
            ,textfont=dict(family="sans serif"
                            ,size=12)
            ,text= [i for i in df_bar_impo['quantity(kg)'][-10:]/1000]
            ,textposition="auto"
            ,hovertemplate ='<b> %{x:,.0f} MT</b>' #<extra></extra>'
            ,name='Imported Qty')

            ,go.Bar(
            y=[i for i in df_bar_impo['importer_name']][-10:]
            # y=[i.split()[0].title()+' '+i.split()[1].title() for i in df_bar_impo['importer_name']][-10:]
            ,x=df_bar_impo['market_share'][-10:]
            ,orientation='h'
            ,marker=dict(color='#636efa')
            ,text= [str(round(i))+'%' for i in df_bar_impo['market_share'][-10:]]
            ,textposition="auto"
            ,textfont=dict(family="sans serif"
                            ,size=12)
            ,hovertemplate ='<b> %{x:,.2f}%</b>'#<extra></extra>' # extra HTML tag is used to remove default trace name
            ,name='Market Share')
        ])

        fig_impo.update_xaxes(showgrid=False, zeroline=False)
        fig_impo.update_yaxes(showgrid=False, zeroline=False)

        fig_impo.update_layout(
            title_text=f'Importers of <b>{selected_supplier}<b>'
            ,title_x=0.5
            ,barmode='stack'
            ,template='plotly_dark'
            ,showlegend=False
            ,hovermode='y'
            # ,margin=dict(b=30, t=60)
            ,height=450
            # ,width=400
            ,yaxis= dict(tickfont= dict(size=10))
            ,xaxis= dict(tickfont= dict(size=10))
        )
        return fig_impo
#------------------------------------------------------------    
    
@app.callback(
    Output('top 10 supplier', 'figure')
    ,Input('date range picker', 'start_date')
    ,Input('date range picker', 'end_date')
    ,Input('top 10 importer','clickData')
    ,Input('reset', 'n_clicks'))

    
def update_on_time(start_date, end_date, clicked_importer, n_clicks):
 
    changed_id = dash.callback_context.triggered[0]['prop_id'].split('.')[0]
    dfx = df[(df.bedate >= start_date) & (df.bedate <= end_date)]
  
    if (clicked_importer is None) | (changed_id == 'reset'):
        dfxx = dfx.groupby(['importer_name','supplier_name'])[['quantity(kg)']].sum().reset_index()
        df_bar_supp = dfxx.groupby('supplier_name')['quantity(kg)'].sum().reset_index().sort_values(by='quantity(kg)')
        df_bar_supp['market_share']= round(df_bar_supp['quantity(kg)']/df_bar_supp['quantity(kg)'].sum()*100,2)

        fig_supp = go.Figure(data=[
            go.Bar(
            y=[i for i in df_bar_supp['supplier_name']][-10:]
            # y=[i.split()[0].title()+' '+i.split()[1].title()+' '+i.split()[2].title() for i in df_bar_supp['supplier_name']][-10:]
            ,x=df_bar_supp['quantity(kg)'][-10:]/1000
            ,orientation='h'
            # ,marker=dict(color='aqua')
            ,textfont=dict(family="sans serif"
                            ,size=12)
            ,text= [i for i in df_bar_supp['quantity(kg)'][-10:]/1000]
            ,hovertemplate ='<b> %{x:,.0f} MT</b>'
            ,name='Exported Qty')

            ,go.Bar(
            y=[i for i in df_bar_supp['supplier_name']][-10:]
            # y=[i.split()[0].title()+' '+i.split()[1].title()+' '+i.split()[2].title() for i in df_bar_supp['supplier_name']][-10:]
            ,x=df_bar_supp['market_share'][-10:]
            ,orientation='h'
            ,marker=dict(color='#636efa')
            ,text= [str(round(i))+'%' for i in df_bar_supp['market_share'][-10:]]
            ,textfont=dict(family="sans serif"
                            ,size=12)
            ,hovertemplate ='<b> %{x:,.2f}%</b>'#<extra></extra>' # extra HTML tag is used to remove default trace name
            ,name='Market Share')
        ])

        fig_supp.update_xaxes(showgrid=False, zeroline=False)
        fig_supp.update_yaxes(showgrid=False, zeroline=False)

        fig_supp.update_layout(
            title_text='Top 10 supplier'
            ,title_x=0.5
            ,barmode='stack'
            ,template='plotly_dark'
            ,showlegend=False
            ,hovermode="y"
            # ,margin=dict(b=30, t=60)
            ,height=450
            # ,width=400    
            # ,paper_bgcolor="#1A2245"
            # ,plot_bgcolor="#1F2D58"
            ,yaxis= dict(tickfont= dict(size=10))
            ,xaxis= dict(tickfont= dict(size=10))
        )
        return fig_supp
    else:
        # print(f'hover data: {clicked_importer}')
        
        selected_importer =  clicked_importer['points'][0]['y']
        dfx= dfx[dfx['importer_name'] == selected_importer]
        dfxx = dfx.groupby(['importer_name','supplier_name'])[['quantity(kg)']].sum().reset_index()
        
        df_bar_supp = dfxx.groupby('supplier_name')['quantity(kg)'].sum().reset_index().sort_values(by='quantity(kg)')
        df_bar_supp['market_share']= round(df_bar_supp['quantity(kg)']/df_bar_supp['quantity(kg)'].sum()*100,2)

        fig_supp = go.Figure(data=[
            go.Bar(
            y=[i for i in df_bar_supp['supplier_name']][-10:]
           
            ,x=df_bar_supp['quantity(kg)'][-10:]/1000
            ,orientation='h'
            ,marker=dict(color='#636efa')
            ,textfont=dict(family="sans serif"
                            ,size=12)
            ,text= [i for i in df_bar_supp['quantity(kg)'][-10:]/1000]
            ,hovertemplate ='<b> %{x:,.0f} MT</b>'
            ,name='Exported Qty')

            ,go.Bar(
            y=[i for i in df_bar_supp['supplier_name']][-10:]
           
            ,x=df_bar_supp['market_share'][-10:]
            ,orientation='h'
            ,marker=dict(color='#636efa')
            ,text= [str(round(i))+'%' for i in df_bar_supp['market_share'][-10:]]
            ,textfont=dict(family="sans serif"
                            ,size=12)
            ,hovertemplate ='<b> %{x:,.2f}%</b>'#<extra></extra>' # extra HTML tag is used to remove default trace name
            ,name='Market Share')
        ])

        fig_supp.update_xaxes(showgrid=False, zeroline=False)
        fig_supp.update_yaxes(showgrid=False, zeroline=False)

        fig_supp.update_layout(
            title_text=f'Suppliers of <b>{selected_importer}<b>'
            ,title_x=0.5
            ,barmode='stack'
            ,template='plotly_dark'
            ,showlegend=False
            ,hovermode="y"
            # ,margin=dict(b=30, t=60)
            ,height=450
            # ,width=400    
            # ,paper_bgcolor="#1A2245"
            # ,plot_bgcolor="#1F2D58"
            ,yaxis= dict(tickfont= dict(size=10))
            ,xaxis= dict(tickfont= dict(size=10))
        )
        return fig_supp
#-----------------------------------------------------------
    
app.layout = html.Div([
    dbc.Row([
        dbc.Col(date_picker)
        ,dbc.Col(html.Button('Reset',id='reset', n_clicks=0))
    ])
    ,dbc.Row([
        dbc.Col([dcc.Graph(id='top 10 importer')])
        ,dbc.Col([dcc.Graph(id='top 10 supplier')])
    ])
])

app.run_server(mode='external', debug=True)

@adamschroeder

Too complex :laughing:, but I think the snippet below may help you.

from dash.exceptions import PreventUpdate

@app.callback(
    Output(...), Output(...),
    Input(...), Input(...),
    State(...)
)
def callback(a, b, c):
    if a is None:
        raise PreventUpdate
    return [a + b, b + c]
1 Like

@stu
Thanks for quick reply.

I’ve tried something like this but it doesn’t work.

Did you notice that I used State()?