This is going to get much harrier combining the filter with edits. What you’re going to have to do is use a callback on the data editor and read the edits saved in Session State, reverse lookup the (pandas) index of any rows that were edited, and commit those changes to the original. If you’re going to go through all that trouble to handle editing on a filtered DataFrame, we can extend that to edits on an unfiltered DataFrame and dispense with the extra rerun command in this case.
import streamlit as st
import pandas as pd
import time
if "dfa" not in st.session_state:
st.session_state["dfa"] = pd.DataFrame(
{
"Par": ["Apple", "Strawberry", "Banana"],
"Cat1": ["good", "good", "bad"],
"Cat2": ["healthy", "healthy", "unhealthy"],
"Active": [False, False, False],
}
)
def active_dfa():
return st.session_state["dfa"][st.session_state["dfa"]["Active"] == True].copy()
def get_index(row):
return active_dfa().iloc[row].name
def commit():
for row in st.session_state.editor["edited_rows"]:
row_index = get_index(row)
for key, value in st.session_state.editor["edited_rows"][row].items():
st.session_state["dfa"].at[row_index, key] = value
st.header("Filter and edit data")
name = st.text_input("Search for ...")
if name == "":
st.session_state["dfa"].Active = True
else:
st.session_state["dfa"].Active = False
st.session_state["dfa"].loc[
st.session_state["dfa"]["Par"].str.contains(name, case=False), "Active"
] = True
edited_dfa = st.data_editor(
active_dfa(), column_order=["Par", "Cat1", "Cat2"], key="editor", on_change=commit
)
This solution can also be extended to num_rows="dynamic"
but you’ll have to be extra careful handling the index to keep it hidden and not mucking up the user interface. Resetting the index with each row addition/deletion should do it…