import dash
from dash import Dash, html, dcc, Output, Input, callback
import plotly.graph_objects as go
import plotly.express as px
df1 = pd.read_csv(filepath+filename, index_col="Date")
df1.index = pd.to_datetime(df1.index)
df1["Measure1_SMA"] = df1["Measure1"].rolling(20).mean()
df1["Measure2_SMA"] = df1["Measure2"].rolling(20).mean()
app = Dash(__name__)
my_dropdown = dcc.Dropdown(options = ['Measure1', 'Measure2'],
value = df1.columns[:2],
multi = False,
style = {'width':'50%'})
my_graph = dcc.Graph(figure={})
app.layout = html.Div([
html.H1('Metrics (Values)', style = {'textAlign':'center'}),
html.Label("Metrics: "),
my_dropdown,
my_graph
])
#callback(
Output(component_id=my_graph, component_property='figure'),
Input(component_id=my_dropdown, component_property='value')
)
def update_graph(dropdown_value):
plot_figure = px.bar(data_frame=df1, y=dropdown_value, x=df1.index)
#plot_figure.add_line()
print(dropdown_value)
return plot_figure
if __name__ == "__main__":
app.run_server(debug=True)
I want to create a single plot on the plotly dashboard with an option to toggle between Measure1 and Measure2. Selecting the dropdown_value will create a bar graph of Measure1 on y-axis and Date on x-axis. I also want to plot a line graph on the same plot which will be the rolling average of previous 20 days for the value selected from the dropdown.
I tried adding a add_line() method but not sure how to use it.
Creates a data frame from which the value columns and SMA columns are extracted, using the values obtained from the drop-down selections. Draw a bar graph in the created data frame and add the SMA in scatter plot line mode. drawing two graphs, I think I need to make a graph with two axes. since I could not add graphs to px.line, I reused the data in px.line to create the first I have used the data from px.line as the first graph. The sample data is stock price data.
import dash
from dash import Dash, html, dcc, Output, Input, callback
import plotly.graph_objects as go
import plotly.express as px
from plotly.subplots import make_subplots
import yfinance as yf
df1 = yf.download("AAPL", start="2021-01-01", end="2021-03-01")
df1["Close_SMA"] = df1["Close"].rolling(20).mean()
df1["High_SMA"] = df1["High"].rolling(20).mean()
df1 = df1[['High','Close','Close_SMA','High_SMA']]
app = Dash(__name__)
my_dropdown = dcc.Dropdown(options = ['Close', 'High'],
value = 'Close',
multi = False,
style = {'width':'50%'})
my_graph = dcc.Graph(figure={})
app.layout = html.Div([
html.H1('Metrics (Values)', style = {'textAlign':'center'}),
html.Label("Metrics: "),
my_dropdown,
my_graph
])
#callback(
Output(component_id=my_graph, component_property='figure'),
Input(component_id=my_dropdown, component_property='value')
)
def update_graph(dropdown_value):
sma = '{}_SMA'.format(dropdown_value)
dff = df1[[dropdown_value,sma]]
dff = dff.dropna()
plot_figure = make_subplots(specs=[[{"secondary_y": True}]])
fig = px.bar(data_frame=dff, y=dropdown_value, x=dff.index)
plot_figure.add_trace(fig.data[0], secondary_y=False)
plot_figure.add_trace(go.Scatter(x=dff.index, y=dff[sma], name=sma, mode='lines'), secondary_y=True)
plot_figure.update_layout(yaxis_title='Close')
return plot_figure
if __name__ == "__main__":
app.run_server(debug=True)
Related
I want to draw a chart of btc and show one hour after one hour like a slideshow (no animation or effect is needed). However I'm not able to update the figure stemming from px.line() without the browser opening a new tab. How would I do this, like remaining in the same tab and just updating the data of the line and redraw it?
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
import time
df = pd.read_csv('btc.csv')
i=0
shown=False
part_df1=df.iloc[0:60]
fig = px.line(part_df1, x = 'date_x', y = 'price_y', title='btc price ..')
fig.show()
while i<600:
time.sleep(0.25)
i=i+60
part_df=df.iloc[i:i+60]
fig = px.line(part_df, x = 'date_x', y = 'price_y', title='btc price ..')
fig.show()
so something like:
fig.update(px.line(part_df, x = 'date_x', y = 'price_y', title='btc price ..'))
instead of
fig = px.line(part_df, x = 'date_x', y = 'price_y', title='btc price ..')
fig.show()
I've put together an example plotly-dash app that performs a live update for data over a predefined period of time. Some of the important features are:
the dcc.Interval object automatically triggers the callback function for updating the figure every interval of time (e.g. update the figure every 1 second). there's also an n_interval counter which will be useful for helping us keep track of the indices in the df we are iterating through (documentation here)
the extendData property of dcc.Graph allows you to return a dictionary from your callback (and saves you the trouble of having to directly modify the data inside the figure object). (documentation here)
import numpy as np
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
import dash
from dash import dcc, html
from dash.dependencies import Input, Output
# df = pd.read_csv('btc.csv')
## create some random walk data
np.random.seed(42)
change = np.random.choice([-1,0,1], 600-1)
btc = [20000]
for y_change in change:
btc_new = btc[-1] + 1000*y_change
btc.append(btc_new)
df = pd.DataFrame({
'date': pd.date_range(start='2022-01-01', periods=600),
'btc': btc
})
part_df=df.iloc[0:60]
fig = px.line(part_df, x = 'date', y = 'btc', title='btc price')
app = dash.Dash(__name__)
app.layout = html.Div(
html.Div([
dcc.Graph(id='live-update-graph', figure=fig),
dcc.Interval(
id='interval-component',
interval=1000, # 0.25*1000, # in milliseconds
n_intervals=1,
max_intervals=len(df) // 60 - 1
)
])
)
#app.callback(Output('live-update-graph', 'extendData'),
[Input('interval-component', 'n_intervals'),
Input('live-update-graph', 'figure')])
def extend_trace(n, fig):
if 60*n > len(df):
return {}
else:
part_df = df.iloc[60*n:60*(n+1)]
return (dict(
x=[part_df['date'].tolist()],
y=[part_df['btc'].tolist()],
))
app.run(debug=True)
Update: if you don't need to the data to extend, and only want to show the new incoming data, then you can use the figure property of dcc.Graph instead of extendData. Then your callback would look like the following:
#app.callback(Output('live-update-graph', 'figure'),
[Input('interval-component', 'n_intervals'),
Input('live-update-graph', 'figure')])
def extend_trace(n, fig):
if 60*n > len(df):
return fig
else:
part_df = df.iloc[60*n:60*(n+1)]
return (dict(
data=[dict(
x=part_df['date'].tolist(),
y=part_df['btc'].tolist(),
)]
))
Hi I'm new to plotly dash. My objective is to draw a graph when excel sheet is updated.
The lines are updated when I add a new row to sheet but axises are not animated or updated. But when I refresh the browser it graph was updated and axis also updated. Here is my code. Any help would be highly appreciated
import dash
from datetime import datetime as dt
from dash.dependencies import Output, Input
from dash import dcc
from dash import html
from plotly.subplots import make_subplots
import plotly.graph_objs as go
import pandas as pd
def check_acc_data():
df = pd.read_excel("test.xlsx")
last_10_df = df.tail(10)
# print(last_10_df)
time_ = last_10_df['time'].values.tolist()
# time_2=["14:00","14:30","15:00","15:30","16:00","16:30","17:00","17:30","18:00","18:30"]
temp = last_10_df['temperature'].values.tolist()
humidity = last_10_df['Humidity'].values.tolist()
test_str = [date_obj.strftime('%H:%M') for date_obj in time_]
return test_str,temp,humidity
app = dash.Dash(__name__)
#fig = px.line(x=test_str, y=[temp, humidity])
app.layout = html.Div([
html.H4('Dashboard'),
dcc.Interval('graph-update', interval = 2000, n_intervals = 0),
html.Div(children='''
Temperature Humidity and Time variation.
'''),
dcc.Graph(
id='example-graph',
figure={},
animate=True
)
])
#app.callback(
dash.dependencies.Output('example-graph','figure'),
[dash.dependencies.Input('graph-update', 'n_intervals')])
def update_figure(n):
time1,temp1,humid1=check_acc_data()
fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.add_trace(
go.Scatter(x=time1, y=temp1, mode="lines+markers", name='Temperature'),
secondary_y=False
)
fig.add_trace(
go.Scatter(x=time1, y=humid1, mode="lines+markers", name='Humidity'),
secondary_y=True,
)
fig.update_layout(yaxis=dict(range=[-2.5,50]),
yaxis1=dict(range=[-2.5,100]),
)
return fig
if __name__ == '__main__':
app.run_server(debug=True, port=10451)
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
I'm quite new to dash but I'm trying to put together a data dashboard. Of the things I want to have is a drop down, that based on the input, renders 1 of two pie charts. The logic to structure the pie chart is included in my callback function. It is saying it is expecting 1 output but it had two. I've had a look online and tried different suggestions. I think I'm pretty close to getting this to work, there is just something dumb I'm not doing.
I know people here are wizards, so I was hoping someone might be able to help me. Also if anyone is Dash savvy, can you point me in the direction of good documentation to learn how to orient this, so I can change the layout to make these plots fit better together in a dashboard, rather than just a web page?
So much love
Thanks
import pandas as pd
import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output, State
from jupyter_dash import JupyterDash
import plotly.graph_objects as go
import plotly.express as px
from dash import no_update
import plotly.figure_factory as ff
app = dash.Dash(__name__)
df = pd.read_csv('nyc-jobs.csv')
#top job categories
counts = df['Job Category'].value_counts()
counts = pd.DataFrame(counts)
counts = counts.head(10)
counts.sort_values(['Job Category'],ascending=True, inplace = True)
fig = px.bar(df, y=counts.index, x=counts['Job Category'])
#Salary range distribution
salary_counts = df['Salary Range To'].value_counts()
salary_counts = pd.DataFrame(counts)
group_labels = ['Salary Range From','Salary Range To']
fig3 = ff.create_distplot([df['Salary Range From'],df['Salary Range To']], group_labels, bin_size= 10000)
fig4 = go.Figure()
fig4.add_trace(go.Box(y=df['Salary Range From'], name='Salary Range From',
marker_color = 'indianred'))
fig4.add_trace(go.Box(y=df['Salary Range To'], name = 'Salary Range To',
marker_color = 'lightseagreen'))
# # of positions
df.sort_values(by = ['# Of Positions'], ascending = True, inplace = True)
df_group = df.groupby(['Business Title']).mean(['# Of Positions'])
df_group.sort_values('# Of Positions', ascending = True, inplace = True)
df_group.index = df_group.index.str.capitalize()
fig5 = px.bar(df, y=df_group.index[-5:], x=df_group['# Of Positions'][-5:])
app.layout = html.Div([
html.H1("New York City Job Postings", style = {'text-align': 'center', 'font-family': 'Helvetica'}),
#Job postings graph
dcc.Graph(
id='Top Job Postings',
figure=fig
),
html.Div([html.H2('Report Type:', style={'margin-right': '2em', 'font-family': 'Helvetica'}),]),
dcc.Dropdown(id='input-type',
options=[
{'label': 'Full vs part time report ', 'value': 'OPT1'},
{'label': 'Posting type', 'value': 'OPT2'}
],
placeholder='Select a report type',
multi=False,
clearable=False,
style={'width':800, 'padding':3, 'font-size':20, 'text-align-last':'center', 'font-family': 'Helvetica'}),
html.Div(id='output_container', children=[]),
html.Div(dcc.Graph(id='pie_chart_reports')),
#Salary Distributions
dcc.Graph(
id="Salary Distribution",
figure = fig3),
dcc.Graph(
id="Salary Distribution boxplot",
figure = fig4),
dcc.Graph(
id='Highest number of positions',
figure=fig5
)
])
#app.callback(
[Output(component_id='pie_chart_reports', component_property='figure')],
[Input(component_id='input-type', component_property='value')]
)
def update_graph(report_type):
dff = df
container = "The chosen report was: {}".format(report_type)
if report_type == 'OPT1':
#full time vs part time
ft_pt = dff['Full-Time/Part-Time indicator']
ft_pt.fillna('Not listed', inplace = True)
ft_pt.replace('F', 'Full Time', inplace = True)
ft_pt.replace('P', 'Part Time', inplace = True)
value_counts_ft_pt = dff['Full-Time/Part-Time indicator'].value_counts()
labels_ft_pt = value_counts_ft_pt.index.tolist()
fig1 = px.pie(dff,
values = value_counts_ft_pt,
names = labels_ft_pt)
return container, dcc.Graph(id='pie_chart_reports',figure=fig1)
else:
#internal vs externl
value_counts_posting_type = dff['Posting Type'].value_counts()
labels_posting_type = value_counts_posting_type.index.tolist()
fig2 = px.pie(
df,
values = value_counts_posting_type,
names = labels_posting_type,
color_discrete_sequence=px.colors.sequential.Bluyl)
return container, dcc.Graph(id='pie_chart_reports',figure=fig2)
if __name__ == '__main__':
app.run_server(debug=True)
The first problem is that your callback has one output, but you return a tuple of two things. So you could add an Output that targets the element which you want to have the value of content, I'm guessing that element is the element with id output_container. The other option is to remove content from the return statement.
The second problem is that you have the Output surrounded by a list, so dash expects the return value to be a list containing one value. You can remove the list surrounding your Ouput so it expects a tuple
Output(component_id='pie_chart_reports', component_property='figure')
or you can surround your return values with a list.
The third problem is that you target the component_property figure, but you're returning a Graph component. So you should return fig1 instead of dcc.Graph(id='pie_chart_reports', figure=fig1) for example.
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)