Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
Build interactive data applications and dashboards with pure Python - no frontend experience required
author
workspace-hub
category
data-analysis
capabilities
["Rapid prototyping of data applications","Interactive widgets and user inputs","Data visualization integration (Plotly, Matplotlib, Altair)","Caching for performance optimization","Session state management","Multi-page application support","Cloud deployment ready"]
Build beautiful, interactive data applications with pure Python. Transform data scripts into shareable web apps in minutes with widgets, charts, and layouts.
When to Use This Skill
USE Streamlit when:
Rapid prototyping - Need to build a data app quickly
Internal tools - Creating tools for your team
Data exploration - Interactive exploration of datasets
Demo applications - Showcasing data science projects
ML model demos - Building interfaces for model inference
Simple dashboards - Quick insights without complex setup
Python-only development - No JavaScript/frontend knowledge required
DON'T USE Streamlit when:
Complex interactivity - Need fine-grained callback control (use Dash)
import streamlit as st
tab1, tab2, tab3 = st.tabs(["📈 Chart", "📊 Data", "⚙️ Settings"])
with tab1:
st.header("Chart View")
# Add chart herewith tab2:
st.header("Data View")
# Add dataframe herewith tab3:
st.header("Settings")
# Add settings here
Expanders and Containers:
import streamlit as st
# Expander (collapsible section)with st.expander("Click to expand"):
st.write("Hidden content revealed!")
st.code("print('Hello')")
# Container (grouping elements)with st.container():
st.write("This is inside a container")
col1, col2 = st.columns(2)
col1.write("Left")
col2.write("Right")
# Container with borderwith st.container(border=True):
st.write("Content with border")
# Empty placeholder (for dynamic updates)
placeholder = st.empty()
placeholder.text("Initial text")
# Later: placeholder.text("Updated text")
4. Data Visualization
Plotly Integration:
import streamlit as st
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
# Sample data
df = pd.DataFrame({
"date": pd.date_range("2025-01-01", periods=100),
"value": [i + (i % 7) * 5for i inrange(100)],
"category": ["A", "B", "C", "D"] * 25
})
# Plotly Express charts
fig = px.line(df, x="date", y="value", color="category", title="Time Series")
st.plotly_chart(fig, use_container_width=True)
# Scatter plot
fig_scatter = px.scatter(
df, x="date", y="value",
color="category", size="value",
hover_data=["category"]
)
st.plotly_chart(fig_scatter, use_container_width=True)
# Bar chart
category_totals = df.groupby("category")["value"].sum().reset_index()
fig_bar = px.bar(category_totals, x="category", y="value", title="Category Totals")
st.plotly_chart(fig_bar, use_container_width=True)
# Graph Objects for more control
fig_go = go.Figure()
fig_go.add_trace(go.Scatter(
x=df["date"],
y=df["value"],
mode="lines+markers",
name="Values"
))
fig_go.update_layout(title="Custom Plotly Chart", hovermode="x unified")
st.plotly_chart(fig_go, use_container_width=True)
Built-in Charts:
import streamlit as st
import pandas as pd
import numpy as np
# Sample data
chart_data = pd.DataFrame(
np.random.randn(20, 3),
columns=["A", "B", "C"]
)
# Simple line chart
st.line_chart(chart_data)
# Area chart
st.area_chart(chart_data)
# Bar chart
st.bar_chart(chart_data)
# Scatter chart (Streamlit 1.26+)
scatter_data = pd.DataFrame({
"x": np.random.randn(100),
"y": np.random.randn(100),
"size": np.random.rand(100) * 100
})
st.scatter_chart(scatter_data, x="x", y="y", size="size")
# Map
map_data = pd.DataFrame({
"lat": np.random.randn(100) / 50 + 37.76,
"lon": np.random.randn(100) / 50 - 122.4
})
st.map(map_data)
Matplotlib Integration:
import streamlit as st
import matplotlib.pyplot as plt
import numpy as np
# Create matplotlib figure
fig, ax = plt.subplots(figsize=(10, 6))
x = np.linspace(0, 10, 100)
ax.plot(x, np.sin(x), label="sin(x)")
ax.plot(x, np.cos(x), label="cos(x)")
ax.legend()
ax.set_title("Matplotlib Chart")
# Display in Streamlit
st.pyplot(fig)
5. Caching for Performance
Cache Data (for expensive data operations):
import streamlit as st
import pandas as pd
import polars as pl
import time
@st.cache_datadefload_data(file_path: str) -> pd.DataFrame:
"""Load and cache data. Cache key: file_path."""
time.sleep(2) # Simulate slow loadreturn pd.read_csv(file_path)
@st.cache_data(ttl=3600) # Cache expires after 1 hourdeffetch_api_data(endpoint: str) -> dict:
"""Fetch data from API with time-based cache."""import requests
response = requests.get(endpoint)
return response.json()
@st.cache_data(show_spinner="Loading data...")defload_with_spinner(path: str) -> pl.DataFrame:
"""Show custom spinner while loading."""return pl.read_parquet(path)
# Using cached functions
df = load_data("data/sales.csv") # First call: slow
df = load_data("data/sales.csv") # Second call: instant (cached)# Clear cache programmaticallyif st.button("Clear cache"):
st.cache_data.clear()
Cache Resources (for global resources):
import streamlit as st
from sqlalchemy import create_engine
@st.cache_resourcedefget_database_connection():
"""Cache database connection (singleton pattern)."""return create_engine("postgresql://user:pass@localhost/db")
@st.cache_resourcedefload_ml_model():
"""Cache ML model (loaded once per session)."""import joblib
return joblib.load("model.pkl")
# Use cached resources
engine = get_database_connection()
model = load_ml_model()
6. Session State
Managing State:
import streamlit as st
# Initialize stateif"counter"notin st.session_state:
st.session_state.counter = 0if"messages"notin st.session_state:
st.session_state.messages = []
# Display current state
st.write(f"Counter: {st.session_state.counter}")
# Update state with buttons
col1, col2, col3 = st.columns(3)
if col1.button("Increment"):
st.session_state.counter += 1
st.rerun()
if col2.button("Decrement"):
st.session_state.counter -= 1
st.rerun()
if col3.button("Reset"):
st.session_state.counter = 0
st.rerun()
# State with widgets
st.text_input("Name", key="user_name")
st.write(f"Hello, {st.session_state.user_name}!")
# State callbackdefon_change():
st.session_state.processed = st.session_state.raw_input.upper()
st.text_input("Raw input", key="raw_input", on_change=on_change)
if"processed"in st.session_state:
st.write(f"Processed: {st.session_state.processed}")
Form State:
import streamlit as st
# Forms prevent rerunning on every widget changewith st.form("my_form"):
st.write("Submit all at once:")
name = st.text_input("Name")
age = st.number_input("Age", min_value=0, max_value=120)
color = st.selectbox("Favorite color", ["Red", "Green", "Blue"])
# Every form needs a submit button
submitted = st.form_submit_button("Submit")
if submitted:
st.success(f"Thanks {name}! You're {age} and like {color}.")
import streamlit as st
st.set_page_config(
page_title="Multi-Page App",
page_icon="🏠",
layout="wide"
)
st.title("Welcome to My App")
st.write("Use the sidebar to navigate between pages.")
# Shared state initializationif"user"notin st.session_state:
st.session_state.user = None
Page 1 (pages/1_Dashboard.py):
import streamlit as st
st.set_page_config(page_title="Dashboard", page_icon="📊")
st.title("📊 Dashboard")
st.write("This is the dashboard page")
# Access shared stateif st.session_state.get("user"):
st.write(f"Welcome back, {st.session_state.user}!")
Page 2 (pages/2_Analytics.py):
import streamlit as st
st.set_page_config(page_title="Analytics", page_icon="📈")
st.title("📈 Analytics")
st.write("This is the analytics page")
# Add analytics content
8. Advanced Features
Status and Progress:
import streamlit as st
import time
# Progress bar
progress = st.progress(0, text="Processing...")
for i inrange(100):
time.sleep(0.01)
progress.progress(i + 1, text=f"Processing... {i+1}%")
# Spinnerwith st.spinner("Loading data..."):
time.sleep(2)
st.success("Done!")
# Status messages
st.success("Operation successful!")
st.info("This is informational")
st.warning("Warning: Check your inputs")
st.error("An error occurred")
st.exception(ValueError("Example exception"))
# Toast notifications
st.toast("Data saved!", icon="✅")
# Balloons and snow
st.balloons()
st.snow()
Chat Interface:
import streamlit as st
import time
st.title("Chat Demo")
# Initialize chat historyif"messages"notin st.session_state:
st.session_state.messages = []
# Display chat historyfor message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
# Chat inputif prompt := st.chat_input("What's on your mind?"):
# Add user message
st.session_state.messages.append({"role": "user", "content": prompt})
with st.chat_message("user"):
st.markdown(prompt)
# Generate responsewith st.chat_message("assistant"):
response = f"You said: {prompt}"
st.markdown(response)
st.session_state.messages.append({"role": "assistant", "content": response})
# GOOD: Initialize state at the topif"data"notin st.session_state:
st.session_state.data = None# GOOD: Use callbacks for complex updatesdefon_filter_change():
st.session_state.filtered_data = apply_filter(st.session_state.data)
st.selectbox("Filter", options, on_change=on_filter_change)
4. Optimize Performance
# Use containers for layout stability
placeholder = st.empty()
# Batch widget updates in formswith st.form("filters"):
# Multiple widgets
st.form_submit_button()
# Use columns for responsive layout
cols = st.columns([1, 2, 1])
Troubleshooting
Common Issues
Issue: App reruns on every interaction
# Use forms to batch inputswith st.form("my_form"):
input1 = st.text_input("Input")
submit = st.form_submit_button()