Dash Ag-Grid - Applying Conditional Styling to the entire grid with partial value match

Hi,

import dash_ag_grid as dag
from dash import Dash, html, dcc, Input, Output, callback
import dash_bootstrap_components as dbc
app = Dash(__name__,external_stylesheets=[dbc.themes.BOOTSTRAP])

rowData = [
    {"Stock": "STOCKA","monthly":'MR (0)',"monthlyR": '2W (78)',"twoWeeks": 'WR (112)',"twoWeeksR": '3DR (56)',"weekly": 'DR (56)',"weeklyR": 'DDSM (2W)',"days3": 'DDSM (W)',"days3R": 'DDSM (D)',"daily": 'DDSM (3D)',"dailyR": '',},
    {"Stock": "STOCKB","monthly":'M (100)', "monthlyR": '2WR (41)',"twoWeeks": 'WR (58)',"twoWeeksR": 'WR (O)',"weekly": 'DR (88)',"weeklyR": 'DDSM (2W)',"days3": '',"days3R": '',"daily": '',"dailyR": '',},
    {"Stock": "STOCKC","monthly":'2W (91)', "monthlyR": '3DR (54)',"twoWeeks": 'DR (101)',"twoWeeksR": 'DDSM (D)',"weekly": 'DDSM (3D)',"weeklyR": 'DDSM (W)',"days3": 'DDSM (2W)',"days3R": '',"daily": '',"dailyR": '',},
]
columnDefs = [
    {"field": "Stock","cellStyle":{'fontSize': '12px',"lineHeight": "unset",'padding-right':0,'padding-left':0},
    },
        {'field': 'monthly', "headerName": "M","cellStyle":{
        #"wordBreak": "normal", "lineHeight": "unset",'padding-right':0,'padding-left':0,
        "styleConditions": [
            {
                "condition": "params.data.monthly.includes('M (')",
                "style": {"backgroundColor": "rgb(255, 138, 101 )","color": 'rgb(30, 30, 30)','fontSize': '12px',"wordBreak": "normal", "lineHeight": "unset",'padding-right':0,'padding-left':0,},
            },
            {
                "condition": "params.data.monthly.includes('MR (')",
                "style": {"backgroundColor": "rgb(255, 171, 145)","color": 'rgb(30, 30, 30)','fontSize': '12px',"wordBreak": "normal", "lineHeight": "unset",'padding-right':0,'padding-left':0,},
            },
            {
                "condition": "params.data.monthly.includes('2WR (')",
                "style": {"backgroundColor": "rgb(255, 204, 128)","color": 'rgb(30, 30, 30)','fontSize': '12px',"wordBreak": "normal", "lineHeight": "unset",'padding-right':0,'padding-left':0,}
            },
            {
              "condition": "params.data.monthly.includes('W (')",
              "style": {"backgroundColor": "rgb(255, 213, 79)","color": 'rgb(30, 30, 30)','fontSize': '12px',"wordBreak": "normal", "lineHeight": "unset",'padding-right':0,'padding-left':0,},
            },
            {
                "condition": "params.data.monthly.includes('WR (')",
                "style": {"backgroundColor": "rgb(255, 224, 130)","color": 'rgb(30, 30, 30)','fontSize': '12px',"wordBreak": "normal", "lineHeight": "unset",'padding-right':0,'padding-left':0,},
            },
            {
                "condition": "params.data.monthly.includes('3D (')",
                "style": {"backgroundColor": "rgb(255, 241, 118)","color": 'rgb(30, 30, 30)','fontSize': '12px',"wordBreak": "normal", "lineHeight": "unset",'padding-right':0,'padding-left':0,},
            },
            {
                "condition": "params.data.monthly.includes('3DR (')",
                "style": {"backgroundColor": "rgb(255, 245, 157)","color": 'rgb(30, 30, 30)','fontSize': '12px',"wordBreak": "normal", "lineHeight": "unset",'padding-right':0,'padding-left':0,},
            },
            {
                "condition": "params.data.monthly.includes('D (')",
                "style": {"backgroundColor": "rgb(220, 231, 117)","color": 'rgb(30, 30, 30)','fontSize': '12px',"wordBreak": "normal", "lineHeight": "unset",'padding-right':0,'padding-left':0,},
            },
            {
                "condition": "params.data.monthly.includes('DR (')",
                "style": {"backgroundColor": "rgb(230, 238, 156)","color": 'rgb(30, 30, 30)','fontSize': '12px',"wordBreak": "normal", "lineHeight": "unset",'padding-right':0,'padding-left':0,},
            },
        ],
        "defaultStyle": {'fontSize': '12px',"wordBreak": "normal", "lineHeight": "unset",'padding-right':0,'padding-left':0},
    },"wrapText": True,
    },
    {'field': 'monthlyR', "headerName": "MR"},
    {'field': 'twoWeeks', "headerName": "2W"},
    {'field': 'twoWeeksR', "headerName": "2WR"},
    {'field': 'weekly', "headerName": "W"},
    {'field': 'weeklyR', "headerName": "WR"},
    {'field': 'days3', "headerName": "3D"},
    {'field': 'days3R', "headerName": "3DR"},
    {'field': 'daily', "headerName": "D"},
    {'field': 'dailyR', "headerName": "DR"},
]   
app.layout = html.Div(
    [
        dag.AgGrid(
            id="styling-cells-styles",
            rowData=rowData,
            columnDefs=columnDefs,
            defaultColDef={
            },
            dashGridOptions={
                "domLayout": "autoHeight",
                'headerHeight': 0,
            },
            columnSize="responsiveSizeToFit",
            columnSizeOptions={
            'defaultMinWidth': 20,
            'columnLimits': [{'key': 'Stock', 'minWidth': 45}],
            },
        ),
    ],
)
if __name__ == "__main__":
    app.run(debug=True)

I’m trying to apply cell formatting for each value under each column.
If the values are M,MR,2W,2WR,3D… etc. It’s easy to do so. However numbers between the brackets are dynamic. So I have to match some part or the beginning of the text to apply formatting.
I only applied conditional formatting to the ‘monthly’ field in above example.
However column headers are also dynamic. For instance if i apply formatting for the ‘daily’ column and if daily column doesn’t exist in the dataframe it causes JS error(which is normal).
So i tried to apply these conditions under defaultColDef,

                defaultColDef={
                 "cellStyle":{
                  "styleConditions": [
                                  {
                "condition": "params.data.M.includes('MR (')",
                "style": {"backgroundColor": "rgb(230, 238, 156)","color": 'rgb(30, 30, 30)','fontSize': '12px',"wordBreak": "normal", "lineHeight": "unset",'padding-right':0,'padding-left':0,},
            },
                  ],
                  "defaultStyle": {"display": "flex","align-items": "center",'padding-right':0,'padding-left':0,"wrapText": True,
                      "wordBreak": "normal",
                      "lineHeight": "unset",
                  },
                  },
                },

which applies formatting to the entire row.
I also tried to use other javascript methods under defaultColDef such as:

"['M ('].startsWith(params.value)"
and under cellClassRules.

What is the best way to apply conditional formatting to the entire grid?
and i also need to apply these options

"wordBreak": "normal", "lineHeight": "unset",'padding-right':0,'padding-left':0,

many thanks in advance.

Hello @celal,

Check this out:

import dash_ag_grid as dag
from dash import Dash, html, dcc, Input, Output, callback
import dash_bootstrap_components as dbc
app = Dash(__name__,external_stylesheets=[dbc.themes.BOOTSTRAP])

cellClassRule_List = ['M', 'MR', '2WR', 'W', 'WR', '3D', '3DR', 'D', 'DR']
cellClassRules = {x: f'params.value.substring(0, ("{x} (").length) === "{x} ("' for x in cellClassRule_List}

rowData = [
    {"Stock": "STOCKA","monthly":'MR (0)',"monthlyR": '2W (78)',"twoWeeks": 'WR (112)',"twoWeeksR": '3DR (56)',"weekly": 'DR (56)',"weeklyR": 'DDSM (2W)',"days3": 'DDSM (W)',"days3R": 'DDSM (D)',"daily": 'DDSM (3D)',"dailyR": '',},
    {"Stock": "STOCKB","monthly":'M (100)', "monthlyR": '2WR (41)',"twoWeeks": 'WR (58)',"twoWeeksR": 'WR (O)',"weekly": 'DR (88)',"weeklyR": 'DDSM (2W)',"days3": '',"days3R": '',"daily": '',"dailyR": '',},
    {"Stock": "STOCKC","monthly":'2W (91)', "monthlyR": '3DR (54)',"twoWeeks": 'DR (101)',"twoWeeksR": 'DDSM (D)',"weekly": 'DDSM (3D)',"weeklyR": 'DDSM (W)',"days3": 'DDSM (2W)',"days3R": '',"daily": '',"dailyR": '',},
]
columnDefs = [
    {"field": "Stock","cellStyle":{'fontSize': '12px',"lineHeight": "unset",'padding-right':0,'padding-left':0},
    },
        {'field': 'monthly', "headerName": "M"},
    {'field': 'monthlyR', "headerName": "MR"},
    {'field': 'twoWeeks', "headerName": "2W"},
    {'field': 'twoWeeksR', "headerName": "2WR"},
    {'field': 'weekly', "headerName": "W"},
    {'field': 'weeklyR', "headerName": "WR"},
    {'field': 'days3', "headerName": "3D"},
    {'field': 'days3R', "headerName": "3DR"},
    {'field': 'daily', "headerName": "D"},
    {'field': 'dailyR', "headerName": "DR"},
]
app.layout = html.Div(
    [
        dag.AgGrid(
            id="styling-cells-styles",
            rowData=rowData,
            columnDefs=columnDefs,
            defaultColDef={
                "cellClassRules": cellClassRules,
                "cellStyle": {"display": "flex","align-items": "center",'padding-right':0,'padding-left':0,"wrapText": True,
                      "wordBreak": "normal",
                      "lineHeight": "unset",
                  }
            },
            dashGridOptions={
                "domLayout": "autoHeight",
                'headerHeight': 0,
            },
            columnSize="responsiveSizeToFit",
            columnSizeOptions={
            'defaultMinWidth': 20,
            'columnLimits': [{'key': 'Stock', 'minWidth': 45}],
            },
        ),
    ],
)
if __name__ == "__main__":
    app.run(debug=True)

Now, to apply your styling, all you need is to add a style sheet mapped to your cell classes. :slight_smile:

image

.M {
    color: red;
}
2 Likes

Dear jinnyzor,
Thanks for the code.
This works like a charm. However I as mentioned in the question if the column doesn’t exist in the streaming dataframe this gives error.

Cannot read properties of undefined (reading ‘substring’)

the function drops empty columns while creating the dataframe as i don’t want empty columns in my grid.

dfx = dfx.dropna(axis=1, how='all')

This code might need to change to this:

cellClassRules = {x: f'params.value ? params.value.substring(0, ("{x} (").length) === "{x} (" : false' for x in cellClassRule_List}
1 Like

Excellent. I feel like i need to learn and use more and more javascript in order to create a unique grid that fulfills my requirements. are there any tutorials that focus on these subjects?

1 Like

None of the options

fontSize': '12px',"wordBreak": "normal", "lineHeight": "unset",'padding-right':0,'padding-left':0,

seems to be working both under columnDefs and defaultColDef.

My bad. I fixed the problem.
One last question.
How do i apply styling to numeric elements in css file?
For instance
.2W {
color: red;
}
NOT working.

}
.\32 W {
    background-color: rgb(255, 213, 79)
}
.\32 WR {
    background-color: rgb(255, 224, 130)
}

Right answer/

You can do that.
I think you can also do a query like this:

div[class=“32”]

Not entirely sure. But glad you got all of it working. :grin: