Update data in data_editor automatically

Summary

Share a clear and concise description of the issue. Aim for 2-3 sentences.

Steps to reproduce

Code snippet:

import streamlit as st 
import pandas as pd
import numpy as np
df=pd.DataFrame(
    [{"x":1,"y":0},
     {"x":2,"y":0},
     {"x":3,"y":0},
     {"x":4,"y":0},

     ]

    
)

edit_df=st.data_editor(df,num_rows="dynamic")
x1=edit_df.x.dropna()
y1=x1**2
edit_df.y=y1


If applicable, please provide the steps we should take to reproduce the error or specified behavior.

I want to get the input data x col in edit_df, update y col to x*x and show the new y on my app’

Explain what you expect to happen when you run the code above.

Actual behavior: the y col doesn’t update as my expect

Explain the undesired behavior or error you see when you run the code above.
If you’re seeing an error message, share the full contents of the error message here.

Debug info

  • Streamlit version: 1.25.0
  • Python version: 3.9.8
  • PyEnv
  • OS version: windows 10 22h2
  • Browser version: Edge 115.0.1901.203

Additional information

Hey every one, I’m new to streamlit and want to create a simple app which has the function I mention above but finally failed. Could anyone explain why the y col doesn’t update and tell me what happens after I input new number to the dynamic data editor? Will streamlit rerun the script automatically or something else? Thanks a lot!

@BioMastee
Please checkout this code for your solution:

import streamlit as st
import pandas as pd

# Create a DataFrame
df = pd.DataFrame([
    {"x": 1, "y": 0},
    {"x": 2, "y": 0},
    {"x": 3, "y": 0},
    {"x": 4, "y": 0}
])

# Create a dynamic data editor
edit_df = st.dataframe(df, height=400)

# Check if there are changes in the editor
if edit_df is not None:
    # Get the updated 'x' column from the editor
    x_values = edit_df['x']

    # Calculate the corresponding 'y' values
    y_values = x_values ** 2

    # Update the 'y' column in the original DataFrame
    df['y'] = y_values

   

Display the updated DataFrame

st.dataframe(df)

With this code, when you make changes in the dynamic data editor and click outside of the editor, it will update the ‘y’ column based on the updated ‘x’ column and display the updated DataFrame in your Streamlit app.

Thank You

Thank you so much. Since the script raises a mistake that ‘DeltaGenerator’ object is not subscriptable, I guess

edit_df = st.dataframe(df, height=400)

should be

edit_df = st.data_editor(df, height=400)

This partly solve my problem, because the new ‘y’ column is shown in the new dataframe. Coult it be possible to update the new ‘y’ in the first data editor ?
By the way, I guess once I change data in the data editor, the dataframe which is returned by data_editor will only update the data and the app will not change the data shown on the screen. Am I right?
Best regards!

The proposed solution shows (modified as @BioMastee suggested, by changing st.dataframe() to st.data_editor() to avoid the error) displays two date editors.

I would also really like to see a solution where a calculated column is displayed in the original data_editor.

I’m trying to update a column in a data editor based on the session state. If the row is edited (as per the edited_rows) then the columns should have a True value for that row, otherwise False.

This is how I am attempting to do this:

import streamlit as st
import pandas as pd

def df_on_change(df):
    state = st.session_state["df_editor"]
    for index, change_dict in state["edited_rows"].items():
        df.loc[df.index == index, "edited"] = True


# Create a DataFrame
df = pd.DataFrame([
    {"name": "Alice", "edited": False},
    {"name": "Bob", "edited": False},
    {"name": "Cecil", "edited": False},
])
edit_df = st.data_editor(df, key="df_editor", on_change=df_on_change, args=[df])

However, this doesn’t work. If I edit one of the rows, the on_change handler runs, but the data_editor keeps displaying False for all rows.

I suspect that this is because the data_editor makes a copy of the data source. There is a comment in the code saying that

# The dataframe should always be a copy of the original data
# since we will apply edits directly to it.

However, the copy that has been created isn’t exposed in any way (or not that I can see), so is it possible that the data of the data-editor cannot be changed from outside?

If that is the case, we could instead try to take another approach:

  1. modify the original dataframe when the data_editor change (using the on_change callback)
  2. re-render the data_editor based on the changed original dataframe.

The first part looks like working, but how do we do we re-render the original editor, as opposed to rendering another editor, as in the first proposed solution above?

I think I solved it with the help of this other post "StreamlitAPIException: Values for st.data_editor cannot be set using st.session_state" using data_editor to delete rows

The key ideas:

  1. save the dataframe to the session state
  2. update session state dataframe when something changes
  3. and use the session state datadrame as the data_edit source
import streamlit as st
import pandas as pd


df = pd.DataFrame([
    {"name": "Alice", "edited": False},
    {"name": "Bob", "edited": False},
    {"name": "Cecil", "edited": False},
])


def df_on_change(df):
    state = st.session_state["df_editor"]
    for index, updates in state["edited_rows"].items():
        st.session_state["df"].loc[st.session_state["df"].index == index, "edited"] = True
        for key, value in updates.items():
            st.session_state["df"].loc[st.session_state["df"].index == index, key] = value


def editor():
    if "df" not in st.session_state:
        st.session_state["df"] = df
    st.data_editor(st.session_state["df"], key="df_editor", on_change=df_on_change, args=[df])


editor()
1 Like