Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve performance of dash-ag-grid #73

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
90 changes: 85 additions & 5 deletions depictio/dash/layouts/stepper_parts/part_one.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ def register_callbacks_stepper_part_one(app):
Input({"type": "datacollection-selection-label", "index": MATCH}, "value"),
Input({"type": "btn-option", "index": MATCH, "value": ALL}, "n_clicks"),
State({"type": "last-button", "index": MATCH}, "data"),
State({"type": "workflow-selection-label", "index": MATCH}, "id"),
prevent_initial_call=True,
)
def update_step_1(workflow_selection, data_collection_selection, input_btn_values, component_selected):
def update_step_1(workflow_selection, data_collection_selection, input_btn_values, component_selected, id):
# Use dcc.Store in store-list to get the latest button clicked using timestamps

logger.info(f"CTX Triggered ID: {ctx.triggered_id}")
Expand Down Expand Up @@ -184,7 +185,7 @@ def update_step_1(workflow_selection, data_collection_selection, input_btn_value
cols = get_columns_from_data_collection(workflow_selection, data_collection_selection)
logger.info(f"Columns: {cols}")
columnDefs = [{"field": c, "headerTooltip": f"Type: {e['type']}"} for c, e in cols.items()]

# if description in col sub dict, update headerTooltip
for col in columnDefs:
if "description" in cols[col["field"]] and cols[col["field"]]["description"] is not None:
Expand All @@ -199,15 +200,23 @@ def update_step_1(workflow_selection, data_collection_selection, input_btn_value
# print(df.head(20).to_dict("records"))
# cellClicked, cellDoubleClicked, cellRendererData, cellValueChanged, className, columnDefs, columnSize, columnSizeOptions, columnState, csvExportParams, dangerously_allow_code, dashGridOptions, defaultColDef, deleteSelectedRows, deselectAll, detailCellRendererParams, enableEnterpriseModules, exportDataAsCsv, filterModel, getDetailRequest, getDetailResponse, getRowId, getRowStyle, getRowsRequest, getRowsResponse, id, licenseKey, masterDetail, paginationGoTo, paginationInfo, persisted_props, persistence, persistence_type, resetColumnState, rowClass, rowClassRules, rowData, rowModelType, rowStyle, rowTransaction, scrollTo, selectAll, selectedRows, style, suppressDragLeaveHidesColumns, updateColumnState, virtualRowData
grid = dag.AgGrid(
id="get-started-example-basic",
# FIXME : full polars
rowData=df.head(2000).to_pandas().to_dict("records"),
id={"type": "get-started-example-basic", "index": id["index"]},
rowModelType="infinite",
columnDefs=columnDefs,
dashGridOptions={
"tooltipShowDelay": 500,
"pagination": True,
"paginationAutoPageSize": False,
"animateRows": False,
# The number of rows rendered outside the viewable area the grid renders.
"rowBuffer": 0,
# How many blocks to keep in the store. Default is no limit, so every requested block is kept.
"maxBlocksInCache": 2,
"cacheBlockSize": 100,
"cacheOverflowSize": 2,
"maxConcurrentDatasourceRequests": 2,
"infiniteInitialRowCount": 1,
"rowSelection": "multiple",
},
columnSize="sizeToFit",
defaultColDef={"resizable": True, "sortable": True, "filter": True},
Expand Down Expand Up @@ -286,3 +295,74 @@ def update_step_1(workflow_selection, data_collection_selection, input_btn_value
color=component_metadata_dict[component_selected]["color"],
leftSection=DashIconify(icon=component_metadata_dict[component_selected]["icon"], width=15, color=component_metadata_dict[component_selected]["color"]),
)

@app.callback(
Output({"type": "get-started-example-basic", "index": MATCH}, "getRowsResponse"),
Input({"type": "get-started-example-basic", "index": MATCH}, "getRowsRequest"),
Input({"type": "workflow-selection-label", "index": MATCH}, "value"),
Input({"type": "datacollection-selection-label", "index": MATCH}, "value"),
prevent_initial_call=True,
)
def infinite_scroll(request, workflow_selection, data_collection_selection):
# simulate slow callback
# time.sleep(2)

if request is None:
return dash.no_update

if workflow_selection is not None and data_collection_selection is not None:

workflow_id, data_collection_id = return_mongoid(workflow_tag=workflow_selection, data_collection_tag=data_collection_selection)

dc_specs = httpx.get(
f"{API_BASE_URL}/depictio/api/v1/datacollections/specs/{workflow_id}/{data_collection_id}",
headers={
"Authorization": f"Bearer {TOKEN}",
},
).json()

if dc_specs["config"]["type"] == "Table":
df = load_deltatable_lite(workflow_id, data_collection_id)

partial = df[request["startRow"] : request["endRow"]]
return {"rowData": partial.to_dicts(), "rowCount": df.shape[0]}
else:
return dash.no_update
else:
return dash.no_update

@app.callback(
Output({"type": "table-aggrid", "index": MATCH}, "getRowsResponse"),
Input({"type": "table-aggrid", "index": MATCH}, "getRowsRequest"),
Input({"type": "stored-metadata-component", "index": MATCH}, "data"),
# prevent_initial_call=True,
)
def infinite_scroll_component(request, stored_metadata):
# simulate slow callback
# time.sleep(2)

if request is None:
return dash.no_update

if stored_metadata is not None:
logger.info(f"Stored metadata: {stored_metadata}")

workflow_id = stored_metadata["wf_id"]
data_collection_id = stored_metadata["dc_id"]

dc_specs = httpx.get(
f"{API_BASE_URL}/depictio/api/v1/datacollections/specs/{workflow_id}/{data_collection_id}",
headers={
"Authorization": f"Bearer {TOKEN}",
},
).json()

if dc_specs["config"]["type"] == "Table":
df = load_deltatable_lite(workflow_id, data_collection_id)

partial = df[request["startRow"] : request["endRow"]]
return {"rowData": partial.to_dicts(), "rowCount": df.shape[0]}
else:
return dash.no_update
else:
return dash.no_update
28 changes: 20 additions & 8 deletions depictio/dash/modules/table_component/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,23 @@ def build_table_frame(index, children=None):


from depictio.api.v1.configs.config import logger


def build_table(**kwargs):
logger.info("build_table")
logger.info("build_table")
# def build_card(index, title, wf_id, dc_id, dc_config, column_name, column_type, aggregation, v, build_frame=False):
index = kwargs.get("index")
wf_id = kwargs.get("wf_id")
dc_id = kwargs.get("dc_id")
dc_config = kwargs.get("dc_config")
cols = kwargs.get("cols_json")
build_frame = kwargs.get("build_frame", False)
import polars as pl

df = kwargs.get("df", pl.DataFrame())


# Load deltatable from the selected data collection
df = load_deltatable_lite(wf_id, dc_id)
if df.is_empty():
df = load_deltatable_lite(wf_id, dc_id)

# Add dah aggrid filters to the columns
for c in cols:
Expand All @@ -69,17 +72,26 @@ def build_table(**kwargs):
# print(cols)
columnDefs = [{"field": c, "headerTooltip": f"Column type: {e['type']}", "filter": e["filter"]} for c, e in cols.items()]

# TODO: use other properties of Dash AgGrid
# Prepare ag grid table
table_aggrid = dag.AgGrid(
id={"type": "table-aggrid", "index": str(index)},
rowData=df.to_dict("records"),
# rowData=df.to_pandas().to_dict("records"),
rowModelType="infinite",
columnDefs=columnDefs,
dashGridOptions={
"tooltipShowDelay": 500,
"pagination": True,
# "paginationAutoPageSize": False,
# "animateRows": False,
"paginationAutoPageSize": False,
"animateRows": False,
# The number of rows rendered outside the viewable area the grid renders.
"rowBuffer": 0,
# How many blocks to keep in the store. Default is no limit, so every requested block is kept.
"maxBlocksInCache": 2,
"cacheBlockSize": 100,
"cacheOverflowSize": 2,
"maxConcurrentDatasourceRequests": 2,
"infiniteInitialRowCount": 1,
"rowSelection": "multiple",
},
# columnSize="sizeToFit",
defaultColDef={"resizable": True, "sortable": True, "filter": True},
Expand Down