I want to apply Advanced Filtering to my dash_ag_grid code, similar to what’s shown in the AG Grid Documentation.
Please someone help me with it.
I want to know if its possible, and if so, any tips or methods on how to implement this would be greatly appreciated.
Below is the code I’m currently working with.
app.py:
from dash import Dash, Input, Output, html, dcc, State
import dash_ag_grid as dag
import requests, json
import flask
import pandas as pd
import pprint
from log import logger
app = Dash(__name__)
server = app.server
df = pd.read_csv(
"https://raw.githubusercontent.com/plotly/datasets/master/ag-grid/olympic-winners.csv"
)
df = df.dropna()
rowData = df.to_dict("records")
def filterDf(df, data, col):
operators = {
"greaterThanOrEqual": "ge",
"lessThanOrEqual": "le",
"lessThan": "lt",
"greaterThan": "gt",
"notEqual": "ne",
"equals": "eq",
}
if "filter" in data:
crit1 = data["filter"]
crit1 = pd.Series(crit1).astype(df[col].dtype)[0]
if "type" in data:
if data["type"] == "contains":
df = df.loc[df[col].str.contains(crit1, na=False)]
elif data["type"] == "notContains":
df = df.loc[~df[col].str.contains(crit1, na=False)]
elif data["type"] == "startsWith":
df = df.loc[df[col].str.startswith(crit1, na=False)]
elif data["type"] == "notStartsWith":
df = df.loc[~df[col].str.startswith(crit1, na=False)]
elif data["type"] == "endsWith":
df = df.loc[df[col].str.endswith(crit1, na=False)]
elif data["type"] == "notEndsWith":
df = df.loc[~df[col].str.endswith(crit1, na=False)]
elif data["type"] == "blank":
df = df.loc[df[col].isnull()]
elif data["type"] == "notBlank":
df = df.loc[~df[col].isnull()]
else:
df = df.loc[getattr(df[col], operators[data["type"]])(crit1)]
elif data["filterType"] == "set":
df = df.loc[df[col].isin(data["values"])]
return df
def extractRowsFromData(request, df):
response = []
logger.info(f"{pprint.pformat(request)}")
dff = df.copy()
if request["filterModel"]:
fils = request["filterModel"]
for k in fils:
try:
if "operator" in fils[k]:
if fils[k]["operator"] == "AND":
for fil in fils[k]["conditions"]:
dff = filterDf(dff, fil, k)
else:
dffs = []
for fil in fils[k]["conditions"]:
dffs.append(filterDf(dff, fil, k))
dff = pd.concat(dffs)
else:
dff = filterDf(dff, fils[k], k)
except:
pass
sorting = []
asc = []
if request["sortModel"]:
for sort in request["sortModel"]:
sorting.append(sort["colId"])
asc.append(sort["sort"] == "asc")
# dff = dff.sort_values(by=sorting, ascending=asc)
groupBy = []
if request["rowGroupCols"]:
groupBy = [i["id"] for i in request["rowGroupCols"]]
if groupBy:
group_counts = dff.groupby(groupBy).size().reset_index(name="childCount")
dff = dff.merge(group_counts, on=groupBy, how="left")
agg = {}
if request["valueCols"]:
agg = {i["id"]: i["aggFunc"] for i in request["valueCols"]}
if not request["groupKeys"]:
if groupBy:
if agg:
dff = dff.groupby(groupBy[0]).agg(agg).reset_index()
else:
dff = dff.groupby(groupBy[0]).agg("count").reset_index()
else:
for i in range(len(request["groupKeys"])):
dff = dff[dff[request["rowGroupCols"][i]["id"]] == request["groupKeys"][i]]
if len(request["groupKeys"]) != len(groupBy):
if agg:
dff = (
dff.groupby(groupBy[: len(request["groupKeys"]) + 1])
.agg(agg)
.reset_index()
)
else:
dff = (
dff.groupby(groupBy[: len(request["groupKeys"]) + 1])
.agg("count")
.reset_index()
)
if groupBy:
logger.info(f"sorting: {sorting}")
logger.info(f"asc: {asc}")
logger.info(f"groupBy[0]: {groupBy[0]}")
if groupBy[0] in sorting:
logger.info(f"dff: {dff.head()}")
logger.info(f"asc[0]: {asc[0]}")
dff = dff.sort_values(by="childCount", ascending=asc[0])
else:
dff = dff.sort_values(by=sorting, ascending=asc)
else:
dff = dff.sort_values(by=sorting, ascending=asc)
logger.info(f"{pprint.pformat(dff)}")
return {
"rowData": dff.to_dict("records")[request["startRow"] : request["endRow"]],
"rowCount": len(dff),
}
@server.route("/api/serverData", methods=["POST"])
def serverData():
response = extractRowsFromData(flask.request.json, df)
# logger.info(pprint.pformat(response))
return json.dumps(response)
grid = html.Div(
[
dag.AgGrid(
id="grid",
columnDefs=[
{"field": "country"},
{"field": "year"},
{"field": "athlete"},
{"field": "age"},
{"field": "date"},
{"field": "sport"},
{"field": "total"},
# {"field": "childCount", "hide": True}, # 기본적으로 숨김
],
defaultColDef={
"filter": True,
"sortable": True,
"resizable": True,
"enableRowGroup": True,
"enableValue": True,
"enablePivot": True,
},
dashGridOptions={
"rowSelection": "multiple",
"sideBar": True,
"rowGroupPanelShow": "always",
"suppressRowGroupHidesColumns": True,
"getChildCount": {"function": "getChildCount(params)"},
},
enableEnterpriseModules=True,
rowModelType="serverSide",
style={"overflow": "auto", "resize": "both", "height": "60vh"},
),
]
)
app.layout = html.Div(
[
dcc.Markdown("Example: Organisational Hierarchy using Tree Data "),
grid,
]
)
app.clientside_callback(
"""async function (id) {
const updateData = (grid) => {
var datasource = createServerSideDatasource();
grid.setServerSideDatasource(datasource);
};
var grid;
grid = await window.dash_ag_grid.getApiAsync(id)
if (grid) {
updateData(grid)
}
return window.dash_clientside.no_update
}""",
Output("grid", "id"),
Input("grid", "id"),
)
if __name__ == "__main__":
app.run(debug=True)
assets\dashAgGridFunctions.js :
async function getServerData(request) {
response = await fetch('./api/serverData', {'method': 'POST', 'body': JSON.stringify(request),
'headers': {'content-type': 'application/json'}})
return response.json()
}
function createServerSideDatasource() {
const dataSource = {
getRows: async (params) => {
console.log('ServerSideDatasource.getRows: params = ', params);
var result = await getServerData(params.request);
console.log('getRows: result = ', result);
params.success(result);
},
};
return dataSource;
}
var dagfuncs = window.dashAgGridFunctions = window.dashAgGridFunctions || {};
dagfuncs.getChildCount = function(data) {
// here child count is stored in the 'childCount' property
// console.log('data = ', data);
return data.childCount;
}