Feed dcc.Slider parameters from dash callback, update other components from new dcc.Slider value

Hello All,

In that example, I want to use callback to feed dcc slider parameters. And this dcc slider component will be used to control both, DataTable & figure components,
dcc slider parameters are declared in app.py through dcc store component and get calculated in code/page_2.

Once we get “min”, “max” and “value” dcc slider parameter values, I try to input those to dcc.Slider() component using dash callbacks.

But dcc.Slider() does not display.

Here is error msg:

null is not an object (evaluating 'n.toString().match(/^-?\d+(?:\.\d{0,0})?/)[0]')

Here is how it is coded.

app.py code:

app.layout = dbc.Container([
    html.Div([
        dcc.Store(id='store', data={}, storage_type='local'),
        dcc.Store(id='store-min', data={}, storage_type='local'),
        dcc.Store(id='store-max', data={}, storage_type='local'),
        dcc.Store(id='store-value', data={}, storage_type='local'),
        dcc.Store(id='store-marks', data={}, storage_type='local')
        ]),

....

page_2 code

layout = dbc.Container([
    dbc.Row([
        dbc.Col([
            html.H2('Full table'),
            html.Br(),
            html.Br(),
            html.Hr(),
            dash_table.DataTable(data=[] , id='full-table', 
                                 fixed_columns={'headers':True, 'data':1},
                                 page_size=15)
            ]),
        ]),
    dbc.Row([
        dcc.Slider(id='slider')
        ]),
    dbc.Row([
        dbc.Col([
            html.H2('dropdown'),
            dcc.Dropdown(id='dropdown-continent', options=[], value='Europe'),
            html.Br(),
            dcc.Dropdown(id='dropdown-country', options=[], value='France'),
            html.Br(),
            dash_table.DataTable(data=[], id='table-country',
                                 fixed_columns={'headers':True, 'data':1},
                                 page_size=15)
        ]),
        dbc.Col([
            html.H2('figure from dropdown'),
            html.Br(),
            dcc.Graph(id='graph-country', figure={})
            ]),
        ]),
    ])


@callback(
    [Output('full-table', 'data'),
     Output('full-table', 'columns')],
    Input('store', 'data'))
def fn_full_table(data):    
    df = pd.DataFrame(data)
    return df.to_dict('records'), [{"name":i, "id": i} for i in df.columns]



@callback(
    [Output('store-min', 'data'),
     Output('store-max', 'data'),
     Output('store-value', 'data')
     ],
     Input('store', 'data')
     )
def fn_store_min_max(data):
    df = pd.DataFrame(data)
    df_year = df.loc[:, 'year']
    min = df_year.min()
    max = df_year.max()
    value = max
    #marks={year: str(year) for year in df['year'].unique()}
        
    return [min, max, value]
    


@callback(
    [Output('slider', 'min'),
     Output('slider', 'max'),
     Output('slider', 'value')
     ],
    
    [Input('store-min', 'data'),
     Input('store-max', 'data'),
     Input('store-value', 'data')
     ])
def fn_slider(min, max, value):
    min_value = min
    max_value = max
    val = value
    
    print(f'Slider: min_value {min_value}')
    print(f'Slider: max_value {max_value}')
    print(f'Slider: value -- {val}')
    
    return [min_value, max_value, val]



@callback(
    Output('dropdown-continent', 'options'),
    Input('store', 'data')
    )
def fn_dropdown_continent(data):
    df = pd.DataFrame(data)
    print(f'df.head() -- {df.head()}')    
    return list(df['continent'].unique())



@callback(
    Output('dropdown-country', 'options'),
    [Input('store', 'data'),
      Input('dropdown-continent', 'value')
      ])
def fn_dropdown_country(data, continent):
    df = pd.DataFrame(data)
    df_cont = df[df['continent'] == continent]
    return list(df_cont['country'].unique())
    


@callback(
    [Output('table-country', 'data'),
     Output('table-country', 'columns')],
    [Input('store', 'data'),
     Input('slider', 'value'),
     Input('dropdown-continent', 'value'),
     Input('dropdown-country', 'value')]
    )
def fn_table_country(data, selected_year_value, continent, country):
    df = pd.DataFrame(data)
    
    print(f'year-value -- {selected_year_value}')
    
    df_cont = df[df['continent'] == continent]
    df_count = df_cont[df_cont['country'] == country]
    
    df_count_period = df_count[(df_count['year'] <= selected_year_value)]
    df_count_period = df_count_period.sort_values(by=['year'], ascending=True, ignore_index=True)
    print(f'df_count_period.head() -- {df_count_period.head()}')
    
    return df_count_period.to_dict('records'), [{"name": col, "id": col} for col in df_count_period.columns]



@callback(
    Output('graph-country', 'figure'),
    Input('table-country', 'data')
    )
def fn_graph(data):
    df_count = pd.DataFrame(data)    
    
    fig = px.bar(df_count, 
                  x='year', 
                  y=['pop'],
                  color='lifeExp',
                  hover_name='country',
                  title='Bar chart, country')
    return fig

Since I have dcc slider parameters, I thought dcc slider has all necessary values to get displayed.
Why is that not the case ?

There is another thing that confuses me. Once the parameters are known, the dcc slider should be able to be displayed. But how to structure the code so that a change of value of the dcc slider can have an effect on the other components, DataTable and graph?

Many thanks for your time on this !

Hey @Olivier_fr , just set min and max of the slider, the values will get updated once the callback executed.

dcc.Slider(id="slider", min=0, max=1)

Many thanks for your time !

If I understand correctly, it means dcc slider parameters must be hardcoded initially, then dcc slider related changes get reflected to other components ?

No other solution than hardcoded ?

Thank you again !

correct

not sure what you are referring to

Adam just published a video yesterday explaining the range slider and how to use it in callbacks, you might be able to find some useful context and learn some stuff in regards to getting your slider working by watching this.

Not exactly specific to your use case but over arching their is overlap in knowledge that could be used that could help you with this.

1 Like

Thank you so much for this !

I understood that dcc slider parameters have to be hardcoded. From this I managed to build slider and go on with what I wanted to do,
For those like me who are beginners, I put here some code as it might help someone,

app.py code:

app = dash.Dash(__name__, 
                use_pages=True,
                external_stylesheets=[dbc.themes.SPACELAB])

sidebar = dbc.Nav(
    [dbc.NavLink(
        
        [html.Div(page['name'], className='ms-2')],
        
        href=page['path'],
        
        active='exact') for page in dash.page_registry.values()],
    
    vertical=True,
    pills=True,
    className='bg-light')




app.layout = dbc.Container([
    html.Div([
        dcc.Store(id='store', data={}, storage_type='local'),
        dcc.Store(id='store-min', data={}, storage_type='local'),
        dcc.Store(id='store-max', data={}, storage_type='local'),
        dcc.Store(id='store-value', data={}, storage_type='local'),
        ]),

    
    dbc.Row([
        dbc.Col(
            html.Div("Gdp -- Life exp Analysis",
            style={'fontsize':100, 'textAlign': 'center', 'font-weight': 'bold'}))
        ]),
    
    
    html.Hr(),
    
    
    dbc.Row([
        dbc.Col([
            sidebar],
            xs=4,
            sm=4,
            md=2,
            lg=2,
            xxl=2),
        dbc.Col([
            dash.page_container],
            xs=8,
            sm=8,
            md=10,
            lg=10,
            xxl=10)])
    ], 
    fluid=True)

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

page_1 code:

df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv')

dash.register_page(__name__,
                   path='/analytics-dashboard',
                   title='Analytics Dashboard 1',
                   name='Analytics Dashboard 1',
                   location="sidebar")
layout = dbc.Row([
    dbc.Col([
        html.H1('Full table', style={'textAlign': 'center'}),
        html.Br(),
        html.Hr(),
        dash_table.DataTable(data=[], id='table', page_size=10),
        html.Br(),
        html.Br(),
        ]),
    dbc.Row([
        dbc.Col([
            html.H2('Table from selected continent'),
            html.Br(),
            html.Br(),
            dcc.Dropdown(id='dropdown-continent', options=df['continent'].unique(), value='Europe'),
            dash_table.DataTable(
                id='table-continent',
                columns=[{"name":i, "id": i} for i in df.columns],
                fixed_columns={'headers': True, 'data': 1},
                page_size=15),
            ]),
        dbc.Col([
            html.H2('Graph from selected continent'),
            html.Br(),
            html.Br(),
            dcc.Graph(id='graph-from-selected-continent', figure={})]),
        ]),
    ])

@callback(
    Output('store', 'data'),
    Input('store', 'data'))
def fn_store(data):
    if data == {}:
        data = df.to_dict('records')
    return data



@callback(
    Output('table', 'data'),
    Input('store', 'data'))
def fn_table(data):
    return data



@callback(
    [Output('table-continent', 'data'),
      Output('table-continent', 'columns')],
    Input('dropdown-continent', 'value'))
def fn_dropdown(continent):
    df_c = df[df['continent'] == continent]
    return df_c.to_dict('records'), [{"name":i, "id": i} for i in df_c.columns]



@callback(
    Output('graph-from-selected-continent', 'figure'),
    Input('table-continent', 'data'))
def fn_graph(data):
    df = pd.DataFrame(data)
    fig = px.scatter(df,
                     x='gdpPercap',
                     y='lifeExp',
                     color='country',
                     hover_name='continent',
                     size='pop')
    return fig

page_2 code:

dash.register_page(__name__, 
                   path='/',
                   location="sidebar")


layout = dbc.Container([
    dbc.Row([
        dbc.Col([
            html.H2('Table from selected continent'),
            html.Br(),
            html.Br(),
            dcc.Input(id='continent-input', type='text', placeholder='select continent...'),
            html.Br(),
            html.Br(),
            dash_table.DataTable(data=[] , id='full-table', 
                                 fixed_columns={'headers':True, 'data':1},
                                 page_size=15,
                                 style_cell={'padding': '5px'},
                                 style_header={'backgroundColor': 'white',
                                               'fontWeight': 'bold',
                                               'border': '1px solid pink'},
                                 style_data={ 'border': '1px solid blue' }
                                 )
            ]),
        dbc.Col([
            html.H2('Gdp factor influence in regards to population'),
            html.Br(),
            html.Br(),
            dcc.Graph(id='graph-gdp-pop', figure={})])
        ]),
    html.Br(),
    html.Br(),
    html.Br(),
    
    dbc.Row([
        dcc.Slider(id='slider', min=0, max=1, marks={year: str(year) for year in range(1950, 2010, 4)})
        ]),
    
    dbc.Row([
        dbc.Col([
            html.H2('Continent dropdown'),
            dcc.Dropdown(id='dropdown-continent', options=[], value='Europe'),
            html.Br(),
            dcc.Dropdown(id='dropdown-country', options=[], value='France'),
            html.Br(),
            dash_table.DataTable(data=[], id='table-country',
                                 fixed_columns={'headers':True, 'data':1},
                                 page_size=15,
                                 style_cell={'padding': '5px'},
                                 style_header={'backgroundColor': 'white',
                                               'fontWeight': 'bold',
                                               'border': '1px solid pink'},
                                 style_data={ 'border': '1px solid blue' }
                                 )
        ]),
        
        dbc.Col([
            html.H2('Figure from Continent dropdown'),
            html.Br(),
            dcc.Graph(id='graph-country', figure={})
            ]),
        ]),
    ])


@callback(
    [Output('full-table', 'data'),
     Output('full-table', 'columns')],
    [Input('store', 'data'),
     Input('continent-input', 'value')
     ])
def fn_full_table(data, continent):    
    df = pd.DataFrame(data)
    df_cont = df[df['continent'] == continent]
    return df_cont.to_dict('records'), [{"name":i, "id": i} for i in df_cont.columns]



@callback(
    Output('graph-gdp-pop', 'figure'),
    [Input('store', 'data'),
     Input('continent-input', 'value')]
    )
def fn_graph_gdp_pop(data, continent):
    df = pd.DataFrame(data)
    df_cont = df[df['continent'] == continent]

    fig = px.scatter(df_cont,
                     x='gdpPercap',
                     y='pop',
                     color='country',
                     size='lifeExp',
                     hover_name='continent')
    return fig



@callback(
    [Output('store-min', 'data'),
     Output('store-max', 'data'),
     Output('store-value', 'data')
     ],
     Input('store', 'data')
     )
def fn_store_min_max(data):
    df = pd.DataFrame(data)
    df_year = df.loc[:, 'year']
    min = df_year.min()
    max = df_year.max()
    value = max
    return [min, max, value]



@callback(
    [Output('slider', 'min'),
     Output('slider', 'max'),
     Output('slider', 'value')
     ],
    
    [Input('store-min', 'data'),
     Input('store-max', 'data'),
     Input('store-value', 'data')
     ])
def fn_slider(min, max, value):
    
    print(f'Slider: min {min}')
    print(f'Slider: max {max}')
    print(f'Slider: value {value}')
    
    return [min, max, value]



@callback(
    Output('dropdown-continent', 'options'),
    Input('store', 'data')
    )
def fn_dropdown_continent(data):
    df = pd.DataFrame(data)
    print(f'df.head() -- {df.head()}')    
    return list(df['continent'].unique())



@callback(
    Output('dropdown-country', 'options'),
    [Input('store', 'data'),
      Input('dropdown-continent', 'value')
      ])
def fn_dropdown_country(data, continent):
    df = pd.DataFrame(data)
    df_cont = df[df['continent'] == continent]
    return list(df_cont['country'].unique())
    


@callback(
    [Output('table-country', 'data'),
     Output('table-country', 'columns')],
    [Input('store', 'data'),
     Input('slider', 'value'),
     Input('dropdown-continent', 'value'),
     Input('dropdown-country', 'value')]
    )
def fn_table_country(data, selected_year_value, continent, country):
    df = pd.DataFrame(data)
    
    print(f'year-value -- {selected_year_value}')
    
    df_cont = df[df['continent'] == continent]
    df_count = df_cont[df_cont['country'] == country]
    
    df_count_period = df_count[(df_count['year'] <= selected_year_value)]
    df_count_period = df_count_period.sort_values(by=['year'], ascending=True, ignore_index=True)
    print(f'df_count_period.head() -- {df_count_period.head()}')
    
    return df_count_period.to_dict('records'), [{"name": col, "id": col} for col in df_count_period.columns]



@callback(
    Output('graph-country', 'figure'),
    Input('table-country', 'data')
    )
def fn_graph(data):
    df_count = pd.DataFrame(data)    
    
    fig = px.bar(df_count, 
                  x='year', 
                  y=['pop'],
                  color='lifeExp',
                  hover_name='country',
                  title='Bar chart, country')
    return fig


Thank you for your time !

1 Like