How to have more than 2 filter conditions in Dash AG Grid?

Hi guys!

I have a Ag-grid with some columns, one is a date-column and I’m trying to filter out specific dates with a Callback function. I can’t figure out how to do this and hope you guys can help or guide me :slight_smile:

Example table:

Date_column / Number_column …
2023-10-01… …1
2023-10-02… …2
2023-10-03… …3
2023-10-04… …4
2023-10-05… …5
2023-10-06… …6

I know what dates I want to filter out, let’s say in this example I want to filter out these dates:

[2023-10-01,
2023-10-04,
2023-10-05]

How can this be done?

(I first tried to use filterModel with ‘operator’: ‘OR’ and ‘conditions’, but this only supports two conditions…)

Hi @Mackan

This page has not yet made it’s way into the Dash docs yet, but it’s possible to have many filter conditions:

The maximum number of Filter Conditions can be controlled by setting the Filter Parameter maxNumConditions (the default value is two).

For complete info, see the AG Grid docs:

Note --if you have AG Grid Enterprise, you could also use the Set Filters .

Here’s a Dash version of the example in the AG Grid docs:

Example: Simple Filter Conditions

The following example demonstrates Filter Condition configuration that can be applied to any Simple Filter.

  • The Athlete column shows a Text Filter with default behaviour for all options.
  • The Country column shows a Text Filter with filterOptions set to show a different list of available options, and defaultOption set to change the default option selected.
  • The Sport column shows a Text Filter with maxNumConditions set to 10 so that up to ten conditions can be entered.
  • The Age column has a Number Filter with numAlwaysVisibleConditions set to 2 so that two conditions are always shown. The defaultJoinOperator is also set to 'OR' rather than the default ('AND').
  • The Date column has a Date Filter with maxNumConditions set to 3. See the Dash docs for more info on formatting dates for the date filter.
import dash_ag_grid as dag
from dash import Dash, html
import pandas as pd

app = Dash(__name__)


df = pd.read_csv(
    "https://raw.githubusercontent.com/plotly/datasets/master/ag-grid/olympic-winners.csv"
)

columnDefs = [
    {"field": "athlete"},
    {
        "field": "country",
        "filterParams": {
            "filterOptions": ["contains", "startsWith", "endsWith"],
            "defaultOption": "startsWith",
        },
    },
    {
        "field": "sport",
        "filterParams": {
            "maxNumConditions": 10,
        },
    },
    {
        "field": "age",
        "filter": "agNumberColumnFilter",
        "filterParams": {
            "numAlwaysVisibleConditions": 2,
            "defaultJoinOperator": "OR",
        },
        "maxWidth": 100,
    },
    {
        "field": "date",
        "filter": "agDateColumnFilter",
        "valueGetter": {"function": "d3.timeParse('%Y-%m-%d')(params.data.date)"},
        "valueFormatter": {"function": "d3.timeFormat('%m/%d/%Y')(params.value)"},
        "filterParams" : {
            "maxNumConditions": 3,
            "defaultJoinOperator": "OR"
        },
    }
]

defaultColDef = {
    "flex": 1,
    "minWidth": 150,
    "filter": True,
}

app.layout = html.Div(
    [
        dag.AgGrid(
            columnDefs=columnDefs,
            rowData=df.to_dict("records"),
            defaultColDef=defaultColDef,
            id="grid-filter-conditions",
        ),
    ]
)


if __name__ == "__main__":
    app.run(debug=True)

dag-docs

2 Likes

Wow, great, thanks! :smiley:

I started to look into making a custom filter function / external filter, but this is a bit too complicated for me. Hopefully the condition route will work now!

A followup question would be if the solution using conditions is ok if I’m filtering out lets say 100 dates at a time? Or is there a better solution I should look into? :slight_smile:

Hi @Mackan

Yes, there are several options when you want to filter lots of conditions.

1. Set Filters (AG Grid Enterprise)

The easiest is if you have AG Grid Enterprise and you can use Set Filters. I won’t go into details here but if you have Enterprise you can check out the docs.

2. External Filters

Another option is to not use the filters in the grid, and have other components such as dropdowns, buttons etc trigger a callback. In the callback you would filter the data and update the rowData prop in a callback. See it live here

"""
Updating rowData in a callback
"""

import dash_ag_grid as dag
from dash import Dash, html, dcc, Input, Output
import pandas as pd

app = Dash(__name__)


df = pd.read_csv(
    "https://raw.githubusercontent.com/plotly/datasets/master/ag-grid/olympic-winners.csv"
)


