Plotly Dash - Error when combining pattern matching and circular callback - python

I’m quite new to Python and Plotly Dash, currently facing issues when refactoring this dashboard to use pattern matching and circular callback.
Key Features of dashboard
User adjust weightage of each factor via Slider or Input. Each Slider and Input are synchronized
Each city have base score for each factor in excel sheet. Download excel
Index of each city is calculated by weighted average for all factors (base score * weightage)
Dashboard
Issues when refactoring:
When printing value for one factor for testing, values of all factors were printed instead of one.
As all values are triggered instead of one, unable to differentiate for weighted average calculation for each factor.
Only the highlighted components can be adjusted. For example, Slider for Smart mobility can be adjusted, which change value for corresponding input. But Input value can’t be adjusted to change slider value.
Synchronizing issue between slider-input pairs
Attempt to refactor
import dash
from dash.dependencies import Input, Output, MATCH
from dash import dcc, ctx
import dash_bootstrap_components as dbc
import dash_daq as daq
from dash import html
import plotly.express as px
import pandas as pd
df= pd.read_excel("C:\\Desktop\\Smart_City.xlsx",
sheet_name='cities')
factors = []
for i in df.columns[1:]:
factors.append(i)
PLOTLY_LOGO = "https://images.plot.ly/logo/new-branding/plotly-logomark.png"
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
app.title = "Smart Cities"
# make a reuseable navitem for the different examples
nav_item = dbc.NavItem(dbc.NavLink("Link", href="https://plotly.com"))
# make a reuseable dropdown for the different examples
dropdown = dbc.DropdownMenu(
children=[
dbc.DropdownMenuItem("Entry 1"),
dbc.DropdownMenuItem("Entry 2"),
dbc.DropdownMenuItem(divider=True),
dbc.DropdownMenuItem("Entry 3"),
],
nav=True,
in_navbar=True,
label="Menu",
)
# this example that adds a logo to the navbar brand
logo = dbc.Navbar(
dbc.Container(
[
html.A(
# Use row and col to control vertical alignment of logo / brand
dbc.Row(
[
dbc.Col(html.Img(src=PLOTLY_LOGO, height="30px")),
dbc.Col(dbc.NavbarBrand("Smart Cities Index", className="ms-2")),
],
align="center",
className="g-0",
),
href="https://plotly.com",
style={"textDecoration": "none"},
),
dbc.NavbarToggler(id="navbar-toggler2", n_clicks=0),
dbc.Collapse(
dbc.Nav(
[nav_item, dropdown],
className="ms-auto",
navbar=True,
),
id="navbar-collapse2",
navbar=True,
),
],
),
color="dark",
dark=True,
className="mb-5",
)
app.layout = html.Div([
logo,
dbc.Row(
[
dbc.Col(html.Div([
dbc.Row(dbc.Col(html.Div([
html.Label(f'{name}'),
dcc.Slider(
id={'type': 'slider','index': name},
min=0, max=100,
marks=None,
value=10,
)],
style={
'font-size': '14px',
'height': '38px',
'width': '100%',
'display': 'inline-block',
'vertical-align': 'bottom',
})
))
for name in factors]), width={"size": 3, "offset": 1}),
dbc.Col(html.Div([
dbc.Row(dbc.Col(html.Div([
html.Br(),
daq.NumericInput(
id={'type': 'num_input','index': name},
min=0, max=100, value=10, size=60,
),],
style={
'height': '38px',
'width': '100%',
'display': 'inline-block',
'vertical-align': 'bottom',
})
))
for name in factors]), width=1),
dbc.Col(html.Div(dbc.Card(html.Div([
dcc.Loading([
dcc.Graph(id="chart", )])], style={'horizontal-align': 'middle' ,'vertical-align': 'middle', 'overflowY': 'scroll'},)
, style={'height': '450px', 'display':'inline-block',})), width=7)
]
),
])
#app.callback(
[Output({'type': 'slider', 'index': MATCH}, 'value'),
Output({'type': 'num_input', 'index': MATCH}, 'value')],
inputs={
"all_inputs": {
"slider": Input({'type': 'slider','index': MATCH}, "value"),
"num_input": Input({'type': 'num_input','index': MATCH}, "value")
}
}
)
def callback(all_inputs):
c = ctx.args_grouping.all_inputs
value_Smart_Mobility = 10 #Quick fix to prevent unbounded error
value_Smart_Mobility = c.num_input.value if c.num_input.id.index == 'Smart_Mobility' else
c.slider.value
print(value_Smart_Mobility) #Values for all factors were printed out, instead of one only
value_Smart_Mobility = c.slider.value if c.slider.id.index == 'Smart_Mobility' else
c.num_input.value
print(value_Smart_Mobility) #Values for all factors were printed out, instead of one only
return value_Smart_Mobility, value_Smart_Mobility
if __name__== '__main__':
app.run_server(debug=True)
Original long callback version
The original long callback version worked but its too lengthy and require manual change in App Callback whenever column names in excel changes.
import dash
from dash.dependencies import Input, Output, MATCH
from dash import dcc, ctx
import dash_bootstrap_components as dbc
import dash_daq as daq
from dash import html
import plotly.express as px
import pandas as pd
# Extract column names from excel file
df= pd.read_excel("C:\\Desktop\\Smart_City.xlsx", sheet_name='cities')
factors = []
for i in df.columns[1:]:
factors.append(i)
PLOTLY_LOGO = "https://images.plot.ly/logo/new-branding/plotly-logomark.png"
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
app.title = "Smart Cities"
# make a reuseable navitem for the different examples
nav_item = dbc.NavItem(dbc.NavLink("Link", href="https://plotly.com"))
# make a reuseable dropdown for the different examples
dropdown = dbc.DropdownMenu(
children=[
dbc.DropdownMenuItem("Entry 1"),
dbc.DropdownMenuItem("Entry 2"),
dbc.DropdownMenuItem(divider=True),
dbc.DropdownMenuItem("Entry 3"),
],
nav=True,
in_navbar=True,
label="Menu",
)
# this example that adds a logo to the navbar brand
logo = dbc.Navbar(
dbc.Container(
[
html.A(
# Use row and col to control vertical alignment of logo / brand
dbc.Row(
[
dbc.Col(html.Img(src=PLOTLY_LOGO, height="30px")),
dbc.Col(dbc.NavbarBrand("Smart Cities Index", className="ms-2")),
],
align="center",
className="g-0",
),
href="https://plotly.com",
style={"textDecoration": "none"},
),
dbc.NavbarToggler(id="navbar-toggler2", n_clicks=0),
dbc.Collapse(
dbc.Nav(
[nav_item, dropdown],
className="ms-auto",
navbar=True,
),
id="navbar-collapse2",
navbar=True,
),
],
),
color="dark",
dark=True,
className="mb-5",
)
# Using list comprehension to create slider and input. ID's Index is column name from
dataframe/excel
app.layout = html.Div([
logo,
dbc.Row(
[
dbc.Col(html.Div([
dbc.Row(dbc.Col(html.Div([
html.Label(f'{name}'),
dcc.Slider(
id={'type': 'slider','index': name},
min=0, max=100,
marks=None,
value=10,
)],
style={
'font-size': '14px',
'height': '38px',
'width': '100%',
'display': 'inline-block',
'vertical-align': 'bottom',
})
))
for name in factors]), width={"size": 3, "offset": 1}),
dbc.Col(html.Div([
dbc.Row(dbc.Col(html.Div([
html.Br(),
daq.NumericInput(
id={'type': 'num_input','index': name},
min=0, max=100, value=10, size=60,
),],
style={
'height': '38px',
'width': '100%',
'display': 'inline-block',
'vertical-align': 'bottom',
})
))
for name in factors]), width=1),
dbc.Col(html.Div(dbc.Card(html.Div([
dcc.Loading([
dcc.Graph(id="chart", )])], style={'horizontal-align': 'middle' ,'vertical-align': 'middle', 'overflowY': 'scroll'},)
, style={'height': '500px', 'display':'inline-block',})), width=7)
]
),
])
# Long callback listing every input and output. Trying to use pattern matching, so that index
wont be hardcoded
#app.callback(
[Output({'type': 'slider','index': "Smart_Mobility"}, "value"),
Output({'type': 'num_input','index': "Smart_Mobility"}, "value"),
Output({'type': 'slider','index': "Smart_Environment"}, "value"),
Output({'type': 'num_input','index': "Smart_Environment"}, "value"),
Output({'type': 'slider','index': "Smart_Government"}, "value"),
Output({'type': 'num_input','index': "Smart_Government"}, "value"),
Output({'type': 'slider','index': "Smart_Economy"}, "value"),
Output({'type': 'num_input','index': "Smart_Economy"}, "value"),
Output({'type': 'slider','index': "Smart_People"}, "value"),
Output({'type': 'num_input','index': "Smart_People"}, "value"),
Output({'type': 'slider','index': "Smart_Living"}, "value"),
Output({'type': 'num_input','index': "Smart_Living"}, "value"),
Output("chart", "figure")],
[Input({'type': 'slider','index': "Smart_Mobility"}, "value"),
Input({'type': 'num_input','index': "Smart_Mobility"}, "value"),
Input({'type': 'slider','index': "Smart_Environment"}, "value"),
Input({'type': 'num_input','index': "Smart_Environment"}, "value"),
Input({'type': 'slider','index': "Smart_Government"}, "value"),
Input({'type': 'num_input','index': "Smart_Government"}, "value"),
Input({'type': 'slider','index': "Smart_Economy"}, "value"),
Input({'type': 'num_input','index': "Smart_Economy"}, "value"),
Input({'type': 'slider','index': "Smart_People"}, "value"),
Input({'type': 'num_input','index': "Smart_People"}, "value"),
Input({'type': 'slider','index': "Smart_Living"}, "value"),
Input({'type': 'num_input','index': "Smart_Living"}, "value")]
)
# Circular callback to synchronize each slider to input. Iterate to calculate weighted average
Index for chart.
def callback(slider_Smart_Mobility, num_input_Smart_Mobility, slider_Smart_Environment,
num_input_Smart_Environment, slider_Smart_Government, num_input_Smart_Government,
slider_Smart_Economy, num_input_Smart_Economy, slider_Smart_People, num_input_Smart_People,
slider_Smart_Living, num_input_Smart_Living):
weightage = []
value_Smart_Mobility = num_input_Smart_Mobility if ctx.triggered_id == {'type':
'num_input','index': "Smart_Mobility"} else slider_Smart_Mobility
weightage.append(value_Smart_Mobility / 100 )
value_Smart_Environment = num_input_Smart_Environment if ctx.triggered_id == {'type':
'num_input','index': "Smart_Environment"} else slider_Smart_Environment
weightage.append(value_Smart_Environment / 100 )
value_Smart_Government = num_input_Smart_Government if ctx.triggered_id == {'type':
'num_input','index': "Smart_Government"} else slider_Smart_Government
weightage.append(value_Smart_Government / 100 )
value_Smart_Economy = num_input_Smart_Economy if ctx.triggered_id == {'type':
'num_input','index': "Smart_Economy"} else slider_Smart_Economy
weightage.append(value_Smart_Economy / 100 )
value_Smart_People = num_input_Smart_People if ctx.triggered_id == {'type':
'num_input','index': "Smart_People"} else slider_Smart_People
weightage.append(value_Smart_People / 100 )
value_Smart_Living = num_input_Smart_Living if ctx.triggered_id == {'type':
'num_input','index': "Smart_Living"} else slider_Smart_Living
weightage.append(value_Smart_Living / 100 )
city_index = []
for index, row in df.iterrows():
base_list = [int(row[i]) for i in factors]
index_list = [int(j*k) for j, k in zip(base_list, weightage)]
index = float("{:.2f}".format(sum(index_list) / sum(weightage)))
city_index.append(index)
df['Index'] = city_index
df['Index'] = pd.to_numeric(df['Index'])
df2 = df.sort_values(by=['Index'], ascending=True)
figure = px.bar(df2, x='Index', y='City', height=500, color='Index',
color_continuous_scale='inferno')
return value_Smart_Mobility, value_Smart_Mobility, value_Smart_Environment,
value_Smart_Environment, value_Smart_Government, value_Smart_Government,
value_Smart_Economy, value_Smart_Economy, value_Smart_People, value_Smart_People,
value_Smart_Living, value_Smart_Living, figure
if __name__== '__main__':
app.run_server(debug=True)

