Session state with pandas - editing a value

Hi all,

Iā€™m using streamlit 0.84.1.

My project loads a dataframe with a unique title on each row, and the user is allowed to modify the ā€œsubscribedā€ status of each row (all set to FALSE in the example below):

Currently when the ā€œsubscribedā€ status gets changed, rerunning the app from top to bottom clears those edits and resets everything. So Iā€™ll need to use session state to preserve those changes across re-runs and not lose that information.

However, I canā€™t figure out how to dynamically add to session state. The documentation example of using a counter worked because the counter variable always had the same name. Here, I think I want my [key] to be the title, and [value] to be the new ā€œsubscribedā€ state. (Users can change the ā€œsubscribedā€ status of the same title multiple times, but I havenā€™t figured out how to track that yet.)

if 'Developmental Biology' not in st.session_state:
    st.session_state['Developmental Biology'] = 'TRUE'

So, in my MWE below, I need some advice on how to proceed within the if st.button block. How do I get title to show as different names each time through the loop, such as Developmental Biology?

import streamlit as st
import pandas as pd

@st.cache(allow_output_mutation=True, suppress_st_warning=True)
def load_data(file):
    st.write("New file loaded")
    return pd.read_csv(file)#, sep=',', encoding='utf-8')  #Process the data in cached way to speed up processing

#load data
file = "test_10lines.csv"
df = load_data(file)

#change the Boolean TRUE/FALSE to simply uppercase strings
df['subscribed'] = df['subscribed'].astype(str)
df['subscribed'] = df['subscribed'].str.upper()
df

#offer user the journal titles, and they select one or multiple to edit at a time
selected_titles = st.multiselect('Journal Name:', pd.Series(df['title']), help='Displayed in order provided by the underlying datafile')
st.write(selected_titles)

#what to change 'subscribed' to
radiovalue = st.radio("Change 'Subscribed' status to:", ['TRUE', 'MAYBE', 'FALSE'])

if st.button('Commit change!'):
    for title in selected_titles:
        if title not in st.session_state:     #initialize counter the first time
            st.session_state.df['title'] = 'test'
        title_filter = (df['title'] == title)
        df.at[title_filter, 'subscribed'] = radiovalue

df

Have you considered using the AgGrid component, which you can set up to allow users to edit cells directly?

I did not know about AgGrid, thank you!

I think I came up with a solution. I made four separate lists, one each to store titles the user wants to change to TRUE, FALSE, MAYBE, and (blank).

# Initialize session_state versions of to_true/false/maybe/blank lists
if 'to_true' not in st.session_state:
    st.session_state.to_true = []
if 'to_false' not in st.session_state:
    st.session_state.to_false = []
if 'to_maybe' not in st.session_state:
    st.session_state.to_maybe = []
if 'to_blank' not in st.session_state:
    st.session_state.to_blank = []

When user commits the change to a title, I use a custom function to remove the title from all four lists so I only keep the most recent change for that title.

Then I add the title to whichever list matches what the user wanted.

            if st.button('Commit change!'):
                for title in selected_titles:
                    clear_title_from_list(title)  #remove title from all lists, so we only keep the most recent change

                if radiovalue == 'TRUE':
                    for title in selected_titles:
                        st.session_state.to_true.append(title)
                        
                if radiovalue == 'FALSE':
                    for title in selected_titles:
                        st.session_state.to_false.append(title)
                        
                if radiovalue == 'MAYBE':
                    for title in selected_titles:
                        st.session_state.to_maybe.append(title)
                        
                if radiovalue == " ":
                    for title in selected_titles:
                        st.session_state.to_blank.append(title)

Finally, I actually execute the changes. This runs every time the script runs but session_state lets me save the previous changes.

for title in st.session_state.to_true:
    title_filter = (df['title'] == title)
    df.at[title_filter, 'subscribed'] = 'TRUE'

for title in st.session_state.to_false:
    title_filter = (df['title'] == title)
    df.at[title_filter, 'subscribed'] = 'FALSE'
    
for title in st.session_state.to_maybe:
    title_filter = (df['title'] == title)
    df.at[title_filter, 'subscribed'] = 'MAYBE'
    
for title in st.session_state.to_blank:
    title_filter = (df['title'] == title)
    df.at[title_filter, 'subscribed'] = ' '

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