Callback not working for Dropdown in Plotly Dash - python

I am trying to create an UI that allows to select a date range and displays the total number of users in that date range.
Also, it allows to select a time frame and gives a plot of number of users per time frame.
For example, if 01/01/2021 to 01/01/2022 is selected, the UI will show the total number of users in that date range. Also, if a time frame of 'Per Week' is selected then a plot of number of users per week between the given date range is generated.
For choosing date range, I have used DateRangePicker and for choosing time frame, I have used a Dropdown component.
This seems to be working fine except for the callback for Dropdown. The dropdown gives the correct plot for a chosen time frame, but when value of the dropdown is changed, the plot shows no changes at all. If I refresh the page and choose a different value in dropdown, the plot gets generated just fine.
Here is the app layout :
app = dash.Dash()
app.layout = dhc.Div([
dhc.H1(children = 'Web Analytics Template',
style = {
'textAlign' : 'center',
'color' : 'Black'
}),
dhc.Div(children = 'Website Overview',
style = {
'textAlign' : 'left',
'color' : 'Black',
'font-size' : 'larger'
}),
dhc.Div(children = 'Select A Date Range',
style = {
'textAlign' : 'left',
'color' : 'Black',
'font-size' : 'larger'
}),
dcc.DatePickerRange(
id = 'Date_Range',
min_date_allowed = date(int(min_date[0 : 4]), int(min_date[4 : 6]), int(min_date[6 : ])),
max_date_allowed = date(int(max_date[0 : 4]), int(max_date[4 : 6]), int(max_date[6 : ]))
),
dhc.Div(children = 'Total Visitors'),
dhc.Br(),
dhc.Div(id = 'total_users'),
dhc.Div(children = 'Select A Time Frame To See A Plot Of No. Of Visitors'),
dcc.Dropdown(
options = ['Per Day', 'Per Week', 'Per Month', 'Per Year'], id = 'Time_Frame_Dropdown'
),
dhc.Div(id = 'users_per_time_frame')
])
And here are the callbacks and functions. The function 'users_per_time_frame' is used to plot the number of visitors per time frame.
#app.callback(
Output(component_id = 'total_users', component_property = 'children'),
Input(component_id = 'Date_Range', component_property = 'start_date'),
Input(component_id = 'Date_Range', component_property = 'end_date'))
def total_users (start_date, end_date):
if start_date == '' and end_date == '':
total_users = len(pd.unique(data['user_pseudo_id']))
elif start_date != '' and end_date == '':
total_users = len(pd.unique(data['user_pseudo_id'].where(data['event_date'] >= start_date)))
elif start_date == '' and end_date != '':
total_users = len(pd.unique(data['user_pseudo_id'].where(data['event_date'] <= end_date)))
elif start_date != '' and end_date != '':
total_users = len(pd.unique(data['user_pseudo_id'].where((data['event_date'] >= start_date) & (data['event_date'] <= end_date))))
return total_users
#app.callback(
Output(component_id = 'users_per_time_frame', component_property = 'children'),
Input(component_id = 'Time_Frame_Dropdown', component_property = 'value'))
def users_per_time_frame (value):
if value == 'Per Day':
users_per_time_frame = data[['user_pseudo_id', 'event_date']].groupby(['event_date']).nunique()
if value == 'Per Week':
users_per_time_frame = data[['user_pseudo_id', 'Year', 'Month', 'Week']].groupby(['Year', 'Month', 'Week']).nunique()
if value == 'Per Month':
users_per_time_frame = data[['user_pseudo_id', 'Year', 'Month']].groupby(['Year', 'Month']).nunique()
if value == 'Per Year':
users_per_time_frame = data[['user_pseudo_id', 'Year']].groupby(['Year']).nunique()
return dcc.Graph(
id = 'users_per_time_frame',
figure = {
'data' : [
{'x' : users_per_time_frame.index, 'y' : users_per_time_frame.user_pseudo_id, 'type' : 'line', 'name' : 'Visitors'}
],
'layout' : {
'plot_bgcolor' : 'black',
'paper_bgcolor' : 'grey',
'title' : 'Visitors'
}
})
Thanks in advance!

