As I mentioned above, it’s possible to format the grid so it looks the way you want. If you are working with dataframes it’s easier to turn mulit-level data into a flat dataframe with pandas first.
Note that the grid can accept more complex data (such as a dict or a list in cells) but it cannot accept a dataframe directly. (ie you can’t do rowData=df
It needs to be in a json format.
Please be sure to read the sections on Column Groups and Row Spanning I referenced above for more information
Note also that if you would like to sort and/or filter the grid, it will be easier if you don’t include the row spanning.
from dash import Dash, html
import dash_ag_grid as dag
import pandas as pd
app = Dash(__name__)
data = [
['Categories', 'Tag / Vers', 'first_1', 'sec_1', 'first_2', 'sec_2', 'first_3', 'sec_3', 'first_4', 'sec_4', 'first_5', 'sec_5',
'first_6', 'sec_6', ''],
['FirstCat', 'Divider1', '6', '7', '2', '3', '8', '8', '6', '7', '2', '4', '8', '8', ''],
['FirstCat', 'Divider2', '0', '1', '0', '1', '0', '0', '0', '1', '0', '2', '0', '0', ''],
['SecondCat', 'Divider1', '1', '1', '3', '2', '2', '1', '1', '2', '2', '2', '3', '1', ''],
['SecondCat', 'Divider2', '0', '0', '1', '0', '1', '0', '0', '1', '0', '0', '2', '0', '']
]
df = pd.DataFrame(data)
# make the first row the column names
df = pd.DataFrame(data[1:], columns=data[0])
# Replace empty strings with NaN
df.replace("", pd.NA, inplace=True)
columnDefs = [
{
"field": "Categories",
"rowSpan": {"function": "params.node.id %2 === 0 ? 2 : 1"},
"cellStyle": {"backgroundColor": "var(--ag-header-background-color"},
"minWidth": 125
},
{"field": "Tag / Vers"},
] + [
{
"headerName": f"Level { i}",
"children": [
{"field": f"first_{i}", "headerName": "First"},
{"field": f"sec_{i}", "headerName": "Second"},
],
}
for i in range(1, 7)
]
app.layout = html.Div(
[
dag.AgGrid(
id="grid",
rowData=df.to_dict("records"),
columnDefs=columnDefs,
columnSize="sizeToFit",
defaultColDef={"minWidth": 100, "sortable": False},
dashGridOptions={"suppressRowTransform": True},
)
]
)
if __name__ == "__main__":
app.run(debug=True)