I have the following minimal example that shows a multi-page app, in which I have a map and an AG Grid.
app.py
import dash
from dash import dcc # pip install dash
import dash_bootstrap_components as dbc # pip install dash-bootstrap-components
import plotly.express as px
df = px.data.carshare()
# convert dataframe to list of dictionaries because dcc.Store
# accepts dict | list | number | string | boolean
df = df.to_dict('records')
app = dash.Dash(
__name__, external_stylesheets=[dbc.themes.FLATLY], suppress_callback_exceptions=True, use_pages=True
)
navbar = dbc.NavbarSimple(
dbc.DropdownMenu(
[
dbc.DropdownMenuItem(page["name"], href=page["path"])
for page in dash.page_registry.values()
if page["module"] != "pages.not_found_404"
],
nav=True,
label="More Pages",
),
brand="Multi Page App Plugin Demo",
color="primary",
dark=True,
className="mb-2",
)
app.layout = dbc.Container(
[navbar,dash.page_container,
dcc.Store(id="stored-data", data=df),
dcc.Store(id="store-dropdown-value", data=None)
],
fluid=True)
if __name__ == "__main__":
app.run_server(debug=True, port=8050)
pages/table.py
import dash
import dash_ag_grid as dag
dash.register_page(__name__)
from dash import html, Input, Output, callback
import pandas as pd
columnDefs = [
{"field": "centroid_lat","maxWidth": 300},
{"field": "centroid_lon","maxWidth": 300},
{"field": "car_hours","filter": "agNumberColumnFilter", "maxWidth": 300},
{"field": "peak_hour", "filter": "agNumberColumnFilter", "maxWidth": 300},
]
layout = html.Div(
[
html.Div(id="table-container", children=[]),
]
)
@callback(Output("table-container", "children"),
Input("stored-data", "data")
)
# def populate_checklist(data, day):
def populate_checklist(data):
dff = pd.DataFrame(data)
my_table = dag.AgGrid(
id='table',
rowData=dff.to_dict("records"),
columnSize="sizeToFit",
columnDefs=columnDefs,
defaultColDef={"resizable": True, "sortable": True, "filter": True},
dashGridOptions={"pagination": True,
"enableCellTextSelection": True,
"ensureDomOrder": True,
"rowSelection": 'simple',},
# getRowId="params.data.State",
persistence_type ='session',
persisted_props=["selectedRows"],
persistence=True,
style={"height": "80vh",}
)
return my_table
pages/map.py
import dash
import dash_leaflet as dl
import dash_leaflet.express as dlx
dash.register_page(__name__, path="/")
from dash import html, Input, Output, callback
layout = html.Div(
[
html.P("Choose Day:"),
# html.Div(id="dropdown-container", children=[]),
html.Div(id="map-container", children=[]),
]
)
@callback(
Output("map-container", "children"),
Input("stored-data", "data")
)
def graph_and_table(data):
return [dl.Map([
dl.TileLayer(),
# From in-memory geojson. All markers at same point forces spiderfy at any zoom level.
dl.GeoJSON(data=dlx.dicts_to_geojson(data, lon="centroid_lon", lat="centroid_lat"), cluster=True,zoomToBoundsOnClick=True,
superClusterOptions={"radius": 100}),
], center=(45.471549, -73.588684), zoom=11, style={'height': '50vh'})]
While working on this Dash app, I’m encountering two main issues:
Preserving Filtered Data in AG Grid:
I have implemented AG Grid with persistence=True
, intending to keep the data filtered across different pages. However, the filtered data doesn’t seem to persist when navigating between pages. My goal is to plot only the filtered data on a map. How can I ensure that the filtered data in the AG Grid table is maintained when the page changes?
Efficient Data Sharing Between Pages:
Currently, I’m using dcc.Store
to share data between pages. However, my dataset is quite large, making dcc.Store unsuitable for this purpose. I’m considering using Flask-Cache with the filesystem for better performance. Unfortunately, I’m struggling to integrate Flask-Cache into my app successfully. Are there any resources or advice available for implementing this? I’m aware of this resource (GitHub - AnnMarieW/dash-multi-page-app-demos: Minimal examples of multi-page apps using Dash Pages), but it hasn’t solved my specific problem.
Any insights or assistance would be greatly appreciated!