columnDefs = [
    {"field": "sport", "filter": False},
    {"field": "athlete"},
    {"field": "age"},
    {"field": "country"},
    {"field": "year"},
    {"field": "total"},
]

app.layout = html.Div(
    [
        html.Label("Select Sport:"),
        dcc.Dropdown(
            df["sport"].unique(),
            "Equestrian",
            id="update-rowdata-dd",
            clearable=False,
            style={"marginBottom": 10},
        ),
        dag.AgGrid(
            id="update-rowdata-grid",
            columnDefs=columnDefs,
            rowData=df.to_dict("records"),
            columnSize="responsiveSizeToFit",
            defaultColDef={
                "resizable": True,
                "sortable": True,
                "filter": True,
                "minWidth": 125,
            },
        ),
    ],
    style={"margin": 20},
)


@app.callback(
    Output("update-rowdata-grid", "rowData"),
    Input("update-rowdata-dd", "value"),
)
def selected(value):
    dff = df[df["sport"] == value]
    return dff.to_dict("records")


if __name__ == "__main__":
    app.run_server(debug=True)

3. Update the Filter Model

Rather than updating the rowData, you can just update the filterModel prop in a callback. That way the user could still interact with the filters in the column header. Note that if you have many many filter conditions, this may not be very user friendly.


import dash_ag_grid as dag
from dash import Dash, html, callback, Input, Output, State, ctx
import pandas as pd

app = Dash(__name__)


df = pd.read_csv(
    "https://raw.githubusercontent.com/plotly/datasets/master/ag-grid/olympic-winners.csv"
)

columnDefs = [
    {"field": "athlete"},
    {
        "field": "country",
        "filterParams": {
            "filterOptions": ["contains", "startsWith", "endsWith"],
            "defaultOption": "startsWith",
        },
    },
    {
        "field": "sport",
        "filterParams": {
            "maxNumConditions": 10,
        },
    },
    {
        "field": "age",
        "filter": "agNumberColumnFilter",
        "filterParams": {
            "numAlwaysVisibleConditions": 2,
            "defaultJoinOperator": "OR",
        },
        "maxWidth": 100,
    },
    {
        "field": "date",
        "filter": "agDateColumnFilter",
        "valueGetter": {"function": "d3.timeParse('%d/%m/%Y')(params.data.date)"},
        "valueFormatter": {"function": "d3.timeFormat('%m/%d/%Y')(params.value)"},
        "filterParams": {"maxNumConditions": 3, "defaultJoinOperator": "OR"},
    },
]

defaultColDef = {
    "flex": 1,
    "minWidth": 150,
    "filter": True,
}

app.layout = html.Div(
    [
        html.Button("Select 08/24/2008 or 08/12/2012", id="btn-filter-model"),
        html.Button("Clear Filters", id="btn-filter-model-clear"),
        dag.AgGrid(
            columnDefs=columnDefs,
            rowData=df.to_dict("records"),
            defaultColDef=defaultColDef,
            id="grid-filter-model",
        ),
    ]
)


@callback(
    Output("grid-filter-model", "filterModel"),
    Input("btn-filter-model", "n_clicks"),
    Input("btn-filter-model-clear", "n_clicks"),
    State("grid-filter-model", "filterModel"),
    prevent_initial_call=True,
)
def update_filter_model(n, n_clear, model):
    print(model)
    if ctx.triggered_id == "btn-filter-model-clear":
        return {}
    return {
        "date": {
            "filterType": "date",
            "operator": "OR",
            "condition1": {
                "dateFrom": "2008-08-24",
                "dateTo": None,
                "filterType": "date",
                "type": "equals",
            },
            "condition2": {
                "dateFrom": "2012-08-12",
                "dateTo": None,
                "filterType": "date",
                "type": "equals",
            },
            "conditions": [
                {
                    "dateFrom": "2008-08-24",
                    "dateTo": None,
                    "filterType": "date",
                    "type": "equals",
                },
                {
                    "dateFrom": "2012-08-12",
                    "dateTo": None,
                    "filterType": "date",
                    "type": "equals",
                },
            ],
        }
    }


if __name__ == "__main__":
    app.run(debug=True)

ag-grid-filter-model

1 Like

:+1:I don’t have Enterprise version at the moment. I tried external filters using the virtualRowData prop, but I couldn’t find a solution that I could wrap my head around :slight_smile: The filterModel solution will have to do until I’ve managed to write my own custom function I think!