Why do all Dash components have borders when clicked? - python

I'm following a simple tutorial to build a stock price dashboard in Plotly Dash. When the app is running on localhost, every Component gets a border when hovered or clicked. See the GIF below.
Is this due to a setting somewhere? It's very annoying, and it seems to happen in most of the Dash apps I've been making.
The code for the app is here:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import plotly.graph_objs as go
import pandas_datareader.data as web
from datetime import datetime, timedelta
app = dash.Dash(title="Stock Dashboard")
app.layout = html.Div(
[
html.H1("Stock Ticker Dashboard"),
html.Div(
[
html.H4("Enter stock symbols:"),
dcc.Input(
id = 'stock_picker',
value = 'AAPL',
style = dict(
fontSize = 24,
width = '100%',
marginRight = '15px',
padding = '10px 5px',
borderRadius = '4px'
)
),
],
style = dict(
display = 'inline-block',
verticalAlign = 'middle',
marginRight = '20px',
width = '40%'
)
),
html.Div(
[
html.H4("Choose a date range:"),
dcc.DatePickerRange(
id = 'date_picker',
min_date_allowed = datetime(2010, 1, 1),
max_date_allowed = datetime.today(),
start_date = datetime.today() - timedelta(days=365),
end_date = datetime.today(),
),
],
style = dict(
display = 'inline-block',
verticalAlign = 'middle',
marginLeft = '20px'
)
),
html.Div(
[
html.Button(
id = 'submit_button',
n_clicks = 0,
children = "Submit",
style = dict(
fontSize = 24,
marginLeft = '30px'
)
)
],
style = dict(
display = 'inline-block',
verticalAlign = 'bottom'
)
),
html.Div(
[
dcc.Graph(
id = 'stock_graph',
figure = dict(
data = [{'x': [1,2], 'y': [3,1]}],
layout = go.Layout(
xaxis = dict(
title = dict(
text = "Date",
),
),
yaxis = dict(
title = dict(
text = "Closing Price / [$]",
)
)
)
),
style = dict(
height = '600px'
)
)
],
style = dict(
height = '600px'
)
)
],
style = dict()
)
#app.callback(
Output('stock_graph', 'figure'),
[Input('submit_button', 'n_clicks')],
[
State('stock_picker', 'value'),
State('date_picker', 'start_date'),
State('date_picker', 'end_date')
],
)
def update_graph(n_clicks, stock_ticker, start_date, end_date):
start = datetime.strptime(start_date[:10], '%Y-%M-%d')
end = datetime.strptime(end_date[:10], '%Y-%M-%d')
print(f"Getting stock prices for: {stock_ticker}, [{start} - {end}]")
df = web.DataReader(stock_ticker, 'yahoo', start, end)
fig = dict(
data = [go.Scatter(
x = df.index,
y = df['Close'],
mode = 'lines'
)],
layout = dict(
title = stock_ticker,
yaxis = dict(
title = 'Closing Price / [$]'
)
)
)
return fig
if __name__ == '__main__':
app.run_server()
Edited to add the version numbers for some of the modules (please let me know if I should include others):
pandas==1.1.1
pandas-datareader==0.9.0
dash-core-components==1.10.2
dash-html-components==1.0.3
dash-renderer==1.6.0
dash-table==4.9.0
Flask==1.1.2
Flask-Compress==1.5.0

I'm a dingus. It was from my React Developer Tools addon (Firefox 79.0). Not sure why that setting got turned on, but there you go. :facepalm:

Related

Plotly Dash `px.bar` not updating in callback function

