Streamlit is a Python framework for rapidly building and deploying interactive web applications for data science and machine learning. Create beautiful web apps with just Python - no frontend development experience required. Apps automatically update in real-time as code changes.
Streamlit是一款用于快速构建和部署数据科学与机器学习交互式Web应用的Python框架。只需使用Python即可创建美观的Web应用,无需前端开发经验。代码更改时,应用会自动实时更新。
When to Use This Skill
何时使用该技能
Activate when the user:
- Wants to build a web app, dashboard, or data visualization tool
- Mentions Streamlit explicitly
- Needs to create an ML/AI demo or prototype
- Wants to visualize data interactively
- Asks for a data exploration tool
- Needs interactive widgets (sliders, buttons, file uploads)
- Wants to share analysis results with stakeholders
当用户有以下需求时激活:
- 想要构建Web应用、仪表板或数据可视化工具
- 明确提到Streamlit
- 需要创建机器学习/人工智能演示或原型
- 想要交互式地可视化数据
- 询问数据探索工具
- 需要交互式组件(滑块、按钮、文件上传)
- 想要与利益相关者分享分析结果
Installation and Setup
安装与设置
Check if Streamlit is installed:
bash
python3 -c "import streamlit; print(streamlit.__version__)"
If not installed:
bash
pip3 install streamlit
Create and run your first app:
检查Streamlit是否已安装:
bash
python3 -c "import streamlit; print(streamlit.__version__)"
如果未安装:
bash
pip3 install streamlit
创建并运行你的第一个应用:
Create app.py with Streamlit code
创建包含Streamlit代码的app.py
streamlit run app.py
The app opens automatically in your browser at `http://localhost:8501`
streamlit run app.py
应用会自动在浏览器中打开,地址为 `http://localhost:8501`
Basic App Structure
基础应用结构
Every Streamlit app follows this simple pattern:
python
import streamlit as st
每个Streamlit应用都遵循以下简单模式:
python
import streamlit as st
Set page configuration (must be first Streamlit command)
设置页面配置(必须是第一个Streamlit命令)
st.set_page_config(
page_title="My App",
page_icon="📊",
layout="wide"
)
st.set_page_config(
page_title="My App",
page_icon="📊",
layout="wide"
)
Title and description
标题与描述
st.title("My Data App")
st.write("Welcome to my interactive dashboard!")
st.title("我的数据应用")
st.write("欢迎来到我的交互式仪表板!")
Streamlit automatically reruns from top to bottom when widgets change
当组件变化时,Streamlit会自动从顶部到底部重新运行代码
1. Displaying Text and Data
1. 文本与数据展示
python
import streamlit as st, pandas as pd
python
import streamlit as st, pandas as pd
st.title("Main Title")
st.header("Section Header")
st.subheader("Subsection Header")
st.text("Fixed-width text")
st.markdown("Bold and italic text")
st.caption("Small caption text")
st.title("主标题")
st.header("章节标题")
st.subheader("子章节标题")
st.text("固定宽度文本")
st.markdown("加粗和斜体文本")
st.caption("小型说明文本")
st.code("""
def hello():
print("Hello, World!")
""", language="python")
st.code("""
def hello():
print("Hello, World!")
""", language="python")
df = pd.DataFrame({
'Column A': [1, 2, 3],
'Column B': [4, 5, 6]
})
st.dataframe(df) # Interactive table
st.table(df) # Static table
st.json({'key': 'value'}) # JSON data
df = pd.DataFrame({
'Column A': [1, 2, 3],
'Column B': [4, 5, 6]
})
st.dataframe(df) # 交互式表格
st.table(df) # 静态表格
st.json({'key': 'value'}) # JSON数据
st.metric(
label="Revenue",
value="$1,234",
delta="12%"
)
st.metric(
label="收入",
value="$1,234",
delta="12%"
)
2. Interactive Widgets
2. 交互式组件
python
import streamlit as st
python
import streamlit as st
name = st.text_input("Enter your name")
email = st.text_input("Email", type="default")
password = st.text_input("Password", type="password")
text = st.text_area("Long text", height=100)
name = st.text_input("输入你的姓名")
email = st.text_input("邮箱", type="default")
password = st.text_input("密码", type="password")
text = st.text_area("长文本输入", height=100)
age = st.number_input("Age", min_value=0, max_value=120, value=25)
slider_val = st.slider("Select a value", 0, 100, 50)
range_val = st.slider("Select range", 0, 100, (25, 75))
age = st.number_input("年龄", min_value=0, max_value=120, value=25)
slider_val = st.slider("选择一个值", 0, 100, 50)
range_val = st.slider("选择范围", 0, 100, (25, 75))
option = st.selectbox("Choose one", ["Option 1", "Option 2", "Option 3"])
options = st.multiselect("Choose multiple", ["A", "B", "C", "D"])
radio = st.radio("Pick one", ["Yes", "No", "Maybe"])
option = st.selectbox("选择一个选项", ["选项1", "选项2", "选项3"])
options = st.multiselect("选择多个选项", ["A", "B", "C", "D"])
radio = st.radio("选择一个", ["是", "否", "可能"])
agree = st.checkbox("I agree to terms")
show_data = st.checkbox("Show raw data")
agree = st.checkbox("我同意条款")
show_data = st.checkbox("显示原始数据")
if st.button("Click me"):
st.write("Button clicked!")
if st.button("点击我"):
st.write("按钮已点击!")
date = st.date_input("Select date")
time = st.time_input("Select time")
date = st.date_input("选择日期")
time = st.time_input("选择时间")
uploaded_file = st.file_uploader("Choose a file", type=['csv', 'xlsx', 'txt'])
if uploaded_file is not None:
df = pd.read_csv(uploaded_file)
st.dataframe(df)
uploaded_file = st.file_uploader("选择文件", type=['csv', 'xlsx', 'txt'])
if uploaded_file is not None:
df = pd.read_csv(uploaded_file)
st.dataframe(df)
st.download_button(
label="Download data",
data=df.to_csv(index=False),
file_name="data.csv",
mime="text/csv"
)
st.download_button(
label="下载数据",
data=df.to_csv(index=False),
file_name="data.csv",
mime="text/csv"
)
3. Charts and Visualizations
3. 图表与可视化
python
import streamlit as st
import pandas as pd, numpy as np, matplotlib.pyplot as plt
import plotly.express as px
python
import streamlit as st
import pandas as pd, numpy as np, matplotlib.pyplot as plt
import plotly.express as px
df = pd.DataFrame({
'x': range(10),
'y': np.random.randn(10)
})
df = pd.DataFrame({
'x': range(10),
'y': np.random.randn(10)
})
Streamlit native charts
Streamlit原生图表
st.line_chart(df)
st.area_chart(df)
st.bar_chart(df)
st.line_chart(df)
st.area_chart(df)
st.bar_chart(df)
Scatter plot with map data
带地图数据的散点图
map_data = pd.DataFrame(
np.random.randn(100, 2) / [50, 50] + [37.76, -122.4],
columns=['lat', 'lon']
)
st.map(map_data)
map_data = pd.DataFrame(
np.random.randn(100, 2) / [50, 50] + [37.76, -122.4],
columns=['lat', 'lon']
)
st.map(map_data)
fig, ax = plt.subplots()
ax.plot(df['x'], df['y'])
ax.set_title("Matplotlib Chart")
st.pyplot(fig)
fig, ax = plt.subplots()
ax.plot(df['x'], df['y'])
ax.set_title("Matplotlib图表")
st.pyplot(fig)
Plotly (interactive)
Plotly(交互式)
fig = px.scatter(df, x='x', y='y', title="Interactive Plotly Chart")
st.plotly_chart(fig, use_container_width=True)
fig = px.scatter(df, x='x', y='y', title="交互式Plotly图表")
st.plotly_chart(fig, use_container_width=True)
Altair, Bokeh, and other libraries also supported
同时支持Altair、Bokeh等其他库
4. Layout and Containers
4. 布局与容器
python
import streamlit as st
python
import streamlit as st
col1, col2, col3 = st.columns(3)
with col1:
st.header("Column 1")
st.write("Content here")
with col2:
st.header("Column 2")
st.write("More content")
with col3:
st.header("Column 3")
st.write("Even more")
col1, col2, col3 = st.columns(3)
with col1:
st.header("列1")
st.write("这里是内容")
with col2:
st.header("列2")
st.write("更多内容")
with col3:
st.header("列3")
st.write("更多内容")
tab1, tab2, tab3 = st.tabs(["Overview", "Data", "Settings"])
with tab1:
st.write("Overview content")
with tab2:
st.write("Data content")
with tab3:
st.write("Settings content")
tab1, tab2, tab3 = st.tabs(["概述", "数据", "设置"])
with tab1:
st.write("概述内容")
with tab2:
st.write("数据内容")
with tab3:
st.write("设置内容")
Expander (collapsible section)
展开面板(可折叠章节)
with st.expander("Click to expand"):
st.write("Hidden content that can be expanded")
with st.expander("点击展开"):
st.write("可展开的隐藏内容")
with st.container():
st.write("This is inside a container")
st.write("Another line")
with st.container():
st.write("这在容器内部")
st.write("另一行内容")
st.sidebar.title("Sidebar")
st.sidebar.selectbox("Choose option", ["A", "B", "C"])
st.sidebar.slider("Sidebar slider", 0, 100)
st.sidebar.title("侧边栏")
st.sidebar.selectbox("选择选项", ["A", "B", "C"])
st.sidebar.slider("侧边栏滑块", 0, 100)
5. Status and Progress
5. 状态与进度
python
import streamlit as st, time
python
import streamlit as st, time
Success, info, warning, error messages
成功、信息、警告、错误消息
st.success("Success! Everything worked.")
st.info("This is an informational message.")
st.warning("This is a warning.")
st.error("This is an error message.")
st.success("成功!一切正常。")
st.info("这是一条信息提示。")
st.warning("这是一条警告。")
st.error("这是一条错误消息。")
progress_bar = st.progress(0)
for i in range(100):
time.sleep(0.01)
progress_bar.progress(i + 1)
progress_bar = st.progress(0)
for i in range(100):
time.sleep(0.01)
progress_bar.progress(i + 1)
Spinner (loading indicator)
加载指示器
with st.spinner("Processing..."):
time.sleep(3)
st.success("Done!")
with st.spinner("处理中..."):
time.sleep(3)
st.success("完成!")
Balloons (celebration)
气球动画(庆祝效果)
Snow (celebration)
雪花动画(庆祝效果)
6. Caching for Performance
6. 缓存优化性能
python
import streamlit as st, pandas as pd, time
python
import streamlit as st, pandas as pd, time
Cache data loading (persists across reruns)
缓存数据加载(在多次运行中持久化)
@st.cache_data
def load_data():
time.sleep(2) # Simulate slow data load
return pd.read_csv('large_file.csv')
@st.cache_data
def load_data():
time.sleep(2) # 模拟缓慢的数据加载
return pd.read_csv('large_file.csv')
Cache resource (connections, models)
缓存资源(连接、模型)
@st.cache_resource
def load_model():
# Load ML model (expensive operation)
return load_my_model()
@st.cache_resource
def load_model():
# 加载机器学习模型(耗时操作)
return load_my_model()
df = load_data() # Only loads once, then cached
model = load_model() # Cached globally
st.write(f"Loaded {len(df)} rows")
df = load_data() # 仅加载一次,之后从缓存获取
model = load_model() # 全局缓存
st.write(f"已加载 {len(df)} 行数据")
7. Session State (Persistent Data)
7. 会话状态(持久化数据)
python
import streamlit as st
python
import streamlit as st
Initialize session state
初始化会话状态
if 'count' not in st.session_state:
st.session_state.count = 0
if 'count' not in st.session_state:
st.session_state.count = 0
if st.button("Increment"):
st.session_state.count += 1
st.write(f"Count: {st.session_state.count}")
if st.button("递增"):
st.session_state.count += 1
st.write(f"计数: {st.session_state.count}")
Store user data across reruns
在多次运行中存储用户数据
if 'user_data' not in st.session_state:
st.session_state.user_data = {}
name = st.text_input("Name")
if name:
st.session_state.user_data['name'] = name
st.write(f"Hello, {st.session_state.user_data['name']}!")
if 'user_data' not in st.session_state:
st.session_state.user_data = {}
name = st.text_input("姓名")
if name:
st.session_state.user_data['name'] = name
st.write(f"你好, {st.session_state.user_data['name']}!")
Pattern 1: Data Dashboard
模式1:数据仪表板
python
import streamlit as st, pandas as pd, plotly.express as px
st.set_page_config(page_title="Sales Dashboard", layout="wide")
python
import streamlit as st, pandas as pd, plotly.express as px
st.set_page_config(page_title="销售仪表板", layout="wide")
st.sidebar.header("Filters")
date_range = st.sidebar.date_input("Date Range", [])
category = st.sidebar.multiselect("Category", ["A", "B", "C"])
st.sidebar.header("过滤器")
date_range = st.sidebar.date_input("日期范围", [])
category = st.sidebar.multiselect("类别", ["A", "B", "C"])
@st.cache_data
def load_sales_data():
return pd.read_csv('sales_data.csv')
df = load_sales_data()
@st.cache_data
def load_sales_data():
return pd.read_csv('sales_data.csv')
df = load_sales_data()
if date_range:
df = df[df['date'].between(date_range[0], date_range[1])]
if category:
df = df[df['category'].isin(category)]
if date_range:
df = df[df['date'].between(date_range[0], date_range[1])]
if category:
df = df[df['category'].isin(category)]
col1, col2, col3, col4 = st.columns(4)
col1.metric("Total Revenue", f"${df['revenue'].sum():,.0f}")
col2.metric("Orders", f"{len(df):,}")
col3.metric("Avg Order", f"${df['revenue'].mean():.2f}")
col4.metric("Top Product", df['product'].mode()[0])
col1, col2, col3, col4 = st.columns(4)
col1.metric("总收入", f"${df['revenue'].sum():,.0f}")
col2.metric("订单数", f"{len(df):,}")
col3.metric("平均订单额", f"${df['revenue'].mean():.2f}")
col4.metric("热门产品", df['product'].mode()[0])
col1, col2 = st.columns(2)
with col1:
st.subheader("Revenue by Category")
fig = px.bar(df.groupby('category')['revenue'].sum().reset_index(),
x='category', y='revenue')
st.plotly_chart(fig, use_container_width=True)
with col2:
st.subheader("Revenue Trend")
fig = px.line(df.groupby('date')['revenue'].sum().reset_index(),
x='date', y='revenue')
st.plotly_chart(fig, use_container_width=True)
col1, col2 = st.columns(2)
with col1:
st.subheader("按类别划分的收入")
fig = px.bar(df.groupby('category')['revenue'].sum().reset_index(),
x='category', y='revenue')
st.plotly_chart(fig, use_container_width=True)
with col2:
st.subheader("收入趋势")
fig = px.line(df.groupby('date')['revenue'].sum().reset_index(),
x='date', y='revenue')
st.plotly_chart(fig, use_container_width=True)
with st.expander("View Raw Data"):
st.dataframe(df)
with st.expander("查看原始数据"):
st.dataframe(df)
Pattern 2: Data Explorer
模式2:数据探索器
python
import streamlit as st, pandas as pd, plotly.express as px
st.title("📊 Data Explorer")
python
import streamlit as st, pandas as pd, plotly.express as px
st.title("📊 数据探索器")
uploaded_file = st.file_uploader("Upload CSV", type=['csv'])
if uploaded_file:
df = pd.read_csv(uploaded_file)
# Show basic info
st.subheader("Dataset Overview")
col1, col2, col3 = st.columns(3)
col1.metric("Rows", len(df))
col2.metric("Columns", len(df.columns))
col3.metric("Memory", f"{df.memory_usage(deep=True).sum() / 1024**2:.2f} MB")
# Column selection
st.subheader("Explore Data")
columns = st.multiselect("Select columns", df.columns.tolist(), default=df.columns.tolist()[:5])
if columns:
st.dataframe(df[columns])
# Statistics
st.subheader("Statistics")
st.write(df[columns].describe())
# Visualization
st.subheader("Visualize")
col1, col2 = st.columns(2)
with col1:
x_col = st.selectbox("X-axis", columns)
with col2:
y_col = st.selectbox("Y-axis", columns)
chart_type = st.radio("Chart Type", ["Scatter", "Line", "Bar"])
if chart_type == "Scatter":
fig = px.scatter(df, x=x_col, y=y_col)
elif chart_type == "Line":
fig = px.line(df, x=x_col, y=y_col)
else:
fig = px.bar(df, x=x_col, y=y_col)
st.plotly_chart(fig, use_container_width=True)
uploaded_file = st.file_uploader("上传CSV文件", type=['csv'])
if uploaded_file:
df = pd.read_csv(uploaded_file)
# 显示基本信息
st.subheader("数据集概述")
col1, col2, col3 = st.columns(3)
col1.metric("行数", len(df))
col2.metric("列数", len(df.columns))
col3.metric("内存占用", f"{df.memory_usage(deep=True).sum() / 1024**2:.2f} MB")
# 列选择
st.subheader("探索数据")
columns = st.multiselect("选择列", df.columns.tolist(), default=df.columns.tolist()[:5])
if columns:
st.dataframe(df[columns])
# 统计信息
st.subheader("统计数据")
st.write(df[columns].describe())
# 可视化
st.subheader("可视化")
col1, col2 = st.columns(2)
with col1:
x_col = st.selectbox("X轴", columns)
with col2:
y_col = st.selectbox("Y轴", columns)
chart_type = st.radio("图表类型", ["散点图", "折线图", "柱状图"])
if chart_type == "散点图":
fig = px.scatter(df, x=x_col, y=y_col)
elif chart_type == "折线图":
fig = px.line(df, x=x_col, y=y_col)
else:
fig = px.bar(df, x=x_col, y=y_col)
st.plotly_chart(fig, use_container_width=True)
Pattern 3: Multi-Page App
模式3:多页面应用
Create a multi-page app with file structure:
app/
├── main.py
└── pages/
├── 1_📊_Dashboard.py
├── 2_📈_Analytics.py
└── 3_⚙️_Settings.py
python
import streamlit as st
st.set_page_config(page_title="Multi-Page App", page_icon="🏠")
st.title("Welcome to My App")
st.sidebar.success("Select a page above.")
st.markdown("""
This is the home page. Navigate using the sidebar.
""")
Pages automatically appear in the sidebar. Each page is a separate Python file.
通过以下文件结构创建多页面应用:
app/
├── main.py
└── pages/
├── 1_📊_Dashboard.py
├── 2_📈_Analytics.py
└── 3_⚙️_Settings.py
python
import streamlit as st
st.set_page_config(page_title="多页面应用", page_icon="🏠")
st.title("欢迎来到我的应用")
st.sidebar.success("选择上方的页面。")
st.markdown("""
这是主页。请使用侧边栏导航。
""")
页面会自动显示在侧边栏中。每个页面都是一个独立的Python文件。
python
import streamlit as st
python
import streamlit as st
Forms prevent rerun on every widget change
表单可避免每次组件交互时重新运行
with st.form("my_form"):
st.write("Fill out the form")
name = st.text_input("Name")
age = st.number_input("Age", min_value=0, max_value=120)
favorite_color = st.selectbox("Favorite Color", ["Red", "Green", "Blue"])
# Form submit button
submitted = st.form_submit_button("Submit")
if submitted:
st.write(f"Name: {name}")
st.write(f"Age: {age}")
st.write(f"Color: {favorite_color}")
with st.form("我的表单"):
st.write("填写表单")
name = st.text_input("姓名")
age = st.number_input("年龄", min_value=0, max_value=120)
favorite_color = st.selectbox("最喜欢的颜色", ["红色", "绿色", "蓝色"])
# 表单提交按钮
submitted = st.form_submit_button("提交")
if submitted:
st.write(f"姓名: {name}")
st.write(f"年龄: {age}")
st.write(f"颜色: {favorite_color}")
- Use caching - Cache expensive operations with and
- Session state for persistence - Use to persist data across reruns
- Organize with containers - Use columns, tabs, and expanders for clean layouts
- Forms for multiple inputs - Prevent reruns with forms when collecting multiple inputs
- Wide layout for dashboards - Use
st.set_page_config(layout="wide")
for dashboards
- Sidebar for controls - Put filters and settings in the sidebar
- Progress indicators - Show spinners for long operations
- 使用缓存 - 使用和缓存耗时操作
- 会话状态实现持久化 - 使用在多次运行中保存数据
- 使用容器组织布局 - 使用列、标签页和展开面板实现整洁的布局
- 表单处理多输入 - 收集多个输入时使用表单避免频繁重运行
- 仪表板使用宽布局 - 对仪表板使用
st.set_page_config(layout="wide")
- 侧边栏放置控件 - 将过滤器和设置放在侧边栏中
- 进度指示器 - 对长时间操作显示加载动画
Issue: App reruns on every interaction
问题:每次交互应用都会重新运行
Use
to batch inputs or
to control behavior.
Issue: Slow performance
问题:性能缓慢
Cache expensive operations:
python
@st.cache_data
def expensive_computation(param):
# Your code here
return result
缓存耗时操作:
python
@st.cache_data
def expensive_computation(param):
# 你的代码
return result
Issue: State not persisting
问题:状态无法持久化
Use session state:
python
if 'my_var' not in st.session_state:
st.session_state.my_var = initial_value
使用会话状态:
python
if 'my_var' not in st.session_state:
st.session_state.my_var = initial_value