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:
- View a DataFrame.
- Add new rows to the DataFrame.
- Edit existing rows in the DataFrame.
- 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()
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"]
})
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)
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()
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()
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()
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! 🎉
Top comments (0)