Related

using hoverData in plotly dash to create hover go.Table

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

create dynamic columns with dash plotly based on user selection

My idea is that my dash_table.Datatable insert new columns based on what the user select in my dropdown.
I've experimented different approachs to receive back a dataframe, dict or list with my actual columns and be able to update my table but either of these worked. Below a reproduceble example:
import pandas as pd
import dash_mantine_components as dmc
import dash_core_components as dcc
import dash_bootstrap_components as dbc
from dash import html
from dash import Dash, Input, Output, dash_table, State
from dash.exceptions import PreventUpdate
import plotly.express as px
import json
from dash_bootstrap_templates import load_figure_template
import datetime
import base64
dff = {'Nome':['Random1','Random2','Random3','Random4'],'tipo':['Random11','Random22','Random33','Random44'],'a': ['1','2','3','4',], 'b':['b1','b2','b3','b4'], 'c':['c1','c2','c3','c4'], 'd':['d1','d2','d3','d3'],'Indicator Name':['a','b','c','d']}
dff = pd.DataFrame(dff)
db_filtered = pd.DataFrame(dff)
app = Dash(__name__, external_stylesheets= [dbc.themes.DARKLY, dbc_css])
#---------------------------------------------------------------------------------------------------------------------------------------#
# 1. FUNCTIONS CONSTRUCTION
# 1.1 - table_creation
#---------------------------------------------------------------------------------------------------------------------------------------#
#------------------------------------------------------- 1.1 ---------------------------------------------------------------------------#
def table_creation(db_filtered):
db_as_list = db_filtered.columns.to_list()
#print(db_as_list)
dash_table.DataTable(
data = [{
}],
columns = [{"name": i,
"id": i
} for i in db_as_list], #<------------ setting columns of datatable
editable=False, #<------------ setting preferences if is or not editable
filter_action="native", #<------------ Filters in columns
sort_action="native", #<------------
sort_mode="multi", #<------------
column_selectable="single", #<------------ Selectable only one column
row_selectable=False, #<------------ dont let select just a row
selected_columns=[], #<------------ no column is selected previously
selected_rows=[], #<------------ no row is selected previously
page_action="native",
page_current= 0, #<------------ First page will be show
page_size= 25) #<------------ n of funds to be showed
#---------------------------------------------------------------------------------------------------------------------------------------#
#---------------------------------------------------------------------------------------------------------------------------------------#
app.layout = html.Div([
#------------------------------------------------------- ---------------------------------------------------------------------------#
dbc.Card(
dbc.CardBody([
# ------------------------------------------------------------------------------------------------------------------#
dbc.Row([
dbc.Col([
html.Div([
dbc.Button("b1", color="warning", id='todos_button', n_clicks_timestamp='0'),
dbc.Button("b2", color="light",id='multimercado_button', n_clicks_timestamp='0' ),
dcc.Dropdown(dff['Indicator Name'].unique(), id = 'dropdown'),
])
]),
]),
#---------------------------------------------------------------------------------------------------------------------------------#
dbc.Row([
dbc.Col([
html.Div([
dash_table.DataTable(table_creation(db_filtered), id = 'tabela-dash',#calling the function with dff, but only will be displayed if the user use the button
)], className="m-4 dbc")
])
])
])
)
])
#---------------------------------------------------------------------------------------------------------------------------------------#
#---------------------------------------------------------------------------------------------------------------------------------------#
#-------------------------------------------------------- 3.1 --------------------------------------------------------------------------#
#app.callback(Output('tabela-dash', 'data'),
Input('multimercado_button','n_clicks_timestamp'),
Input('todos_button','n_clicks_timestamp')
)
def display(multimercado_button, todos_button ):
if int(multimercado_button) > int(todos_button): #Multimercado button
value = 'Macro Alta Vol'
db_filtered = pd.DataFrame(dff[dff['tipo'] == value])
db_filtered = db_filtered.loc[:,['Nome','tipo']]
print(db_filtered)
db_filtered = db_filtered.to_dict('Records')
return db_filtered #<------------ Extracting data as dict, easy way to do
elif int(todos_button) > int(multimercado_button):
db_filtered = pd.DataFrame(dff)
db_filtered = db_filtered.loc[:,['Nome','tipo']]
print(db_filtered)
db_filtered = db_filtered.to_dict('Records')
return db_filtered#<------------ Extracting data as dict, easy way to do
else:
db_filtered = pd.DataFrame(dff)
db_filtered = db_filtered.loc[:,['Nome','tipo']]
db_filtered = db_filtered.to_dict('Records')
return db_filtered #<------------ Extracting data as dict, easy way to do
#-------------------------------------------------------- 3.2 --------------------------------------------------------------------------#
#app.callback(
Output('tabela-dash', 'columns'),
[Input('dropdown', 'value')],
[State('tabela-dash', 'columns')]
)
def update_table(value, columns):
if value is None:
print('test 1: Value is None')
else:
print('test 1: Value is not None')
raise PreventUpdate
if columns is None:
print('test 2: Columns is None')
else:
print('test 2: Columns in not None')
app.run_server(debug=True, use_reloader=False)
I dont know why, but this code should work like this.
import dash
from dash.dependencies import Input, Output, State
from dash.exceptions import PreventUpdate
from dash_table import DataTable, FormatTemplate
import dash_core_components as dcc
import dash_html_components as html
app = dash.Dash(__name__)
app.layout = html.Div([
dcc.Dropdown(
id='dropdown',
options=[{
'label': 'label: ' + id,
'value': id
} for id in ['b', 'c', 'd', 'e', 'f']]
),
DataTable(
id='table',
columns=[{
'name': x,
'id': x,
'selectable': True
} for x in ['a']],
column_selectable="single",
data=[{
'a': 'a' + str(x),
'b': 'b' + str(x),
'c': 'c' + str(x),
'd': 'd' + str(x),
'e': 'e' + str(x),
'f': 'f' + str(x)
} for x in range(0,100)]
)
])
#app.callback(
Output('table', 'columns'),
[Input('dropdown', 'value')],
[State('table', 'columns')]
)
def update_columns(value, columns):
if value is None or columns is None:
raise PreventUpdate
inColumns = any(c.get('id') == value for c in columns)
if inColumns == True:
raise PreventUpdate
columns.append({
'label': 'label: ' + value,
'id': value
})
return columns
if __name__ == '__main__':
app.run_server(debug=False)
i can imagine that my problem is that the function dont bring back the columns.

