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)
Related
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.
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.
I am trying to apply callbacks between different dash pages. I have setup my app components in different files:
Hotspot_App.py
index.py
folder apps
GeoPlot.py
ScatterPlot.py
So the first page contains the layout of app1 and it's callbacks and components. But now I want to create a checklist in the second tab on the values that have been selected on a checklist in tab1. I tried to create the app.validation layout in the index but that does not work. See below my code:
Index.py
import dash_bootstrap_components as dbc
import dash_html_components as html
from dash.dependencies import Input, Output
import dash_auth
import dash_core_components as dcc
from Hotspot_App_Local import app
from apps import GeoPlot, ScatterPlot
app.title = 'Hotspot Analysis'
auth = dash_auth.BasicAuth(
app,
VALID_USERNAME_PASSWORD_PAIRS
)
scr_oord = 'www.animage.com' #dummy
nav_item = dbc.NavItem(dbc.NavLink("website.com", href="https://www.website.com/"))
dropdown_menu = dbc.DropdownMenu(
children=[
dbc.DropdownMenuItem("GeoPlot", href= "/page-1"),
dbc.DropdownMenuItem("ScatterPlot", href= "/page-2"),
],
nav=True,
in_navbar=True,
label="Menu",
)
navbar = html.Div([dbc.Navbar(
dbc.Container(
[
html.A(
# Use row and col to control vertical alignment of logo / brand
dbc.Row(
[
dbc.Col(html.Img(src= scr_oord, height="50px")),
dbc.Col(dbc.NavbarBrand("\tHotspot Analysis", className="ml-2", style= {'color': 'navy', 'font-weight': 'bold'})),
],
align="center",
no_gutters=True,
),
href="https://plot.ly",
),
dbc.NavbarToggler(id="navbar-toggler2"),
dbc.Collapse(
dbc.Nav(
[nav_item, dropdown_menu], className="ml-auto", navbar=True
),
id="navbar-collapse2",
navbar=True,
),
]
),
color="white",
dark= False,
className="mb-5",
),
html.Div(id= 'page_content')
])
app.layout = html.Div([
dcc.Location(id= 'tab', refresh= False, pathname= "/page-1"),
navbar,
html.Div(id= 'page')
])
app.validation_layout = html.Div([navbar, GeoPlot.layout, ScatterPlot.layout])
#app.callback(Output("page", "children"), [Input("tab", "pathname")])
def display_page(pathname):
if pathname == "/page-1":
return GeoPlot.layout
if pathname == "/page-2":
return ScatterPlot.layout
# if not recognised, return 404 message
return html.P("404 - page not found")
if __name__ == '__main__':
app.run_server(debug=True)
app.py
import dash_bootstrap_components as dbc
import dash
app = dash.Dash(__name__, suppress_callback_exceptions=True, external_stylesheets=[dbc.themes.BOOTSTRAP])
server = app.server
Geoplot.py
import dash_bootstrap_components as dbc
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output, State, ALL, MATCH
import plotly.graph_objects as go
import pandas as pd
import flask
import ast
from flask import send_file
import io
import datetime
from Hotspot_App_Local import app
from Cards import Cards
df = pd.read_csv('merged_layers.csv')
df = df.round(2)
available_indicators = ['PercBelowMSL', 'PopDens2015', 'RPC4.5', 'PortDist', 'RPC8.5']
df['text'] = 'TotPop2020: '+ round(df["TotPop2020"], 0).astype(str)
Storedata = dcc.Store(id= 'store_columns')
Dropdown = dcc.Dropdown(id= 'Chose setting',
options= [
{'label': 'Marine', 'value': 'Marine'},
{'label': 'Environmental', 'value': 'Env'},
{'label': 'Urban', 'value': 'Urban'},
{'label': 'Ports', 'value': 'Ports'}
], value= 'Marine', clearable= False)
card2 = Cards('Select The Setting', [Storedata, Dropdown], Header= True)
checkbox = dbc.Checklist(id = 'col_list')
card3 = Cards('Select The Layers', [checkbox], Header= True)
htmlA = html.A([dbc.Button("Store Values", color= 'success', block= True)], id= 'store-values')
#csvbutton = dbc.Button('Store Values', id= 'csv', block= True)
card4 = Cards('', [htmlA])
sizer = 2 * df['PopDens2020'].max() / (30 ** 2)
fig = go.Figure(data=go.Scattermapbox(
lon = df['center_lon'],
lat = df['center_lat'],
text = df['text'],
mode = 'markers',
marker= go.scattermapbox.Marker(
color= df['PopDens2020'],
cmin = df['PopDens2020'].min(),
cmax= df['PopDens2020'].max(),
colorscale = 'Viridis',
colorbar=dict(
title="PopDens2020"
),
showscale= True,
size= df['PopDens2020'],
sizeref= sizer,
sizemode= 'area'
),
))
fig.update_layout(
title= {'text': f'{len(df)} Hotspot Locations',
'font': {
'size': 36,
'color': 'darkblue'
},
'xref': 'container',
'x': 0.5},
geo_scope='world',
mapbox_style= 'open-street-map',
width= 1200,
height= 800
)
hotspotgraph = dcc.Graph(id= 'Hotspot_Plot', figure= fig)
card5 = Cards("", [hotspotgraph], Header= False)
rangeslider = html.Div(id='RangeSlider', children=[])
card6 = Cards("Select the Range", [rangeslider], Header= True)
size = dcc.Dropdown(id= 'markersize')
card7 = Cards('Select Markersize', [size], Header= True)
color = dcc.Dropdown(id= 'markercolor')
card8 = Cards('Select Markercolor', [color], Header= True)
layout = html.Div(
[
dbc.Row(
[
dbc.Col([
dbc.Col(dbc.Card(card2, color="light", outline=True)),
dbc.Col(dbc.Card(card3, color="light", outline=True)),
dbc.Col(dbc.Card(card4, color="light", outline=True)),
dbc.Row([
dbc.Col(dbc.Card(card7, color="light", outline= True)),
dbc.Col(dbc.Card(card8, color="light", outline= True))
])
]),
dbc.Col(dbc.Card(card5, color="light", outline=True)),
],
className="mb-4",
),
dbc.Row(
[
dbc.Col(dbc.Card(card6, color="light", outline=True), md= 12),
],
className="mb-4",
),
]
)
#app.callback(
Output('store_columns', 'data'),
[Input('Chose setting', 'value')]
)
def change_cols(value):
if value == 'Marine':
data = ['PortDist', 'PercBelow-5m', 'RPC4.5', 'RPC8.5']
if value == 'Urban':
data = ['PopDens2020', 'area']
if value == 'Env':
data = ['ManPc2016', 'WWCrAr2018', 'count_PA', 'NearestDist_PA']
if value == 'Ports':
data = ['RPC4.5', 'PortDist']
return data
#app.callback(
Output('col_list', 'options'),
[Input('store_columns','data')],
)
def change_multiselect(data):
if data is not None:
return [{'label': i, 'value': i} for i in sorted(data)]
#app.callback(
Output('col_list', 'value'),
[Input('store_columns','data')]
)
def change_multiselect(data):
return sorted(data)
#app.callback(
Output('markersize', 'options'),
[Input('col_list','value')]
)
def markersize(values):
default = ['PopDens2020']
default.extend(values)
return [{'label': value, 'value': value} for value in default]
#app.callback(
Output('markersize', 'value'),
[Input('col_list','value')]
)
def markersize(values):
return 'PopDens2020'
#app.callback(
Output('markercolor', 'options'),
[Input('col_list','value')]
)
def markersize(values):
default = ['PopDens2020']
default.extend(values)
return [{'label': value, 'value': value} for value in default]
#app.callback(
Output('markercolor', 'value'),
[Input('col_list','value')]
)
def markersize(values):
return 'PopDens2020'
#app.callback(
Output('RangeSlider', 'children'),
[Input('col_list', 'value')],
[State('RangeSlider', 'children')])
def display_dropdowns(value, ranges):
df = pd.read_csv('merged_layers.csv')
lst = []
if value != None:
for v in value:
fig = go.Figure()
fig.add_trace(go.Histogram(x = df[v]))
fig.add_shape(
dict(
type='line',
yref='paper', y0=0, y1=1,
x0=df[v].median(), x1=df[v].median()
)
)
hist = dcc.Graph(id={'type': 'histogram', 'index': v}, figure=fig)
reset_button = dbc.Button('Reset Values',id={'type': 'reset_button', 'index': v}, block= True, color= 'danger')
card_button = Cards("", [reset_button])
min = df[v].min()
max = df[v].max()
range_slider = dcc.RangeSlider(
id={
'type': 'range_slider',
'index': v
}, tooltip={'always_visible': True, 'placement': 'bottomRight'}, min=min, max=max, value=[min, max], step= 0.01)
store_minmax = dcc.Store(id={'type': 'store', 'index': v}, data= [min, max])
card_slider = Cards(f'{v}', [range_slider, store_minmax], Header= True)
marklen = dcc.Markdown(children= f'**{len(df)} Hotspot Locations**', id={'type': 'len_df', 'index': v},
style= {'textAlign': 'center', 'color': 'darkblue', 'font-size': 25})
card_hist = Cards(f"", [marklen, hist])
ap = html.Div([
dbc.Row(
[
dbc.Col([
dbc.Col(dbc.Card(card_slider, color="light", outline=True)),
dbc.Col(dbc.Card(card_button, color= "light", outline= True))], md= 6),
dbc.Col(dbc.Card(card_hist, color="light", outline=True), md=6)
],
className="mb-4",
),
])
lst.append(ap)
return lst
#app.callback(
Output({'type': 'len_df', 'index': ALL}, 'children'),
[Input({'type': 'range_slider', 'index': ALL}, 'value')],
[State('col_list', 'value'),
State({'type': 'len_df', 'index': ALL}, 'children')]
)
def store_len_df(values, cols, text):
df = pd.read_csv('merged_layers.csv')
for i in range(len(cols)):
min = values[i][0]
max = values[i][1]
df = df[df[cols[i]].between(min, max)]
text = [f'**{len(df)} Hotspot Locations**'] * len(text)
return text
#app.callback(
Output({'type': 'histogram', 'index': MATCH}, 'figure'),
[Input({'type': 'range_slider', 'index': MATCH}, 'value')],
[State({'type': 'histogram', 'index': MATCH}, 'figure')])
def add_verts(range, fig):
fig['layout']['shapes'] = [{'type': 'line', 'x0': range[0], 'x1': range[0], 'y0': 0, 'y1': 1, 'yref': 'paper'},
{'type': 'line', 'x0': range[1], 'x1': range[1], 'y0': 0, 'y1': 1, 'yref': 'paper'}]
return fig
#app.callback(
Output({'type': 'range_slider', 'index': MATCH}, 'value'),
[Input({'type': 'reset_button', 'index': MATCH}, 'n_clicks')],
[State({'type': 'store', 'index': MATCH}, 'data')])
def reset(click, data):
return data
#app.callback(
Output('Hotspot_Plot', 'figure'),
[Input({'type': 'range_slider', 'index': ALL}, 'value'),
Input('markersize', 'value'),
Input('markercolor', 'value')],
[State('col_list', 'value'),
State('Hotspot_Plot', 'figure'),]
)
def update_figure(values, col_size, col_color, cols, fig):
if cols is not None and len(values) > 0 and len(cols) > 0:
df = pd.read_csv('merged_layers.csv')
if col_size != col_color:
df['text'] = f'{col_size}: ' + round(df[col_size], 0).astype(str) + '\n' + f'{col_color}: ' + round(df[col_color], 0).astype(str)
else:
df['text'] = f'{col_size}: ' + round(df[col_size], 0).astype(str)
size_series = df[col_size]
for value in df[col_size]:
if value < 0:
size_series += abs(df[col_size].min()) + 0.01 #No Negative Values Allowed
break
color_series = df[col_color]
sizer = 2 * df[col_size].max() / (30 ** 2)
for i in range(len(cols)):
min = values[i][0]
max = values[i][1]
df = df[df[cols[i]].between(min, max)]
fig['data'][0]['lat'] = df['center_lat']
fig['data'][0]['lon'] = df['center_lon']
fig['data'][0]['marker'] = go.scattermapbox.Marker(
color= color_series,
cmin = color_series.min(),
cmax= color_series.max(),
colorscale = 'Viridis',
colorbar=dict(
title= col_color
),
showscale=True,
size= size_series,
sizeref=sizer,
sizemode='area'
)
fig['data'][0]['text'] = df['text']
fig['layout']['title']['text'] = f'{len(df)} Hotspot Locations'
return fig
#app.callback(
Output('store-values', 'href'),
[Input('col_list', 'value'),
Input({'type': 'range_slider', 'index': ALL}, 'value'),
Input('Chose setting', 'value')])
def update_link(columns, ranges, setting):
return '/dash/urlToDownload?value={}*{}*{}'.format(columns, ranges, setting)
#app.server.route('/dash/urlToDownload')
def download_excel():
data = flask.request.args.get('value').split('*')
columns = ast.literal_eval(data[0])
ranges = ast.literal_eval(data[1])
setting = data[2]
minlst, maxlst= [], []
for r in ranges:
min, max = r
minlst.append(min)
maxlst.append(max)
range_df = pd.DataFrame(list(zip(columns, minlst, maxlst)), columns=['Column', 'Min_Value', 'Max_Value'])
df = pd.read_csv('Dash/merged_layers.csv')
for (i, range) in enumerate(ranges):
min, max = range
df = df[df[columns[i]].between(min, max)]
center_lon = df['center_lon'].values
center_lat = df['center_lat'].values
country = df['country'].values
loc_df = pd.DataFrame(list(zip(center_lon, center_lat, country)), columns= ['center_lon', 'center_lat', 'country'])
loc_df = loc_df.sort_values('country')
buf = io.BytesIO()
excel_writer = pd.ExcelWriter(buf, engine="xlsxwriter")
range_df.to_excel(excel_writer, sheet_name="Ranges", index=False)
loc_df.to_excel(excel_writer, sheet_name="Locations", index=False)
excel_writer.save()
excel_data = buf.getvalue()
buf.seek(0)
now = datetime.datetime.now()
today = str(now.year) + '-' + str(now.month) + '-' + str(now.day)+ ' ' + str(now.hour) + str(":") + str(now.minute)
return send_file(
buf,
mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
attachment_filename=f"{setting}_{today}.xlsx",
as_attachment=True,
cache_timeout=0
)
Scatterplot.py
import dash_html_components as html
import dash_core_components as dcc
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State, ALL, MATCH
from Hotspot_App_Local import app
from Cards import Cards
test = dcc.Checklist(id= 'scatterlst')
card1 = Cards('Test', test, Header= True)
layout = html.Div(
dbc.Row(dbc.Card(card1, color="light", outline=True))
)
#app.callback(
Output('scatterlst', 'value'),
[Input('col_list','value')]
)
def change_multiselect(data):
print('hi')
print(data)
return sorted(data)
So the problem is that Scatterplot.py does not recognizes the indexes from Geoplot.py.
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()
I would like to select dates in several tables, using dash_table . This works when using a different date picker for each table, but not when using a single date picker for all separate tables.
A simple reproducible example shows a single table, and data can be selected and displayed for different dates (here 1st, 2nd, or 3rd January).
My question: how to make three tables, – one for each country -, using a single date picker (not three). Thank you very much in advance for any suggestions!
Modules
import pandas as pd
import plotly.graph_objs as go
import dash
import dash_table
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State, Event
import datetime
from datetime import datetime as dt
Fictive DataFrame
df = pd.DataFrame({'dd':['2019-01-01', '2019-01-01', '2019-01-01', '2019-01-02', '2019-01-02', '2019-01-02', '2019-01-03', '2019-01-03'], 'country':['Belgium', 'Belgium','France', 'France', 'Belgium', 'France', 'Belgium', 'Germany'], 'value':[10,20,30,10,15,25,5,70]})
Script
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.config['suppress_callback_exceptions']=True
currentday = 1
currentmonth = 1
currentyear = 2019
app.layout = html.Div(
[
html.H4('All countries'),
dcc.DatePickerSingle(
id='my-date-picker-single1',
min_date_allowed=dt(2012, 1, 1),
max_date_allowed=dt(2019, 2, 25),
initial_visible_month=dt(currentyear, currentmonth, currentday),
date=dt(currentyear, currentmonth, currentday),
disabled=False
),
dcc.Store(id="selected-rows1", storage_type="memory"),
html.Div(id="tables-container1"),
dash_table.DataTable(
id="table1",
columns=[{"name": i, "id": i} for i in ['dd', 'country', 'value'] ],
style_cell_conditional=[
{
'if':{'filter':'Country eq "France"'},
'backgroundColor':'rgb(150, 150, 150)'
}
] + [
{'if': {'column_id': c},
'textAlign': 'left'
} for c in ['dd', 'country']
],
sorting=True,
sorting_type='multi',
sorting_settings=[],
)
]
)
#app.callback(
Output("selected-rows1", "data"),
[Input("my-date-picker-single1", "date")],
[State("selected-rows1", "data")],
)
def display_output(value, storage):
if value is not None:
return {"selected_rows1": df[df["dd"].str.contains(value)].to_json()}
#app.callback(
Output("table1", "data"),
[Input("table1", "sorting_settings"), Input("selected-rows1", "data")],
)
def update_graph(sorting_settings, rows):
_df = pd.read_json(rows["selected_rows1"])
if sorting_settings is not None and len(sorting_settings):
for setting in sorting_settings:
_df.sort_values(
by=setting["column_id"],
ascending=(setting["direction"] == "asc"),
inplace=True,
)
return _df.to_dict("rows")
else:
return _df.to_dict("rows")
if __name__ == "__main__":
app.run_server(debug=True)
Your advice is highly appreciated!
You should use multiple callbacks. Check section on "Multiple Outputs". Example:
#app.callback(
Output("selected-rows1", "data"),
[Input("my-date-picker-single1", "date")],
[State("selected-rows1", "data")])
def display_output_1(value, storage):
if value is not None:
return {"selected_rows1": df[df["dd"].str.contains(value)].to_json()}
#app.callback(
Output("selected-rows2", "data"),
[Input("my-date-picker-single1", "date")],
[State("selected-rows2", "data")])
def display_output_2(value, storage):
if value is not None:
return {"selected_rows2": df[df["dd"].str.contains(value)].to_json()}