DEV Community

A0mineTV
A0mineTV

Posted on

Interactive DataFrame Management with Streamlit Fragments ๐Ÿš€

Introduction

Streamlit is a powerful Python framework designed to create interactive web applications for data analysis and visualization effortlessly. With the addition of the @st.fragment decorator, Streamlit allows developers to modularize their applications more effectively, improving performance and maintainability.

In this article, we'll explore how to create an interactive DataFrame management tool using the @st.fragment decorator. This tool will enable users to:

  1. View a DataFrame.
  2. Add new rows to the DataFrame.
  3. Edit existing rows in the DataFrame.
  4. Delete rows from the DataFrame.

Why Use @st.fragment?

The @st.fragment decorator provides a mechanism to encapsulate specific portions of your Streamlit app, minimizing unnecessary re-runs and improving performance. This feature is particularly useful in applications where distinct components interact independently but still share a global state.

By using @st.fragment, you:

  • Optimize Performance: Only the fragments involved in an interaction are refreshed, reducing the computational overhead.
  • Enhance Code Modularity: You can isolate different functionalities into separate fragments, making your codebase easier to maintain and debug.
  • Improve User Experience: Smooth and responsive interactions for your users without reloading unrelated components.

Full Code Example

Below is the complete code for the interactive DataFrame management tool:

import streamlit as st
import pandas as pd

# Initialize session state if not already set
if "data" not in st.session_state:
    st.session_state.data = pd.DataFrame({
        "Nom": ["Alice", "Bob", "Charlie"],
        "ร‚ge": [25, 30, 35],
        "Ville": ["Paris", "Londres", "Berlin"]
    })

@st.fragment
def display_dataframe_fragment():
    """
    Fragment to display the current DataFrame.
    """
    st.subheader('Current DataFrame')
    st.dataframe(st.session_state.data)

@st.fragment
def add_row_fragment():
    """
    Fragment to add a new row to the DataFrame.
    """
    st.subheader('Add a Row')
    with st.form(key="add_row_form"):
        name = st.text_input('Name')
        age = st.number_input('Age', min_value=0, max_value=120, step=1)
        city = st.text_input('City')
        submitted = st.form_submit_button("Add")
        if submitted:
            if name and city:
                new_row = {"Nom": name, "ร‚ge": age, "Ville": city}
                st.session_state.data = pd.concat(
                    [st.session_state.data, pd.DataFrame([new_row])], ignore_index=True
                )
                st.success('Row added successfully.')
                st.rerun()
            else:
                st.error('Please fill in all required fields.')

@st.fragment
def edit_row_fragment():
    """
    Fragment to edit an existing row in the DataFrame.
    """
    st.subheader('Edit a Row')
    if not st.session_state.data.empty:
        row_index = st.selectbox(
            'Select a row to edit (by index)',
            st.session_state.data.index
        )
        row_data = st.session_state.data.iloc[row_index]
        with st.form(key='edit_row_form'):
            name = st.text_input('Name', value=row_data['Nom'])
            age = st.number_input('Age', min_value=0, max_value=120, step=1, value=row_data["ร‚ge"])
            city = st.text_input('City', value=row_data['Ville'])
            submitted = st.form_submit_button('Edit')
            if submitted:
                st.session_state.data.loc[row_index] = [name, age, city]
                st.success(f'Row {row_index} edited successfully.')
                st.rerun()
    else:
        st.warning('No data available for editing.')

@st.fragment
def delete_row_fragment():
    """
    Fragment to delete a row from the DataFrame.
    """
    st.subheader('Delete a Row')
    if not st.session_state.data.empty:
        row_index = st.selectbox(
            "Select a row to delete (by index)",
            st.session_state.data.index
        )
        if st.button('Delete'):
            st.session_state.data = st.session_state.data.drop(row_index).reset_index(drop=True)
            st.success(f'Row {row_index} deleted successfully.')
            st.rerun()
    else:
        st.warning('No data available for deletion.')

# Main interface
st.title("Interactive DataFrame Management")

# Call the fragments
display_dataframe_fragment()
add_row_fragment()
edit_row_fragment()
delete_row_fragment()
Enter fullscreen mode Exit fullscreen mode

Detailed Explanation of the Code

1. Session State Initialization

