Dash datatable - updating a single row takes a long time (with MWE)

When trying to update a single row in a datatable, it seems like the only option is to return the full list of data for the datatable. This can lead to significant loading times for a rather simple operation, especially when the table is large.
In one of my applications, I need to be able to adjust a row based on whether or not the row checkbox is selected or not. However, adjusting the single row triggers a full table reload and can take a relatively long time given the complexity of the operation. I have added a MWE to illustrate the issue. In this MWE, a cell in the first column is highlighted if it differs from the second column. Selecting the row, copies the value of the second column to the first column.


import dash
import dash_html_components as html
import dash_table
from dash.dependencies import Input, Output, State
import dash_core_components as dcc

columns_dict = {'Column #1':'Item #1',
                'Column #2':'Item #2'}
data_for_table = [columns_dict for x in range(1000)]

style_data_conditional = [{'if': {'column_id': 'Column #1',
                                  'filter_query': '{Column #1} ne {Column #2}'},
                           'backgroundColor': '#ffff00 '}]

datatable =  dash_table.DataTable(id='big-table',
                                  columns=[{'id':col,
                                            'name':col,
                                            'presentation':'input',
                                            'editable':False} for col in columns_dict],
                                  data=data_for_table,
                                  row_deletable=False,
                                  row_selectable="multi",
                                  fixed_rows={'headers': True},
                                  virtualization=False,
                                  page_current= 0,
                                  page_size= 50,
                                  style_data_conditional=style_data_conditional,
                                  page_action='custom',
                                  filter_action='custom',
                                  filter_query='',
                                  sort_action='custom',
                                  sort_mode='multi',
                                  sort_by=[])


app = dash.Dash(__name__)
app.layout = dcc.Loading(html.Div(datatable))

# Callback
@app.callback(Output('big-table','data'),
              Input('big-table', 'derived_virtual_selected_rows'),
              State('big-table','data'),
              prevent_initial_call=True)
def update_row(input_selected_rows,state_table_data):
    # This takes a long time to just update one or a couple of rows since
    #  the entire table data is passed back
    for row_index in input_selected_rows:
        row = state_table_data[row_index]
        row['Column #1']=row['Column #2']
    return state_table_data

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

Is it possible to use a callback to update just the selected row and thus speed up the operation?

Hi there!

I don’t think it is possible to partially update props like data.

If you are a bit comfortable with JavaScript, you could try to convert your callback to a clientside one, depending on which operation you want to perform. There is a significant performance gain to avoid sending data back and forth and serializing it.

As noted by @jlfsjunior, you cannot update properties partially. But you can speed up the operation by using a clientside callacback. For your example it would be something like,

# Clientside callback
app.clientside_callback(
    """
    function(input_selected_rows,state_table_data){
        for (let i = 0; i < input_selected_rows.length; i++) {
            let row = state_table_data[input_selected_rows[i]];
            row['Column #1'] = row['Column #2'];
        }
        return state_table_data;
    }
    """,
    Output('big-table', 'data'),
    Input('big-table', 'derived_virtual_selected_rows'),
    State('big-table', 'data'),
    prevent_initial_call=True)