Related

using hoverData in plotly dash to create hover go.Table

I am trying to use the hoverData of a plot with many traces to display a side table of values related to each trace. The main code runs as follows. (note this is not the full code, but i included the relevant info)
def plots(self,):
df_lists = self.df_lists
plots_names = ['weakness', 'std', 'std_average', 'std_weak', 'p_average', 'p_repitition_average', 'p_median','p_median_all', 'p_median_average','p_range', 'p_range_average']
colors = {'background': '#111111', 'text': '#7FDBFF'}
from dash import Dash, dcc, html, Input, Output, State
names = self.names
app = Dash()
app.layout = html.Div( children=[
html.H4('Dieharder Tests Plots'),
html.P('Chose Plot Type'),
dcc.RadioItems(plots_names, plots_names[0], id="plot-picker", ),
html.P('Test Description'),
dcc.Markdown(id='test-explain', link_target="_blank", ),
html.P("Filter by test:"),
dcc.Dropdown(names, names[0], id="test-picker", multi = True),
dcc.Graph(id="plot", style={'width':'75%', 'float': 'left','height': '70vh','display':'inline-block'}),
html.Div([dcc.Graph(id='hover-data', style ={'float':'right'})], style={'width':'20%', 'paddingTop':35}),
])
#app.callback(
Output("plot", "figure"),
[Input("plot-picker", "value"), Input("test-picker", "value")])
def update_bar_chart(plot_picker, picker_test):
i=0
if plot_picker == 'weakness':
data = []
for test in picker_test:
df = df_lists[test]
p_value = [x for x in df.columns if x.startswith('pva')]
n_rounds = len(p_value)
trace = go.Bar(x=df.test_name, y = df.weak_rate, name = '{}, #rounds: {}'.format(test,n_rounds))
data.append(trace)
layout = go.Layout(title = 'Fraction of weak and failed results per each Dieharder test')
fig = go.Figure(data, layout)
fig.update_yaxes(title_text='Failed/weak fractions')
fig.update_layout(legend=dict(yanchor="top", y=0.99, xanchor="left", x=0.01))
return fig
The hover data includes the number of the trace not its name, which i need to specify the df source of the data. I am using the following code to get the hover data to generate the table:
#app.callback(Output('hover-data', 'graph'),
[Input('plot', 'hoverData')] )
def hover_data(hoverData):
Die_test = hoverData['points'][0]['x']
curve_number = hoverData['points'][0]['curveNumber']
trace_name = app.layout['plot'].figure['data'][curve_number]['name']
df = df_lists[trace_name]
df = df[df['test_name'] == Die_test]
data = [go.Table(header=dict(values=['p_mean', 'p_median', 'range', 'std'], fill_color='paleturquoise', align='left'), cells=dict(values=[df['p_mean'], df['p_median'], df['range'], df['std']] ))]
fig = go.Figure(data,)
return fig
The problem it is not working. I am not seeing anything when i hover over the data. I am not sure where the problem is coming, but most probably from the trace_name variable as i am getting the error:
Callback error updating hover-data.graph
AttributeError: 'Graph' object has no attribute 'figure'.
I tried to include a [State('plot', 'figure')] in the input of the callback. and then use the .figure['data'][curve_number]['name'] directly (instead of using app.layout['plot'] first), but it also didn't work.
Any help is appreciated.
Thanks
I don't have your dataframe so I think you can refer my code to revise yours:
from dash import Dash, html, dcc, Input, Output
import pandas as pd
import plotly.express as px
import dash_bootstrap_components as dbc
app = Dash(__name__, external_stylesheets=[dbc.themes.LUX])
df = pd.read_csv('https://plotly.github.io/datasets/country_indicators.csv')
app.layout = html.Div([
dbc.Row([
dbc.Col([
dcc.Dropdown(
df['Indicator Name'].unique(),
'Fertility rate, total (births per woman)',
id='crossfilter-xaxis-column',
),
dcc.RadioItems(
['Linear', 'Log'],
'Linear',
id='crossfilter-xaxis-type',
labelStyle={'display': 'inline-block', 'marginTop': '5px'}
)
], width={'size': 6, "offset": 0, 'order': 1}),
dbc.Col([
dcc.Dropdown(
df['Indicator Name'].unique(),
'Life expectancy at birth, total (years)',
id='crossfilter-yaxis-column'
),
dcc.RadioItems(
['Linear', 'Log'],
'Linear',
id='crossfilter-yaxis-type',
labelStyle={'display': 'inline-block', 'marginTop': '5px'}
)
], width={'size': 6, "offset": 0, 'order': 1})
], style={'padding': '10px 5px'}, className='p-2 align-items-center'),
dbc.Row([
dbc.Col([
dcc.Graph(
id='crossfilter-indicator-scatter',
hoverData={'points': [{'customdata': 'Japan'}]}
)
], width={'size': 6, "offset": 0, 'order': 1}),
dbc.Col([
dash_table.DataTable(id='table',
columns=[{"name": i, "id": i} for i in df.columns],
data=[],
style_table={'height': 550},
style_header={'backgroundColor': 'orange', 'padding': '10px', 'color': '#000000'},
style_cell={'textAlign': 'center', 'font_size': '12px',
'whiteSpace': 'normal', 'height': 'auto'},
editable=True, # allow editing of data inside all cells
filter_action="native", # allow filtering of data by user ('native') or not ('none)
sort_action="native", # enables data to be sorted per-column by user or not ('none')
sort_mode="single", # sort across 'multi' or 'single' columns
column_selectable="multi", # allow users to select 'multi' or 'single' columns
row_selectable="multi", # allow users to select 'multi' or 'single' rows
row_deletable=True, # choose if user can delete a row (True) or not (False)
selected_columns=[], # ids of columns that user selects
selected_rows=[], # indices of rows that user selects
page_action="native",
export_headers='display')
], width={'size': 6, "offset": 0, 'order': 1}),
], className='p-2 align-items-center'),
dbc.Row([
dbc.Col([
dcc.Slider(
df['Year'].min(),
df['Year'].max(),
step=None,
id='crossfilter-year--slider',
value=df['Year'].max(),
marks={str(year): str(year) for year in df['Year'].unique()}
)
], width={'size': 6, "offset": 0, 'order': 1})
], className='p-2 align-items-center')
])
#app.callback(
Output('crossfilter-indicator-scatter', 'figure'),
Input('crossfilter-xaxis-column', 'value'),
Input('crossfilter-yaxis-column', 'value'),
Input('crossfilter-xaxis-type', 'value'),
Input('crossfilter-yaxis-type', 'value'),
Input('crossfilter-year--slider', 'value'))
def update_graph(xaxis_column_name, yaxis_column_name,
xaxis_type, yaxis_type,
year_value):
dff = df[df['Year'] == year_value]
fig = px.scatter(x=dff[dff['Indicator Name'] == xaxis_column_name]['Value'],
y=dff[dff['Indicator Name'] == yaxis_column_name]['Value'],
hover_name=dff[dff['Indicator Name'] == yaxis_column_name]['Country Name'])
fig.update_traces(customdata=dff[dff['Indicator Name'] == yaxis_column_name]['Country Name'])
fig.update_xaxes(title=xaxis_column_name, type='linear' if xaxis_type == 'Linear' else 'log')
fig.update_yaxes(title=yaxis_column_name, type='linear' if yaxis_type == 'Linear' else 'log')
fig.update_layout(margin={'l': 40, 'b': 40, 't': 10, 'r': 0}, hovermode='closest')
return fig
#app.callback(
Output('table', 'data'),
Input('crossfilter-indicator-scatter', 'hoverData'),
Input('crossfilter-xaxis-column', 'value'),
Input('crossfilter-xaxis-type', 'value'))
def update_y_timeseries(hoverData, xaxis_column_name, axis_type):
country_name = hoverData['points'][0]['customdata']
dff = df[df['Country Name'] == country_name]
dff = dff[dff['Indicator Name'] == xaxis_column_name]
return dff.to_dict(orient='records')
if __name__ == '__main__':
app.run_server(debug=False, port=1414)
I think instead of return go.Table, you can use dash_table in your Div and then return filtered data frame. Hope this help.

Is it possible to use zoom from one graph in a Dash app to select input for second graph

I have a dash app that plots a dataframe which has a date component, and an entry that is either true or false. There are two graphs in the dashboard, one with the data vs date, and one with a percentage of True/False like below:
I can zoom in on the date range and select a subset clicking with the mouse.
I would like to feed this range back into the second graph.
At the moment to produce the above dashboard the relevant part of the code looks like:
from re import template
import pandas as pd
import plotly.express as px
from dash import Dash, Input, Output, dcc, html
from flask import globals
def init_dashboard(server):
evicted_df = pd.read_csv("app/data/evicted_jobs_node.csv", sep="\t")
all_df = pd.read_csv("app/data/all_jobs_node.csv", sep="\t")
all_df["datetime"] = pd.to_datetime(all_df["datetime"])
all_df = all_df.set_index(["datetime"])
all_df["evicted"] = all_df["id_job"].isin(evicted_df["id_job"])
app = Dash(__name__, server=server, routes_pathname_prefix="/dash/")
app.layout = html.Div(
[
html.Div(
className="row",
children=[
html.Div(
className="six columns",
children=[dcc.Graph(id="graph-with-dropdown")],
style=dict(width="75%"),
),
html.Div(
className="six columns",
children=[dcc.Graph(id="graph-with-dropdown2")],
style=dict(width="25%"),
),
],
style=dict(display="flex"),
),
html.Div(
className="row",
children=[
html.Div(
className="six columns",
children=[
dcc.Dropdown(
id="partition-dropdown",
options=[
"Partition (default is all)",
*all_df["partition"].unique(),
],
value="Partition (default is all)",
clearable=False,
searchable=False,
)
],
style={
"width": "50%",
"justify-content": "center",
},
),
html.Div(
className="six columns",
children=[
dcc.Dropdown(
id="node-dropdown",
options=[
"Number of Nodes (default is all)",
*sorted(
[
int(nodes)
for nodes in all_df["nodes_alloc"].unique()
]
),
],
value="Number of Nodes (default is all)",
clearable=False,
searchable=False,
)
],
style=dict(width="50%"),
),
],
style=dict(display="flex"),
),
]
)
init_callbacks(app, df, all_df)
return app.server
def init_callbacks(app, df, all_df):
#app.callback(
Output("graph-with-dropdown2", "figure"),
[Input("node-dropdown", "value"), Input("partition-dropdown", "value")],
)
def update_evicted_fig(selected_nodes, selected_partition):
if selected_nodes != "Number of Nodes (default is all)":
filtered_df = all_df[all_df["nodes_alloc"] == selected_nodes]
else:
filtered_df = all_df
if selected_partition != "Partition (default is all)":
filtered_df = filtered_df[filtered_df["partition"] == selected_partition]
x = ["Not Evicted", "Evicted"]
df1 = filtered_df.groupby(["evicted"]).count().reset_index()
fig = px.bar(
df1,
y=[
100
* filtered_df[filtered_df["evicted"] == False].size
/ filtered_df.size,
100
* filtered_df[filtered_df["evicted"] == True].size
/ filtered_df.size,
],
x=x,
color="evicted",
color_discrete_map={True: "red", False: "green"},
labels={"x": "Job Status", "y": "% of Jobs"},
)
fig.update_layout(transition_duration=500)
return fig
#app.callback(
Output("graph-with-dropdown", "figure"),
[Input("node-dropdown", "value"), Input("partition-dropdown", "value")],
)
def update_evicted_fig(selected_nodes, selected_partition):
if selected_nodes != "Number of Nodes (default is all)":
filtered_df = all_df[all_df["nodes_alloc"] == selected_nodes]
else:
filtered_df = all_df
if selected_partition != "Partition (default is all)":
filtered_df = filtered_df[filtered_df["partition"] == selected_partition]
print(
filtered_df[filtered_df["evicted"] == True]
.groupby([pd.Grouper(freq="6H")])
.sum(numeric_only=True)["node_hours"]
)
fig = px.bar(
x=filtered_df[filtered_df["evicted"] == False]
.groupby([pd.Grouper(freq="6H")])
.sum(numeric_only=True)["node_hours"]
.index,
y=filtered_df[filtered_df["evicted"] == False]
.groupby([pd.Grouper(freq="6H")])
.sum(numeric_only=True)["node_hours"],
labels={
"x": "Date",
"y": "Node hours",
},
title="Job Status",
barmode="stack",
)
fig.add_bar(
name="Evicted",
x=filtered_df[filtered_df["evicted"] == True]
.groupby([pd.Grouper(freq="6H")])
.sum(numeric_only=True)["node_hours"]
.index,
y=filtered_df[filtered_df["evicted"] == True]
.groupby([pd.Grouper(freq="6H")])
.sum(numeric_only=True)["node_hours"],
)
fig.update_layout(transition_duration=500)
return fig
return app.server
Is what I am hoping to do possible, and if so is there some documentation or a worked example someone could highlight for me?
I don't have you df so maybe you can refer my code to revise yours:
import pandas as pd
import numpy as np
import plotly.express as px
import dash
import dash_html_components as html
from dash import dcc
from dash_extensions.enrich import Input, Output, State, ServersideOutput
import dash_bootstrap_components as dbc
from dash.exceptions import PreventUpdate
df_2 = df[(df['BAS_DT'] >= '2022-01-01')]
df5 = df_2.pivot_table(values='USD_XC_BL',
index=['BAS_DT'],
aggfunc=np.sum).reset_index()
fig_3 = px.bar(df5,
x='BAS_DT',
y='USD_XC_BL',
labels='BAS_DT',
hover_name='BAS_DT', color_discrete_sequence=px.colors.qualitative.Alphabet)
fig_3.update_layout(xaxis_title="", yaxis_title="", plot_bgcolor='rgba(0,0,0,0)', margin=dict(l=0, r=0, t=0, b=0))
fig_3.update_xaxes(showline=False, showgrid=False),
fig_3.update_yaxes(showline=False, showgrid=False, separatethousands=True, tickformat=',.0f')
app = dash.Dash(__name__)
app.layout = html.Div([
dbc.Row([
dbc.Col([
dbc.Card([
dbc.CardBody([
dbc.Row([
dbc.Col([
html.H5('Amount by Currency', style={"text-align": "center"}),
dcc.Loading(children=[dcc.Graph(id='histogram_map', figure=fig_3)], color='#119DFF',
type='dot')
], width={'size': 12, 'offset': 0, 'order': 2}, style={"text-align": "left"}),
]),
])
]),
], xs=6),
dbc.Col([
dbc.Card([
dbc.CardBody([
dbc.Row([
dbc.Col([
html.H5('Overdue Status', style={"text-align": "center"}),
dcc.Loading(children=[dcc.Graph(id='overdue_map', figure={})], color='#119DFF', type='dot')
], width={'size': 12, 'offset': 0, 'order': 2}, style={"text-align": "left"}),
]),
])
]),
], xs=6),
], className='p-2 align-items-stretch')
])
#app.callback(
Output('overdue_map', 'figure'),
Input('histogram_map', 'clickData'))
def update_y_timeseries(clickData):
if clickData:
country_name = clickData['points'][0]['hovertext']
df_3 = df[df['BAS_DT'] == country_name]
df_4 = df_3.pivot_table(values='CLOC_CUR_XC_BL',
index=['APL_DTL_NAME'],
aggfunc=pd.Series.nunique).reset_index()
fig = px.bar(df_4,
x='APL_DTL_NAME',
y='CLOC_CUR_XC_BL'
, color_discrete_sequence=px.colors.qualitative.Alphabet)
fig.update_layout(xaxis_title="", yaxis_title="", plot_bgcolor='rgba(0,0,0,0)') # plot_bgcolor='rgba(0,0,0,0)'
fig.update_xaxes(showline=False, showgrid=False),
fig.update_yaxes(showline=False, showgrid=False, separatethousands=True)
fig.update_traces(width=0.3)
return fig
else:
raise PreventUpdate
if __name__ == "__main__":
app.run_server(debug=True)
I'm using clickData to return point as date, and then use this date to filter data and then make new bar graph.
Hope this help.

