Search code examples
pythonjsondatatableplotly-dashstore

Store edited DataTable in Dash


I am trying to store an edited Python Dash DataTable into a dcc.store container with a button component and use the saved data at a later point. However, once I change the original DataTable, the stored container also changes. I found the following post (save a modified dash datatable to dataframe) but was not able to figure it out.

My core question is how can I store (copy) some data in a Python dash app and then manipulate the original data without altering the stored copy.

# Libraries
import pandas as pd
import dash
from dash import html, dash_table
import dash_core_components as dcc
from dash.dependencies import Input, Output

# Data
test_data = pd.DataFrame([[1,2],[3,4]], columns=['Col1', 'Col2'])
saved_test_data = None

# App
app = dash.Dash(__name__)

app.layout = html.Div(children=[dash_table.DataTable(columns = [{"name": i, "id": i} for i in test_data.columns],
                                                     data = test_data.to_dict('records'),
                                                     id = 'test_data_table',
                                                     editable=True,
                                                     ),
                                html.Button('Save data', id='save_test_data', n_clicks=0),
                                dcc.Store(id = 'test_data_store'),
                                dash_table.DataTable(id = 'check_table', data=saved_test_data),
                                ],
                      style={'width': '50%', 'display': 'inline-block', 'padding-left':'25%', 'padding-right':'25%'}
                      )

# Callbacks
@app.callback(Output('test_data_store', 'data'),
              [Input('save_test_data', 'n_clicks'), Input('test_data_table', 'data')])
def save_test_data(n, data):
    if n == 0:
        saved_test_data = None
    else:
        saved_test_data = data
    return saved_test_data

@app.callback(Output('check_table', 'data'),
              Input('test_data_store', 'data'))
def restore_saved_test_data(data):
    return data

if __name__ == '__main__':
    app.run_server(debug=True, use_reloader=False)

If I change a value in the upper table after pressing the button, the lower table also changes, but it should display the value saved before the click, i.e.

  1. Original Table

1

  1. Press the button to save the table.

  2. Stored table should be displayed below

2

  1. Changing the upper table should not change the lower table before hitting the button again, but it changes immediately.

Solution

  • There are two problems. First, you have the original table as an Input, which triggers the callback every time it changes. This should be a State instead,

    State('test_data_table', 'data')

    Second, and maybe not so important if you make the above change, is this condition, if n == 0:. This will always be False after one click of the button. From there, every time the table updates.