The DataFrame is stored in st.session_state to persist its state across user interactions. If the app is run for the first time or reloaded, st.session_state.data is initialized with some default data.

if "data" not in st.session_state:
    st.session_state.data = pd.DataFrame({
        "Nom": ["Alice", "Bob", "Charlie"],
        "ร‚ge": [25, 30, 35],
        "Ville": ["Paris", "Londres", "Berlin"]
    })
Enter fullscreen mode Exit fullscreen mode

2. Fragment: Display DataFrame

The display_dataframe_fragment uses st.dataframe() to display the current state of the DataFrame. This fragment ensures that the displayed data is always up-to-date.

@st.fragment
def display_dataframe_fragment():
    st.subheader('Current DataFrame')
    st.dataframe(st.session_state.data)
Enter fullscreen mode Exit fullscreen mode

3. Fragment: Add a Row

The add_row_fragment uses a form to gather user input for adding a new row. When the form is submitted, the new data is concatenated to the existing DataFrame, and the app is refreshed using st.rerun().

@st.fragment
def add_row_fragment():
    st.subheader('Add a Row')
    with st.form(key="add_row_form"):
        name = st.text_input('Name')
        age = st.number_input('Age', min_value=0, max_value=120, step=1)
        city = st.text_input('City')
        submitted = st.form_submit_button("Add")
        if submitted:
            if name and city:
                new_row = {"Nom": name, "ร‚ge": age, "Ville": city}
                st.session_state.data = pd.concat(
                    [st.session_state.data, pd.DataFrame([new_row])], ignore_index=True
                )
                st.success('Row added successfully.')
                st.rerun()
Enter fullscreen mode Exit fullscreen mode

4. Fragment: Edit a Row

The edit_row_fragment allows users to select a row by its index and update its values through a form. The changes are applied to the DataFrame, and the app is refreshed.

@st.fragment
def edit_row_fragment():
    st.subheader('Edit a Row')
    if not st.session_state.data.empty:
        row_index = st.selectbox(
            'Select a row to edit (by index)',
            st.session_state.data.index
        )
        row_data = st.session_state.data.iloc[row_index]
        with st.form(key='edit_row_form'):
            name = st.text_input('Name', value=row_data['Nom'])
            age = st.number_input('Age', min_value=0, max_value=120, step=1, value=row_data["ร‚ge"])
            city = st.text_input('City', value=row_data['Ville'])
            submitted = st.form_submit_button('Edit')
            if submitted:
                st.session_state.data.loc[row_index] = [name, age, city]
                st.success(f'Row {row_index} edited successfully.')
                st.rerun()
Enter fullscreen mode Exit fullscreen mode

5. Fragment: Delete a Row

The delete_row_fragment enables row deletion based on a selected index. After deletion, the DataFrame is updated, and the app refreshes to reflect the changes.

@st.fragment
def delete_row_fragment():
    st.subheader('Delete a Row')
    if not st.session_state.data.empty:
        row_index = st.selectbox(
            "Select a row to delete (by index)",
            st.session_state.data.index
        )
        if st.button('Delete'):
            st.session_state.data = st.session_state.data.drop(row_index).reset_index(drop=True)
            st.success(f'Row {row_index} deleted successfully.')
            st.rerun()
Enter fullscreen mode Exit fullscreen mode

Conclusion

By leveraging the @st.fragment decorator, Streamlit applications can become more modular, efficient, and responsive. This example demonstrates a simple yet effective way to manage a DataFrame interactively, but the same principles can be applied to other use cases involving user interactions and dynamic updates.

Let us know in the comments how you plan to use @st.fragment in your projects, or share any feedback or improvements! ๐Ÿš€


Happy coding! ๐ŸŽ‰

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (0)

Heroku

This site is powered by Heroku

Heroku was created by developers, for developers. Get started today and find out why Heroku has been the platform of choice for brands like DEV for over a decade.

Sign Up

๐Ÿ‘‹ Kindness is contagious

Explore a sea of insights with this enlightening post, highly esteemed within the nurturing DEV Community. Coders of all stripes are invited to participate and contribute to our shared knowledge.

Expressing gratitude with a simple "thank you" can make a big impact. Leave your thanks in the comments!

On DEV, exchanging ideas smooths our way and strengthens our community bonds. Found this useful? A quick note of thanks to the author can mean a lot.

Okay