Why Prevent_initial_call does not stop the initial call?

I have the written code below. I have two dropdown menus that work based on chained callbacks. the first dropdown menu gets the datasets and reads the columns' names and updates the options in the second dropdown menu. Then, the parameters can be plotted on the chart.
my dataframes look like this:
df={'col1':[12,15,25,33,26,33,39,17,28,25],
'col2':[35,33,37,36,36,26,31,21,15,29],
'col3':['A','A','A','A','B','B','B','B','B','B'],
'col4':[1,2,3,4,5,6,7,8,9,10]
I want to highlight the chart background depending on the categories in col3. I don't understand why when I select the dataset from the first dropdown menu the background color for col3 appears on the chart (before selecting the parameters). I have used Prevent_initial_call = True, but the second callback still triggers.
import dash
from dash import Dash, html, dcc, Output, Input, State, MATCH, ALL
import plotly.express as px
import pandas as pd
import numpy as np
import dash_bootstrap_components as dbc
app = Dash(__name__)
app.layout = html.Div([
html.Div(children=[
html.Button('add Chart', id='add-chart', n_clicks=0)
]),
html.Div(id='container', children=[])
])
#app.callback(
Output('container', 'children'),
[Input('add-chart', 'n_clicks'),
Input({'type': 'remove-btn', 'index': ALL}, 'n_clicks')],
[State('container', 'children')],
prevent_initial_call=True
)
def display_graphs(n_clicks, n, div_children):
ctx = dash.callback_context
triggered_id = ctx.triggered[0]['prop_id'].split('.')[0]
elm_in_div = len(div_children)
if triggered_id == 'add-chart':
new_child = html.Div(
id={'type': 'div-num', 'index': elm_in_div},
style={'width': '25%',
'display': 'inline-block',
'outline': 'none',
'padding': 5},
children=[
dbc.Container([
dbc.Row([
dbc.Col([dcc.Dropdown(id={'type': 'dataset-choice', 'index': n_clicks},
options=['dataset1'],
clearable=True,
value=[]
)], width=6),
dbc.Col([dcc.Dropdown(id={'type': 'feature-choice', 'index': n_clicks},
options=[],
multi=True,
clearable=True,
value=[]
)], width=6)
]),
dbc.Row([
dbc.Col([dcc.Graph(id={'type': 'dynamic-graph','index': n_clicks},
figure={}
)])
]),
dbc.Row([
dbc.Col([html.Button("Remove", id={'type': 'remove-btn', 'index': elm_in_div})
])
]),
])
]
)
div_children.append(new_child)
return div_children
if triggered_id != 'add-chart':
for idx, val in enumerate(n):
if val is not None:
del div_children[idx]
return div_children
#app.callback(
Output({'type': 'feature-choice', 'index': MATCH}, 'options'),
[Input({'type': 'dataset-choice', 'index': MATCH}, 'value')],
prevent_initial_call=True
)
def set_dataset_options(chosen_dataset):
if chosen_dataset is None:
return dash.no_update
else:
path = 'C:/Users/pymnb/OneDrive/Desktop/test/'
df = pd.read_csv(path + chosen_dataset+'.csv')
features = df.columns.values[0:2]
return features
#app.callback(
Output({'type': 'dynamic-graph', 'index': MATCH}, 'figure'),
[Input({'type': 'dataset-choice', 'index': MATCH}, 'value'),
Input({'type': 'feature-choice', 'index': MATCH}, 'value')],
prevent_initial_call=True
)
def update_graph(chosen_dataset1, chosen_feature):
if chosen_feature is None:
return dash.no_update
if chosen_dataset1 is None:
return dash.no_update
path = 'C:/Users/pymnb/OneDrive/Desktop/test/'
df = pd.read_csv(path + chosen_dataset1+'.csv')
Xmin = df[chosen_feature].min().min()
print(Xmin)
Xmax = df[chosen_feature].max().max()
# to find the height of y-axis(col4)
col4_max = df['col4'].max()
col4_min = df['col4'].min()
fig1 = px.line(df, x=chosen_feature, y='col4')
fig1.update_layout({'height': 600,
'legend': {'title': '', 'x': 0, 'y': 1.06, 'orientation': 'h'},
'margin': {'l': 0, 'r': 20, 't': 50, 'b': 0},
'paper_bgcolor': 'black',
'plot_bgcolor': 'white',
}
)
fig1.update_yaxes(range=[col4_max, col4_min], showgrid=False)
fig1.update_xaxes(showgrid=False)
categ_col3 = df.col3.dropna().unique()
colors = ['#54FF9F', '#87CEFF']
for (i,j) in zip(categ_col3, colors):
index_min = df.loc[df.col3 == i].index[0]
index_max = df.loc[df.col3 == i].index[-1]
if index_min == 0:
cat_min = df['col4'][index_min]
else:
cat_min = df['col4'][index_min-1]
cat_max = df['col4'][index_max]
fig1.add_shape(type="rect", x0=Xmin, y0=cat_min, x1=Xmax, y1=cat_max,
fillcolor=j, layer='below', opacity=0.5,
)
return fig1
if __name__ == '__main__':
app.run_server(debug=True)
You can fix it by modifying your code to the following:
#app.callback(
Output({'type': 'dynamic-graph', 'index': MATCH}, 'figure'),
[Input({'type': 'dataset-choice', 'index': MATCH}, 'value'),
Input({'type': 'feature-choice', 'index': MATCH}, 'value')],
prevent_initial_call=True
)
def update_graph(chosen_dataset1, chosen_feature):
if (chosen_feature == []) or (chosen_dataset1 is None): #<--- correct the condition
return dash.no_update
else: #<---- add the else condition to prevent any update
Xmin = df[chosen_feature].min().min()
Xmax = df[chosen_feature].max().max()
The reason behind that because all the elements are created on fly and they are not within the app.layout. Please read the following from the documentation:
In other words, if the output of the callback is already present in
the app layout before its input is inserted into the layout,
prevent_initial_call will not prevent its execution when the input is
first inserted into the layout.

