How to update chained dropdown value in Dash dcc?

Viewed 3380

In dash, how do I update the values of one dropdown into another checklist or slider? In the below code, I am selecting one value from a dropdown which should update checklist values based on the selected value from the dropdown. Here I am partially successful in taking value from the dropdown but it's accumulating with older selected values in the checklist. Please find below part of the code.

import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
import dash_table
import pandas as pd
from dash.exceptions import PreventUpdate

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

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.config['suppress_callback_exceptions'] = True

app.layout = html.Div([
                dash_table.DataTable(
                        id='datatable-upload-container',
                        columns=[{"name": i, "id": i} for i in df.columns],
                        data=df.to_dict('records'),
                        ),
                html.Div(dcc.Dropdown(
                    id='data_selector1',
                    options=[
                        {'label': '', 'value': ''}
                        ],
                    value=[]
                    )
                ),
                html.Br(),
                html.Div([
                    html.Div(id='numerical-slider'),
                    # this is a hack: include a hidden dcc component so that
                    # dash registers and serve's this component's JS and CSS
                    # libraries
                     dcc.Input(style={'display': 'none'})
                ])
           ])

@app.callback(Output('data_selector1', 'options'),
              [Input('datatable-upload-container', 'data')])
def update_dropdown(rows):
    print('updating menus')
    numerical_col = [i for i in df.columns if df[i].dtypes != "object"]
    col_labels=[{'label' :k, 'value' :k} for k in numerical_col]
    return col_labels

@app.callback(Output('numerical-slider','children'),
              [Input('data_selector1', 'value'),
              Input('datatable-upload-container', 'data')])
def explanatory_cat_slider(value, rows):
    if value:
        categories, intervals = pd.cut(df[value], 3, retbins=True)
        return html.Div(html.Label([value,
                            dcc.RangeSlider(id='numerical-slider',
                               min=min(intervals),
                               max=max(intervals),
                               step=None,
                               marks={str(val): str(round(val,2)) for val in intervals},
                               value = [intervals[0],intervals[-1]]
                               )
                            ],style={'width': '50%', 'display': 'inline-block', 'textAlign': 'left'})
                        )
    else:
        return []

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

updated code... I am getting an issue with explanatory_cat_slider, it's not getting updated with new selected values.

In the first image I can select one value of dropdown which automatically shows slider of that value

In the second image sliders getting accumulated on upon other. How do I rectify this issue?

In the last image, how it becomes slider overlapped

1 Answers

The code you posted is incomplete, because you have the Input ID data_selector and the ID datatable-upload-container in your callback, but they do not exist in your layout. I can see that the callback will have a problem with its Output as well, because it's trying to update the children of categorical-checklist with an element that contains an ID of the same. This would result in non-unique IDs in your layout, which will break.

I may be able to help more with the complete code but, essentially, you have the right idea to check if value: and run your code inside that block. Make sure you do not let the callback silently end, because that will return None and cause trouble for you. You should include a return [] or return '' at the end, or inside an else: block to protect against that, and keep the children component valid, even if only with an empty value.

You should also include the dcc.Checklist in your initial layout. Give it options=[] to start with and have your callback update its options prop. That should work but, if there are still problems, update your posted code and I'll take another look.

Related