Ag Grid showing a compared dataframe

I have two dataframes with following structure:

dfA = pd.DataFrame({
        "Run": (
            1, 1, 1, 2, 2, 2, 3, 3, 3
        ),
        "Point": (
            1, 2, 3, 1, 2, 3, 1, 2, 3
        ),
        "Val": (
            78, 79, 77, 78, 79, 77, 78, 79, 77
        )
    })

and

dfB = pd.DataFrame({
        "Run": (
            1, 1, 1, 2, 2, 2, 3, 3, 3,
        ),
        "Point": (
            1, 2, 3, 1, 2, 3, 1, 2, 3, 
        ),
        "Val": (
            68, 69, 67, 68, 69, 67, 68, 69, 67,
        ),
    })

With

result_df = dfA.compare(dfB, keep_equal=True, keep_shape=True).rename(columns={'self': 'A', 'other': 'B'}, level=-1)

I got this table-like output:

  Run    Point    Val    
    A  B     A  B   A   B
0   1  1     1  1  78  68
1   1  1     2  2  79  69
2   1  1     3  3  77  67
3   2  2     1  1  78  68
4   2  2     2  2  79  69
5   2  2     3  3  77  67
6   3  3     1  1  78  68
7   3  3     2  2  79  69
8   3  3     3  3  77  67

Is there a way to put this result_df in a AG grid table?

Thanks!

Hi @Bakira

You can display data like this using column groups

Hi @AnnMarieW ,
thanks for the hint.

I tried this one but it still fails to return the table.

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

def aggridtest(app) -> None:
    @app.callback(
        Output("figure", "children"),
        Input('submit-val', 'n_clicks'),
    )
    def plot(clicks):

        dfA = pd.DataFrame({
            "Run": (
                1, 1, 1, 2, 2, 2, 3, 3, 3
            ),
            "Point": (
                1, 2, 3, 1, 2, 3, 1, 2, 3
            ),
            "Val": (
                78, 79, 77, 78, 79, 77, 78, 79, 77
            )
        })

        dfB = pd.DataFrame({
            "Run": (
                1, 1, 1, 2, 2, 2, 3, 3, 3,
            ),
            "Point": (
                1, 2, 3, 1, 2, 3, 1, 2, 3, 
            ),
            "Val": (
                68, 69, 67, 68, 69, 67, 68, 69, 67,
            ),
        })

        res = dfA.compare(dfB, keep_equal=True, keep_shape=True).rename(columns={'self': 'A', 'other': 'B'}, level=-1)

        lev1 = res.columns.get_level_values(0)
        lev2 = res.columns.get_level_values(1)

        try:
            grid = dag.AgGrid(
                rowData=res.to_dict("records"),
                columnDefs=[
                    {
                        "headerName": "Run", 
                        "children" : [
                            {"field" : "A"},
                            {"field" : "B"},
                        ]
                    },
                    {
                        "headerName": "Point", 
                        "children" : [
                            {"field" : "A"},
                            {"field" : "B"},
                        ]
                    },
                    {
                        "headerName": "Val", 
                        "children" : [
                            {"field" : "A"},
                            {"field" : "B"},
                        ] 
                    }
                    ],
                style={"height": "600px"},
                columnSize="sizeToFit",
                defaultColDef={"resizable": True, "sortable": True, "filter": True},
                dashGridOptions={
                                "pagination": False, 
                                "columnHoverHighlight": True,
                                "skipHeaderOnAutoSize": True},
            )

            return grid
        except:
            return dash.no_update

        

    return html.Div(
            children=[
                html.Div(children=[
                    html.Button('Plot', id='submit-val', n_clicks=0),
                    html.Div(children=[
                    ],
                    id="figure")
                ])
            ],
            
        )

def main() -> None:
    app = Dash()
    app.title = "Test"
    app.layout = aggridtest(app)
    app.run(debug=True, port=8080)

if __name__ == "__main__":
    main()

Any idea?

I think Dash Ag Grid can’t access multilevel columns in the way you want. I would flat the levels and access then the resulting unambiguously columns direct in the children fields. May there are better solutions.

1 Like

Hi @Werner,

thanks for your advice. My solution so far looks like this.

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

def aggridtest(app) -> None:
    @app.callback(
        Output("figure", "children"),
        Input('submit-val', 'n_clicks'),
    )
    def plot(clicks):

        dfA = pd.DataFrame({
            "Run": (
                1, 1, 1, 2, 2, 2, 3, 3, 3
            ),
            "Point": (
                1, 2, 3, 1, 2, 3, 1, 2, 3
            ),
            "Val": (
                78, 79, 77, 78, 79, 77, 78, 79, 77
            )
        })

        dfB = pd.DataFrame({
            "Run": (
                1, 1, 1, 2, 2, 2, 3, 3, 3,
            ),
            "Point": (
                1, 2, 3, 1, 2, 3, 1, 2, 3, 
            ),
            "Val": (
                68, 69, 67, 68, 69, 67, 68, 69, 67,
            ),
        })

        res = dfA.compare(dfB, keep_equal=True, keep_shape=True).rename(columns={'self': 'A', 'other': 'B'}, level=-1)    
        res.columns = map("_".join, res.columns) 

        try:
            grid = dag.AgGrid(
                rowData=res.to_dict("records"),
                columnDefs=[
                    {
                    "field": i, 
                    "cellStyle": {"fontSize": '12px'},
                    } for i in res.columns
                ],
                style={"height": "600px"},
                columnSize="sizeToFit",
                defaultColDef={"resizable": True, "sortable": True, "filter": True},
                dashGridOptions={
                                "pagination": False, 
                                "columnHoverHighlight": True,
                                "skipHeaderOnAutoSize": True},
            )

            return grid
        except:
            return dash.no_update

        

    return html.Div(
            children=[
                html.Div(children=[
                    html.Button('Plot', id='submit-val', n_clicks=0),
                    html.Div(children=[
                    ],
                    id="figure")
                ])
            ],
            
        )

def main() -> None:
    app = Dash()
    app.title = "Test"
    app.layout = aggridtest(app)
    app.run(debug=True, port=8080)

if __name__ == "__main__":
    main()

@Bakira

Now that the dataframe is flat, try changing the columnDefs to what’s shown below. Note that

  • field needs to match the column name in the df.
  • headerName is what’s displayed in the grid.
        columnDefs=[
            {
                "headerName": "Run",
                "children": [
                    {"headerName": "A", "field": "Run_A"},
                    {"headerName": "B", "field": "Run_B"},
                ]
            },
            {
                "headerName": "Point",
                "children": [
                    {"headerName": "A", "field": "Point_A"},
                    {"headerName": "B", "field": "Point_B"},
                ]
            },
            {
                "headerName": "Val",
                "children": [
                    {"headerName": "A", "field": "Val_A"},
                    {"headerName": "B", "field": "Val_B"},
                ]
            }
        ]

3 Likes

Now its perfectly working :slight_smile:
Thanks for the help.