How to insert several dropdowns in plotly dash

I am trying to get into using Plotly Dash and I am getting stuck on this one piece where I would like to dynamically add a user-defined number of dropdowns. Here is what I tried:
# Import required libraries
import dash
import math
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
# App Begins
app = dash.Dash(
__name__, meta_tags=[{"name": "viewport", "content": "width=device-width"}],
)
app.title = "Tool"
server = app.server
# Create global chart template
mapbox_access_token = "pk.eyJ1IjoicGxvdGx5bWFwYm94IiwiYSI6ImNrOWJqb2F4djBnMjEzbG50amg0dnJieG4ifQ.Zme1-Uzoi75IaFbieBDl3A"
layout = dict(
autosize=True,
automargin=True,
margin=dict(l=30, r=30, b=20, t=40),
hovermode="closest",
plot_bgcolor="#F9F9F9",
paper_bgcolor="#F9F9F9",
legend=dict(font=dict(size=10), orientation="h"),
title="Satellite Overview",
mapbox=dict(
accesstoken=mapbox_access_token,
style="light",
center=dict(lon=-78.05, lat=42.54),
zoom=7,
),
)
# Create app layout
app.layout = html.Div(
[
dcc.Store(id="aggregate_data"),
# empty Div to trigger javascript file for graph resizing
html.Div(id="output-clientside"),
html.Div(
[
html.Div(
[
html.Img(
src=app.get_asset_url("dash-logo.png"),
id="plotly-image",
style={
"height": "60px",
"width": "auto",
"margin-bottom": "25px",
},
)
],
className="one-third column",
),
html.Div(
[
html.Div(
[
html.H3(
"Dash Tool",
style={"margin-bottom": "0px"},
),
]
)
],
className="one-half column",
id="title",
),
],
id="header",
className="row flex-display",
style={"margin-bottom": "25px"},
),
html.Div(
[
html.Div(
[
html.P("Quantity 1:", className="control_label"),
dcc.Input(
id="quantity_1",
type="number",
placeholder=33.
),
html.P("Quantity 2:", className="control_label"),
dcc.Input(
id="quantity_2",
type="number",
placeholder=-115.
),
html.P("Number of Drop Downs:", className="control_label"),
dcc.Slider(
id="drop_downs",
min=2,
max=10,
value=2,
step=1.0,
className="dcc_control",
),
html.P("Load Inputs:", className="control_label"),
dcc.Checklist(
id='sources_flag',
options=[
{'label': 'Yes', 'value': 'Y'},
],
value=['Y'],
labelStyle={'display': 'inline-block'}
),
html.Div(id='source_dropdown_container', children=[]),
html.Div(id='source_dropdown_container_output'),
html.Div(id='source_file_container', children=[]),
html.Div(id='source_file_container_output'),
],
className="pretty_container four columns",
id="cross-filter-options",
),
],
className="row flex-display",
),
],
id="mainContainer",
style={"display": "flex", "flex-direction": "column"},
)
# Create callbacks
#app.callback(
[
Output(component_id='source_dropdown_container_output', component_property='children'),
],
[
Input(component_id='drop_downs', component_property='value'),
Input(component_id='sources_flag', component_property='value'),
]
)
def update_source_dropdowns(value, value_1):
"""Controls the number of drop-downs available to choose sources"""
if value_1 == 'Y':
children = []
for i in range(0, value):
new_dropdown = dcc.Dropdown(
id=f'''source_dropdown_{str(i)}''',
options=['GOOG', 'FB', 'TDOC', 'FANG']
)
children.append(new_dropdown)
print(children)
print(type(children))
return children
I keep running into a callback error. The drop down is constructed properly, so I am kind of confused as to why that error is being invoked.
dash.exceptions.InvalidCallbackReturnValue: The callback ..source_dropdown_container_output.children.. is a multi-output.
Expected the output type to be a list or tuple but got:
None.
Any guidance or help is appreciated. All I am trying to do is add based on user input a dynamic number of drop downs to the layout.
you have three errors in your callback
there is only one return, hence do not define Output as a list
conditional check is wrong, should be if value_1 == ['Y']:
doc.Dropdown() options argument needs to define list of dict
# Create callbacks
#app.callback(
Output(component_id='source_dropdown_container_output', component_property='children'),
[
Input(component_id='drop_downs', component_property='value'),
Input(component_id='sources_flag', component_property='value'),
]
)
def update_source_dropdowns(value, value_1):
"""Controls the number of drop-downs available to choose sources"""
print("cb", value, value_1)
if value_1 == ['Y']:
children = []
for i in range(0, value):
new_dropdown = dcc.Dropdown(
id=f'''source_dropdown_{str(i)}''',
options=[{"label":v, "value":v } for v in ['GOOG', 'FB', 'TDOC', 'FANG']],
)
children.append(new_dropdown)
print(children)
print(type(children))
return children

