Hi! I am trying to use Dash Pages, but I am getting the below error:
A nonexistent object was used in an `Input` of a Dash callback. The id of this object is `dataframe_picker` and the property is `value`. The string ids in the current layout are: [data_refresh_interval_component, data_refresh_signal, last_updated_timer, CV_interval_component, CV_signal, last_validated_timer, hourly_forecast_interval_component, hourly_forecast_signal, daily_forecast_interval_component, daily_forecast_signal, _pages_location, _pages_content, _pages_store, _pages_dummy]
My app is structured as such:
- app.py
- pages
|-- alltime.py
|-- today.py
|-- home.py
This is in app.py:
# app instantiation
app = dash.Dash(__name__, use_pages=True,
external_stylesheets=[dbc.themes.LUX],
suppress_callback_exceptions=True)
server = app.server
# cache
CACHE_CONFIG = {
'CACHE_TYPE': 'FileSystemCache',
'CACHE_DIR': "cache/",
'CACHE_THRESHOLD': 20
}
cache = Cache()
cache.init_app(app.server, config=CACHE_CONFIG)
app.layout = html.Div([
html.H1('slrpEV Dashboard'),
html.Div(
[
html.Div([
dcc.Link(
f"All Time", href="/alltime"
),
dcc.Link(
f"Today", href="/today"
)
]),
html.Div([
dcc.Interval(
id="data_refresh_interval_component",
interval=60 * 60 * 1000, # update every 60 minutes
n_intervals=0
),
dcc.Store(id="data_refresh_signal"),
]),
html.Div(
id="last_updated_timer"
),
html.Div([
dcc.Interval(
id="CV_interval_component",
interval=14 * 24 * 60 * 60 * 1000, # update every two weeks
n_intervals=0
),
dcc.Store(id="CV_signal"),
]),
html.Div(
id="last_validated_timer"
),
html.Div([
dcc.Interval(
id="hourly_forecast_interval_component",
interval=60 * 60 * 1000, # update every 60 minutes
n_intervals=0
),
dcc.Store(id="hourly_forecast_signal"),
]),
html.Div([
dcc.Interval(
id="daily_forecast_interval_component",
interval=24 * 60 * 60 * 1000, # update every day
n_intervals=0
),
dcc.Store(id="daily_forecast_signal"),
]),
]
),
dash.page_container,
])
# jump to present button
@app.callback(
Output("date_picker", "start_date"),
Output("date_picker", "end_date"),
Input("jump_to_present_btn", "n_clicks")
)
def jump_to_present(button_press):
return get_last_days_datetime(7), get_last_days_datetime(-1)
@app.callback(
Output("daily_time_series", "figure"),
Input("data_refresh_signal", "data"),
)
def display_daily_time_series(signal):
# load data
data = update_data().get("dataframes")
data = data.get("todays_sessions")
# plot figure
fig = PlotDailySessionTimeSeries.plot_daily_time_series(data)
return fig
@app.callback(
Output("vehicle_pie_chart", "figure"),
Input("data_refresh_signal", "data"),
)
def display_vehicle_pie_chart(signal):
# load data
data = update_data().get("dataframes")
data = data.get("todays_sessions")
# plot figure
fig = PlotDailySessionEnergyBreakdown.plot_daily_energy_breakdown(data)
return fig
@app.callback(
Output("cumulative_energy_delivered", "figure"),
Input("date_picker", "start_date"),
Input("date_picker", "end_date"),
Input("data_refresh_signal", "data")
)
def display_cumulative_energy_figure(start_date, end_date, signal):
# load data
data = update_data().get("dataframes").get("raw_data")
# plot figure
fig = PlotCumulativeEnergyDelivered.plot_cumulative_energy_delivered(
data, start_date, end_date)
return fig
@app.callback(
Output("time_series_plot", "figure"),
Output("last_updated_timer", "children"),
Input("dataframe_picker", "value"),
Input("quantity_picker", "value"),
Input("date_picker", "start_date"),
Input("date_picker", "end_date"),
Input("toggle_forecasts", "value"),
Input("data_refresh_signal", "data"),
Input("hourly_forecast_signal", "data"),
Input("daily_forecast_signal", "data"),
)
def display_main_figure(granularity, quantity, start_date, end_date, forecasts, data_signal, hourly_forecast_signal, daily_forecast_signal):
# load data
data = update_data().get("dataframes")
data = data.get(granularity)
# update refresh timestamp
last_updated = update_data().get('last_updated_time')
# plot main time series
fig = PlotMainTimeSeries.plot_main_time_series(
data, granularity, quantity, start_date, end_date)
# plot predictions
if forecasts:
forecast_df = prediction_to_run(granularity)
fig = PlotForecasts.plot_forecasts(
fig, forecast_df, quantity, granularity)
return fig, f"Data last updated at {last_updated}."
@app.callback(
Output("num_sessions_user", "children"),
Output("avg_duration_user", "children"),
Output("freq_connect_time_user", "children"),
Output("total_nrg_consumed_user", "children"),
Input("daily_time_series", "hoverData"),
prevent_initial_callback=True
)
def display_user_hover(hoverData):
# place holder for no hover
if hoverData is None:
return "# of Sessions by User", "Avg. Stay Duration", "Frequent Connect Time", "Total Energy Consumed by User"
# load data
data = update_data().get("dataframes").get("raw_data")
# get user ID
userId = int(hoverData["points"][0]["customdata"][2])
# get user hover data
num_sessions, avg_duration, freq_connect, total_nrg = GetUserHoverData.get_user_hover_data(
data, userId)
text = (
f"User has been here {num_sessions} times!",
f"User charges on average {avg_duration} hours!",
f"User usually charges: {freq_connect}",
f"User has consumed {total_nrg} kWh to date!"
)
return text
@app.callback(
Output("data_refresh_signal", "data"),
Input("data_refresh_interval_component", "n_intervals"),
)
def data_refresh_interval(n):
update_data() # expensive process
return n
@app.callback(
Output("CV_signal", "data"),
Output("last_validated_timer", "children"),
Input("CV_interval_component", "n_intervals"),
)
def CV_interval(n):
params = update_ml_parameters() # expensive process
# calculate new models with ML parameters
return n, f"Parameters last validated {params['last_validated_time']}."
@app.callback(
Output("hourly_forecast_signal", "data"),
Input("hourly_forecast_interval_component", "n_intervals"),
Input("data_refresh_signal", "data"),
)
def hourly_forecast_interval(n, signal):
forecast_hourly()
return n
@app.callback(
Output("daily_forecast_signal", "data"),
Input("daily_forecast_interval_component", "n_intervals"),
Input("data_refresh_signal", "data"),
)
def daily_forecast_interval(n, signal):
forecast_daily()
return n
# Cached functions
@cache.memoize(timeout=3600) # refresh every hour
def update_data() -> dict:
print("Fetching data...")
raw_data = FetchData.scan_save_all_records()
print("Cleaning data...")
cleaned_dataframes = CleanData.clean_save_raw_data(raw_data)
print("Done!")
return {"dataframes": cleaned_dataframes, "last_updated_time": datetime.now().strftime('%H:%M:%S')}
@cache.memoize(timeout=1209600) # retrain every two weeks
def update_ml_parameters() -> dict:
# get parameters
hard_coded_params_hourly = {'energy_demand_kWh':
{'best_depth': 57, 'best_n_neighbors': 25},
'peak_power_W':
{'best_depth': 57, 'best_n_neighbors': 23},
'avg_power_demand_W':
{'best_depth': 57, 'best_n_neighbors': 25}
}
hard_coded_params_daily = {'energy_demand_kWh':
{'order': (2, 0, 1),
'seasonal_order': (0, 1, 2, 7)},
'peak_power_W':
{'order': (1, 0, 0),
'seasonal_order': (0, 1, 2, 7)},
'avg_power_demand_W':
{'order': (2, 0, 1),
'seasonal_order': (0, 1, 2, 7)}
}
best_params = {}
best_params["hourlydemand"] = hard_coded_params_hourly
best_params["dailydemand"] = hard_coded_params_daily
# clear predictions
CreateHourlyForecasts.save_empty_prediction_df()
CreateDailyForecasts.save_empty_prediction_df()
return {"best_params": best_params, "last_validated_time": datetime.now().strftime('%m/%d/%y %H:%M:%S')}
The Input id dataframe_picker
is present in alltime.py
. While it is true that the id dataframe_picker
is not present in app.py, doesn’t Dash pages automatically validate the layout? Any help would be appreciated! Thank you!
Edit: Here are page files:
import dash
import dash_bootstrap_components as dbc
from dash import html, dcc
from dash.dependencies import Output, Input, State
import dash_daq as daq
import pandas as pd
from datetime import timedelta
from app_utils import get_last_days_datetime
dash.register_page(__name__)
layout = html.Div(
[
html.Div([
html.Div([
dcc.DatePickerRange(
id="date_picker",
clearable=True,
start_date=get_last_days_datetime(7),
end_date=get_last_days_datetime(0),
start_date_placeholder_text="mm/dd/yyyy",
end_date_placeholder_text="mm/dd/yyyy",
with_portal=False
),
],
className="calendar"),
html.Div([
dcc.Dropdown(
id="dataframe_picker",
options=[
{'label': '5-Min', 'value': 'fivemindemand'},
{'label': 'Hourly', 'value': 'hourlydemand'},
{'label': 'Daily', 'value': "dailydemand"},
{'label': 'Monthly', 'value': 'monthlydemand'}
],
value='hourlydemand', # default value
clearable=False,
searchable=False
),
dcc.Dropdown(
id="quantity_picker",
options=[
{'label': 'Energy Demand',
'value': 'energy_demand_kWh'},
{'label': 'Average Power Demand',
'value': 'avg_power_demand_W'},
{'label': 'Peak Power Demand',
'value': 'peak_power_W'}
],
value='energy_demand_kWh', # default value
clearable=False,
searchable=False
),
]),
html.Button("Today", id="jump_to_present_btn"),
daq.ToggleSwitch(
label="Toggle Forecasts",
value=False,
id="toggle_forecasts",
)
]),
html.Div([
dcc.Graph(
id="time_series_plot",
config={
"displaylogo": False,
"modeBarButtonsToAdd": ["hoverCompare", "hoverClosest"]
}
)
]),
html.Div([
"Cumulative Energy Delivered",
dcc.Graph(
id="cumulative_energy_delivered",
config={
"displaylogo": False
}
),
]),
]
)
import dash
import dash_bootstrap_components as dbc
from dash import html, dcc
import dash_daq as daq
dash.register_page(__name__)
layout = html.Div(
[
html.Div([
html.Div([
"Today's Sessions",
dcc.Graph(
id="daily_time_series",
config={
"displaylogo": False,
"modeBarButtonsToAdd": ["hoverCompare", "hoverClosest"]
}
),
]),
"User Information",
html.Div([
html.Li("# of Sessions by User",
id="num_sessions_user"),
html.Li("Avg. Stay Duration", id="avg_duration_user"),
html.Li("Frequent Connect Time",
id="freq_connect_time_user"),
html.Li("Total Energy Consumed",
id="total_nrg_consumed_user")
],
id='user-information',
),
html.Div([
"Energy Breakdown",
dcc.Graph(
id="vehicle_pie_chart"
)
]),
]),
],
)