How to create click events?

I Have a several questions for click events

Q1.

Already saw check button in dataframe But I don’t want to check button

Just Click dataframe row Then occur events!!

Q2.

IF Streamlit have that dataframe click event After Want to create another dataframe

My plan is that when people click on a row of the data frame, they will see a data frame showing relevant information next to it.

Hi there!
You can use the streamlit-aggrid custom module for callbacks after clicks. Though it is not exactly a dataframe, it creates an interactive table based on a dataframe. I think this post has the answer to your question:

Cheers,
Moiz

Thank you for your appreciate

I’ll make a nice visualization

You can also get the same behavior with some hacks with session state and experimental_data_editor. This adds a column called “select”, and if you check one of the boxes, it puts the selected row into st.session_state["last_selected_row"]

import streamlit as st
from datetime import date
import pandas as pd
import random
import numpy as np


@st.cache_data
def get_data():
    return pd.DataFrame(
        {
            "categorical": np.random.choice(
                ["A", "B", "C", "D", "E", "F", "G", "H", "I"], 30
            ),
            "date": np.random.choice(
                pd.date_range(date(2023, 7, 1), date(2023, 7, 31)), 30
            ),
            "numerical": np.random.randint(1, 10, 30),
        }
    )


if "data" not in st.session_state:
    df = get_data()
    df["select"] = False
    st.session_state["data"] = df

if "editor_key" not in st.session_state:
    st.session_state["editor_key"] = random.randint(0, 100000)

if "last_selected_row" not in st.session_state:
    st.session_state["last_selected_row"] = None


def get_row_and_clear_selection():
    key = st.session_state["editor_key"]
    df = st.session_state["data"]
    selected_rows = st.session_state[key]["edited_rows"]
    selected_rows = [int(row) for row in selected_rows if selected_rows[row]["select"]]
    try:
        last_row = selected_rows[-1]
    except IndexError:
        return
    df["select"] = False
    st.session_state["data"] = df
    st.session_state["editor_key"] = random.randint(0, 100000)
    st.session_state["last_selected_row"] = df.iloc[last_row]


st.data_editor(
    st.session_state["data"],
    key=st.session_state["editor_key"],
    on_change=get_row_and_clear_selection,
)

last_row = st.session_state["last_selected_row"]

if last_row is not None:
    st.write("Last selected row:", last_row)
    st.write("Do something with that data...")
1 Like

hello!
thank for your beautiful coding.
I need a checkbox with radio button-like functionality, like the one you implemented.

I want to display images saved on my computer when I click the ‘select’ checkbox.
(A different image must be displayed for each checkbox)
please help me. thank you!

Hi @wuram806 could you create a new forum post for this, since this is a new topic?

Thanks @blackary for this.

Just wondering if the “random.randint(0, 100000)” is to make the key different from the previous key?

If I’m assuming right, I might use something like “abs(st.session_state[“editor_key”] - 1)”.

Cheers

Yes, using a 2-cycle to update the key would also work. Avoiding the randomness does avoid the (small) chance of a repeat key twice in a row. :slight_smile:

1 Like

Hello! Thanks for your example, it is very useful.

I have a problem when updating the value of some widgets (concretely with the st.checkboxes).

I show on screen some widgets with the deafault values of those selected in the row from the dataframe.

Example:

When i edit these widgets, i could press the modify button (imagine this activates a function and save de changes), then, when i try to select another row to modify the values, and show its values in the widgets, all of them update their default values but the st. selectbox does not.
I was expecting a similar behaviour regarding the st.checkbox. But it keeps the value once you edit it.

If you try the code, notice that the default values of the widgets update correctly if you don´t edit them, but if you change something on the inputs, then select another row, all of them update but the checkbox does not.

import streamlit as st
from datetime import date
import pandas as pd
import random
import numpy as np


@st.cache_data
def get_data():
    return pd.DataFrame(
        {
            "categorical": np.random.choice(["A", "B", "C", "D", "E", "F", "G", "H", "I"], 30),
            "date": np.random.choice(pd.date_range(date(2023, 7, 1), date(2023, 7, 31)), 30 ),
            "numerical": np.random.randint(1, 10, 30),
            "bool": np.random.choice([True, False], 30)
        }
    )


if "data" not in st.session_state:
    df = get_data()
    df["select"] = False
    st.session_state["data"] = df

if "editor_key" not in st.session_state:
    st.session_state["editor_key"] = random.randint(0, 100000)

if "last_selected_row" not in st.session_state:
    st.session_state["last_selected_row"] = None


def get_row_and_clear_selection():
    key = st.session_state["editor_key"]
    df = st.session_state["data"]
    selected_rows = st.session_state[key]["edited_rows"]
    selected_rows = [int(row) for row in selected_rows if selected_rows[row]["select"]]
    try:
        last_row = selected_rows[-1]
    except IndexError:
        return
    df["select"] = False
    st.session_state["data"] = df
    st.session_state["editor_key"] = random.randint(0, 100000)
    st.session_state["last_selected_row"] = df.iloc[last_row]


st.data_editor(
    st.session_state["data"],
    key=st.session_state["editor_key"],
    on_change=get_row_and_clear_selection,
)

last_row = st.session_state["last_selected_row"]

if last_row is not None:
    st.write("Last selected row:", last_row)
    st.write("Do something with that data...")

    st.checkbox("Prueba", value= last_row["bool"])
    st.number_input("Prueba Number", value = last_row["numerical"])
    st.text_input("Prueba Text", value= last_row["categorical"])
    st.date_input("Prueba Date", value= last_row["date"])

    st.button("Modify") #on_click =...)

Hope you colud help me.

@Gonzalo_Marcos You can resolve this by adding an on_click button that updates the data, like this

def update_row():
    idx = st.session_state["last_selected_row_index"]

    st.session_state["data"].loc[idx, "categorical"] = st.session_state["prueba_text"]
    st.session_state["data"].loc[idx, "numerical"] = st.session_state["prueba_number"]
    st.session_state["data"].loc[idx, "bool"] = st.session_state["prueba"]
    st.session_state["data"].loc[idx, "date"] = str(st.session_state["prueba_date"])

...

    st.button("Modify", on_click=update_row)

Here’s the full script that worked for me

import streamlit as st
from datetime import date
import pandas as pd
import random
import numpy as np


@st.cache_data
def get_data():
    return pd.DataFrame(
        {
            "categorical": np.random.choice(
                ["A", "B", "C", "D", "E", "F", "G", "H", "I"], 30
            ),
            "date": np.random.choice(
                pd.date_range(date(2023, 7, 1), date(2023, 7, 31)), 30
            ),
            "numerical": np.random.randint(1, 10, 30),
            "bool": np.random.choice([True, False], 30),
        }
    )


if "data" not in st.session_state:
    df = get_data()
    df["select"] = False
    st.session_state["data"] = df

if "editor_key" not in st.session_state:
    st.session_state["editor_key"] = random.randint(0, 100000)

if "last_selected_row" not in st.session_state:
    st.session_state["last_selected_row"] = None


def get_row_and_clear_selection():
    key = st.session_state["editor_key"]
    df = st.session_state["data"]
    selected_rows = st.session_state[key]["edited_rows"]
    print(selected_rows)
    selected_rows = [int(row) for row in selected_rows if selected_rows[row]["select"]]
    try:
        last_row = selected_rows[-1]
    except IndexError:
        return
    df["select"] = False
    st.session_state["data"] = df
    st.session_state["editor_key"] = random.randint(0, 100000)
    st.session_state["last_selected_row"] = df.iloc[last_row]
    st.session_state["data"].loc[last_row, "select"] = True
    st.session_state["last_selected_row_index"] = last_row


st.data_editor(
    st.session_state["data"],
    key=st.session_state["editor_key"],
    on_change=get_row_and_clear_selection,
)


def update_row():
    idx = st.session_state["last_selected_row_index"]

    st.session_state["data"].loc[idx, "categorical"] = st.session_state["prueba_text"]
    st.session_state["data"].loc[idx, "numerical"] = st.session_state["prueba_number"]
    st.session_state["data"].loc[idx, "bool"] = st.session_state["prueba"]
    st.session_state["data"].loc[idx, "date"] = str(st.session_state["prueba_date"])


last_row = st.session_state["last_selected_row"]

if last_row is not None:
    st.write("Last selected row:", last_row)
    st.write("Do something with that data...")

    st.checkbox("Prueba", value=last_row["bool"], key="prueba")
    st.number_input("Prueba Number", value=last_row["numerical"], key="prueba_number")
    st.text_input("Prueba Text", value=last_row["categorical"], key="prueba_text")
    st.date_input("Prueba Date", value=last_row["date"], key="prueba_date")

    st.button("Modify", on_click=update_row)
