Unexpectedly behavior of fragment

Im running a local app of streamlit connected to aws.

I’m having a unexpectedly behavior related to fragment function.

This is my code:

    @st.fragment(run_every=5)
    def show_monitor(cluster_name: str) -> None:
        
        df = get_task_df(cluster_name)
        
        if not df.empty:
        
            st.dataframe(
                df.replace(
                    {'PROVISIONING':'INICIANDO', 
                    'PENDING':'ESPERANDO', 
                    'RUNNING':'TRANSCRIBIENDO', 
                    'STOPPED':'FINALIZADA'}
                ), 
                use_container_width=True, 
                selection_mode='single-row', 
                on_select='rerun', 
                hide_index=True,
                key='selected_row'
            )
            if st.session_state.selected_row['selection']['rows']:
                st.write(st.session_state.selected_row)
                selected_task_id = df.loc[st.session_state.selected_row['selection']['rows'][0], 'Task ID']
                st.write(f"Has seleccionado la task: `{selected_task_id}`")
                stop_task_button = st.button('Detener tarea')
                
                if stop_task_button:
                    try:
                        stop_task(cluster_name, selected_task_id, reason=f"Detencion manual por: {st.session_state.display_name}")
                        st.success(f"Se ha detenido con éxito la task: `{selected_task_id}`")
                    except:
                        st.warning(f"Ha ocurrido un error al detener la task: `{selected_task_id}`")
                        
    show_monitor(CLUSTER_NAME)

The issue occurs when I try to select a row; the app doesn’t display the selection, and I’m not sure why. Occasionally, if I repeatedly try to select the row, the selection does appear, but it’s inconsistent

Hi @sebastian.urbina, welcome to the forum!

I’m trying to reproduce what you’re seeing, but I’m not seeing any issue with this script:

import streamlit as st
from time import sleep
import pandas as pd


def get_task_df(cluster_name: str) -> pd.DataFrame:
    return pd.DataFrame(
        {"Task ID": [1, 2, 3], "Status": ["RUNNING", "PENDING", "STOPPED"]}
    )


def stop_task(cluster_name: str, task_id: str, reason: str) -> None:
    sleep(1)
    print(f"Stopping task {task_id} in cluster {cluster_name} because {reason}")


@st.fragment(run_every=5)
def show_monitor(cluster_name: str) -> None:
    df = get_task_df(cluster_name)

    if not df.empty:
        st.dataframe(
            df.replace(
                {
                    "PROVISIONING": "INICIANDO",
                    "PENDING": "ESPERANDO",
                    "RUNNING": "TRANSCRIBIENDO",
                    "STOPPED": "FINALIZADA",
                }
            ),
            use_container_width=True,
            selection_mode="single-row",
            on_select="rerun",
            hide_index=True,
            key="selected_row",
        )
        if st.session_state.selected_row["selection"]["rows"]:
            st.write(st.session_state.selected_row)
            selected_task_id = df.loc[
                st.session_state.selected_row["selection"]["rows"][0], "Task ID"
            ]
            st.write(f"Has seleccionado la task: `{selected_task_id}`")
            stop_task_button = st.button("Detener tarea")

            if stop_task_button:
                try:
                    stop_task(
                        cluster_name,
                        selected_task_id,
                        reason=f"Detencion manual por: {st.session_state.display_name}",
                    )
                    st.success(
                        f"Se ha detenido con éxito la task: `{selected_task_id}`"
                    )
                except:
                    st.warning(
                        f"Ha ocurrido un error al detener la task: `{selected_task_id}`"
                    )


CLUSTER_NAME = "cluster1"
show_monitor(CLUSTER_NAME)

My best guess is that it’s somehow related to the run_every=5, but that’s just a guess. I also tried adding a new column in the get_task_df function like this:

def get_task_df(cluster_name: str) -> pd.DataFrame:
    df = pd.DataFrame(
        {"Task ID": [1, 2, 3], "Status": ["RUNNING", "PENDING", "STOPPED"]}
    )
    df["current_time"] = pd.Timestamp.now()
    return df

If I do that, then it returns a new dataframe every time (because of the timestamp.now), and so the dataframe gets drawn from scratch and the selection gets undone.

If that function returns a new dataframe with different data sometimes, that could potentially explain what you’re seeing.

1 Like

How do you think I could fix the problem of the timestamp?

I want to track a process and I included the timestamp column… But If Iwant to delete one task sometimes it doesnt work as expectedly

Thank so much for your reply.

Hi @sebastian.urbina, I don’t think there’s a great way to preserve the selected row if the dataframe’s data changes under the hood.

If you load a given dataset, and the data doesn’t change, then selections, and triggering actions based on those selections, should work just fine.

If the underlying data needs to change dynamically, or every 5 seconds when the fragment reruns, I can’t think of a great solution to keeping your selections from the previous time a dataframe was shown.