Hello,
First of all, Dash is amazing and it’s such a blast to work on it, great work!
I have massive problem with how my Dash app is unable to run.
What I try to achieve is a Dashboard for a Forecast. One Tab will be used to see specific forecasts for a given item and country. The second tab would be used for say - comparison purposes, compare items of a given country with items from a different country etc.
I get Dash to render the app just fine, the problem is with the callbacks to update the graph with two drop downs, I just don’t know where they should be put.
This is the AttributeError I receive:
AttributeError: 'Div' object has no attribute 'keys'
This is the code to my whole app:
import forecast
import dash
import dash_auth
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import dash_table as dt
import plotly as pt
import pandas as pd
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
forecast = forecast.run_forecast()
forecast_transposed = forecast.set_index('SALES GROUP').T
forecast_transposed['month'] = forecast_transposed.index
sales_grp = forecast['SALES GROUP'].unique()
cntr_grp = list(set([i.split('-')[0] for i in sales_grp]))
item_grp = list(set([i.split('-')[1] for i in sales_grp]))
valid_user_password_pairs = [
['user', 'password']
]
app = dash.Dash(__name__, external_stylesheets = external_stylesheets)
auth = dash_auth.BasicAuth(
app,
valid_user_password_pairs
)
app.layout = html.Div([
dcc.Tabs(id='forecast_tabs',
value='tab-1',
children=[
dcc.Tab(label='Tab One', value='tab-1'),
dcc.Tab(label='Tab Two', value='tab-2'),
]),
html.Div(id='tabs-content')
])
@app.callback(
Output(component_id='forecast_table', component_property='children'),
[Input(component_id='cntr_dropdown', component_property='value'),
Input(component_id='item_dropdown', component_property='value')]
)
def update_table(cntr_name, item_name):
cntr_detail = forecast[forecast['SALES GROUP'] == cntr_name + "-" + item_name]
# return cntr_detail
return dt.DataTable(
id='cntr_table',
columns=[{'name': i, 'id': i} for i in forecast.columns],
data=cntr_detail.to_dict('rows'),
# editable=True,
# filtering=True,
style_table={
'maxHeight': '300',
'overflowY': 'scroll',
'whiteSpace': 'normal',
'maxWidth': '300'
},
style_cell={'textAlign': 'center'},
css=[{
'selector': '.dash-spreadsheet-container .dash-spreadsheet-inner *, .dash-spreadsheet-container .dash-spreadsheet-inner *:after, .dash-spreadsheet-container .dash-spreadsheet-inner *:before',
'rule': ' box-sizing: inherit; width: 100%;'
}]
# style_cell_conditional=[{
# 'if': {'row_index': 'odd'},
# 'backgroundColor': 'rgb(248, 248, 248)'
# }]
)
@app.callback(
Output(component_id='forecast_graph', component_property='figure'),
[Input(component_id='cntr_dropdown', component_property='value'),
Input(component_id='item_dropdown', component_property='value')]
)
def update_graph(cntr_name, item_name):
data_name = cntr_name + '-' + item_name
mnths = forecast_transposed['month'].unique()
figure = {
'data': [
{
'y': forecast_transposed[data_name],
'x': mnths,
'type': 'line',
'name': f'Line Graph for {data_name}'
}
]
}
return figure
@app.callback(
Output(component_id='tabs-content', component_property='children'),
[Input(component_id='forecast_tabs', component_property='value')]
)
def render_content(tab):
if tab == 'tab-1':
return html.Div([
html.Div([
html.Div(
[html.H2('Forecast Dashboard',
)],
className='app-header-h1',
style={
'flex': 5,
'font-size': '2.65em',
'margin': '7px',
'margin-top': '20px',
'margin-bottom': '0'
},
),
],
className='app-header',
style={
'display': 'flex'
}
),
dcc.Dropdown(
id='cntr_dropdown',
options=[{'label': i, 'value': i} for i in cntr_grp],
value=cntr_grp[0]
),
dcc.Dropdown(
id='item_dropdown',
options=[{'label': i, 'value': i} for i in item_grp],
value=item_grp[0],
style={
'margin-top': '20px'
}
),
html.Div(
id='forecast_table',
style={
'width': '100%',
'margin-top': '20px',
'table-layout': 'fixed'
}
),
dcc.Graph(
id='forecast_graph'
),
])
elif tab == 'tab-2':
return html.Div([
html.H3('Tab Content 2')
])
# @app.callback(
# Output('content', 'children'),
# events=[Event('refresh', 'interval')]
# )
app.scripts.config.serve_locally = True
if __name__ == '__main__':
app.run_server(debug=False,
# dev_tools_props_check=False)
Any help would be greatly appreciated.
The issue I believe lies in the callbacks for the dropdowns, don’t know how to deal with those.
I tried a number of different methods, keeping the callbacks below the callback to render the tabs, above it, nothing worked.
Here is the traceback I receive:
Traceback (most recent call last):
File "app.py", line 121, in <module>
Input(component_id='item_dropdown', component_property='value')]
File "C:\Users\AppData\Local\Continuum\anaconda3\lib\site-packages\dash\dash.py", line 1156, in callback
self._validate_callback(output, inputs, state)
File "C:\Users\AppData\Local\Continuum\anaconda3\lib\site-packages\dash\dash.py", line 865, in _validate_callback
list(layout.keys()) + (
AttributeError: 'Div' object has no attribute 'keys'