how to alter a dash_table.DataTable cell and update other callbacks

I have a Plotly-Dash dashboard here that is updated using the variable inputs on the left-hand side, as well as a few "fixed" variables.
These fixed variables are shown in the dash_table.DataTable at the bottom of image.
Should the user choose to alter the value in the DataTable, I would like to update the callbacks that used these fixed values.
As of now, the callbacks use the the dropdown and numeric inputs as [Input(' ', ' ')]
and the fixed variables are stored as variables, and used in the relevant equations.
Is there a way to either:
use a callback to define these fixed variable values. And when the table is changed, so are these "fixed" variables,..
or, use a callback to search the table and if changes are made, update the fixed variable value(s).
A bit of a vague question I know, I've googled this just about every which way and most of the info has to do with filtering dataTables and displaying rows, less so selecting and storing cell values as variables.
All I really need is an example of taking a cell numeric value, using as a callback [Input()], and that callback using the input in a basic algebraic formula.
I have attached the code, you will see I've been tinkering with the first callback, the rest of the code works fine.
import dash
import dash_design_kit as ddk
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objects as go
import pandas as pd
import dash_daq as daq
import dash_table
from dash.dependencies import Input, Output
import math
import pandas as pd
import pathlib
from crunch_numbers import *
num_datacards = 5
# theme.js supplies some additional styling, generated using editor
# REQUIRED FOR DEPLOYMENT
app = dash.Dash(__name__, suppress_callback_exceptions=True) # keep suppress_ in production code
server = app.server # expose server variable for Procfile
app.layout = ddk.App(show_editor=True, children=[
ddk.Header([
ddk.Logo("assets/komatsuLogo.png",
style={
"height": "30px",
"margin-right":"0px",
"width": "auto",
},
),
ddk.Title('Drivetrain Selection'),
]), # end of ddk.Header
ddk.Block(width=20,children=[ # left-side (inputs)
ddk.Card([ # machine Configuration
ddk.CardHeader("Machine Configuration"),
html.Br(),
dcc.Dropdown(
id='Platform',
options=[
{'label': 'Badger', 'value': 'Badger'},
{'label': 'Weasel', 'value': 'Weasel'},
],
value='Badger',
clearable=False,
placeholder="Select Machine",
),
html.Br(),
dcc.Dropdown(
id='battery_size',
options=[
{'label': '5S1P ( 66kWh)', 'value': 66},
{'label': '5S2P (132kWh)', 'value': 132},
],
value=66,
clearable=False,
#placeholder="Battery Size (kWh)",
),
html.Br(),
dcc.Dropdown(
id='Motor Selection',
options=[
{'label': 'MD 2200', 'value': 'sumo_md_2200'},
],
value='sumo_md_2200',
clearable=False,
placeholder="Motor Selection",
),
]), # end of Machine Configuration
ddk.Card([ # "Inputs"
ddk.CardHeader("Inputs"),
daq.NumericInput(
id='ramp_angle',
label='% Grade',
labelPosition='top',
value=0,
min=0,
max=18,
size='auto',
),
html.Br(),
daq.NumericInput(
id='ground_speed',
label='Speed (kph)',
labelPosition='top',
value=0,
min=0,
max=15,
size='auto',
),
html.Br(),
daq.NumericInput(
id='parasitics',
label='Parasitic Loads (kw)',
labelPosition='top',
value=0,
min=0,
max=30,
size='auto',
),
#html.Br(),
]), # end of "Inputs"
]), # end of left-side
ddk.Block(width=80, children=[ # right side block
ddk.Card([ # datacards and plot
ddk.DataCard(
width=100/num_datacards, # num_datacards is defined at top of file
id='motor_speed',
value=0,
label="(RPM)",
),
ddk.DataCard(
width=100/num_datacards,
id='motor_torque',
value=0,
label="(NM)",
),
ddk.DataCard(
width=100/num_datacards,
id='traction_efficiency',
value=0,
label="(Tot. %)",
),
ddk.DataCard(
width=100/num_datacards,
id='total_power',
value=0,
label="(kW)",
),
ddk.DataCard(
width=100/num_datacards,
id='autonomy',
value=0,
label="(km)",
),
dcc.Graph(id='plot'),
]), # end datacards and plot
ddk.Card(width=100,children=[ # table card
ddk.CardHeader("Machine Characteristics"),
dcc.Markdown(
"""
Update values in the table to modify machine performance.
""",
style={'textAlign': 'justify'}
),
dash_table.DataTable(
id='machine_spec_table',
data=Badger.to_dict("rows"),
columns=[ # only 'Values' and 'Mechanical Efficiency' are editable!
{"name": i, "id": i,"editable":False,"selectable":True}
if i == "Description" or i == "Units"
else {"name": i, "id": i,"selectable":True}
for i in Badger.columns
],
style_as_list_view=True,
style_header={"fontWeight": "bold", "textTransform": "capitalize"},
style_data_conditional=[
{
"if": {"row_index": "even"},
"backgroundColor": "var(--report_background_page)",
}
],
editable=True,
),
]) # end of table card
]) # end of right side block
]) # end of ddk.App
"""
Example of how to manage column width, should the need arise
style_cell_conditional=[
{
'if': {'column_id': 'Units'},
'width': 25
} for c in ['Units']
],
"""
############################# TABLE CALLBACKS ##################################################
################################################################################################
def find_fixed_variables(dict_list,var):
return dict_list[]
############################# DRIVETRAIN SELECTION CALLBACKS ###################################
################################################################################################
#app.callback(
Output('motor_speed', 'value'),
[Input('ground_speed', 'value'),
Input('machine_spec_table','data')] # , Input('tire_rr', 'value'), Input('diff_ratio', 'value'), Input('transfer_ratio', 'value')
)
def update_output(ground_speed,dict_list): #tire_rr, diff_ratio, transfer_ratio
return math.floor((ground_speed*1000)/60/(2*math.pi*tire_rr)*diff_ratio*transfer_ratio)
#app.callback(
Output('total_power', 'value'),
[Input('ground_speed', 'value'),
Input('ramp_angle', 'value')] #, Input('parasitics', 'value')] # Input('GVW', 'value'), Input('RR', 'value'),, Input('traction_efficiency', 'value')
)
def update_output(ground_speed, ramp_angle): #, traction_efficiency
power = math.floor(((RR/100)*(ground_speed*0.278) * GVW * gravity_cnst * math.cos(math.atan(ramp_angle/100))
/ 0.9 / 1000)
+ ((ground_speed * 0.278) * GVW * gravity_cnst * math.sin(math.atan(ramp_angle / 100))
/ 0.9 / 1000)
)
if ground_speed == 0:
return 0
else:
return power
#app.callback(
Output('motor_torque', 'value'),
[Input('ground_speed', 'value'),
Input('motor_speed', 'value'),
Input('total_power', 'value'),]
)
def update_output(ground_speed, motor_speed, total_power):
if ground_speed == 0:
return 0
elif math.floor(9.5488*total_power*1000/motor_speed) < 50:
return 50
else:
return math.floor(9.5488*total_power*1000/motor_speed)
#app.callback(
Output('plot', 'figure'),
[Input('motor_speed', 'value'),
Input('motor_torque', 'value')] #Input('Motor Selection', 'value')
)
def update_output(motor_speed, motor_torque): # , Motor_Selection
fig = go.Figure(
layout=go.Layout(
# title="Motor Efficiency Plot",
# autosize=False,
# width=500,
paper_bgcolor="rgba(0,0,0,0)",
plot_bgcolor="rgba(0,0,0,0)",
yaxis=dict(title="Motor Torque (Nm)"),
xaxis=dict(title="Motor Speed (RPM)"),
)
)
fig.update_layout(legend=dict(
orientation="h",
yanchor="bottom",
y=1,
xanchor="left",
x=0
)
)
fig.add_trace(go.Scatter(
x=TM4_BoundaryCurve['Speed (rpm)'],
y=TM4_BoundaryCurve['Peak Torque (Nm)'],
name="Peak Torque",
)
)
fig.add_trace(go.Scatter(
x=TM4_BoundaryCurve['Speed (rpm)'],
y=TM4_BoundaryCurve['Continuous Torque (Nm)'],
name="Cont. Torque",
)
)
fig.add_trace(go.Contour(
z=[TM4_EfficiencyMap['0'], TM4_EfficiencyMap['280'], TM4_EfficiencyMap['420'], TM4_EfficiencyMap['560'],
TM4_EfficiencyMap['700'],
TM4_EfficiencyMap['840'], TM4_EfficiencyMap['980'], TM4_EfficiencyMap['1120'], TM4_EfficiencyMap['1260'],
TM4_EfficiencyMap['1400'],
TM4_EfficiencyMap['1540'], TM4_EfficiencyMap['1680'], TM4_EfficiencyMap['1820'], TM4_EfficiencyMap['1960'],
TM4_EfficiencyMap['2100'],
TM4_EfficiencyMap['2240'], TM4_EfficiencyMap['2380'], TM4_EfficiencyMap['2520'], TM4_EfficiencyMap['2660'],
TM4_EfficiencyMap['2800'],
TM4_EfficiencyMap['2940'], TM4_EfficiencyMap['3080'], TM4_EfficiencyMap['3220'], TM4_EfficiencyMap['3360'],
TM4_EfficiencyMap['3500'], ],
x=TM4_EfficiencyMap['Speed'],
y=TM4_EfficiencyMap['Torque'],
transpose=True,
colorscale='Blues',
ncontours=20,
opacity=0.5,
showscale=False,
contours=dict(
showlabels=True, # show labels on contours
labelfont=dict( # label font properties
size=12,
color='white',
)
)
)
)
fig.add_trace(go.Scatter(
x=[motor_speed],
y=[motor_torque],
name="Actual",
mode="markers",
marker=dict(size=20, color='black', symbol="x"),
)
)
return fig
#app.callback(
Output('autonomy', 'value'),
[Input('ground_speed', 'value'),
Input('total_power', 'value'),
Input('battery_size', 'value')]
)
def update_output(ground_speed, total_power, battery_size):
if ground_speed == 0 or total_power == 0:
return 0
else:
return round((battery_size * DOD / total_power) * ground_speed, 2)
#app.callback(
Output('traction_efficiency', 'value'),
[Input('motor_speed', 'value'),
Input('motor_torque', 'value')]
)
def update_output(motor_speed, motor_torque):
df = pd.DataFrame(TM4_EfficiencyMap)
if motor_speed <= 280:
speed = str(0)
torque = 50
else:
speed = str(int((round(motor_speed / 140, 0) / 2) * 280))
torque = round(motor_torque / 50, 0) * 50
z = sum(round(df.loc[df['Torque'] == torque, speed] / 100 * diff_eff * transfer_eff * driveshaft_mt * driveshaft_td, 2))
return z
################################# MANDATORY SERVER CODE ##################################
if __name__ == '__main__':
app.run_server(debug=True)
Alright so easy fix, nothing a few print() test statements can't fix lol.
Essentially depending on the type of callback input you use for Input('machine_spec_table','data')
Here I used 'data', there are plenty of others available and explained in documentation,
the input to the function is as follows:
your_var = [
{'Description': 'Gross Vehicle Weight', 'Values': 29500, 'Units': 'kg', 'Mechanical Efficiency': '-'},
{'Description': 'Weight Distribution', 'Values': '60/40', 'Units': '', 'Mechanical Efficiency': '-'},
{'Description': 'Tire Rolling Radius', 'Values': 0.589, 'Units': 'm', 'Mechanical Efficiency': '-'},
{'Description': 'Differential Ratio', 'Values': 20.65, 'Units': '', 'Mechanical Efficiency': 0.93},
{'Description': 'Transfer Case Ratio', 'Values': 2.48, 'Units': '', 'Mechanical Efficiency': 0.98},
{'Description': 'Rolling Resistance', 'Values': 0.02, 'Units': '', 'Mechanical Efficiency': '-'},
{'Description': 'Drive Shaft', 'Values': '-', 'Units': '', 'Mechanical Efficiency': 0.98}
]
A list of dictionaries! Easy to access, something along the lines of table[0]['Values] does just fine :) (0 being a the list index,'Values' the dictionary key).

Categories

Resources