Select multiple options in checkboxes in Streamlit
Asked Answered
W

5

6

I am new to Streamlit. I want to make a multiple-choice user input (checkboxes). But I want to select a maximum of 3 options out of 4 options.

I have tried with the dropdown feature of multiselect.

import streamlit as st
option = st.multiselect('Select three known variables:', ['initial velocity (u)', 'final velocity (v)', 'acceleration (a)', 'time (t)'])  

It works. But I think it won't be user-friendly for my case. Also, here I couldn't limit the selections to 3 out of 4. The user can select all 4 options here. But I want the code such that if the 4th one is selected, the previous selection (3rd option) will be automatically un-selected. I prefer the looks of the checkboxes such as the radio buttons:

import streamlit as st
option = st.radio('Select three known variables:', ['initial velocity (u)', 'final velocity (v)', 'acceleration (a)', 'time (t)'])  

But using radio, I can't select multiple options. How can I edit it such that I can display it as checkboxes and only 3 options can be selected?

Whelm answered 20/3, 2021 at 4:24 Comment(1)
It seems that the limiting checkbox options is not possible yet...There's an open feature request for this in their Github repo - linkIncipit
I
5

This is visually closest to what you want, because they are actually checkboxes, not the radiobuttons. But you can't limit selected options, so all of them can be checked.

st.write('Select three known variables:')
option_1 = st.checkbox('initial velocity (u)')
option_2 = st.checkbox('final velocity (v)')
option_3 = st.checkbox('acceleration (a)')
option_4 = st.checkbox('time (t)')

enter image description here

As a workaround, you can use radiobuttons in a following way since they allow to check one combination only:

option = st.radio('Select three known variables:',
                  ['initial velocity (u), final velocity (v), acceleration (a)',
                   'initial velocity (u), final velocity (v), time (t)',
                   'initial velocity (u), acceleration (a), time (t)',
                   'final velocity (v),acceleration (a), time (t)'])

enter image description here

Incipit answered 21/3, 2021 at 22:16 Comment(2)
Thank you for answering. I was also thinking about this grouping technique with radio. But in my main program, the number of total options is 5. And I want to select any 3 from them. So, I would need to provide a total of 10 combinations that don't look good for my purpose.Whelm
checkbox can't limit selections. But is it possible to apply conditional statements such that if the user selects the 4th one, the previous selection (3rd option) will be automatically un-selected?Whelm
W
2

I haven't found any streamlit function that fulfills my need properly. So, I am using the function streamlit.checkbox as anilewe suggested and adding some extra conditional statements such that the user must select any 3 checkboxes. Here's my code:

import streamlit as st
st.write('Select three known variables:')
option_s = st.checkbox('displacement (s)')
option_u = st.checkbox('initial velocity (u)')
option_v = st.checkbox('final velocity (v)')
option_a = st.checkbox('acceleration (a)')
option_t = st.checkbox('time (t)')
known_variables = option_s + option_u + option_v + option_a + option_t

if known_variables <3:
    st.write('You have to select minimum 3 variables.')
elif known_variables == 3:
   st.write('Now put the values of your selected variables in SI units.')
else:
    st.write('You can select maximum 3 variables.')

Update: Creating a dictionary can be more automatic & useful; also helpful in case of changing the method from st.checkbox to something else:

import streamlit as st
st.write('Select three known variables:')
opts = [ ('s', 'displacement'), ('u', 'initial velocity'), ('v', 'final velocity'), ('a', 'acceleration'), ('t', 'time') ]
known_variables = {symbol: st.checkbox(f"{name} ({symbol})") for symbol, name in opts}    

if sum(known_variables.values()) < 3:
    st.write('You have to select minimum 3 variables.')
elif sum(known_variables.values()) == 3:
    st.write('Now put the values of your selected variables in SI units.')
else:
    st.write('You can select maximum 3 variables.')

Still, I am wishing to get a function that looks like checkbox or radio buttons but with a built-in feature to limit specific numbers of selections. In a word, I think my desired function can be called "multiselect-radio". Thus I won't have put the additional conditions on limiting selection by myself.

Whelm answered 23/3, 2021 at 13:45 Comment(0)
E
1

Consider using st.multiselect with argument max_selections=3.

import streamlit as st

st.multiselect(
    "Select three known variables:",
    ["initial velocity (u)", "final velocity (v)", "acceleration (a)", "time (t)"],
    max_selections=3,
)

enter image description here

You might also want to check for additional conditions, and then use combination of st.error(“please fix this problem”) and st.stop() to inform user about it.

Eu answered 25/8, 2023 at 23:46 Comment(2)
Nice. Seems like this argument max_selections didn't exist when I asked the question!Whelm
Also i dont see anyone mentioning st.error and st.stop, they would allow using just the checkboxes (you could check if exactly three are checked with “if sum(a+b+c+d)==3”, where “a=st.checkbox()”. If it’s not three, use st.error and then st.stopBurra
T
1

I created a class which can do pretty much what is requested. As a small difference, I chose to not unselect the last selected item (when reaching max_select). Instead, all non-selected items are dynamically disabled. If a selected item gets unselected, this "blockade" is lifted.

Also, you will have to give each of your CheckBoxArrays a name/key (but that is not a bad idea in any case). This name is prefixed to all the checkboxes in it for future reference and value checking.

Note that my solution is somewhat unusual, but I did not know how to do it properly (and frankly did not care enough for a deep dive into ST and finding out). Hope it helps though!

import streamlit as st 


class CheckBoxArray:
    def __init__(self, name: str, anchor, checkboxes: list[str], max_select: int, num_cols=1):
        self.name = name
        self.anchor = anchor
        cols = self.anchor.columns(num_cols)
        cb_values = [st.session_state.get(f"{self.name}_{i}", False) for i, _ in enumerate(checkboxes)]
        disable = sum(cb_values) == max_select
        for i, cb in enumerate(checkboxes):
            cols[i % num_cols].checkbox(label=cb, disabled=(not cb_values[i] and disable), key=f"{self.name}_{i}")


cb_array = CheckBoxArray("cb_array1", st, checkboxes=["a", "b", "c", "d"], num_cols=2, max_select=3)
st.write(st.session_state)

enter image description here

Teddi answered 18/7 at 15:49 Comment(0)
W
1

st.multiselect now has a max_selections argument (I tested this in Streamlit 1.39.0). Here's a demo.

enter image description here

import streamlit as st

st.title("Multiple Choice Example")

options = st.multiselect(
    "Select your options (max 3)",
    options=["Option 1", "Option 2", "Option 3", "Option 4"],
    max_selections=3,
)

st.write("You selected:", options)
Whiff answered 23/10 at 0:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.