I am trying to change the value in a column based on changes made by the user in a different column with st.data_editor, and want to do it live on change. But the following code only works after 2 changes and only shows the initial change.
code is run by running streamlit run main.py
from page import page
page()
import streamlit as st
import pandas as pd
boq_df = pd.DataFrame()
def update_dataframe():
boq_df.loc[boq_df["ANALYZE"] == False, "TYPE"] = None
boq_df.ffill(inplace=True)
def page():
global boq_df
st.write("# Test")
if st.button("Analyze", type="primary"):
boq_df = pd.DataFrame(
data={
"ANALYZE": [True, False, True],
"CAT": ["Car", "Truck", "Bike"],
"TYPE": ["blue", False, "yellow"],
"DESC": ["two door", "four door", "single"],
}
)
if not boq_df.empty:
boq_df = st.data_editor(boq_df, height=700, on_change=update_dataframe())
Do not use a global variable in streamlit. Streamlit always rerun the code from top to bottom when there is a change in the user interface. Instead use the built-in dictionary-like session_state.
Also the on_change
in the data editor is only useful when you add or delete a row. For editing, use the return value of the data_editor
directly.
I tried to fix your code.
import streamlit as st
import pandas as pd
# Create a session variable
if 'boq' not in st.session_state:
st.session_state['boq'] = pd.DataFrame()
def page():
st.write("# Test")
# If button is pressed, assign a pre-built dataframe to the variable.
if st.button("Analyze", type="primary"):
st.session_state['boq'] = pd.DataFrame(
data={
"ANALYZE": [True, False, True],
"CAT": ["Car", "Truck", "Bike"],
"TYPE": ["blue", False, "yellow"],
"DESC": ["two door", "four door", "single"],
}
)
# If variable is not empty, construct a data_editor.
if not st.session_state['boq'].empty:
edited_df = st.data_editor(
st.session_state['boq'],
height=700
)
# If column "ANALYZE" is set to False, set the value of
# "TYPE" to None. Be sure to update column "TYPE" only if
# there are changes to column "ANALYZE".
is_equal = edited_df['ANALYZE'].equals(st.session_state['boq']['ANALYZE'])
if not is_equal:
edited_df.loc[edited_df["ANALYZE"] == False, "TYPE"] = None
edited_df.ffill(inplace=True)
st.session_state['boq'] = edited_df # update the variable
# Set streamlit to rerun the script from top to bottom
# to update the data editor.
st.rerun()
page()