Selecting a single row while using st.data_editor with column config st.column_config.CheckboxColumn

Summary

Would love to enable checkbox for single selection while using st.data_editor() with column_config={"Select": st.column_config.CheckboxColumn()}

Code snippet: (from documentation )

                def dataframe_with_selections(df):
                    df_with_selections = df.copy()
                    df_with_selections.insert(0, "Select", False)
                    # Get dataframe row-selections from user with st.data_editor
                    edited_df = st.data_editor(
                        df_with_selections,
                        hide_index=True,
                        column_config={"Select": st.column_config.CheckboxColumn(required=True)},
                        disabled=df.columns,
                        num_rows="dynamic",
                    )

                    # Filter the dataframe using the temporary column, then drop the column
                    selected_rows = edited_df[edited_df.Select]
                    return selected_rows.drop('Select', axis=1)
                  
                selection = dataframe_with_selections(df)
                st.write("Your selection:")
                st.write(selection)

What I’m aiming for :

Single checkbox selection is enabled only.

How the above code is working:

With the above code, end-user can opt for multiple selections.


Probably I’m missing something very obvious. Any help would be appreciated! :balloon:

Cheers
Avra

Hi @AvratanuBiswas

Thanks for the question, could you elaborate a bit more on “single checkbox selection is enabled only”, not quite sure what the intended checkbox should be like.

In addition to default, st.column_config.CheckboxColumn() also has disabled and default parameters that may be explored upon.

Best regards,
Chanin

Hi,
I think I have the same issue. Is there a possibility to implement the option for single selection next to multiple selection in st.column_config.CheckboxColumn() or data_editor? Or maybe it was done and I don’t see the corresponding parameter. As far as I know, *it is only possible to check multiple check boxes. However, I want the user to only check one box. It is not possible via session_state to figure out which was the last selection due to the row index sorting. Otherwise, I could force to put all to false except the last selection. My workaround at the moment: If the user checks a second box and the index of the selection therefore exceeds 1, i force a page reload to uncheck (put false) all the boxes. This is rather ugly solution but the only one I have found.

Thanks a lot for your help!
Best regards,
Liv

def dataframe_with_selections(df_tools):
df_with_selections = df_tools.copy()
df_with_selections.insert(0, “Select”, False)

 # Get dataframe row-selections from user with st.data_editor
 edited_df = st.data_editor(
    df_with_selections,
    key="data_editor",
    hide_index=True,
    column_config={"Select": st.column_config.CheckboxColumn(required=True)},
    disabled=df_tools.columns,
 )

 # Filter the dataframe using the temporary column, then drop the column
 selected_rows = edited_df[edited_df.Select]
 return selected_rows.drop('Select', axis=1)
 if len(selected_rows.index) > 1:
  streamlit_js_eval(js_expressions="parent.window.location.reload()")

 return selected_rows

selection = dataframe_with_selections(df_tools)

2 Likes

Hey Avra, sorry totally forgot to answer on this. We already chatted that there’s probably no good way to do this today. I thought about it a bit today but I also couldn’t find any workaround (other than manually checking how many rows were selected and showing an error). We’ll definitely support this though once we implement row selections as a built-in feature!

3 Likes

This would be so useful!

Hi there
I believe that the implementation of a st.column_config.radiobutton or something similar might solve the issue

+1 for this feature (something equivalent to CheckboxColumn but only one cell can be selected at any given time. Many useful use cases for this , and the current workaround is very very messy (I’m using st.data_editor’s onchange, having to reset all the oother checked columns, and then rebuilding the dataframe. Which has a side effect that it loses any columnst he user may have sorted on).

1 Like

Essential for me – multiselect is a very different problem being solved, single select is essential for many (or at least my) applications. Stuck using a dodgey aggrid workaround until this is solved.
Radio, checkbox, or double-click row select (if highlighted) would be fine as long as it’s single-select.
Vote +1!

1 Like

Any update on that?

Any updates here ?

+1 This feature would be quite useful.

1 Like

Any workarounds while we await the update?

Utilize the on_change parameter. Record what has changed, set the column value to false, and update the dataframe on the change.

Complete sample code

import streamlit as st
from streamlit import session_state as ss
import pandas as pd


if 'selected_row_index' not in ss:
    ss.selected_row_index = None


@st.cache_data
def get_data(nrows):
    url = 'https://raw.githubusercontent.com/Munees11/Auto-MPG-prediction/master/Scripts/auto_mpg_dataset.csv'
    return pd.read_csv(url, nrows=nrows)


if 'df' not in ss:
    ss.df = get_data(10)
    ss.df['selected'] = [False] * len(ss.df)
    ss.df = ss.df[['cylinders', 'car_name', 'mpg', 'selected']]


def mpg_change():
    edited_rows: dict = ss.mpg['edited_rows']
    ss.selected_row_index = next(iter(edited_rows))
    ss.df = ss.df.assign(selected=False)
    update_dict = {idx: values for idx, values in edited_rows.items()}
    ss.df.update(pd.DataFrame.from_dict(update_dict, orient='index'))


def main():
    st.markdown('### Data Editor')
    with st.container(border=True):
        edf = st.data_editor(
            ss.df,
            hide_index=True,
            on_change=mpg_change,
            key='mpg',
            use_container_width=True
        )
    st.write(f'selected row index: {ss.selected_row_index}')
    if ss.selected_row_index is not None:
        st.write(f'car name: {ss.df.at[ss.selected_row_index, "car_name"]}')


if __name__ == '__main__':
    main()

1 Like

Thank you @ferdy , not sure I would have figured that one out. Still a bit more blinking than I would like but it does work!

Use this around 2x faster:

ss.df.loc[ss.df['selected'], 'selected'] = False

instead of:

ss.df = ss.df.assign(selected=False)
1 Like

This will be great feature to have. Any updates?

Some examples are here.

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