Hi,
I’ve seen numerous posts on this topic, but most of the solutions don’t seem to work. I’ve found a way to make changes persist across pages for the data editor. While there may be a better solution out there, this approach actually works.
Problem
When the same key is used for both initializing and saving changes (as in the following setup), the data keeps disappearing. Users are forced to enter each change twice before the session state is updated.
st.session_state['df'] = st.data_editor(st.session_state['df'])
Additionally, data is deleted when switching between pages. This happens because the widgets are cleared from the session state during page transitions.
Solution
All edits are stored in a dictionary under their respective categories (edit, add, delete). By applying these changes to the dataframe stored in the session state within the ‘on change’ callback, we can update the session state before the page reloads.
Code example
First initialize the private key.
if 'df' not in st.session_state:
st.session_state['df'] = DEFAULT_DF
def store_df(key):
pkey = '_' + key
changes = st.session_state[pkey]
df = st.session_state[key]
# Apply edits
for row, edit in changes['edited_rows'].items():
for column, new_value in edit.items():
df.loc[row, column] = new_value
# Apply added rows
for row in changes['added_rows']:
# Create empty row
df.loc[df.shape[0]] = None
df = df.reset_index(drop=True)
# Remove deleted rows
df = df.drop(changes['deleted_rows'])
# Store the dataframe in the session key
st.session_state[key] = df
Now call the editor using:
data = st.session_state['df']
edited_data = st.data_editor(data, num_rows='dynamic', key='_df', on_change=store_df, args=['df'], hide_index=True)
Alternatives considered
Some alternatives that work for selection boxes and other widgets often don’t work for the data editor. For example:
def on_change(key):
st.session_state[key] = st.session_state['_'+key]
Does not work properly as it appears to be called before the private session state variable is updated.