keyerror 'column name' updating plotly dash figure

Issue:
I'm trying to load a simple plotly scatter plot, where
x axis = keyword
y axis = date
color = locale
however, even plotly throws a key error every time I add the "color" variable. The error code I get states that I don't have a column by that name, but when I print the column names I see the column there.
Anyone faced a similar issue?
Data:
Code:
# Importing needed libraries
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
import dash_table
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
import random
import datetime
import plotly.graph_objects as go
# Reading the dataframe
df = pd.read_csv('./beanstalk_app/ti_data_ti_dash_v1.csv')
categories = df['category']
locales = df['locale']
# clean dataframe
ti_data = df.copy()
ti_data = ti_data.sample(1000)
# Contents of the app
# 1.Controls
# 1.1 Dropdown list
locs = dcc.Dropdown(id='choose_loc',
options=[
{
'label': locale, 'value': locale
} for locale in locales.unique()
],
placeholder='Select Locale')
cats = dcc.Dropdown(id='choose_cat',
options=[
{
'label': c, 'value': c
} for c in categories.unique()
],
placeholder='Select Category')
# 1.2 DatePicker
datepick = dcc.DatePickerRange(
id='choose_date',
min_date_allowed=df.date.min(),
max_date_allowed=df.date.max(),
initial_visible_month=df.date.min(),
clearable=True,
start_date=df.date.min(),
end_date=df.date.max()
)
# 2.Interactive table
table = dash_table.DataTable(
id='datatable',
columns=[
{"name": i, "id": i, "selectable": True, "presentation": "markdown"}
if i == "google_query"
else {"name": i, "id": i, "selectable": True}
for i in df.columns
],
data=df.to_dict('records'),
editable=False,
filter_action="native",
sort_action="native",
sort_mode="multi",
column_selectable="single",
row_selectable="multi",
row_deletable=True,
selected_columns=[],
selected_rows=[],
page_action="native",
page_current=0,
page_size=10,
style_cell={
'whiteSpace': 'normal',
'height': 'auto',
},
)
# Initialize the app
app = dash.Dash(__name__)
app.title = 'Dot Graph Demo - All Entities'
app.layout = html.Div([
# modifiable table
dbc.Container([
dbc.Row(
[
dbc.Col(locs, width=4),
dbc.Col(cats, width=4),
dbc.Col(datepick, width=4)
]
),
dbc.Row(
table
),
], style={'backgroundColor': '#faf9f9'}),
# graphs resulting from modified table
html.Div(dcc.Graph(id='key_graph_l'))
],
style={'backgroundColor': '#faf9f9'})
# add callback functions
#app.callback(
Output('datatable', 'data'),
[
Input('choose_cat', 'value'),
Input('choose_loc', 'value'),
Input('choose_date', 'start_date'),
Input('choose_date', 'end_date')
]
)
def update_table(choose_cat, choose_loc, start_date, end_date):
df = ti_data.copy()
df['date'] = pd.to_datetime(df['date'])
df['date'] = df['date'].dt.date
if choose_cat is not None:
df = df[df['category'] == choose_cat]
if choose_loc is not None:
df = df[df['locale'] == choose_loc]
if start_date is not None and end_date is not None:
start_date = datetime.datetime.strptime(start_date, "%Y-%m-%d").date()
end_date = datetime.datetime.strptime(end_date, "%Y-%m-%d").date()
df = df.loc[(df.date >= start_date) & (df.date <= end_date)]
data = df.to_dict('records')
return data
#app.callback(
Output('datatable', 'style_data_conditional'),
Input('datatable', 'selected_columns')
)
def update_styles(selected_columns):
return [{
'if': {'column_id': column},
'background_color': '#D2F3FF'
} for column in selected_columns]
#app.callback(
Output('key_graph_l', 'figure'),
[
Input('choose_date', 'start_date'),
Input('choose_date', 'end_date'),
Input('choose_cat', 'value'),
Input('choose_loc', 'value')
]
)
def update_key_l(choose_loc, choose_cat, start_date, end_date):
df = ti_data.copy()
if choose_cat is not None:
df = df[df['category'] == choose_cat]
if choose_loc is not None:
df = df[df['locale'] == choose_loc]
if start_date is not None and end_date is not None:
df = df.loc[(df.date >= start_date) & (df.date <= end_date)]
df = df.sort_values('total_count', ascending=False)[:25]
figure = px.scatter(df, x='keyword', y='date', color='locale', size='total_count',labels={'keyword': 'Keyword', 'total_count': 'Total Count', 'locale': 'Locale', 'date': 'Date'},
title='Weighing top words accross locales')
return figure
# requirements for beanstalk (aws)
if __name__ == '__main__':
app.run_server(debug=True)
The reason for the error is that the order of the arguments in the callback function is different. The error occurs because the date format that is set when there is no calendar selection does not match the date format handled in Dash.
# Importing needed libraries
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
import dash_table
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
import random
import datetime
import plotly.graph_objects as go
from jupyter_dash import JupyterDash
# Reading the dataframe
df = pd.read_csv('./beanstalk_app/ti_data_ti_dash_v1.csv')
categories = df['category']
locales = df['locale']
# clean dataframe
ti_data = df.copy()
ti_data = ti_data.sample(4) # sample data
# Contents of the app
# 1.Controls
# 1.1 Dropdown list
locs = dcc.Dropdown(id='choose_loc',
options=[
{
'label': locale, 'value': locale
} for locale in locales.unique()
],
placeholder='Select Locale')
cats = dcc.Dropdown(id='choose_cat',
options=[
{
'label': c, 'value': c
} for c in categories.unique()
],
placeholder='Select Category')
# 1.2 DatePicker
datepick = dcc.DatePickerRange(
id='choose_date',
min_date_allowed=df.date.min(),
max_date_allowed=df.date.max(),
initial_visible_month=df.date.min(),
clearable=True,
start_date=df.date.min(),
end_date=df.date.max()
)
# 2.Interactive table
table = dash_table.DataTable(
id='datatable',
columns=[
{"name": i, "id": i, "selectable": True, "presentation": "markdown"}
if i == "google_query"
else {"name": i, "id": i, "selectable": True}
for i in df.columns
],
data=df.to_dict('records'),
editable=False,
filter_action="native",
sort_action="native",
sort_mode="multi",
column_selectable="single",
row_selectable="multi",
row_deletable=True,
selected_columns=[],
selected_rows=[],
page_action="native",
page_current=0,
page_size=10,
style_cell={
'whiteSpace': 'normal',
'height': 'auto',
},
)
# Initialize the app
app = dash.Dash(__name__)
app.title = 'Dot Graph Demo - All Entities'
app.layout = html.Div([
# modifiable table
dbc.Container([
dbc.Row(
[
dbc.Col(locs, width=4),
dbc.Col(cats, width=4),
dbc.Col(datepick, width=4)
]
),
dbc.Row(
table
),
], style={'backgroundColor': '#faf9f9'}),
# graphs resulting from modified table
html.Div(dcc.Graph(id='key_graph_l'))
],
style={'backgroundColor': '#faf9f9'})
# add callback functions
#app.callback(
Output('datatable', 'data'),
[
Input('choose_cat', 'value'),
Input('choose_loc', 'value'),
Input('choose_date', 'start_date'),
Input('choose_date', 'end_date')
]
)
def update_table(choose_cat, choose_loc, start_date, end_date):
df = ti_data.copy()
# df['date'] = pd.to_datetime(df['date'])
# df['date'] = df['date'].dt.date
if choose_cat is not None:
df = df[df['category'] == choose_cat]
if choose_loc is not None:
df = df[df['locale'] == choose_loc]
if start_date is not None and end_date is not None:
# start_date = datetime.datetime.strptime(start_date, "%Y-%m-%dT00:00:00").date()
# end_date = datetime.datetime.strptime(end_date, "%Y-%m-%dT00:00:00").date()
df = df.loc[(df.date >= start_date) & (df.date <= end_date)]
data = df.to_dict('records')
return data
#app.callback(
Output('datatable', 'style_data_conditional'),
Input('datatable', 'selected_columns')
)
def update_styles(selected_columns):
return [{
'if': {'column_id': column},
'background_color': '#D2F3FF'
} for column in selected_columns]
#app.callback(
Output('key_graph_l', 'figure'),
[
Input('choose_cat', 'value'),
Input('choose_loc', 'value'),
Input('choose_date', 'start_date'),
Input('choose_date', 'end_date')
]
)
def update_key_l(choose_cat, choose_loc, start_date, end_date):
df = ti_data.copy()
if choose_cat is not None:
df = df[df['category'] == choose_cat]
if choose_loc is not None:
df = df[df['locale'] == choose_loc]
if start_date is not None and end_date is not None:
df = df.loc[(df.date >= start_date) & (df.date <= end_date)]
df = df.sort_values('total_count', ascending=False)[:25]
figure = px.scatter(df, x='keyword', y='date', color='locale', size='total_count',labels={'keyword': 'Keyword', 'total_count': 'Total Count', 'locale': 'Locale', 'date': 'Date'},
title='Weighing top words accross locales')
return figure
# requirements for beanstalk (aws)
if __name__ == '__main__':
app.run_server(debug=True)

