Problem Statement :
I have a problem that I wanted some ideas to solve. I have built a dashboard to process some factory data I get in my work.
My layout is such that I have a button, on whose clicks a new html.Div gets created… this Div has two two tabs, each of which has a graph inside (one tab is for box plot, one tab is for histogram). This works great as it is on the default button state.
My layout is like this.
→ Button (has n_clicks)
—-> html.Div
--------> Tab-1 (plots box plot)
--------> Tab-2 (plots histogram)
However, my problem starts with the state of these graphs.
My default value of tab is box plot (tab-1).
Current state (n_click = 0):
Let’s say, my dashboard is currently displaying histogram (tab-2).
Next state (n_clicks = 1):
A new html.Div gets created and shows the two tabs, and displays box plot by default.
However, with this button click, the state of the plot in the first div also changes. So the plot in the first div is now automatically changed to box since that is the default.
So, basically no matter in which Div I click the tab, it is affecting all Divs.
I understand there is no n_clicks option for tabs but I still need to retain the tab state somehow of each Div, corresponding to the button clicks. How do I get around this problem ?
Sample Code :
This is the part where I define the Div, tabs and the graph… I have included the commented out code that tried hoping it would work, basically it is adding n_clicks to the dcc.Tabs section… but I get the following error when I enable it - “A nonexistent object was used in an Input
of a Dash callback”.
@app.callback(
Output('tabs_content', 'children'),
[Input('add_chart', 'n_clicks')],
[State('tabs_content', 'children')]
)
def display_graphs(n_clicks, div_children):
new_section = html.Div(
children = [
html.Label(['Select Config'], style={'color': 'black', 'font-weight': 'bold', "text-align": "left", 'paddingleft':"10px"}),
dcc.Dropdown( id={'type': 'DUT_config', 'index': n_clicks}, options=[{'label': str(x), 'value': x} for x in sorted(df['Config'].unique())], value='NA', multi=True, disabled=False, clearable=True, searchable=True, placeholder='Choose Config...', style={'width':"99%", 'padding-left':"10px"}, persistence='string',persistence_type='session'),
html.Br(),
# html.Div(id={'type': 'Div-0', 'index': n_clicks}),
# children = [
# dcc.Tabs(id="tabs_inline", value = 'tab-1',
# children = [ # dcc.Tab(label = 'Box Plot', value = 'tab-1', selected_style = selected_tab_style, style = tab_style,),
# dcc.Tab(label = 'Histogram', value = 'tab-2', selected_style = selected_tab_style, style = tab_style,)
# ]),
# ]),
dcc.Tabs(id="tabs_inline", value = 'tab-1', colors = {"border":'blue', "primary":'gold', "background": 'green'},
# id={'type': 'tabs-inline', 'index': n_clicks}, value = 'tab-1',
children = [
dcc.Tab(label = 'Box Plot', value = 'tab-1', selected_style = selected_tab_style, style = tab_style,),
dcc.Tab(label = 'Histogram', value = 'tab-2', selected_style = selected_tab_style, style = tab_style,) ]),
dcc.Graph(id={'type': 'data_graph', 'index': n_clicks}),
html.Div(id={'type': 'Div-1', 'index': n_clicks})
])
div_children.append(new_section)
return div_children
This is where I then define the plot types… I deleted a bit of irrelevant code for this problem that does the calculations for the graph based on dataframe
@app.callback(
[Output({'type': 'data_graph', 'index': MATCH}, 'figure'),
Output({'type': 'Div-1', 'index': MATCH}, 'children')],
[
# Input({'type': 'tabs_inline', 'index': MATCH}, 'value')
Input('tabs_inline', 'value')
# Input({'type': 'Div-0', 'index': MATCH}, 'children')],
# [State('tabs_inline', 'value')
])
def build_graph( tab_sel):
if tab_sel == 'tab-1':
fig = px.box(df_testcondition, y="Measured", color="Channel", facet_col="Config", points='all', hover_data=["SN"])
fig.update_layout(
title = {'text':f'<b>{modulation_rb_allocation_sel}, {lte_band_sel}, {bandwidth_sel} - {testitem_sel}, {rb_sel}</b>',
'x':0.5, 'xanchor': 'center', 'yanchor': 'bottom'}
)
elif tab_sel == 'tab-2':
fig = px.histogram(df_testcondition, x="Measured", color="Channel", facet_col="Config")
fig.update_layout(
title = {'text':f'<b>{modulation_rb_allocation_sel}, {lte_band_sel}, {bandwidth_sel} - {testitem_sel}, {rb_sel}</b>',
'x':0.5, 'xanchor': 'center', 'yanchor': 'bottom'}
)
return [fig,
dash_table.DataTable(data=data, columns=columns, merge_duplicate_headers=True, filter_action="native", sort_action="native", sort_mode="multi",
style_header = {'fontWeight': 'bold', 'backgroundColor': 'rgb(230, 230, 230)', 'border': '1px solid black'},
style_data={'border': '1px solid black'},
style_cell={'textAlign': 'center'})]