1 Like

Thanks for your response!

I tried your script, and it modifies the cells properly, but when i change the selection in the dataframe, the default value of the checkbox does not update to the corresponding value of the new selected cell. Let me explain it with pictures:
In this first picture, i select one cell which has the bool value set to TRUE (by default), and the widgets appear, everything is ok.

Then, without editing any of the widgets and without clicking the modify button; i change the selection to a cell which has the bool value False, and the widgets update their default value. All ok.

When i edit the checkbox widget and press the modify button, it updates properly on the dataframe:

In the previous picture, i have already edited the checkbox, and everything is ok, but the problem i am dealing with arises when i change the selection to a cell that has the opposite default value of the one i edited before, that the default value of the widget does not update properly.

I have tried with possible solutions such as on_change events… but i cannot obtain the desired behaviour.

I don´t know if i have explained myself peoperly, in any case you can ask me.

Hope you could help me and thank you so much in advance.

Hello again, i still have problems regarding this behaviour, colud you please help me with this issue, i think this could be helpful for the community,
hope you could help me with the last post of this topic

I tweaked the script so that the keys of the widgets, including the checkbox, include the index of the selected row, so “prueba27” rather than just “prueba”, this seems to work to force streamlit to recreate the widget, which solves the problem of the checkbox keeping its old state

import streamlit as st
from datetime import date
import pandas as pd
import random
import numpy as np


@st.cache_data
def get_data():
    return pd.DataFrame(
        {
            "categorical": np.random.choice(
                ["A", "B", "C", "D", "E", "F", "G", "H", "I"], 30
            ),
            "date": np.random.choice(
                pd.date_range(date(2023, 7, 1), date(2023, 7, 31)), 30
            ),
            "numerical": np.random.randint(1, 10, 30),
            "bool": np.random.choice([True, False], 30),
        }
    )


if "data" not in st.session_state:
    df = get_data()
    df["select"] = False
    st.session_state["data"] = df

if "editor_key" not in st.session_state:
    st.session_state["editor_key"] = random.randint(0, 100000)

if "last_selected_row" not in st.session_state:
    st.session_state["last_selected_row"] = None


def get_row_and_clear_selection():
    key = st.session_state["editor_key"]
    df = st.session_state["data"]
    selected_rows = st.session_state[key]["edited_rows"]
    print(selected_rows)
    selected_rows = [int(row) for row in selected_rows if selected_rows[row]["select"]]
    try:
        last_row = selected_rows[-1]
    except IndexError:
        return
    df["select"] = False
    st.session_state["data"] = df
    st.session_state["editor_key"] = random.randint(0, 100000)
    st.session_state["last_selected_row"] = df.iloc[last_row]
    st.session_state["data"].loc[last_row, "select"] = True
    st.session_state["last_selected_row_index"] = last_row


st.data_editor(
    st.session_state["data"],
    key=st.session_state["editor_key"],
    on_change=get_row_and_clear_selection,
)


def update_row():
    idx = st.session_state["last_selected_row_index"]

    st.session_state["data"].loc[idx, "categorical"] = st.session_state[
        f"prueba_text{idx}"
    ]
    st.session_state["data"].loc[idx, "numerical"] = st.session_state[
        f"prueba_number{idx}"
    ]
    st.session_state["data"].loc[idx, "bool"] = st.session_state[f"prueba{idx}"]
    st.session_state["data"].loc[idx, "date"] = str(
        st.session_state[f"prueba_date{idx}"]
    )


last_row = st.session_state["last_selected_row"]
idx = st.session_state.get("last_selected_row_index", 0)

if last_row is not None:
    st.write("Last selected row:", last_row)
    st.write("Do something with that data...")

    st.checkbox("Prueba", value=last_row["bool"], key=f"prueba{idx}")
    st.number_input(
        "Prueba Number", value=last_row["numerical"], key=f"prueba_number{idx}"
    )
    st.text_input("Prueba Text", value=last_row["categorical"], key=f"prueba_text{idx}")
    st.date_input("Prueba Date", value=last_row["date"], key=f"prueba_date{idx}")

    st.button("Modify", on_click=update_row)
1 Like

Thank you so much !!

1 Like