Dash drop down menu graph - plotly-dash

I'm attempting to implement a live-update graph that is only displayed if the user selected it from the drop down menu. I've made a callback with input from "intervals" and from the dropdown menu "oxygen". I thought if "value" is "0" then no chart has been selected and I could return "null"(???), and if 'value' = '1', then the graph would update. Is this possible? or is my approach incorrect?
dcc.Graph(id='live-graph2', animate=False),
dcc.Interval(
id='graph-update',
interval=10000,
n_intervals=0
)),
dbc.Col(html.Div([
dcc.Dropdown(
id='oxygen',
options=[{'label': s, 'value': s}
for s in main_graph.keys()],
value=[],
multi=True),
#app.callback(
dash.dependencies.Output('live-graph2', 'figure'),
[dash.dependencies.Input('oxygen', 'value'),
dash.dependencies.Input('graph-update', 'n_intervals')],
)
def update_graph_scatter_2(n,value):
if value == 0:
....
else:
data = {}

I would approach the problem differently.
If you don't want to display the graph at all when no dropdown option is selected then the Graph component doesn't need to be in the layout by default.
Instead you could create a container component that your Graph component is appended to dynamically based on the option values of your Dropdown component.
Below is a simplified example using sample data, adjust per your requirements:
import dash
import dash_html_components as html
import dash_core_components as dcc
import plotly.express as px
import dash_bootstrap_components as dbc
df = px.data.iris()
app = dash.Dash(__name__)
app.layout = html.Div(
[
dcc.Interval(id="graph-update", interval=10000, n_intervals=0),
html.Div(id="graph-container"),
dbc.Col(
html.Div(
[
dcc.Dropdown(
id="oxygen",
options=[{"label": s, "value": s} for s in [1, 2, 3]],
value=[],
multi=True,
)
]
)
),
]
)
#app.callback(
dash.dependencies.Output("graph-container", "children"),
[
dash.dependencies.Input("oxygen", "value"),
dash.dependencies.Input("graph-update", "n_intervals"),
],
)
def update_graph_scatter_2(value, n):
if value:
# Change the line below to dynamically create the figure based on value
fig = px.scatter(df, x="sepal_width", y="sepal_length")
return dcc.Graph(id="live-graph2", figure=fig)
return html.Div()

Related

Plotly Dashboard: How to make a simple dropdown to display figures?

My figures are saved in a dictionary and they are accessible, but I am lost on what to put on options and value.
app = JupyterDash(__name__)
app.layout = html.Div([
dcc.Dropdown(
id='launch-data',
options=[
{"label":"All","value":"launch_tot_fig"}],
value=launch_tot_fig
),
html.Div(id="dd-output-container")]
)
#app.callback(Output('dd-output-container', 'children'),Input('launch-data', 'value'))
def update_output(value):
return 'You have selected "{}"'.format(value)
if __name__ == '__main__':
app.run_server(debug = True)
I also have the figure launch_tot_fig that is a pie chart for the launch sites. So that is to show when the input is "All".
The Dictionary is launchmass with the SPACEX launchsites as keys
If you want to show a graph you need to add a graph component to your layout and then use a callback to update it given the dropdown value. You should have something like this :
app.layout = html.Div([
dcc.Dropdown(
id='launch-data',
options=[
{"label": "All", "value": "launch_tot_fig"}, {"label": "Other", "value": "Other"}],
value="Other"
),
html.Div(id="dd-output-container"),
dcc.Graph(id='my-fig')
]
)
And the callback should look like this :
#app.callback(Output('my-fig', 'figure'),
Input('launch-data', 'value'))
def update_output(value):
fig = px.bar()
if value == 'launch_tot_fig':
fig = dictionnary_with_graphs['launch_tot_fig']
return fig

output of a callback as input of another callback, second callback run twice

The dashboard include a dropdown, a table and a graph.
By selecting a item from dropdown, some rows of the table is shown and figure plot the data in the table.
I have two callback,
at the first one:
input : dropdown
output: table
second one:
input: table
output: figure
So the output of first callback is input of the second one.
The following code output look like this:
import dash
import dash_table
import pandas as pd
from copy import deepcopy
import plotly.graph_objects as go
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
data = pd.DataFrame({"a": ["a1", "a2"],
"b": [1, 2]})
app = dash.Dash(
__name__,
external_stylesheets=[dbc.themes.BOOTSTRAP],
prevent_initial_callbacks=True,
)
app.layout = dbc.Container(
[
dbc.Row(dbc.Col([dcc.Dropdown(
id='dropdown1',
options=[
{'label': '1', 'value': 1},
{'label': '2', 'value': 2}
],
value=1)])),
dbc.Row(
dbc.Col([
dash_table.DataTable(
id="datatable",
columns=[dict(id=i,
name=j,
)
for i, j in zip(
["a", "b"],
["a", "b"],
)],
data=data.loc[data['a'] ==
"a1"].to_dict("records"),
sort_mode="single",
)
])),
dbc.Row([dbc.Col([html.Div(
children=dcc.Graph(id="graph"), className="card")
])]),
], fluid=True,
)
########################################################
#app.callback(
Output("datatable", "data"),
[Input("dropdown1", "value")],
prevent_initial_call=True
)
def update_current_table(value):
idx = int(value)
print(idx)
if idx == 1:
df = (data.loc[data["a"] == "a1"])
return df.to_dict("records")
else:
df = deepcopy(data.loc[data["a"] == "a2"])
return df.to_dict("records")
########################################################
# app.callback(
Output('graph', 'figure'),
[Input("datatable", "derived_virtual_data"),
Input("dropdown1", "value")
],
prevent_initial_call=True
)
def update_figure(table, value):
df = pd.DataFrame(table)
print(df)
fig = go.Figure()
return fig
if __name__ == "__main__":
app.run_server(debug=True, port=8000)
The problem here is callback run twice:
a b
0 a1 1
a b
0 a2 2
and for the first time print the previous values of the table
This cause error in the main code that I am working on.
How to prevent dash from runnig callback twice?
I found some other questions complaining about running the callback twic, but I could not found a proper solution for that.
The problem is that you have two inputs for the callback that's running twice:
# app.callback(
Output('graph', 'figure'),
[Input("datatable", "derived_virtual_data"),
Input("dropdown1", "value")
],
prevent_initial_call=True
)
def update_figure(table, value):
The dropdown changes, and triggers this callback, but it also triggers the table to update. The updated table causes the derived_virtual_datato trigger this callback again. You can fix this by making the dropdown value a State instead, like this:
# app.callback(
Output('graph', 'figure'),
[Input("datatable", "derived_virtual_data")],
[State("dropdown1", "value"),]
prevent_initial_call=True
)
def update_figure(table, value):
Edit:
On another read through, you don't even use the value from the dropdown in the second input. Just removing it entirely will also work:
# app.callback(
Output('graph', 'figure'),
[Input("datatable", "derived_virtual_data")],
prevent_initial_call=True
)
def update_figure(table):

Dash plotly Datatable column filtering or cropping

I have implemented a live-update datatable to correspond with a live-update graph. Functionally, both work very well. I do have a problem with filtering the datatable to include certain columns and exclude others. For ex. If the graph is zoomed in for certain x-value (09:00-10:00), is there any way I can also crop the corresponding datatable to represent columns from that same value? Perhaps add a button with a callback that deletes specific column ids? Is there a way to delete specific 'column' 'id' inputs through python with out using the GUI? As of now, I can only manually delete individual columns which is very tedious given the amount of columns. Thank you. I hope this question is not too open-ended.
table_contents = ['Propofol/Remi # 6.5 ug/ml', 'Fentanyl (ug)', 'Propofol (mg)', 'Remi (ug)',
'Ketorolac (mg)']
html.Div([dash_table.DataTable(
id='editing-columns',
columns=[{
'name': 'Parameter',
'id': 'column1',
'deletable': True,
'renamable': True
}],
data=[
{'column1': j}
for j in table_contents
],
editable=True,
)]),
# The callback stores the previous length of the csv file in dcc.store and appends new columns if new csv data uploaded
#app.callback(Output('editing-columns', 'columns'),
[Input('graph-update', 'n_intervals')],
[State('editing-columns', 'columns')],
[State('mystore', 'data')])
def update_columns(n, btn, existing_columns, data):
with open('temp.csv', 'r') as rf:
reader = csv.reader(rf)
for a in reader:
existing_columns.append({
'id': a[3], 'name': a[3],
'renamable': True, 'deletable': True
})
return existing_columns, html.Div('Program running')
else:
check_length = []
de_serialized = json.loads(data)
with open('temp.csv', 'r') as rf:
reader = csv.reader(rf)
for a in reader:
check_length.append(a[3])
if len(check_length) == 0:
return existing_columns, html.Div('Program running')
elif len(check_length) > len(de_serialized):
existing_columns.append({
'id': check_length[-1], 'name': check_length[-1],
'renamable': True, 'deletable': True
})
return existing_columns, html.Div('Program running')
else:
return existing_columns, html.Div('Program running')
#The graph is a bar and scatter graph that is updated with x,y values derived from the same csv as the datatable.
#app.callback(
dash.dependencies.Output('live-graph', 'figure'),
[dash.dependencies.Input('graph-update-BP', 'n_intervals')],
)
def update_graph_scatter_1(btn, n):
trace = []
trace2 = []
blood_pressure = []
hr = []
with open('temp.csv', 'r') as rf:
reader_2 = csv.reader(rf)
for a in reader_2:
blood_pressure.append(eval(a[4]))
time.append(a[3])
for i in range(0, len(blood_pressure)):
trace.append(go.Box(y=blood_pressure[i],
x=triple_time[i],
line=dict(color='#6a92ff'),
hoverinfo='all'))
for a in range(0, len(hr)):
trace2.append(go.Scatter(y=coated_hr[a],
x=coated_time[a],
name='HR',
Whenever you pan or zoom, a relayoutData interaction is triggered, from there you can get the axis ranges.
The dcc.Graph component has four attributes that can change through
user-interaction: hoverData, clickData, selectedData, relayoutData.
These properties update when you hover over points, click on points,
or select regions of points in a graph.
https://dash.plotly.com/interactive-graphing
import json
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
from dash.exceptions import PreventUpdate
import plotly.express as px
import pandas as pd
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
df = pd.DataFrame({
"x": [1,2,1,2],
"y": [1,2,3,4],
"customdata": [1,2,3,4],
"fruit": ["apple", "apple", "orange", "orange"]
})
fig = px.scatter(df, x="x", y="y", color="fruit", custom_data=["customdata"])
fig.update_traces(marker_size=20)
app.layout = html.Div([
dcc.Graph(
id='basic-interactions',
figure=fig
),
html.Div(className='row', children=[
html.Div([
dcc.Markdown("""
**Zoom and Relayout Data**
Click and drag on the graph to zoom or click on the zoom
buttons in the graph's menu bar.
Clicking on legend items will also fire
this event.
"""),
html.Pre(id='relayout-data'),
])
])
])
#app.callback(
Output('relayout-data', 'children'),
Input('basic-interactions', 'relayoutData'))
def display_relayout_data(relayoutData):
if relayoutData is None:
raise PreventUpdate
elif "xaxis.range[0]" not in relayoutData.keys():
raise PreventUpdate
else:
#get the relevant axis ranges, you can use to drop columns from the datatable
print(relayoutData,type(relayoutData))
return json.dumps(relayoutData, indent=2)
if __name__ == '__main__':
app.run_server(debug=True)

Plotly-dash - update graphs in tabs

I like to put plotly graph1 in tab1 and graph2 in tab 2, but there is no trace visible.
Why are traces not visible?
The graph in tab2 is also showing no traces.
It would be great to know whats wrong.
Simular example code would also be a big help.
Many thanks
''' import pandas as pd
import numpy as np
import plotly.express as px
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.graph_objs as go
import requests
import dash_bootstrap_components as dbc
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
#fig1 = px.line(title='title1')
#fig2 = px.line(title='title2')
app.layout = dbc.Container(fluid=True, children=[
html.H1('Title',id="Titel",className='ml-1',style={'text-align': 'center', 'font-weight': 'bold', 'text-decoration': 'underline'}),
## Body
dbc.Row([
dbc.Col(md=6,children=[
html.Br(),html.Br(),
dbc.Col(md=9, children=[
dbc.Col(html.H4("graphs in tabs"), width={"size":6,"offset":3}),
dbc.Tabs(className="nav nav-pills", children=[
dbc.Tab(dcc.Graph(id="grafiek1"), label="tab1"),
dbc.Tab(dcc.Graph(id="grafiek2"), label="tab2")
])
])
#html.Div(id="tab-content", className="mx-auto"), #m=marge p=padding 0-5 of auto vb: P-4
]), # einde kolom 1
dbc.Col(md=6,children=[
]), # einde kolom 2
]), #einde rij
])
#,style={"background-image": 'url(image)'})
#app.callback(
Output("grafiek1", "figure"),
[Input("tabs", "active_tab")])
def tab_content(active_tab):
if active_tab is not None:
if active_tab == "tab1":
fig1 = go.Figure()
fig.add_trace(go.Scatter(x=df['Date'], y=df['AAPL.Low'], mode='markers', name='data', line={"color":"black"}))
## add slider
fig.update_xaxes(rangeslider_visible=True)
## set background color
fig.update_layout(plot_bgcolor='white', autosize=False, width=1000, height=550)
return fig1
#app.callback(
Output("grafiek2", "figure"),
[Input("tabs", "active_tab")])
def tab_content(active_tab):
if active_tab is not None:
if active_tab == "tab2":
fig2 = go.Figure()
fig.add_trace(go.Scatter(x=df['Date'], y=df['AAPL.High'], mode='markers', name='data', line={"color":"black"}))
## add slider
fig.update_xaxes(rangeslider_visible=True)
## set background color
fig.update_layout(plot_bgcolor='white', autosize=False, width=1000, height=550)
return fig2
if __name__ == '__main__':
app.run_server(debug='True')
'''
The 'tabs' id you reference in your callbacks doesn't exist in your layout. Dash doesn't tell you about this because you do this
app.run_server(debug='True')
instead of
app.run_server(debug=True)
You also check if active_tab equals "tab1" in the first callback and "tab2" in the second, but the active_tab prop of your Tabs component isn't set to either of these values. The default active_tab value for the first tab is actually tab-0.
active_tab (string, optional): The tab_id of the currently active tab. If tab_id has not been specified for the active tab, this will default to tab-i, where i is the index (starting from 0) of the tab.
https://dash-bootstrap-components.opensource.faculty.ai/docs/components/tabs/
Since this if statement fails nothing is returned from either callback.
Also the callback function have the same function name, this is not allowed.
Lastly in both callbacks you create a figure, but you add the trace to another figure, so the trace also doesn't show up because you're returning an empty figure.
So instead you could do something like this:
import pandas as pd
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
import plotly.graph_objects as go
df = pd.read_csv(
"https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv"
)
app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
app.layout = dbc.Container(
fluid=True,
children=[
html.H1(
"Title",
id="Titel",
className="ml-1",
style={
"text-align": "center",
"font-weight": "bold",
"text-decoration": "underline",
},
),
dbc.Row(
[
dbc.Col(
md=6,
children=[
html.Br(),
html.Br(),
dbc.Col(
md=9,
children=[
dbc.Col(
html.H4("graphs in tabs"),
width={"size": 6, "offset": 3},
),
dbc.Tabs(
id="tabs",
className="nav nav-pills",
children=[
dbc.Tab(
label="tab1",
children=[dcc.Graph(id="grafiek1")],
),
dbc.Tab(
label="tab2",
children=[dcc.Graph(id="grafiek2")],
),
],
),
],
),
],
),
dbc.Col(md=6, children=[]),
]
),
],
)
#app.callback(Output("grafiek1", "figure"), [Input("tabs", "active_tab")])
def tab_content1(active_tab):
if active_tab is not None:
if active_tab == "tab-0":
fig1 = go.Figure()
fig1.add_trace(
go.Scatter(
x=df["Date"],
y=df["AAPL.Low"],
mode="markers",
name="data",
line={"color": "black"},
)
)
return fig1
return go.Figure()
#app.callback(Output("grafiek2", "figure"), [Input("tabs", "active_tab")])
def tab_content2(active_tab):
if active_tab is not None:
if active_tab == "tab-1":
fig2 = go.Figure()
fig2.add_trace(
go.Scatter(
x=df["Date"],
y=df["AAPL.High"],
mode="markers",
name="data",
line={"color": "black"},
)
)
# add slider
fig2.update_xaxes(rangeslider_visible=True)
# set background color
fig2.update_layout(
plot_bgcolor="white", autosize=False, width=1000, height=550
)
return fig2
return go.Figure()
if __name__ == "__main__":
app.run_server(debug=True)

How Dynamically populate the DropDown from the data uploaded through Plotly Dash dcc upload option

I have uploaded the data using Plotly Dash dcc upload option. I am not able to dynamically populated the unique columns of uploaded dataframe as part of DropDown
I am able to successfuly upload the file using dcc upload option; i am able to see the output in dash table. but using same input, i am not able to see the output from dropdown.
the dataframe, i have uploaded with the columns of (country, continent, population)
i should able to get the unique columns dropdown
this is my code:
import base64
import datetime
import io
import plotly.graph_objs as go
import dash
import dash_html_components as html
import dash_core_components as dcc
import dash_table
import dash_table_experiments as dte
from dash.dependencies import Input, Output, State
import pandas as pd
app = dash.Dash()
app.layout = html.Div([
html.Div([
dcc.Upload(
id='upload-data',
children=html.Div([
'Drag and Drop or ',
html.A('Select Files')
]),
multiple=True
),
html.Div(id='output-data-upload'),
])
dcc.Tab(label='Discrete Info', children=[
html.Div([
dcc.Dropdown(
id='select_column',
),
]),
html.Div([
dcc.Graph(
id='bar1',
hoverData={'points': [{'customdata': ''}]},
)
], style={'width': '100%', 'display': 'inline-block', 'padding': '0 10'}),
]),
])
def parse_contents(contents, filename, date):
content_type, content_string = contents.split(',')
decoded = base64.b64decode(content_string)
try:
if 'csv' in filename:
# Assume that the user uploaded a CSV file
df = pd.read_csv(
io.StringIO(decoded.decode('utf-8')))
elif 'xls' in filename:
# Assume that the user uploaded an excel file
df = pd.read_excel(io.BytesIO(decoded))
except Exception as e:
print(e)
return html.Div([
'There was an error processing this file.'
])
return html.Div([
html.H5(filename),
html.H6(datetime.datetime.fromtimestamp(date)),
dash_table.DataTable(
data=df.to_dict('records'),
columns=[{'name': i, 'id': i} for i in df.columns]
),
html.Hr(), # horizontal line
# For debugging, display the raw contents provided by the web browser
html.Div('Raw Content'),
html.Pre(contents[0:200] + '...', style={
'whiteSpace': 'pre-wrap',
'wordBreak': 'break-all'
})
])
#app.callback(Output('output-data-upload', 'children'),
[Input('upload-data', 'contents')],
[State('upload-data', 'filename'),
State('upload-data', 'last_modified')])
def update_output (list_of_contents, list_of_names, list_of_dates):
if list_of_contents is not None:
children = [
parse_contents(c, n, d) for c, n, d in
zip(list_of_contents, list_of_names, list_of_dates)]
return children
#app.callback(Output('select_column', 'options'
[Input('output-data-upload', 'children'')]
def dd_update (options)
return(options)
This is a little tricky without specific code to reference, but the basic idea is to set up a callback that will update the options prop of your dcc.Dropdown. You can have that callback triggered (Input) by the upload, make it read in the dataframe, obtain the columns, and then output the properly formatted list of dictionaries.
Please use a following simple example that solves your problem
import base64
import io
import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
from dash.dependencies import Input, Output
app = dash.Dash()
app.layout = html.Div([
dcc.Upload(
id='upload-data',
children=html.Div([
'Drag and Drop or ',
html.A('Select Files')
]),
style={
'width': '100%',
'height': '60px',
'lineHeight': '60px',
'borderWidth': '1px',
'borderStyle': 'dashed',
'borderRadius': '5px',
'textAlign': 'center',
'margin': '10px'
},
),
dcc.Dropdown(
id='dropdown',
options=[],
value=None),
])
def parse_data(contents, filename):
content_type, content_string = contents.split(',')
decoded = base64.b64decode(content_string)
try:
if 'csv' in filename:
# Assume that the user uploaded a CSV or TXT file
df = pd.read_csv(
io.StringIO(decoded.decode('utf-8')))
elif 'xls' in filename:
# Assume that the user uploaded an excel file
df = pd.read_excel(io.BytesIO(decoded))
elif 'txt' or 'tsv' in filename:
# Assume that the user upl, delimiter = r'\s+'oaded an excel file
df = pd.read_csv(
io.StringIO(decoded.decode('utf-8')), delimiter = r'\s+')
except Exception as e:
print(e)
return html.Div([
'There was an error processing this file.'
])
return df
#app.callback(
Output('dropdown', 'options'),
[Input('upload-data', 'contents'),
Input('upload-data', 'filename')])
def update_options(contents, filename):
if contents:
df = parse_data(contents, filename)
df = df.set_index(df.columns[0])
lst = [{'label': i, 'value': i} for i in df.columns]
return lst
else:
return []
if __name__ == '__main__':
app.run_server(debug=True)
Here is my working code, very basic, that you can use as a reference
html.Div(children=[
html.Div(children=[
dcc.Dropdown(id='dropdown_students_cols', options=[{'label': i, 'value': i} for i in list(filter(lambda x: x!='userid', list(df)))], value='component'),
]),
html.Div(children=[
dcc.Dropdown(id='dropdown_row_names'),
]),
])
#app.callback(
Output(component_id='dropdown_row_names', component_property='options'),
[Input(component_id='dropdown_students_cols', component_property='value')],)
def get_row_names(column_name='component'):
row_names = df[column_name].unique().tolist()
lst = [{'label': i, 'value': i} for i in row_names]
print(lst)
return lst
The print statement in the callback returns a list of dictionaries that I can use for options:
[{'label': 'mod_glossary', 'value': 'mod_glossary'}, {'label': 'mod_quiz', 'value': 'mod_quiz'},...]
Don't pay attention to lambda function in the original dropdown id='dropdown_students_cols', I just needed to exclude this column from selection.
When you make selection in the original dropdown id='dropdown_students_cols', it invokes the callback function with the selection as an argument.
This selection gives me a required column in the df and then I build a list of unique rows in this column.
Then I iterate over this list to build a list of dictionaries with label:value
The print statement confirms that the list is built successfully
Then I return that list as options for the child dropdown id='dropdown_row_names'
So you can use another trigger as Input, in your case Upload, pass values into the callback, process the data as you need and then return a list if dictionaries as options for the dropdown.
I suggest you trim your code to a vary basic working example and then slowly build up from it.