Using form_submit_button and st.sidebar.multiselect

Hello everyone!

I am new to streamlit and I am trying to build an app with the following functionality:

  1. Select / drop some features and train a bunch of models. I created st.sidebar.multiselect to drop features and using form_submit_button to create a button to initiate training.
  2. After training, print the scores for all the models.
  3. After looking at the scores, select few models (using st.sidebar.multiselect) and plot a graph between actual and predicted for only those models.

I wrote the following code:

drops = st.sidebar.multiselect('Pick any items you want to remove from the analysis.', df.keys())
form = st.form(key = 'myform', clear_on_submit = False)
submit = form.form_submit_button('Train Models')
if submit:
    scores, features, predictions, y_test, data_raw, scaler, lr, ridge, lasso, tree, forest, gbr, lin_svr = main_analysis(df, target_name, drops)
    st.write('Here are the scores from the models that were run:')
    df_scores = pd.DataFrame.from_dict(scores)
    df_scores
    st.write('Based on the model scores above, pick the models you want to use to continue this analysis.')

    best_models = st.sidebar.multiselect('Pick top model scores:',df_scores.keys())

When I run the code, I see a submit button (Train Models), I am able to train models and get the scores after I click on the submit button. When I try to select few models with st.sidebar.multiselect, everything is getting reset and reverting to ‘Train Models’ stage. The selections are not stored.

I tried the same thing using st.button, it does the same thing.

How do I store the selections after using a submit button?
Any help is greatly appreciated

Hi @ceeva ,

How about using st.session_state function to store your scores data frame . Please do check the doc for quick start .

Cheers
Avra

Hi @AvratanuBiswas Thanks for responding! I was doing some research on the same thing, but I was unsure of what or how to store in st.session_state. I did something like this, I know this looks really silly

if 'df' not in st.session_state:
        st.session_state.df = df_scores

which obviously did not work :zipper_mouth_face:

Hi @ceeva ,

Oh, what error did you get ?
if it’s a DatFrame, it can be stored using session state.

Try the easy snipet below, it works for me.

import streamlit as st
import pandas as pd

d = {'col1': [1, 2], 'col2': [3, 4]}
df_Scores = pd.DataFrame(data = d)

if 'df' not in st.session_state:
    st.session_state.df = df_Scores

st.write(st.session_state.df)

Cheers
Avra

Hi Avra,

I did the same thing, there was no error, but when I select my models, it goes back to the ‘train’ dataset step. I tried recording what happens, but I am no able to attach the file. I took screen shots instead.




Thanks a lot!
Ceeva

Hi @ceeva ,

So it seems that after you select from the multiselect option, the app re runs from the very beggining and it stops just before the “train” button.

  • One workaround (not the best) can be is to use checkbox instead of button, but in that way you are reperforming the computational part
  • Other workaround, use session_state to keep the state of the Button widget “ON”
  • Otherwise, what about wrapping the main analysis into a function, and use @st.cache / st.experimental_memo[ refer to the doc for it’s usage] , in this way you can avoid the recomputation of the main_analyis

Goodluck,
Avra

Hi Avra!

I actually have my main_analysis() wrapped around a @st.cache:
I am doing something like this:

@st.cache(allow_output_mutation=True)
def main_analysis(df, target_name, drops):
   target = df[[target_name]]
   data_raw = df.drop(drops, axis=1)

This did not make any changes - it still resets the page and stops at ‘Train’ button. (Not working)

With keeping the button state ON,
I tried something like this :

def_button = st.button('train')
if 'def_button' not in st.session_state:
    st.session_state.def_button = True
  
if st.session_state.def_button:
    scores, features, predictions, y_test, data_raw, scaler, lr, ridge, lasso, lin_svr = main_analysis(df, target_name, drops)

This keeps the state of button ON even before clicking, which trains the model even before I click the button - I think there is no use of having a button and setting it to true before clicking.

I tried setting the button state ON after clicking the button, but this does the same thing as before - rerun from the beginning and stopping at ‘train’ button (Not Working)

def_button = st.button('train')
if def_button:
   if 'def_button' not in st.session_state:
         st.session_state.def_button = True
    scores, features, predictions, y_test, data_raw, scaler, lr, ridge, lasso, lin_svr = main_analysis(df, target_name, drops)

Thanks a lo for all the help!
Ceeva

Hi @ceeva ,

I’m glad! Perferct ! If @st.cache worked, that’s the best possible workaround!

Have a good time with your work,

Cheers,
Avra

Hi Avra,

Sorry for miscommunication :sweat_smile:, using @st.cache did not make any changes, I had the function wrapped around @st.cache right from the beginning.

Thank you,
Ceeva

Yes, st.cache needs to be used in that way.

Like you did here ,

Best,
Avra