Ag Grid highlighting duplicated cell values

I was wondering if there was a way I could highlight duplicated cell values for a given column.
I’ve tried:

columnDefs = [ {
“field”: “sample_id”,
“cellClassRules”: {“duplicate-sample-id”: ‘isDuplicateSampleID(params)’},
}]

Then in assets/dashAgGrudFunctions.js

dagfuncs.isDuplicateSampleID = function(params) {
let count = 0;
params.api.forEachNode((node) => {
if (node.data.sample_id === params.value) {
count++;
}
});
return count > 1; // Return true if duplicate is found
}

and assets/some_css.css

.duplicate-sample-id {
background-color: red !important;
color: white !important;
}

Hello @Redhotmoons,

This looks like it could work. Did you give it a test?

It doesn’t seem to :neutral_face:

Perhaps the grid I’m testing with is a little complex, I’ll create an simplified example and re-test :slight_smile:

Can you provide an example set?

I’d like to test too.

@jinnyzor

Ah it seems there was something funky happening using my application, I’ve reproduced it using a simplfied version:

from dash import Dash, html
import dash_ag_grid as dag
import pandas as pd

df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/wind_dataset.csv")


app = Dash(__name__)

columnDefs = [
    {"field": "direction"},
    {"field": "strength"},
    {"field": "frequency", "cellClassRules": {"duplicate-sample-id": "isDuplicate(params)"}},
]

grid = dag.AgGrid(
    id="get-started-example-basic",
    rowData=df.to_dict("records"),
    columnDefs=columnDefs,
)

app.layout = html.Div([grid])

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

/assets/dashAgGridFunctions.js

 dagfuncs.isDuplicate = function(params) {
            let count = 0;
            const targetFrequency = params.value;
            const currentRowNodeId = params.node.id;

            params.api.forEachNode((node) => {
                if (node.id !== currentRowNodeId && node.data.frequency === targetFrequency) {
                    count++;
                }
            });

            return count >= 1;  // True if another row with the same frequency is found
}

assets/some_css.css

.duplicate-sample-id {
    background-color: red !important;
    color: white !important;
}

I think it’s not working in my application due to a valueGetter on the same column, I’ll have a play around and see if I can get an example set up :slight_smile:

Hmm, you were able to get the above version to work?

You could always use the params.data.frequency instead of your params.value

The above example seems to work fine:

example_1

It doesn’t currently work in the application I’m working on, I think because I’m using a valueGetter at the same time.

Try this instead. :wink:

Ah yes!

dagfuncs.isDuplicateSampleID = function(params) {
    let count = 0;
    const targetSampleID = params.data.frequency;
    const currentRowNodeId = params.node.id;

    params.api.forEachNode((node) => {
        // Check if the node being examined isn't the current node
        if (node.id !== currentRowNodeId && node.data.sample_id === targetSampleID) {
            count++;
        }
    });

    return count >= 1;  // True if another row with the same sample_id is found
}

seems to have worked nicely :smiley:

1 Like

@jinnyzor

Actually, it does not :expressionless:

from dash import Dash, html
import dash_ag_grid as dag

app = Dash(__name__)

columnDefs = [
    {"headerName": "Column A", "field": "columnA"},
    {"headerName": "Column B", "field": "columnB"},
    {
        "headerName": "Column C",
        "field": "columnC",
    },
    {
        "headerName": "Generated ID",
        "field": "generatedID",
        "valueGetter": {"function": "getGeneratedID(params)"},
        "cellClassRules": {"duplicate-id": "isDuplicateID(params)"},
    },
]

rowData = [
    {"columnA": "A1", "columnB": "B1", "columnC": "C1"},
    {"columnA": "A2", "columnB": "B2", "columnC": "C2"},
    {"columnA": "A1", "columnB": "B1", "columnC": "C3"},
    {"columnA": "A3", "columnB": "B3", "columnC": "C4"},
    {"columnA": "A4", "columnB": "B4", "columnC": "C5"},
    {"columnA": "A1", "columnB": "B1", "columnC": "C6"},
    {"columnA": "A5", "columnB": "B5", "columnC": "C7"},
    {"columnA": "A6", "columnB": "B2", "columnC": "C8"},
    {"columnA": "A7", "columnB": "B7", "columnC": "C9"},
]


grid = dag.AgGrid(
    id="get-started-example-basic",
    rowData=rowData,
    columnDefs=columnDefs,
)

app.layout = html.Div([grid])

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

assets/dashAgGridFunctions.js

dagfuncs.getGeneratedID = function(params) {
    // Placeholder logic to generate an ID, adapt as needed
    return params.data.columnA + "-" + params.data.columnB;
}

dagfuncs.isDuplicateID = function(params) {
    let count = 0;
    const targetID = params.data.generatedID;
    const currentRowNodeId = params.node.id;

    params.api.forEachNode((node) => {
        if (node.id !== currentRowNodeId && node.data.generatedID === targetID) {
            count++;
        }
    });

    return count >= 1;  // True if another row with the same ID is found
}

assets/some_css.css

.duplicate-id {
    background-color: red !important;
    color: white !important;
}

Undefined always equals undefined:

dagfuncs.isDuplicateID = function(params) {
    let count = 0;
    const targetID = dagfuncs.getGeneratedID(params);
    const currentRowNodeId = params.node.id;

    params.api.forEachNode((node) => {
        if (node.id !== currentRowNodeId && dagfuncs.getGeneratedID(node) === targetID) {
            count++;
        }
    });

    return count >= 1;  // True if another row with the same ID is found
}

You have to apply the formulas together…

2 Likes

arrggh :expressionless:

my apologies <3

Haha, no worries.

params.data is only what data you pass to the grid. Since you are making the column GeneratedID, it doesnt exist in the data.

1 Like

@jinnyzor

I’ve noticed that the data in the generated_id column is not contained in the rowData property of the grid when I try to access it via a callback.

I don’t suppose you know if there’s a way to retrieve the data?

Best wishes
-D

import dash_ag_grid as dag
import dash_mantine_components as dmc
from dash import Dash, html, Output, Input, no_update, dcc

app = Dash(__name__)

columnDefs = [
    {"headerName": "Column A", "field": "columnA"},
    {"headerName": "Column B", "field": "columnB"},
    {
        "headerName": "Column C",
        "field": "columnC",
    },
    {
        "headerName": "Generated ID",
        "field": "generatedID",
        "valueGetter": {"function": "getGeneratedID(params)"},
        "cellClassRules": {"duplicate-id": "isDuplicateID(params)"},
    },
]

rowData = [
    {"columnA": "A1", "columnB": "B1", "columnC": "C1"},
    {"columnA": "A2", "columnB": "B2", "columnC": "C2"},
    {"columnA": "A1", "columnB": "B1", "columnC": "C3"},
    {"columnA": "A3", "columnB": "B3", "columnC": "C4"},
    {"columnA": "A4", "columnB": "B4", "columnC": "C5"},
    {"columnA": "A1", "columnB": "B1", "columnC": "C6"},
    {"columnA": "A5", "columnB": "B5", "columnC": "C7"},
    {"columnA": "A6", "columnB": "B2", "columnC": "C8"},
    {"columnA": "A7", "columnB": "B7", "columnC": "C9"},
]


grid = dag.AgGrid(
    id="get-started-example-basic",
    rowData=rowData,
    columnDefs=columnDefs,
)

app.layout = html.Div([dmc.Button("test", id="test_button"), grid, dcc.Store(id="test_store")])


@app.callback(
    Output("test_store", "data"), Input("get-started-example-basic", "rowData"), Input("test_button", "n_clicks")
)
def get_rowdata(rowData, n_clicks):
    print(f"rowData = {rowData}")
    return no_update


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

Not unless you set the data to a blank field in the data, which you could do that I guess, during the function…

1 Like

Seems to have done the trick :slight_smile:

example updating sample_id column:

dagfuncs.isDuplicateSampleID = function(params) {
    let count = 0;
    const targetSampleID = dagfuncs.getSampleID(params);  // Use the getSampleID function here
    const currentRowNodeId = params.node.id;

    params.api.forEachNode((node) => {
        // Check if the node being examined isn't the current node
        if (node.id !== currentRowNodeId && dagfuncs.getSampleID(node) === targetSampleID) {
            count++;
        }
    });

    if (count === 0) {
        params.node.setDataValue('sample_id', targetSampleID);
    }

    return count >= 1;  // True if another row with the same sample_id is found
}
1 Like