Filter data in data_editor

Ah, yes. You’ll have to collect edits then only commit them upon changing the filter instead, I think. I’m on mobile now, but I’ll try to write something up in a little bit.

Hi Debbie,

for a better overview I sent you the full code structure.
If the solution has anything to do with containers, nested functions, st.stop or similar, this has perhaps influence on the full code.

You can probably ignore the details of the widgets - only that you know the whole structure (with your filter solution inside :heart: )

import pandas as pd
import streamlit as st
import as px
from streamlit import session_state as ss
import time

st.set_page_config(layout='wide', page_title='Test')

# Set title and design elements according to RB brand guide

def run_query():
    # Here is normally my SQL query 
    return df_sql

if 'df' not in ss:
    ss.df = run_query()
    ss.df['Active'] = True
if 'setvis' not in ss:
    ss.setvis = 'B'

# Upload new file and add to data_editor (here - double existing df)
if 'file_processed' not in ss:
    ss['file_processed'] = False

uploaded_file = st.file_uploader('**Upload file**', type= ['csv'] )

if uploaded_file is None:
    ss['file_processed'] = False

if uploaded_file is not None and not ss['file_processed']:
    ss['filter']= ''
    ss['file_processed'] = True

# Create columns 
col1, col2 = st.columns([8,2],gap="large")

# Complex filter mechanism in combination with st.data_editor by mathcatsand 🧡
def active_dfa():
    return ss.df[ss.df['Active'] == True].copy()

def get_index(row):
    return active_dfa().iloc[row].name

def commit():
    for row in ss.editor['edited_rows']:
        row_index = get_index(row)
        for key, value in ss.editor['edited_rows'][row].items():
  [row_index, key] = value

# Create filter
name = col1.text_input('Search for ....',key='filter')

if name == '':
    ss.df.Active = True
    ss.df.Active = False
    ss.df.loc[ss.df['A'].str.contains(name, case=False), 'Active'] = True

# Dataeditor
df_ed=col1.data_editor(active_dfa(),hide_index=True, use_container_width=True,column_order=['A','B','C'],key='editor',on_change=commit)

# Plot precreation depending radiobutton'Set visualization category',['B','C'], horizontal=True)
fig1= px.pie(names=df_plot.index,values=df_plot).update_traces(sort=False)
fig2=, y=df_plot, log_y=True).update_layout(showlegend=False)

# Establish vizualisation in different tabs
tab1, tab2 = col2.tabs(['distribution pie', 'distribution bar'])
with tab1:
    st.plotly_chart(fig1, theme='streamlit', use_container_width=True)
with tab2:
    st.plotly_chart(fig2, theme='streamlit', use_container_width=True)

# Save dataframe
if col1.button('Save dataframe'):
    time(5) # Save it anywhere
    del ss.df

It’s not particularly dependent on other stuff. Basically move the commit callback function to the filter input and then ensure the commit action is at the top of every other page to make sure edits are not lost if someone filters+edits+changes pages (without unfiltering) or makes an edit while not filtered (and doesn’t immediately change the filter). You could also add a confirm button or something to make sure any final edits are committed; it just depends on what kind of a workflow you want the users to have.

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 ...", on_change=commit)
if name == "":
    st.session_state["dfa"].Active = True
    st.session_state["dfa"].Active = False
        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"

st.button("Save", on_click=commit)

At the beginning of every other page (if you have them), after importing or redefining the necessary functions, add:

if "dfa" in st.session_state:
1 Like

Thanks @mathcatsand !!!
Great to have solved this with you.

Think about the different commit possibilities.

Another idea I had is using a form, where the data_editor is nested. With the form_submit_button I raised the commit then.

with st.form('fde') as f:
  edited_dfa = st.data_editor(
      active_dfa(), column_order=["Par", "Cat1", "Cat2"], key="editor"

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.