Interdependent widgets in forms

Hi everyone,

I am really stoked by the introduction of forms having first discovered the need more than a year ago :grin:And I must say the functionality works splendidly and intuitively out of the box - it took me just a few minutes for each app to start using forms in various places! So big kudos to the Streamlit team with the great functionality and documentation!

The only issue I have encountered, is that it is for obvious reasons a bit clonky to have interdependent widgets in forms, as also stated clearly in the docs.

I was wondering if it was possible to partly circumvent this issue by having a widget visually inside a form, which is not programmatically inside the form. I.e. a widget placed inside the ā€˜form widgetā€™ where changing its values should cause reruns. I tried a bit myself without luck and Iā€™m guessing it is not possible - but perhaps someone has already figured out a workaround? Thus far, my ā€˜workaroundā€™ is to click the submit button twice :sweat_smile:

Best regards,
Peter

1 Like

Glad you like the feature @PeterT! I have no idea the answer here, but Iā€™ll pass this feedback along to the product team in general about interdependent widgets :slight_smile:

Best,
Randy

@PeterT : Thanks for sharing your feedback! As of now, we donā€™t allow for interdependent widgets by design. We made this decision to simplify forms in v1.

Our focus in the near term is:

  1. To keep the API/feature relatively stable and fix bugs/errors
  2. See how the community uses st.forms and collect additional use cases

Can you please share your use case for ā€œhaving a widget visually inside a form, which is not programmatically inside the formā€ ? - It would be useful for us to keep in mind as we think about what to build in forms in the next version. Thanks!

Hi @abhi and Randy

Thanks for getting back to me.

Completely understand the focus you have.

To elaborate on what I need, Iā€™ve prepared a minimal example. This example is a bit contrived, as the layout here looks fine, but when you have a large form and the interdependent widgets are somewhere in the middle, the problem is more real. But I hope the example here makes it more clear what I mean. I am interested in the functionality from example 1 with the layout from example 2 below.

import streamlit as st
import pandas as pd
import numpy as np

@st.cache
def filter_df(df, column, min_value, max_value, default_min=0, default_max=100):
    if min_value != default_min or max_value != default_max:
        filter = (df[column] >= min_value) & (df[column] <= max_value)
        df = df[filter]
    return df

st.title("Example 1")
df = pd.DataFrame({"A" : np.arange(100), "B": np.arange(100), "C": np.arange(100)})

## With not so nice layout but right functionality
options = st.multiselect("Select columns", options=["A","B", "C"])
with st.form(key="example_1"):
    sliders = {option : st.slider(option, min_value=0, max_value=100, value=(0,100)) for option in options}
    st.form_submit_button("Submit")

# Here we apply filter from all sliders on the DF. This is potentially an expensive operation
# with large dfs, thus we want to use a form for the sliders
for column, (min_value, max_value) in sliders.items():
    df = filter_df(df, column, min_value, max_value)

st.write(df)

st.title("Example 2")
df = pd.DataFrame({"A" : np.arange(100), "B": np.arange(100), "C": np.arange(100)})

## With nice layout but needs to "double click" submit
with st.form(key="example_2"):
    options = st.multiselect("Select columns", options=["A","B", "C"])
    sliders = {option : st.slider(option, min_value=0, max_value=100, value=(0,100)) for option in options}
    st.form_submit_button("Submit")

# Here we apply filter from all sliders on the DF. This is potentially an expensive operation
# with large dfs, thus we want to use a form for the sliders
for column, (min_value, max_value) in sliders.items():
    df = filter_df(df, column, min_value, max_value)

st.write(df)

Best,
Peter

facing the same issue man. Iā€™ve a form which takes a file & seperator, then produces a pandas profile and ANOTHER form which is a selectbox (with options as df.columns from the file). Once I submit the 2nd form the whole app is re-run.