The graph in the app.layout is not updated at callback. Code is shown below, however, it requires a csv file of data that is turned into a pandas.Dataframe. I will post the first 26 rows here for reference. (This is a subset of results of the Houston Marathon that took place on the Saturday of the 15th of Jan!)
The code takes datetime.time data, bins it into 5 minutes of length, before creating a histogram in px.bar. Given a user's time input - their percentile in the sample distribution is visualized.
place,name,time
1,Dominic Ondoro,02:10:36
2,Tsedat Ayana,02:10:37
3,Teshome Mekonen,02:11:05
4,Parker Stinson,02:12:11
5,Tyler Pennel,02:12:16
6,Kenta Uchida,02:14:13
7,James Ngandu,02:14:28
8,Alvaro Abreu,02:14:28
9,Kevin Salvano,02:16:39
10,Tyler Pence,02:16:44
11,Phillip Reid,02:16:46
12,Mark Messmer,02:17:27
13,Shadrack Biwott,02:17:36
14,Hitomi Niiya,02:19:24
15,David Fuentes,02:20:28
16,Patrice Labonte,02:20:49
17,Joseph Niemiec,02:21:06
18,Jesse Joseph,02:21:09
19,Aaron Davidson,02:21:40
20,Stan Linton,02:21:43
21,Mitchell Klingler,02:21:53
22,Michael Babinec,02:22:52
23,Tom Derr,02:23:07
24,Matt Dynan,02:23:33
25,Alexander Diltz,02:23:41
CSV_FILE_NAME = 'houston_marathon_2023.csv'
# Contents of the CSV file are above
def parse_data_as_df():
df = pd.read_csv(CSV_FILE_NAME, encoding='latin-1')
df['time'] = pd.to_datetime(df['time']).dt.time
return df
def create_histogram(cutoff_time):
BIN_SIZE_MINUTES = 5
MIN_TIME = dt.time(hour=2, minute=0, second=0)
MAX_TIME = dt.time(hour=6, minute=10, second=0)
time_increment = MIN_TIME
time_bins = {}
data = parse_data_as_df()
# get bins for original
while time_increment <= MAX_TIME:
next_time = dt.time(hour=time_increment.hour + int((time_increment.minute + BIN_SIZE_MINUTES) / 60),
minute=(time_increment.minute + BIN_SIZE_MINUTES) % 60,
second=0)
time_bins[time_increment] = 0
for a_time in data['time']:
if time_increment <= a_time < next_time:
time_bins[time_increment] += 1/len(data['time'])
time_increment = next_time
df = pd.DataFrame({'bin_times': time_bins.keys(), 'percent': time_bins.values()})
df["color"] = np.select(
[df["bin_times"].lt(cutoff_time)],
["#fd7e14"],
"#158cba",
)
load_figure_template(['lumen'])
fig = px.bar(
df,
x="bin_times",
y="percent",
color="color",
color_discrete_map={
"#fd7e14": "#fd7e14",
"#158cba": "#158cba",
},
template='lumen',
hover_data={
'color': False,
'percent': ':.1%'
}
)
fig.update_xaxes(tickformat='%H:%M',
ticktext=[d.strftime('%H:%M') for d in df['bin_times']])
fig.update_yaxes(tickformat='0%',
range=[0, 0.05])
fig.update_layout(xaxis_title="Time (HH:MM)",
yaxis_title="Density (%)",
showlegend=False,
bargap=0.025)
return fig
def create_dash_application():
APP_STYLESHEET = "https://cdn.jsdelivr.net/npm/bootswatch#5.2.3/dist/lux/bootstrap.min.css"
DEFAULT_CUTOFF_TIME = dt.time(hour=3)
dash_app = Dash(__name__, external_stylesheets=[APP_STYLESHEET])
dash_app.layout = html.Div([
html.Br(),
dcc.Graph(id='histogram_graph',
figure=create_histogram(DEFAULT_CUTOFF_TIME),
config={'displayModeBar': False},
animate=True),
html.Br(),
html.Div(
[
html.B('Hours: '),
dcc.Input(id='time_hours', value='', type='text', style={'width': '25%'}),
]),
html.Br(),
html.Div(
[
html.B('Minutes: '),
dcc.Input(id='time_minutes', value='', type='text', style={'width': '25%'}),
]),
html.Br(),
html.Div(
[
html.B('Seconds: '),
dcc.Input(id='time_seconds', value='', type='text', style={'width': '25%'}),
]),
html.Br(),
html.Button(children='Analyse', id='button_submit', n_clicks=0, style={'width': '25%'}, type='button'),
], style={'width': '75%'})
#dash_app.callback(
Output('histogram_graph', 'figure'),
[Input('button_submit', 'n_clicks'),
Input('time_hours', 'value'),
Input('time_minutes', 'value'),
Input('time_seconds', 'value')],
prevent_initial_call=True)
def update_output(n_clicks, the_hours, the_minutes, the_seconds):
if n_clicks > 0 and the_hours != '' and the_minutes != '' and the_seconds != '':
in_time = dt.time(hour=int(the_hours), minute=int(the_minutes), second=int(the_seconds))
# Something wrong here, as histogram is correctly generated but not changed in Dash App
return create_histogram(cutoff_time=in_time)
else:
return None
dash_app.run_server(debug=True)
create_dash_application()
I've isolated the issue to the callback returning a correct fig, that is not being updated in the app.layout. It is not an issue in the creation of fig, as confirmed by observing fig.show().
I am expecting fig in dcc.Graph to be updated.
What am I missing?
If you want to use the button to run the inputs, you need to switch those inputs to State. Please use below code to run:
import datetime as dt
import dash
CSV_FILE_NAME = 'houston_marathon_2023.csv'
# Contents of the CSV file are above
def parse_data_as_df():
df = pd.read_csv(CSV_FILE_NAME, encoding='latin-1')
df['time'] = pd.to_datetime(df['time']).dt.time
return df
def create_histogram(cutoff_time):
BIN_SIZE_MINUTES = 5
MIN_TIME = dt.time(hour=2, minute=0, second=0)
MAX_TIME = dt.time(hour=6, minute=10, second=0)
time_increment = MIN_TIME
time_bins = {}
data = parse_data_as_df()
# get bins for original
while time_increment <= MAX_TIME:
next_time = dt.time(hour=time_increment.hour + int((time_increment.minute + BIN_SIZE_MINUTES) / 60),
minute=(time_increment.minute + BIN_SIZE_MINUTES) % 60,
second=0)
time_bins[time_increment] = 0
for a_time in data['time']:
if time_increment <= a_time < next_time:
time_bins[time_increment] += 1/len(data['time'])
time_increment = next_time
df = pd.DataFrame({'bin_times': time_bins.keys(), 'percent': time_bins.values()})
df["color"] = np.select(
[df["bin_times"].lt(cutoff_time)],
["#fd7e14"],
"#158cba",
)
fig = px.bar(
df,
x="bin_times",
y="percent",
color="color",
color_discrete_map={
"#fd7e14": "#fd7e14",
"#158cba": "#158cba",
},
hover_data={
'color': False,
'percent': ':.1%'
}
)
fig.update_xaxes(tickformat='%H:%M',
ticktext=[d.strftime('%H:%M') for d in df['bin_times']])
fig.update_yaxes(tickformat='0%',
range=[0, 0.05])
fig.update_layout(xaxis_title="Time (HH:MM)",
yaxis_title="Density (%)",
showlegend=False,
bargap=0.025)
return fig
def create_dash_application():
APP_STYLESHEET = "https://cdn.jsdelivr.net/npm/bootswatch#5.2.3/dist/lux/bootstrap.min.css"
DEFAULT_CUTOFF_TIME = dt.time(hour=3)
dash_app = dash.Dash(__name__, external_stylesheets=[APP_STYLESHEET])
dash_app.layout = html.Div([
html.Br(),
dcc.Graph(id='histogram_graph',
figure=create_histogram(DEFAULT_CUTOFF_TIME),
config={'displayModeBar': False},
animate=True),
html.Br(),
html.Div(
[
html.B('Hours: '),
dcc.Input(id='time_hours', value='', type='text', style={'width': '25%'}),
]),
html.Br(),
html.Div(
[
html.B('Minutes: '),
dcc.Input(id='time_minutes', value='', type='text', style={'width': '25%'}),
]),
html.Br(),
html.Div(
[
html.B('Seconds: '),
dcc.Input(id='time_seconds', value='', type='text', style={'width': '25%'}),
]),
html.Br(),
html.Button(children='Analyse', id='button_submit', n_clicks=0, style={'width': '25%'}, type='button'),
], style={'width': '75%'})
#dash_app.callback(
Output('histogram_graph', 'figure'),
[Input('button_submit', 'n_clicks')],
[State('time_hours', 'value'),
State('time_minutes', 'value'),
State('time_seconds', 'value')],
prevent_initial_call=True)
def update_output(n_clicks, the_hours, the_minutes, the_seconds):
if n_clicks > 0 and the_hours != '' and the_minutes != '' and the_seconds != '':
in_time = dt.time(hour=int(the_hours), minute=int(the_minutes), second=int(the_seconds))
# Something wrong here, as histogram is correctly generated but not changed in Dash App
return create_histogram(cutoff_time=in_time)
else:
return None
dash_app.run_server(debug=True)
create_dash_application()
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.

Data from Django-model not showing updates in Django dash app

import plotly.express as px
import pandas as pd
from django_plotly_dash import DjangoDash
from product.models import Products
app = DjangoDash("SimpleExample")
products = Products.objects.all()
to_dic = list(Products.objects.all().values("name", "price"))
keys_are = []
values_are = []
dictionary = {}
for i in to_dic:
keys_are.append(i["name"])
values_are.append(i["price"])
dictionary["name"] = keys_are
dictionary["price"] = values_are
opts = []
for i in to_dic:
opts.append({"label": i["name"], "value": i["price"]})
app.layout = html.Div(
[
html.Div(
children=[
html.Label("Products"),
dcc.Dropdown(id="pid", options=opts, value=values_are[0]),
],
style={"padding": 10, "flex": 1},
),
html.Div(id="gr_container", children=[]),
html.Br(),
dcc.Graph(id="pro_graph", figure={}),
],
)
#app.callback(
[
Output(component_id="pro_graph", component_property="figure"),
Output(component_id="gr_container", component_property="children"),
],
[
Input(component_id="pid", component_property="value"),
],
)
def update_graph(selected):
message = "The option selected is :{}".format(selected)
fig = px.bar(dictionary, x="name", y="price")
return fig, message
if __name__ == "__main__":
app.run_server(debug=True)
this is my dash-graph.py file in django project, when I run the project it show bar on dashboard, but when I update database i.e. the product model it does not update the bar and show the old graph until I run the server again, also the select box is just for testing no use for that here. Also is their a better way write this code, like the dictionary one.
moved it to update_graph function and it works
import plotly.express as px
import pandas as pd
from django_plotly_dash import DjangoDash
from product.models import Products
app = DjangoDash("SimpleExample")
app.layout = html.Div(
[
html.Div(
children=[
html.Label("Products"),
dcc.Dropdown(
id="pid",
),
],
style={"padding": 10, "flex": 1},
),
html.Div(id="gr_container", children=[]),
html.Br(),
dcc.Graph(id="pro_graph", figure={}),
],
)
#app.callback(
[
Output(component_id="pid", component_property="options"),
Output(component_id="pro_graph", component_property="figure"),
Output(component_id="gr_container", component_property="children"),
],
[
Input(component_id="pid", component_property="value"),
],
)
def update_graph(selected):
products = Products.objects.all()
to_dic = list(Products.objects.all().values("pk", "name", "price"))
keys_are = []
values_are = []
dictionary = {}
for i in to_dic:
keys_are.append(i["name"])
values_are.append(i["price"])
opts.append({"label": i["name"], "value": str(i["pk"])})
dictionary["name"] = keys_are
dictionary["price"] = values_are
opts = []
message = "The option selected is :{}".format(selected)
fig = px.bar(dictionary, x="name", y="price")
return opts, fig, message```

Dash Python how to make multiple updating graphs, how to title

new coder here, I'm trying to make 4 graphs that share the same random data (although I plan on splitting them apart later). When it was just the one graph it took the random data fine and automatically scaled. In the go.layout there's no way to put which graph you're labeling. Now that I've added multiple none of them have any titles, axis labels, or data. Please help!
import dash
from dash.dependencies import Output, Input
import dash_core_components as dcc
import dash_html_components as html
import plotly.express as px
import random
import plotly.graph_objs as go
from collections import deque
#setting first points
X = deque(maxlen = 20)
X.append(1)
Y = deque(maxlen = 20)
Y.append(1)
#app settings, html layout
app = dash.Dash(__name__)
app.layout = html.Div(children=[
html.H1([
html.H1(children='Graphs'),
dcc.Graph(id = 'Battery Voltage', animate = True),
dcc.Interval(
id = 'graph-update',
interval = 1000,
n_intervals = 0
),
],
),
html.Div(
[
dcc.Graph(id = 'Signal', animate = True),
dcc.Interval(
id = 'graph-update2',
interval = 1000,
n_intervals = 0
),
],
),
html.Div(
[
dcc.Graph(id = 'Health', animate = True),
dcc.Interval(
id = 'graph-update3',
interval = 1000,
n_intervals = 0
),
],
),
html.Div(
[
dcc.Graph(id = 'Prognastics', animate = True),
dcc.Interval(
id = 'graph-update4',
interval = 1000,
n_intervals = 0
),
],
)])
#this is what keeps the graph updating
#app.callback(
[Output('Battery Voltage', 'figure'),
Output('Signal', 'figure'),
Output('Health', 'figure'),
Output('Prognastics', 'figure')],
[ Input('graph-update', 'n_intervals'),
Input('graph-update2', 'n_intervals'),
Input('graph-update3', 'n_intervals'),
Input('graph-update4', 'n_intervals')]
)
def update_graph_scatter(n):
X.append(X[-1]+1)
Y.append(Y[-1]+Y[-1] * random.uniform(-0.1,0.1))
data = go.Scatter(
x=list(X),
y=list(Y),
name='Scatter',
mode= 'lines+markers'
)
return {'data': [data],
'layout' : go.Layout(title="Battery Voltage",
xaxis_title="Time",
yaxis_title="Voltage",
xaxis=dict(range=[min(X),max(X)]),
yaxis = dict(range = [min(Y),max(Y)])
)
}
if __name__ == '__main__':
app.run_server()
When ran with multiple
Just the one
if anyone else has this problem, the definition has to come immediately after their callback. My formatting was also bad I guess. It should look like:
#app.callback(Output('Health', 'figure'),
Input('graph-update3', 'n_intervals'))
def update_graph3(n):
X.append(X[-1]+1)
Y.append(Y[-1]+Y[-1] * random.uniform(-0.1,0.1))
#those are random points, we'd socket something in
data = go.Scatter(
x=list(X),
y=list(Y),
name='Scatter',
mode= 'lines+markers'
)
print("data:", data)
return {'data': [data],
'layout' : go.Layout(title="Health",
xaxis_title="Time",
yaxis_title="Health",
xaxis=dict(range=[min(X),max(X)]),
yaxis = dict(range = [min(Y),max(Y)])
)
}

In dash, how do I use a callback to update a graph when a radio button is selected?

I'm new to dash and I'm having problems finding examples on using data frames within a callback. I created a weekly radio button and a monthly radio button.
When the monthly radio button is selected I would like the graph to pull data from df_monthly where each bar would be a monthly sum of pay. When the weekly radio button is checked I would like to see the graph populate each bar on a weekly basis which would be each row in the data frame since I get paid once a week.
I'm not certain where I'm going wrong but I keep receiving an error stating TypeError: update_fig() takes 0 positional arguments but 1 was given
The graph populates without data like the picture below. Thanks for any help on this matter.
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.plotly as py
import plotly.graph_objs as go
import sqlite3
import pandas as pd
from functools import reduce
import datetime
conn = sqlite3.connect('paychecks.db')
df_ct = pd.read_sql('SELECT * FROM CheckTotal',conn)
df_earn = pd.read_sql('SELECT * FROM Earnings', conn)
df_whold = pd.read_sql('SELECT * FROM Withholdings', conn)
data_frames = [df_ct, df_earn, df_whold]
df_paystub = reduce(lambda left,right: pd.merge(left,right,on=['Date'], how='outer'), data_frames)
def date_extraction(df):
df['Date'] = pd.to_datetime(df['Date'])
df['Year'] = df['Date'].dt.strftime('%Y')
df['Month'] = df['Date'].dt.strftime('%B')
df['Day'] = df['Date'].dt.strftime('%d')
return df
date_extraction(df_paystub)
df_monthly = df_paystub.groupby(['Month']).sum()
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.css.append_css({'external_url': 'https://codepen.io/amyoshino/pen/jzXypZ.css'})
app.layout = html.Div(children=[
html.Div([
html.Div([
dcc.RadioItems(
id='data-view',
options=[
{'label': 'Weekly', 'value': 'Weekly'},
{'label': 'Monthly', 'value': 'Monthly'},
],
value='',
labelStyle={'display': 'inline-block'}
),
], className = 'two columns'),
html.Div([
dcc.Dropdown(
id='year-dropdown',
options=[
{'label': i, 'value': i} for i in df_paystub['Year'].unique()
],
placeholder="Select a year",
),
], className='five columns'),
html.Div([
dcc.Dropdown(
id='month-dropdown',
options=[
{'label': i, 'value': i} for i in df_paystub['Month'].unique()
],
placeholder="Select a month(s)",
multi=True,
),
], className='five columns'),
], className = 'row'),
# HTML ROW CREATED IN DASH
html.Div([
# HTML COLUMN CREATED IN DASH
html.Div([
# PLOTLY BAR GRAPH
dcc.Graph(
id='pay',
)
], className = 'six columns'),
# HTML COLUMN CREATED IN DASH
html.Div([
# PLOTLY LINE GRAPH
dcc.Graph(
id='hours',
figure={
'data': [
go.Scatter(
x = df_earn['Date'],
y = df_earn['RegHours'],
mode = 'lines',
name = 'Regular Hours',
),
go.Scatter(
x = df_earn['Date'],
y = df_earn['OtHours'],
mode = 'lines',
name = 'Overtime Hours',
)
]
}
)
], className='six columns')
], className='row')
], className='ten columns offset-by-one')
#app.callback(dash.dependencies.Output('pay', 'figure'),
[dash.dependencies.Input('data-view', 'value')])
def update_fig():
figure={
'data': [
go.Bar(
x = df_monthly['Month'],
y = df_monthly['CheckTotal'],
name = 'Take Home Pay',
),
go.Bar(
x = df_monthly['Month'],
y = df_monthly['EarnTotal'],
name = 'Earnings',
)
],
'layout': go.Layout(
title = 'Take Home Pay vs. Earnings',
barmode = 'group',
yaxis = dict(title = 'Pay (U.S. Dollars)'),
xaxis = dict(title = 'Date Paid')
)
}
return figure
if __name__ == "__main__":
app.run_server(debug=True)
Hi #prime90 and welcome to Dash.
In glancing at your callback signature it looks like the update_fig() function needs to take the Input you've given it (using dash.dependencies.Input).
The callback is sending this Input what changes in your app you've specified. So it's sending along the value of #data-view you've given to your function update_fig(), which doesn't currently accept any variables, causing the error message.
Just update your function signature and add a couple of boolean variables to rid yourself of the error and get the potential functionality:
def update_fig(dataview_value):
# define your weekly OR monthly dataframe
# you'll need to supply df_weekly similarly to df_monthly
# though DO NOT modify these, see note below!
df = df_weekly if dataview == 'weekly' else df_monthly
dfkey = 'Week' if 'week' in df.columns else 'Month' # eh, worth a shot!
figure={
'data': [
go.Bar(
x = df[dfkey],
y = df['CheckTotal'],
name = 'Take Home Pay',
),
go.Bar(
x = df[dfkey],
y = df['EarnTotal'],
name = 'Earnings',
)
],
'layout': go.Layout(
title = 'Take Home Pay vs. Earnings',
barmode = 'group',
yaxis = dict(title = 'Pay (U.S. Dollars)'),
xaxis = dict(title = 'Date Paid')
)
}
return figure
As was written in the comments above, you'll need to do some type of prior manipulation to create a df_weekly, as you have with your current df_monthly.
In addition, the code snippet I wrote assumes the df column is named "Week" and "Month"--obviously update these as is necessary.
Data manipulation in Dash:
Ensure you read the data sharing docs, as they highlight how data should never be modified out of scope.
I hope this helps :-)

Categories

Resources