Streamlit 定制化的 Web 应用
Streamlit 定制化的 Web 应用
目录
- Streamlit 简介
- 1.1 什么是 Streamlit?
- 1.2 为什么选择 Streamlit?
- 1.3 核心特性
- 1.4 目标用户
- 核心概念
- 2.1 数据流与脚本执行模型
- 2.2 “魔法”命令 (Magic Commands)
- 2.3 控件 (Widgets) 与交互
- 2.4 状态管理 (Session State)
- 2.5 缓存 (Caching)
- 安装教程
- 3.1 环境要求
- 3.2 使用 pip 安装
- 3.3 验证安装
- 3.4 运行第一个应用
- 主要组件与常用 API
- 4.1 文本显示
- 4.2 数据展示
- 4.3 图表绘制
- 4.4 输入控件
- 4.5 布局与容器
- 4.6 媒体文件
- 4.7 状态与控制流
- 进阶功能与策略
- 5.1 深入 Session State
- 5.2 高效使用缓存 (@st.cache_data vs @st.cache_resource)
- 5.3 优化应用布局
- 5.4 连接数据源 (数据库, API)
- 5.5 应用部署 (Streamlit Community Cloud)
- 5.6 自定义组件 (Brief Mention)
- 策略示例 (代码驱动)
- 6.1 示例一:交互式数据探索器
- 6.2 示例二:参数可调的可视化
- 6.3 示例三:简单的机器学习模型演示
- 最佳实践与技巧
- 总结
- 学习资源
1. Streamlit 简介
1.1 什么是 Streamlit?
Streamlit 是一个开源的 Python 库,它使得为机器学习和数据科学项目创建和共享美观、定制化的 Web 应用变得极其简单快捷。你无需任何前端知识(HTML, CSS, JavaScript),只需使用 Python 即可构建交互式的数据应用。
1.2 为什么选择 Streamlit?
- 快速开发: 将数据脚本转化为可共享的 Web 应用通常只需要几行代码。
- 纯 Python: 无需学习前端框架,专注于 Python 和数据。
- 交互性: 内置丰富的交互式控件(滑块、按钮、下拉菜单等)。
- 易于共享: 可以轻松部署到 Streamlit Community Cloud 或其他平台。
- 代码即应用: 应用的 UI 和逻辑直接由 Python 脚本定义,所见即所得。
- 活跃社区: 拥有庞大且活跃的社区支持。
1.3 核心特性
- 即时反馈: 修改代码并保存后,浏览器中的应用会自动刷新。
- 数据缓存: 智能缓存机制避免重复计算和加载数据,提升性能。
- 内置控件: 提供大量开箱即用的 UI 控件。
- 布局灵活: 支持侧边栏、列、选项卡等布局方式。
- 主题定制: 支持浅色、深色主题及自定义主题。
1.4 目标用户
- 数据科学家: 快速将模型、分析结果可视化并分享给他人。
- 机器学习工程师: 构建模型演示、数据标注工具等。
- 数据分析师: 创建交互式报告和仪表板。
- Python 开发者: 需要快速构建简单 Web 应用的场景。
2. 核心概念
2.1 数据流与脚本执行模型
Streamlit 应用的核心在于其独特的执行模型:每当用户与应用中的控件交互(如点击按钮、拖动滑块)或者源代码被修改时,整个 Python 脚本会从头到尾重新执行一次。
这听起来可能效率低下,但 Streamlit 通过智能的缓存机制(见 2.5)来优化性能。这种模型的优点是极大地简化了应用开发,开发者只需编写线性的 Python 脚本,Streamlit 负责处理 Web 应用的复杂性。
2.2 “魔法”命令 (Magic Commands)
Streamlit 支持“魔法”命令。如果你在脚本中单独写一个变量或一个字面量值(如 DataFrame、字符串、数字),Streamlit 会自动调用 st.write() 将其显示在应用中。
import streamlit as st import pandas as pd df = pd.DataFrame({'col1': [1, 2], 'col2': [3, 4]}) "这是一个 Markdown 文本" # Magic command, 等同于 st.write("这是一个 Markdown 文本") df # Magic command, 等同于 st.write(df) 或 st.dataframe(df)
2.3 控件 (Widgets) 与交互
控件是用户与 Streamlit 应用交互的主要方式。每个控件本质上是一个 Python 函数调用,其返回值通常是用户输入的值。
name = st.text_input("请输入你的名字:") if name: st.write(f"你好, {name}!") age = st.slider("选择你的年龄:", 0, 100, 25) # 最小值, 最大值, 默认值 st.write(f"你的年龄是: {age}") clicked = st.button("点我") if clicked: st.write("按钮被点击了!")
当用户与控件交互(例如输入文本、移动滑块、点击按钮),Streamlit 会:
- 记录控件的新值。
- 重新运行整个脚本。
- 在重新运行时,控件函数会返回用户设置的新值。
2.4 状态管理 (Session State)
由于每次交互都会重新运行脚本,局部变量无法在多次运行之间保持其值。为了解决这个问题,Streamlit 提供了 st.session_state。这是一个类似字典的对象,用于存储需要在脚本重新运行时保留的信息(会话状态)。
import streamlit as st # 初始化 session state 中的计数器(如果它不存在) if 'count' not in st.session_state: st.session_state.count = 0 increment = st.button('增加计数') if increment: st.session_state.count += 1 st.write('计数器: ', st.session_state.count)
2.5 缓存 (Caching)
为了避免在每次脚本重新运行时都执行耗时的操作(如加载大型数据集、训练模型、访问 API),Streamlit 提供了缓存装饰器:
- @st.cache_data: 用于缓存可序列化的数据(如 DataFrame, list, dict)。当函数的输入参数或函数代码改变时,缓存才会失效。
- @st.cache_resource: 用于缓存不方便或不应该被序列化的全局资源(如数据库连接、机器学习模型)。当函数代码改变时,缓存才会失效(对输入参数不敏感)。
import streamlit as st import pandas as pd import time @st.cache_data # 缓存数据加载函数 def load_data(url): df = pd.read_csv(url) time.sleep(3) # 模拟耗时操作 return df data_url = "https://raw.githubusercontent.com/streamlit/demo-data/master/uber-raw-data-sep14.csv.gz" df = load_data(data_url) st.dataframe(df.head()) st.button("再次运行脚本") # 点击按钮会重新运行,但 load_data 不会再次执行耗时操作
3. 安装教程
3.1 环境要求
- Python 3.8 - 3.11
- PIP 包管理器
建议在虚拟环境中安装 Streamlit,以避免与其他项目的依赖冲突。
创建和激活虚拟环境 (可选但推荐):
# Linux/macOS python3 -m venv .venv source .venv/bin/activate # Windows (cmd) python -m venv .venv .venv\Scripts\activate.bat # Windows (PowerShell) python -m venv .venv .venv\Scripts\Activate.ps1
3.2 使用 pip 安装
在你的终端或命令行中运行:
pip install streamlit
3.3 验证安装
安装完成后,运行以下命令:
streamlit hello
这会启动一个演示应用,并在你的默认浏览器中打开一个新的标签页。如果能看到 Streamlit 的欢迎页面和演示,说明安装成功。
3.4 运行第一个应用
-
创建一个 Python 文件,例如 my_first_app.py。
(图片来源网络,侵删) -
在文件中写入以下代码:
import streamlit as st import numpy as np import pandas as pd st.title('我的第一个 Streamlit 应用') st.write("这是一个简单的 Streamlit 应用示例。") # 使用魔法命令显示 DataFrame df = pd.DataFrame({ '第一列': [1, 2, 3, 4], '第二列': [10, 20, 30, 40] }) df # 添加一个滑块控件 x = st.slider('选择一个值', 0, 10) st.write('你选择的值是:', x) # 绘制一个简单的图表 st.line_chart(np.random.randn(20, 2))
-
在终端中,切换到包含 my_first_app.py 的目录,然后运行:
(图片来源网络,侵删)streamlit run my_first_app.py
-
Streamlit 会启动一个本地 Web 服务器,并在浏览器中打开你的应用。
4. 主要组件与常用 API
Streamlit 提供了丰富的 API 来构建应用的 UI。
(图片来源网络,侵删)4.1 文本显示
- st.title(): 应用标题
- st.header(): 一级标题
- st.subheader(): 二级标题
- st.write(): 通用显示函数,可以显示文本、Markdown、数字、DataFrame、图表等。
- st.markdown(): 渲染 Markdown 格式的文本。
- st.code(): 显示代码块。
- st.latex(): 显示 LaTeX 公式。
4.2 数据展示
- st.dataframe(): 显示可交互的 DataFrame (支持排序)。
- st.table(): 显示静态表格。
- st.json(): 显示 JSON 数据。
- st.metric(): 显示指标(KPI),可带变化量。
4.3 图表绘制
Streamlit 支持多种图表库:
- 内置图表: st.line_chart(), st.area_chart(), st.bar_chart(), st.scatter_chart() (基于 Vega-Lite)。
- 第三方库集成:
- st.pyplot(): 显示 Matplotlib 图表。
- st.plotly_chart(): 显示 Plotly 图表。
- st.altair_chart(): 显示 Altair 图表。
- st.vega_lite_chart(): 显示 Vega-Lite 图表。
- (以及 Bokeh, PyDeck 等)
4.4 输入控件
这些控件用于收集用户输入,它们的返回值是用户提供的值。
- st.button(): 按钮。
- st.checkbox(): 复选框。
- st.radio(): 单选按钮。
- st.selectbox(): 下拉选择框。
- st.multiselect(): 多选下拉框。
- st.slider(): 滑块。
- st.select_slider(): 在一组离散值中选择的滑块。
- st.text_input(): 单行文本输入框。
- st.text_area(): 多行文本输入框。
- st.number_input(): 数字输入框。
- st.date_input(): 日期选择器。
- st.time_input(): 时间选择器。
- st.file_uploader(): 文件上传控件。
- st.color_picker(): 颜色选择器。
4.5 布局与容器
用于组织页面元素:
- st.sidebar: 在页面左侧创建一个侧边栏,控件可以放在这里。
add_selectbox = st.sidebar.selectbox( "你想联系谁?", ("邮件", "电话", "短信") )
- st.columns(): 创建并排的列。
col1, col2, col3 = st.columns(3) with col1: st.header("第一列") st.write("内容...") with col2: st.header("第二列") # ...
- st.tabs(): 创建选项卡布局。
tab1, tab2 = st.tabs(["图表", "数据"]) with tab1: st.line_chart(...) with tab2: st.dataframe(...)
- st.expander(): 创建可折叠的区域。
- st.container(): 创建一个多元素容器,可以用于控制元素插入顺序。
- st.empty(): 创建一个占位符,后续可以用内容替换或清空。
4.6 媒体文件
- st.image(): 显示图片。
- st.audio(): 播放音频文件。
- st.video(): 播放视频文件。
4.7 状态与控制流
- st.form(): 创建一个表单,可以批量提交一组输入控件的值。在表单内的控件交互不会触发脚本重新运行,只有点击表单的提交按钮 (st.form_submit_button) 时才会。
- st.spinner(): 显示一个加载指示器,用于耗时操作。
- st.progress(): 显示一个进度条。
- st.error(), st.warning(), st.info(), st.success(): 显示不同类型的消息框。
- st.exception(): 显示异常信息。
- st.stop(): 停止脚本执行。
- st.rerun(): 手动触发脚本重新运行。
5. 进阶功能与策略
5.1 深入 Session State
st.session_state 是构建复杂交互应用的关键。
- 初始化: 务必在使用前检查 key 是否存在并进行初始化,通常在脚本开头完成。
- 回调函数: 许多控件(如 st.button, st.slider)支持 on_change 参数,可以绑定一个回调函数。当控件值改变时,回调函数会在脚本重新运行 之前 执行,这对于更新 st.session_state 非常有用。
import streamlit as st def increment_counter(): st.session_state.count += 1 if 'count' not in st.session_state: st.session_state.count = 0 st.button('增加', on_click=increment_counter) # 使用回调 st.write('计数器: ', st.session_state.count)
5.2 高效使用缓存 (@st.cache_data vs @st.cache_resource)
- 选择合适的装饰器:
- 加载 DataFrame、处理 JSON/API 结果等返回普通数据的函数,使用 @st.cache_data。
- 初始化数据库连接、加载大型机器学习模型等返回复杂对象或需要全局共享资源的函数,使用 @st.cache_resource。
- 缓存粒度: 尽量将耗时操作封装在独立的函数中,并对该函数应用缓存。
- 注意参数: @st.cache_data 对输入参数敏感。如果参数是可变对象(如列表、字典)且在函数内部被修改,可能会导致意外的缓存行为。考虑传递不可变对象或对象的副本。
- 清除缓存: 有时需要手动清除缓存,可以在 Streamlit 应用的右上角菜单中找到 “Clear cache” 选项。
5.3 优化应用布局
- 使用 st.sidebar: 将全局设置、导航或不常变化的控件放在侧边栏,保持主区域清爽。
- 使用 st.columns 或 st.tabs: 合理组织内容,避免页面过长。
- 使用 st.expander: 将详细信息或次要内容隐藏在可展开区域内。
- 使用 st.container: 控制元素的添加顺序,或将一组相关的元素打包。
5.4 连接数据源 (数据库, API)
Streamlit 本身不直接提供数据库或 API 连接器,但可以无缝集成标准的 Python 库:
- 数据库: 使用 SQLAlchemy, psycopg2 (PostgreSQL), mysql-connector-python (MySQL), sqlite3 等库连接数据库。将数据库连接和查询操作封装在函数中,并考虑使用 @st.cache_resource 缓存连接,使用 @st.cache_data 缓存查询结果。
- API: 使用 requests 或 httpx 等库访问外部 API。同样,将 API 调用封装并使用 @st.cache_data 缓存结果,避免频繁请求。
import streamlit as st import requests import pandas as pd @st.cache_data(ttl=600) # 缓存 10 分钟 def get_api_data(api_url): response = requests.get(api_url) response.raise_for_status() # 检查请求是否成功 return response.json() # 示例:获取 GitHub 星标信息 try: data = get_api_data("https://api.github.com/repos/streamlit/streamlit") st.write("Streamlit GitHub Repo Stars:", data.get('stargazers_count')) except requests.exceptions.RequestException as e: st.error(f"API 请求失败: {e}")
5.5 应用部署 (Streamlit Community Cloud)
Streamlit Community Cloud 是官方提供的免费部署平台,非常适合共享公共应用。
- 准备代码: 将你的 Streamlit 应用代码 (.py 文件) 和依赖文件 (requirements.txt) 托管在 GitHub 公开仓库中。
- 注册/登录: 访问 share.streamlit.io 并使用 GitHub 账号登录。
- 部署应用: 点击 “New app”,选择你的 GitHub 仓库、分支和主应用文件。
- 配置 (可选): 可以设置 Python 版本和高级设置。
- 点击 “Deploy!” Streamlit 会自动拉取代码、安装依赖并运行你的应用。
其他部署选项包括:Heroku, AWS, Google Cloud, Azure, Docker 容器等,这些通常需要更多的配置。
5.6 自定义组件 (Brief Mention)
对于更高级的需求,如果内置控件不满足,可以创建自己的 Streamlit 组件。这需要一些前端知识(React),允许你将任何 Web 技术集成到 Streamlit 应用中。这是一个更深入的主题,可以查阅官方文档了解更多。
6. 策略示例 (代码驱动)
6.1 示例一:交互式数据探索器
这个例子展示了如何上传 CSV 文件,并使用控件进行筛选和可视化。
import streamlit as st import pandas as pd import numpy as np st.title("交互式数据探索器") uploaded_file = st.file_uploader("上传你的 CSV 文件", type=["csv"]) if uploaded_file is not None: # 使用缓存加载数据 @st.cache_data def load_csv(file): return pd.read_csv(file) df = load_csv(uploaded_file) st.header("原始数据") st.dataframe(df) st.header("数据筛选与可视化") # 使用列进行布局 col1, col2 = st.columns(2) with col1: # 选择列进行可视化 all_columns = df.columns.tolist() selected_columns = st.multiselect("选择要显示的列:", all_columns, default=all_columns[:min(5, len(all_columns))]) if selected_columns: st.dataframe(df[selected_columns]) else: st.warning("请至少选择一列") with col2: # 基于数值列进行过滤 numeric_columns = df.select_dtypes(include=np.number).columns.tolist() if numeric_columns: filter_column = st.selectbox("选择用于过滤的数值列:", numeric_columns) min_val = float(df[filter_column].min()) max_val = float(df[filter_column].max()) value_range = st.slider( f"选择 {filter_column} 的范围:", min_value=min_val, max_value=max_val, value=(min_val, max_val) # 默认选择整个范围 ) # 应用过滤 filtered_df = df[(df[filter_column] >= value_range[0]) & (df[filter_column]
- 选择合适的装饰器:
- st.sidebar: 在页面左侧创建一个侧边栏,控件可以放在这里。
-