In Python dash - how to populate data-table after reading JSON file from callback memory

Want to create two data-table (table-1, table-2) which has individual data-frame as input data.
Rows in table-2 needs to be populated based on rows selected in table-1.
Not able to return data2, columns2 to populate table-2, as in case of table-1.
However, this works when returning entire data-table.
Problem is for further processing on table-2, need data-table properties, which can only be available if the callback function return data2, columns2.
import dash
from dash.dependencies import Input, Output, State
import dash_html_components as html
import dash_core_components as dcc
from datetime import date as dt
from datetime import timedelta
import dash_table
import pandas as pd
import os
os.chdir('C:\\Users\\......................')
from pbts import pbts_f
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
today = dt.today()
enddate = today.replace(day=1)
enddate = enddate - timedelta(days=1)
startdate = enddate - timedelta(days = 180)
startdate = startdate.replace(day=1)
enddate = startdate + timedelta(days = 3)
st = startdate
st = st.strftime('%Y%m%d')
ed = enddate
ed = ed.strftime('%Y%m%d')
n = 0.0
m = 0.0
(df1, df2) = pbts_f(st, ed, n, m)
app.layout = html.Div([
html.Div([
html.Div([
html.Label ('COB Date Range:', style = {'text-align' : 'left','padding-left' : 0}),
html.Div([
dcc.DatePickerRange(
id = 'COBdates',
min_date_allowed = dt(2019,1,1),
max_date_allowed = str(today),
start_date = startdate,
end_date = enddate
)
], style = {'padding' : 5, 'display': 'inline-block'}),
html.Div([html.Button('Submit Date Range', id = 'button')]),
], style = {'width': '40%', 'display': 'inline-block'}),
], style = {'padding' : 20}),
dcc.Tabs([
dcc.Tab(label='Tab1', children = [
html.Div([
html.Div([dash_table.DataTable(
id='table1',
columns = [{"name": i, "id": i} for i in df1.columns],
data = df1.to_dict('rows'),
sort_action='native',
filter_action='native',
row_selectable='multi',
)]),
])
]),
dcc.Tab(label='Tab2', children = [
html.Div([
html.Div(id = 'table2_memory', style = {'display' : 'none'}),
# html.Div(id='table3_div'),
html.Div([dash_table.DataTable(
id='table2',
data = [{}],
# data = df2.to_dict('rows'),
columns = [{"name": i, "id": i} for i in df2.columns],
sort_action='native',
filter_action='native',
row_selectable='multi',
)])
])
]),
], style = {'padding': 10}
),
])
#app.callback(
[Output('table1','data'), Output('table1','columns'),Output('table2_memory','children')],
[Input('button','n_clicks')],
[State('COBdates', 'start_date'), State('COBdates', 'end_date')]
)
def update_table1(n_clicks, start_date, end_date):
x = start_date
x = x[0:4] + x[5:7] + x[8:11]
st = x
y = end_date
y = y[0:4] + y[5:7] + y[8:11]
ed = y
(df1, df2) = pbts_f(st, ed, n, m)
columns1 = [{'name': i, 'id': i} for i in df1.columns]
data1 = df1.to_dict('records')
return data1, columns1, df2.to_json(date_format = 'iso', orient = 'split')
#app.callback(
[Output('table2', 'data'), Output('table2', 'columns')],
# [Output('table3_div', 'children')],
[Input('table1', "selected_rows"), Input('table2_memory', "children")],
[State('table1', "data")])
def update_table2(selected_rows, data, rows):
if selected_rows is None:
selected_rows = []
if rows is None:
dff1 = df1
else:
dff1 = pd.DataFrame(rows)
dff1 = dff1.iloc[selected_rows]
portfolioname = dff1['Portfolio_Name'].unique()
dff2 = pd.read_json(data, orient='split')
dff2 = dff2[dff2['Portfolio_Name'].isin (portfolioname)]
columns2 = [{"name": i, "id": i} for i in dff2.columns],
data2 = dff2.to_dict("rows")
return data2, columns2,
# return [html.Div([
# dash_table.DataTable(
# id='table2',
# columns = [{"name": i, "id": i} for i in dff2.columns],
# data = dff2.to_dict('rows'),
# style_cell = {'textAlign': 'left'},
# style_header = {'backgroundColor' : 'White', 'frontWeight' : 'bold'},
# sort_action='native',
# filter_action='native',
# row_selectable='multi',
# )]
# )]
if __name__ == '__main__':
app.run_server()

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