Save an editable data frame

Hey there !
first of all I want to say this is a great platform and I enjoy to work with it !

I have an editable data frame that I want the user to filter (base on a few columns) and insert/edit rows . after adding/editing the data I want to save it and use it for further calculation .

This is the code I’m using but somehow every time I change the filter the added row deletes …
feels like every time I choose an app filter it starts the code all over agin

def load_and_edit_dataframe():

    budget_data = f'''
                select case WHEN app_name = 'popslot' then 'popslots' else app_name END as app_name,
     date_trunc('month',cast(b."month" as date)) as target_month,
    -- insertion_time,
          sum(cast(b.daily as decimal) ) AS daily_target,
          SUM (cast(b.monthly as decimal)) as monthly_target
    from postgresql.prod_global_ua.ua_budgets_v b 
    WHERE daily != ''    and  monthly  != '' and b."month" != '' and != '' and b.platform != '' and b.channel_type != ''
         AND cast(substr(b."month",1,4) as integer) > 2022
         --and app_name not like '%tetris2%' 
         --AND channel = 'adaction' AND platform = 'Android'
    group by app_name, 
             date_trunc('month',cast(b."month" as date)) '''

    budget_data = extract_data(budget_data)

    df = pd.DataFrame(budget_data)
    df = pd.DataFrame(df, columns=['app_name','target_month','platform','channel_type','channel','daily_target','monthly_target'])
    return df

# Create a Streamlit app
st.title("Budget Data Editor")

App = ["popslots", "mgms", "bingo", "bgpoker", "myvegas", "konami", "tetris", "tetris3", "brn_solitaire", "brn_spider",
Month = ["2023-01-01", "2023-02-01", "2023-03-01", "2023-04-01", "2023-05-01", "2023-06-01", "2023-07-01", "2023-08-01",
         "2023-09-01", "2023-10-01", "2023-11-01", "2023-12-01"]
Type = ["A-UA", "B-RT"]
channel_type = ["CPE", "Direct Deal", "DSP", "Native", "Preload", "Retargeting", "Search"]
channel = ["KashKick", "Prodege", "Blindferret", "bluestacks", "mistplay", "bigabid", "Moloco", "Taboola", "Aura",
           "digital", "kayzen", "Liftoff", "Tiktok", "YouAppi", "applesearchads", "google_ads", "Snapchat", "Liftoff"]
platform = ["Android", "iOS"]

editable_df = load_and_edit_dataframe()

edited_data = {}

column_config = {
        'app_name' : st.column_config.SelectboxColumn('App name', options=App),
        'target_month' : st.column_config.SelectboxColumn('Target month', options=Month),
        'platform' : st.column_config.SelectboxColumn('Platform', options=platform),
        'channel_type' : st.column_config.SelectboxColumn('Channel type', options=channel_type),
        'channel' : st.column_config.SelectboxColumn('Channel', options=channel),
        'daily_target' : st.column_config.NumberColumn('Daily target'),
        'monthly_target' : st.column_config.NumberColumn('Monthly target')

filter_text = st.selectbox("App name:", editable_df["app_name"].unique())

if filter_text in edited_data:
    filtered_df = edited_data[filter_text]
    filtered_df = editable_df[editable_df['app_name'] == filter_text]

edited_df = st.data_editor(filtered_df, column_config=column_config, key='data_editor',num_rows="dynamic")

edited_data[filter_text] = edited_df

counter = 0
counter +=1

Thank you for your help !

Hey Yuval, I had a similar issue with the data_editor.

I think, since you are (re)creating your “filtered_df” that goes into the data editor, any changes to the data in the data editor do not persist.

My hacky solution was to wrap the data editor into a function that continuously updates my “actual data” (in the session state) with the changes from the data editor. And I only work with this “actual data” everywhere else.

Not sure if this helps…

Hey !
Thank you !
Do you have an example that you can send to me ? :upside_down_face:

Thanks !!

Hey Yuval,

My existing code is working with st.session_state[ID_of_data_editor] (i.e. st.session_state[ID_of_data_editor]["added_rows"], "edited_rows" and "deleted_rows") instead of edited_df, which I can not recommend at all!
Instead, directly using the data_editor and triggering st.experimental_rerun should be much simpler. I have bookmarked this post on the topic: Experimental_data_editor column basic calculation - #5 by lim

This is schematically what I would do next time:

st.session_state.persistent_df = ...  # contains the actual data so that it is not lost when the data_editor is edited.
df = st.session_state.persistent_df  # or subset of
edited_df = st.data_editor(df)  # try column_order= to hide additional columns, see:
merge_df(st.session_state.persistent_df, edited_df)

def merge_df(st.session_state.persistent_df, edited_df):
    # merge the two dataframes

Hope this helps :slight_smile: