Update selectedRows and rowData of AgGrid at once

I’d like to select rows in a grid, according to a selection made in a graph. At the same time I’d like to move the selected points on top. As far as I can see, there is now order-by-selection-method or anything like that.
When trying to do so: The ordering done but that resets the grid and the selectedData disappears:

import numpy as np
import plotly.graph_objects as go
from dash import Dash, html, dcc, callback
from dash.dependencies import Input, Output, State
import dash_ag_grid as dag

app = Dash(__name__)

np.random.seed(0)
x = np.random.rand(50)
y = np.random.rand(50)

app.layout = html.Div([
    dcc.Graph(
        id='graph',
        figure={
            'data': [go.Scatter(x=x, y=y, mode='markers')],
            'layout': go.Layout(
                xaxis=dict(title='X'),
                yaxis=dict(title='Y'),
                hovermode='closest'
            )
        }
    ),
    dag.AgGrid(
        id="grid",
        columnDefs=[
            {"field": "x", "sortable": True, "filter": True},
            {"field": "y", "sortable": True, "filter": True},
        ],
        rowData=[{"x": x_val, "y": y_val, "id": i} for i, (x_val, y_val) in enumerate(zip(x, y))]),
])


@callback(
    Output('grid', 'rowData'),
    Input('graph', 'selectedData'),
    State('grid', 'rowData'),
    prevent_initial_call=True,
)
def update_grid(selected_data, row_data):
    if selected_data:
        selected_points = selected_data['points']
        selected_ids = [point['pointIndex'] for point in selected_points]
        for row in row_data:
            if row['id'] in selected_ids:
                row['selected'] = True
            else:
                row['selected'] = False
        sorted_row_data = sorted(row_data, key=lambda row: not row['selected'])
        return sorted_row_data
    return row_data


@callback(
    Output('grid', 'selectedRows'),
    Input('graph', 'selectedData'),
    State('grid', 'rowData'),
    prevent_initial_call=True,
)
def update_selected_rows(selected_data, row_data):
    if selected_data:
        selected_points = selected_data['points']
        selected_ids = [point['pointIndex'] for point in selected_points]
        selected_rows = [str(row['id']) for row in row_data if row['id'] in selected_ids]
        return {"ids": selected_rows}
    return {"ids": []}


if __name__ == '__main__':
    app.run_server(debug=True, port=7000)

Hello @luggie,

This is a known issue and will be fixed with an updated release shortly.

@nathandrezner is so close to being done with his updates. :grin:

1 Like

I thought this fix in Dash-AG-Grid 31.2.0 would have solved this. Was it concerning something else or am I missing something?

I tried my above example again and another, slightly altered one with an intermediate trigger-div:


import numpy as np
import plotly.graph_objects as go
from dash import Dash, html, dcc, callback, no_update
from dash.dependencies import Input, Output, State
import dash_ag_grid as dag

app = Dash(__name__)

np.random.seed(0)
x = np.random.rand(10)
y = np.random.rand(10)

app.layout = html.Div([
    dcc.Graph(
        id='graph',
        figure={
            'data': [go.Scatter(x=x, y=y, mode='markers')],
            'layout': go.Layout(
                xaxis=dict(title='X'),
                yaxis=dict(title='Y'),
                hovermode='closest'
            )
        }
    ),
    dag.AgGrid(
        id="grid",
        columnDefs=[
            {"field": "x", "sortable": True, "filter": True},
            {"field": "y", "sortable": True, "filter": True},
        ],
        rowData=[{"x": x_val, "y": y_val, "id": i} for i, (x_val, y_val) in enumerate(zip(x, y))]),
    html.Div(id='trigger-selection', style={'display': 'none'}, children=None),
])


@callback(
    Output('trigger-selection', 'children'),
    Output('grid', 'rowData'),
    Input('graph', 'selectedData'),
    State('grid', 'rowData'),
    prevent_initial_call=True,
)
def update_and_sort_grid(selected_data, row_data):
    if selected_data:
        selected_points = selected_data['points']
        selected_ids = [point['pointIndex'] for point in selected_points]
        for row in row_data:
            if row['id'] in selected_ids:
                row['selected'] = True
            else:
                row['selected'] = False
        sorted_row_data = sorted(row_data, key=lambda row: not row['selected'])
        return "select", sorted_row_data
    return None, row_data


@callback(
    Output('grid', 'selectedRows'),
    Input('trigger-selection', 'children'),
    State('graph', 'selectedData'),
    State('grid', 'rowData'),
    prevent_initial_call=True,
)
def update_selected_rows(trigger, selected_data, row_data):
    if selected_data and trigger is not None:
        selected_points = selected_data['points']
        selected_ids = [point['pointIndex'] for point in selected_points]
        selected_rows = [str(row['id']) for row in row_data if row['id'] in selected_ids]
        return {"ids": selected_rows}
    return {"ids": []}


if __name__ == '__main__':
    app.run_server(debug=True, port=7000)

or with all functionality in just one callback:

import numpy as np
import plotly.graph_objects as go
from dash import Dash, html, dcc, callback
from dash.dependencies import Input, Output, State
import dash_ag_grid as dag

app = Dash(__name__)

np.random.seed(0)
x = np.random.rand(10)
y = np.random.rand(10)

app.layout = html.Div([
    dcc.Graph(
        id='graph',
        figure={
            'data': [go.Scatter(x=x, y=y, mode='markers')],
            'layout': go.Layout(
                xaxis=dict(title='X'),
                yaxis=dict(title='Y'),
                hovermode='closest'
            )
        }
    ),
    dag.AgGrid(
        id="grid",
        columnDefs=[
            {"field": "x", "sortable": True, "filter": True},
            {"field": "y", "sortable": True, "filter": True},
        ],
        rowData=[{"x": x_val, "y": y_val, "id": i} for i, (x_val, y_val) in enumerate(zip(x, y))]),
])


@callback(
    Output('grid', 'selectedRows'),
    Output('grid', 'rowData'),
    Input('graph', 'selectedData'),
    State('grid', 'rowData'),
    prevent_initial_call=True,
)
def update_and_sort_grid(selected_data, row_data):
    if selected_data:
        selected_points = selected_data['points']
        selected_ids = [point['pointIndex'] for point in selected_points]
        selected_rows = [str(row['id']) for row in row_data if row['id'] in selected_ids]
        selected_points = selected_data['points']
        selected_ids = [point['pointIndex'] for point in selected_points]
        for row in row_data:
            if row['id'] in selected_ids:
                row['selected'] = True
            else:
                row['selected'] = False
        sorted_row_data = sorted(row_data, key=lambda row: not row['selected'])
        return {"ids": selected_rows}, sorted_row_data
    return None, row_data


if __name__ == '__main__':
    app.run_server(debug=True, port=7000)

but both are still not able to select and sort the grid at the same time :frowning:

Hi @luggie

Starting from the code in the original post, it will work if you add getRowId="params.data.id",
It’s also easier to see that the rows are selected by using checkboxes.

Try it with the grid defined like this:

dag.AgGrid(
        id="grid",
        columnDefs=[
            {"field": "x", "sortable": True, "filter": True, "checkboxSelection": True},
            {"field": "y", "sortable": True, "filter": True},
        ],
        rowData=[{"x": x_val, "y": y_val, "id": i} for i, (x_val, y_val) in enumerate(zip(x, y))],
        getRowId="params.data.id",
        dashGridOptions={
            "rowSelection": "multiple",
            "suppressRowClickSelection": True,
            "animateRows": False},
    ),

3 Likes