I would like to add a dropdown menu to show only one figure. I mean, if I select fig the dash must show me only the fig and if I select fig2 the dash must show me the fig 2. Is it possible?
My code is an example, I have more than 500 figs.
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objects as go # or plotly.express as px
fig = go.Figure()
fig2 = go.Figure()
fig.add_trace(go.Scatter(y=[4, 2, 1], mode="lines"))
fig2.add_trace(go.Bar(y=[2, 1, 3]))
figs = [fig, fig2]
div = []
for item in figs:
div.append(dcc.Graph(figure=item))
app = dash.Dash()
app.layout = html.Div(div)
"""
add a dropdown to show only one fig
"""
app.run_server(debug=True, use_reloader=False)
Yes, it is possible.
First you need to create the dropdown containing the figure-names / filenames or the identifier you wish, just keep the {'label': x, 'value': x} structure for the option parameter. label is what you will see in the dropdown, and value will be passed to the callback (s. below).
fig_names = ['fig1', 'fig2']
fig_dropdown = html.Div([
dcc.Dropdown(
id='fig_dropdown',
options=[{'label': x, 'value': x} for x in fig_names],
value=None
)])
Next you need a blank div (with an id) where the plot will appear:
fig_plot = html.Div(id='fig_plot')
Now create a callback. When an input with the id='fig_dropdown' is changed, the value parameter will be passed to the update_output function. The output of this function will be passed to passed to the children parameter of the id='fig_plot' div.
#app.callback(
dash.dependencies.Output('fig_plot', 'children'),
[dash.dependencies.Input('fig_dropdown', 'value')])
def update_output(fig_name):
return name_to_figure(fig_name)
The name_to_figure(fig_name) function returns a dcc.Graph() objects, containing your figure, depending on the fig_name value of the dropdown.
Full example:
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objects as go # or plotly.express as px
app = dash.Dash()
fig_names = ['fig1', 'fig2']
fig_dropdown = html.Div([
dcc.Dropdown(
id='fig_dropdown',
options=[{'label': x, 'value': x} for x in fig_names],
value=None
)])
fig_plot = html.Div(id='fig_plot')
app.layout = html.Div([fig_dropdown, fig_plot])
#app.callback(
dash.dependencies.Output('fig_plot', 'children'),
[dash.dependencies.Input('fig_dropdown', 'value')])
def update_output(fig_name):
return name_to_figure(fig_name)
def name_to_figure(fig_name):
figure = go.Figure()
if fig_name == 'fig1':
figure.add_trace(go.Scatter(y=[4, 2, 1]))
elif fig_name == 'fig2':
figure.add_trace(go.Bar(y=[2, 1, 3]))
return dcc.Graph(figure=figure)
app.run_server(debug=True, use_reloader=False)
Incase you have so many fig to choose from in your Drop Down box, the following changes to the code may be necessary to implement:
#app.callback(Output('fig_plot', 'figure'), [Input('fig_dropdown', 'value')])
def cb(plot_type):
plot_type = plot_type if plot_type else 'fig1'
df_year = head_db.copy()
if plot_type:
return px.bar(df_year, x='Week #', y=str(plot_type), color='Name')
#Libraries/Imports
from dash import Dash, html, dcc, Input, Output
import plotly.graph_objects as go
fig = go.Figure()
fig2 = go.Figure()
fig.add_trace(go.Scatter(y=[4, 2, 1], mode="lines"))
fig2.add_trace(go.Bar(y=2, 1, 3]))
figs = ['fig', 'fig2']
#Your HTML to display the graph
#Disables the multiple dropdown values attributes
app.layout = html.Div([
html.Div(children=[
html.label('Dropdown'),
dcc.Dropdown(id='dropdown', options=(figs), multi=False
html.div(id='show-my-graph')
])
])
#Your callback; is used to display the graph when the dropdown values are selected or updated
#app.callback(
Output(component_id='show-my-graph'), component_property='children'),
Input(component_id='dropdown', component_property='value')
)
#Defines the Function used to display the graph when an option is selected or updated
def update_graph(dropdown_value):
"Returns the appropriate graph component to display when a dropdown is selected or updated"
if(dropdown_value == 'fig'):
ret_val = dcc.Graph(id='scatter-plot-graph', figure=fig)
return ret_val
if (dropdown_value == 'fig2'):
ret_val = dcc.Graph(id='bar-graph', figure=fig2)
return ret_val
app.run_server(debug=True, use_reloader=False)
Related
I'm trying to display live location data on a mapbox scatter plot. In order to mimic new data received from the server the callback moves all points every 3 seconds:
import plotly.express as px
from dash import Dash, html, dcc
from dash.dependencies import Input, Output
px.set_mapbox_access_token(open(".mapbox_token").read())
df = px.data.carshare()
app = Dash(__name__)
app.layout = html.Div([
dcc.Graph(id='map', animate=True),
dcc.Interval(
id='interval-component',
interval=3000,
)
])
#app.callback(Output('map', 'figure'), [Input('interval-component', 'n_intervals')])
def update_map(n):
df['centroid_lon'] += 0.01
fig = px.scatter_mapbox(df, lat="centroid_lat", lon="centroid_lon")
return fig
if __name__ == '__main__':
app.run_server(debug=True)
While the labels are correctly changing their location, the markers are stuck at their original positions.
result
I found a work around by having two callbacks.
my html looks like this dbc.Col > dcc.Graph(figure = fig)
#app.callback(
Output('graph-id','figure'),
Input('control-id', 'n_clicks')
)
def update_func(scatter_map_fig):
return go.Figure
The second callback returns a new graph component with the updated information of the figure
#app.callback(
Output('col-id','children'),
Input('graph-id', 'figure'),
State('date_range','start_date'),
State('date_range','end_date'),
)
def update_func_2(scatter_map_fig):
scatter_fig = go.Figure()
scatter_fig.update_layout(...)
... (put your figure logic here)
return dcc.Graph(figure=fig)
It is a bit janky but it works until there's a better solution. Hope it helps.
I am trying to do something relatively simple. I want to create a radio button that switches between two plotting formats. The radio button switches between two options. Let us call them 'a' and 'b.'
When 'a' is selected, I want to plot two figures side by side using bootstrap row/col. When option 'b' is selected, I want to use the entire column for a single figure.
I believe I coded that correctly below, but when I switch from 'a' to 'b' and back to 'a', the plot screws up the plot and the two figures show up vertically.
import dash
from dash import dcc, html, Input, Output
import dash_bootstrap_components as dbc
import plotly.graph_objs as go
app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
app.layout = html.Div(
children=html.Div(children=[
dcc.RadioItems(id='radio', options=('a', 'b'), value='a', inline=True),
dbc.Row(id='row')
])
)
#app.callback(
Output("row", "children"),
[Input("radio", "value")],
)
def fill_row(radio):
f1 = go.Figure()
f2 = go.Figure()
f3 = go.Figure()
if radio == 'a':
return [
dbc.Col(dcc.Graph(figure=f1)),
dbc.Col(dcc.Graph(figure=f2)),
]
else:
return [
dbc.Col(dcc.Graph(figure=f3)),
]
if __name__ == "__main__":
app.run_server(debug=True, port=8051)
Here are the screenshots:
The default behavior for dbc.Col components filling up a dbc.Row component is a horizontal alignment, so I can see the confusion here. However, the default size of column components is 12. And if you're trying to put two components of that size next to eachother will cause an overflow, and the columns will be stacked on top og eachother. Therefore, a possible solution is to set width = 6 for the columns in your first return statement. Or other numbers that do not sum to more than 12:
Solution
#app.callback(
Output("row", "children"),
[Input("radio", "value")],
)
def fill_row(radio):
f1 = go.Figure()
f2 = go.Figure()
f3 = go.Figure()
if radio == "a":
return [
dbc.Col([dcc.Graph(figure=f1)], width=6),
dbc.Col([dcc.Graph(figure=f2)], width=6),
]
else:
return [
dbc.Col(dcc.Graph(figure=f3), width=12),
]
Below are a few images from a test run. You'll find a complete code snippet at the end of the answer
Output 1: radio = a
Output 2: radio = b
Output 1: radio = a again
Complete code:
import dash
from dash import dcc, html, Input, Output
import dash_bootstrap_components as dbc
import plotly.graph_objs as go
app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
app.layout = html.Div(
children=html.Div(
children=[
dcc.RadioItems(id="radio", options=("a", "b"), value="a", inline=True),
dbc.Row(id="row"),
]
)
)
#app.callback(
Output("row", "children"),
[Input("radio", "value")],
)
def fill_row(radio):
f1 = go.Figure()
f2 = go.Figure()
f3 = go.Figure()
if radio == "a":
return [
dbc.Col([dcc.Graph(figure=f1)], width=),
dbc.Col([dcc.Graph(figure=f2)], width=6),
]
else:
return [
dbc.Col(dcc.Graph(figure=f3), width=12),
]
# if __name__ == "__main__":
app.run_server(debug=True, port=8052)
I'm not clear how I could dynamically create multiple charts at once - or if that is not possible then how I could loop through a list of values using a single callback.
For example in the code below list of continents is a a list of filter options. Is it possible to basically make it so when this page loads, I see 5 charts automatically?
Currently, what I'm doing is I have to type 5 #app.callback...make_scatter_plot(option=_dropdown_value) which ends up with a million lines of code in my file and makes it hard to read even though everything is doing the same thing.
What am I missing? Thanks
from dash import Dash, dcc, html, Input, Output
import plotly.express as px
import pandas as pd
import numpy as np
app = Dash(__name__)
df = px.data.gapminder()
list_of_continents = ["Asia", "Africa", "Europe", 'Oceania', 'Americas']
app.layout = html.Div([
html.H4('Restaurant tips by day of week'),
dcc.Dropdown(
id="dropdown",
options=list_of_continents,
multi=False
),
dcc.Graph(id="graph"),
#dcc.Graph(id ='graph2') ##????
])
#app.callback(
Output("graph", "figure"),
Input("dropdown", "value")
)
def make_scatter_plot( value =[i for i in list_of_continents], df = df):
"""
"""
data = df[df['continent'].isin([value])]
fig = px.scatter(data, x="lifeExp", y="gdpPercap",
size="pop")
return fig
if __name__ == '__main__':
app.run_server(debug=True)
although plotly express can help you set up a graph with just one line of code it’s not very handy when it comes to customizing each trace. So, for that, you’ve to switch to graphs_objects.
In the following lines of code, the callback generates a Graph component for each trace and appends each graph component to a Div component. Hence you get multiple graphs using a single callback.
from dash import Dash, dcc, html, Input, Output
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import numpy as np
app = Dash(__name__)
df = px.data.gapminder()
app.layout = html.Div([
html.H4('Restaurant tips by day of week'),
html.Div(id='graphs',children=[])
])
#app.callback(
Output("graphs", "children"),
Input("graphs", "children")
)
def make_scatter_plot(child):
"""
"""
for continent in df['continent'].unique():
df_filtered = df[df['continent'] == continent]
fig = go.Figure()
fig.add_trace(
go.Scatter(x = df_filtered['lifeExp'],
y = df_filtered['gdpPercap'],
mode = 'markers',
marker = dict(size = 10 + (df_filtered['pop'] - df_filtered['pop'].min()) * 20
/ (df_filtered['pop'].max() - df_filtered['pop'].min())) # This is just to scale the marker size value between 10 and 20.
)
)
fig.update_layout(
title_text = continent
)
child.append(dcc.Graph(figure=fig))
return child
if __name__ == '__main__':
app.run_server(debug=True)
The output of the Code:
Click here
In this app, I'm trying to display a plot that changes when the value in the dropdown menu is changed. The values are the boroughs in London. The data can be found here. Below is the code for base plot.
import plotly.graph_objects as go
df = pd.read_excel('multi-year-station-entry-and-exit-figures.xls', sheet_name='2017 Entry & Exit', skiprows=6)
df = df.loc[df['Borough'] == 'Islington']
df['Sunday'] = df['Sunday'] + df['Sunday.1']
df['Saturday'] = df['Saturday'] + df['Saturday.1']
df = df[['Borough', 'Station', 'Saturday', 'Sunday']]
df.index = range(len(df))
print(df['Borough'])
fig = go.Figure(data=[
go.Bar(name='Saturday', x=df["Station"], y=df["Saturday"]),
go.Bar(name='Sunday', x=df["Station"], y=df["Sunday"])
])
fig.update_layout(title='Weekend entry and exit figures in 2017',
xaxis_tickfont_size=14,
yaxis=dict(
title='Entry and exit numbers',
titlefont_size=16,
tickfont_size=14,
)
, barmode='group', template='plotly_dark', bargap=0.3, bargroupgap=0.1)
fig.show()
I am able to change the the borough name manually to change the plot. I then created the Dash app with the the dropdown menu. However, I can't figure out how to change the plot when a dropdown option is selected. I created a version using conditional statements where I add an if-elif statement for each borough. I am still unable to change the plot itself however. Basically, I need to incorporate this piece of code df = df.loc[df['Borough'] == 'Islington'] to the Dash app. The Dash app code is shown below.
import dash_core_components as dcc
import dash_html_components as html
import plotly.express as px
import pandas as pd
import os
import plotly.io as pio
import plotly.graph_objects as go
import dash_bootstrap_components as dbc
df = pd.read_excel('multi-year-station-entry-and-exit-figures.xls', sheet_name='2017 Entry & Exit', skiprows=6)
df['Sunday'] = df['Sunday'] + df['Sunday.1']
df['Saturday'] = df['Saturday'] + df['Saturday.1']
df = df[['Borough', 'Station', 'Saturday', 'Sunday']]
df.index = range(len(df))
df = df[:-3]
app = dash.Dash()
fig_names = ['Islington', 'Camden']
fig_dropdown = html.Div([
dcc.Dropdown(
id='fig_dropdown',
options=[{'label': x, 'value': x} for x in fig_names],
value=None
)])
fig_plot = html.Div(id='fig_plot')
app.layout = html.Div([fig_dropdown, fig_plot])
#app.callback(
dash.dependencies.Output('fig_plot', 'children'),
[dash.dependencies.Input('fig_dropdown', 'value')])
def update_output(fig_name):
return name_to_figure(fig_name)
def name_to_figure(fig_name):
figure = go.Figure()
if fig_name == 'Islington':
figure = go.Figure(data=[
go.Bar(name='Saturday', x=df["Station"], y=df["Saturday"]),
go.Bar(name='Sunday', x=df["Station"], y=df["Sunday"])
])
elif fig_name == 'Camden':
figure = go.Figure(data=[
go.Bar(name='Saturday', x=df["Station"], y=df["Saturday"]),
go.Bar(name='Sunday', x=df["Station"], y=df["Sunday"])
])
return dcc.Graph(figure=figure)
app.run_server(debug=True, use_reloader=False)
You can create a copy of your data frame containing only the data corresponding to the dropdown selection, and then use this filtered data frame for generating the figure:
import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.graph_objects as go
app = dash.Dash()
# load the data
df = pd.read_excel('multi-year-station-entry-and-exit-figures.xls', sheet_name='2017 Entry & Exit', skiprows=6)
df['Sunday'] = df['Sunday'] + df['Sunday.1']
df['Saturday'] = df['Saturday'] + df['Saturday.1']
df = df[['Borough', 'Station', 'Saturday', 'Sunday']]
df.index = range(len(df))
df = df[:-3]
# extract the list of all boroughs
fig_names = df['Borough'].unique().tolist()
# generate the app layout
app.layout = html.Div([
# add a dropdown for selecting the borough
html.Div([
dcc.Dropdown(
id='fig_dropdown',
options=[{'label': x, 'value': x} for x in fig_names],
value=fig_names[0] # use the first borough as the initial selection
)]),
# add a container for the figure
html.Div(id='fig_plot'),
])
# define a callback for updating the figure
# based on the dropdown selection
#app.callback(dash.dependencies.Output('fig_plot', 'children'),
[dash.dependencies.Input('fig_dropdown', 'value')])
def update_output(fig_name):
# extract the data for the selected borough
df_fig = df[df['Borough'] == fig_name]
# plot the data for the selected borough
figure = go.Figure(data=[
go.Bar(name='Saturday', x=df_fig['Station'], y=df_fig['Saturday']),
go.Bar(name='Sunday', x=df_fig['Station'], y=df_fig['Sunday'])
])
return dcc.Graph(figure=figure)
if __name__ == '__main__':
app.run_server(debug=True, host='0.0.0.0', port=1234)
I am trying to update a plotly graph dash with two different dropdowns as inputs.
This is my sample dataframe:
import pandas as pd
df1 = {'category' : ['A','A','A','B','B','B'],'subcategory' : ['x', 'y', 'z', 'x1','y1','z1'],
'x_coord' : [1, 2,3,2,2,2],'y_coord' : [1,3,2,1,3,2]}
df_test = pd.DataFrame(df1)
df_test
And what I pretend to do is if I select category A, that plots in a scatter all the correspondent points to the category, but If Also I select a subcategory that modifies the graph plotting only the correspondent category-subcategory point of the dataframe.
The code is below, and it works if I only add the callback of the first dropdown, but when I add the second callback to the subcategory it doesn't work.
I am following the suggestions in the dash plotly tutorial where it says:
A word of caution: it's not always a good idea to combine Outputs, even if you can:
If the Outputs depend on some but not all of the same Inputs, keeping them separate can avoid unnecessary updates.
If they have the same Inputs but do independent computations with these inputs, keeping the callbacks separate can allow them to run in parallel.
Dash documentation callbacks
But anyway if I put the output in separate callbacks or in the same I cannot make it work, here is the code that I am trying (using jupyter notebook):
import dash
import plotly as py
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.graph_objects as go
from jupyter_plotly_dash import JupyterDash
py.offline.init_notebook_mode(connected = True)
app = JupyterDash('Test')
app.layout = html.Div([
dcc.Dropdown(id='dropdown1',
options=[{'label':i, 'value':i} for i in df_test['category'].unique()]),
dcc.Dropdown(id='dropdown2',
options=[{'label':i, 'value':i} for i in df_test['subcategory'].unique()]),
dcc.Graph(id='graphic')
])
#app.callback(
Output('dropdown2', 'options'),
[Input('dropdown1', 'value')])
def update_drop2(selected_drop):
filtered_df = df_test[(df_test.category == selected_drop)]
return [{'label':i, 'value':i} for i in filtered_df['subcategory'].unique()]
#app.callback(
Output('graphic', 'figure'),
[Input('dropdown1', 'value')])
def update_figure(selected_drop):
filtered_df = df_test[(df_test.category == selected_drop)]
fig = go.Figure()
fig.add_trace(go.Scatter(x=filtered_df.x_coord,y=filtered_df.y_coord, marker = dict(size=15, color='green'), mode='markers'))
return fig
#app.callback(
Output('graphic', 'figure'),
[Input('dropdown2', 'value')])
def update_figure(selected_drop):
filtered_df = df_test[(df_test.subcategory == selected_drop)]
fig = go.Figure()
fig.add_trace(go.Scatter(x=filtered_df.x_coord,y=filtered_df.y_coord, marker = dict(size=15, color='green'), mode='markers'))
return fig
app
If I use multiple inputs on the callback like this:
#app.callback(
Output('graphic', 'figure'),
[Input('dropdown1', 'value'), Input('dropdown2', 'value')])
def update_figure(selected_drop1, selected_drop2):
if not selected_drop2:
filtered_df = df_test[(df_test.category == selected_drop1)]
else:
filtered_df = df_test[(df_test.category == selected_drop1) &
(df_test.subcategory == selected_drop2)]
fig = go.Figure()
fig.add_trace(go.Scatter(x=filtered_df.x_coord,y=filtered_df.y_coord,
marker = dict(size=15, color='green'), mode='markers'))
return fig
It works better (or more near what I pretend), but however when I switch between categories I see no data.
Thanks in advance for your help and reccomendations.
I had a similar problems the trick is to add to the second dropdown an option all. Then I wanted on the second dropdown to show only the subcategories in the given category. So I actually use 2 callbacks for dropdowns and 1 callback for the plot.
app.py
import pandas as pd
import os
import plotly.graph_objs as go
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
df = pd.DataFrame({'category' : ['A','A','A','B','B','B'],
'subcategory' : ['x', 'y', 'z', 'x1','y1','z1'],
'x_coord' : [1, 2,3,2,2,2],
'y_coord' : [1,3,2,1,3,2]})
# lists of categories
options1 = sorted(df["category"].unique().tolist())
# dictionary of category - subcategories
all_options = df.groupby("category")["subcategory"].unique()\
.apply(list).to_dict()
# we add as first subcategory for each category `all`
for k, v in all_options.items():
all_options[k].insert(0, 'all')
app = dash.Dash()
app.layout = html.Div([
dcc.Dropdown(
id='first-dropdown',
options=[{'label': k, 'value': k} for k in all_options.keys()],
value=options1[0]
),
html.Hr(),
dcc.Dropdown(id='second-dropdown'),
html.Hr(),
dcc.Graph(id='display-selected-values')
])
# the following two callbacks generate a dynamic 2 option
#app.callback(
dash.dependencies.Output('second-dropdown', 'options'),
[dash.dependencies.Input('first-dropdown', 'value')])
def set_2_options(first_option):
return [{'label': i, 'value': i} for i in all_options[first_option]]
#app.callback(
dash.dependencies.Output('second-dropdown', 'value'),
[dash.dependencies.Input('second-dropdown', 'options')])
def set_2_value(available_options):
return available_options[0]['value']
#app.callback(
dash.dependencies.Output('display-selected-values', 'figure'),
[dash.dependencies.Input('first-dropdown', 'value'),
dash.dependencies.Input('second-dropdown', 'value')])
def update_graph(selected_first, selected_second):
if selected_second == 'all':
ddf = df[df["category"]==selected_first]
else:
ddf = df[(df["category"]==selected_first) &
(df["subcategory"]==selected_second)]
fig = go.Figure()
fig.add_trace(
go.Scatter(x=ddf["x_coord"],
y=ddf["y_coord"],
marker = dict(size=15, color='green'),
mode='markers'))
return fig
if __name__ == '__main__':
app.run_server(debug=True, port=8051)