Python Streamlit

🍦 Streamlit用于机器学习、数据可视化,由Streamlit公司开发并维护,几行简单的代码就能构建一个精美的在线app应用。

1 简介

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 安装streamlit第三方库
pip install streamlit

# 查看streamlit安装版本,尽可能使用新版
# 版本迭代速度快,以下部分函数只在新版中出现
streamlit --version
Streamlit, version 1.37.1

# 先进行配置,再命令查看配置信息
streamlit config show

# 完成配置后,运行Streamlit应用
# 当命令行出现Email时,回车继续
streamlit hello

# 执行自定义文件,默认浏览器跳转到Streamlit应用
streamlit run file_name.py

1-1 应用配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Windows:C:/Users/.streamlit/config.toml
# macOS、Linux:~/.streamlit/config.toml
# 在config.toml文件中,大小写是敏感的
# 确保配置文件的各个部分和参数名的大小写一致

[server]
# Streamlit应用的端口号,默认8501
port = 8501
# 是否启用跨域资源共享,默认false
# 设为true,则开放Streamlit应用,允许其他电脑访问
enableCORS = false

[browser]
# Streamlit服务器的地址,默认localhost
serverAddress = "localhost"
# 默认true,允许Streamlit收集使用统计信息
gatherUsageStats = false

[runner]
# 默认true,允许启用Streamlit的魔法命令功能
# 启用时,如果Streamlit看到变量或常量,会使用st.write自动将其写入
# 容易导致网页速度变慢、重复加载数据等情况
magicEnabled = false

1-2 工作流程

  • 工作流程
    • Streamlit应用程序是从上到下运行的Python脚本,每一次交互也是脚本从头到尾执行一遍。
    • 脚本执行时,Streamlit在浏览器中实时绘制输出,使用缓存来避免重复请求数据或重复计算。
    • 每次用户与小组件进行交互,脚本都会重新执行,在这运行期间小组件的输出值将重新设置。
    • Streamlit应用可以包含多个页面,这些页面在pages文件夹中的单独.py文件里进行自定义。

2 显示

  • 显示
    • 原生图表组件:map(地图)、bar_chart(柱状图)、line_chart(折线图)、area_chart(面积图)。
    • 外部图表组件
      • pyplot(多图表)、altair_chart、plotly_chart、bokeh_chart。
      • pydeck_chart(3D地图)、graphviz_chart、vega_lite_chart。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
import numpy as np
import pandas as pd
import altair as alt
import pydeck as pdk
from PIL import Image
import streamlit as st
import plotly.express as px
from graphviz import Digraph
import matplotlib.pyplot as plt
from bokeh.plotting import figure

# 创建页面的主要标题,通常是最大最显眼的标题
st.title("Streamlit显示")

# 创建侧边栏
st.sidebar.title("显示项目")

# 添加分类
category = st.sidebar.selectbox("", ["文本", "数据", "媒体", "图表"])

if category == "文本":
# 添加按钮作为分类项目的标题
if st.sidebar.button("❀ 标题"):

# 创建相对较小的标题,比title()稍微小一些
st.header("较小标题")

# 创建相对较小的标题,比st.header()还要小
st.subheader("更小标题")

# 创建最小标题
st.caption("最小标题")

# 用于展示文本或数据的多功能通用函数,接受多种类型参数
# 例如:Markdown格式的字符串、数字、DataFrame、图表等
st.write("🌹 这里可以放置与“标题”相关的信息和数据。")

elif st.sidebar.button("❀ Text"):
st.subheader("Text")

st.text("""
人们并非生来平等,人的善恶感也生来各异。——《了不起的盖茨比》
""")

st.write("🌹 这里可以放置与“Text”相关的信息和数据。")

elif st.sidebar.button("❀ Json"):
st.subheader("Json")

st.json({
"id": 1,
"username": "钱三两",
"address": {
"street": "梨花巷",
"city": "庐州"
}
})

st.write("🌹 这里可以放置与“Json”相关的信息和数据。")

elif st.sidebar.button("❀ Code"):
st.subheader("Python")

st.code(
"""
import importlib.metadata

for dist in importlib.metadata.distributions():
try:
print(f"Package: {dist.name}")
print(f"Location: {dist.locate_file('')}")
print("---")
except FileNotFoundError:
print(
f"Package: {dist.name} - " +
f"Location not found (likely built-in or stdlib)"
)
print("---")
except Exception as e:
print(f"Package: {dist.name} - Error: {e}")
print("---")
""",
# language大写无效
language="python"
)

st.write("🌹 这里可以放置与“Code”相关的信息和数据。")

elif st.sidebar.button("❀ LaTeX"):
st.subheader("LaTeX")

st.latex(
r"""
a + ar + a r ^ 2 + a r ^ 3 + \cdots + a r ^ {n - 1}
= \sum_{k = 0} ^ {n - 1} ar ^ k =
a \left(\frac{1 - r ^ {n}}{1 - r} \right)
"""
)

st.write("🌹 这里可以放置与“LaTeX”相关的信息和数据。")

elif st.sidebar.button("❀ Markdown"):
st.subheader("Markdown")

st.markdown("""
###### 北回归线
现在我住在波勒兹别墅,这里找不到一点儿灰尘,
也没有一件东西摆得不是地方,
除了我们,这里再没有别人,我们死了。
###### 受戒
人间存一角,聊放侧枝花。欣然亦自得,不共赤城霞。
""")

st.write("🌹 Markdown格式文本,使用两个空格实现硬换行。")
st.write("🌹 这里可以放置与“Markdown”相关的信息和数据。")

elif category == "数据":
if st.sidebar.button("☆ Table"):
st.subheader("Table")

df = pd.DataFrame(
np.random.randn(10, 5),
columns=["col %d" % i for i in range(5)]
)

# 显示通用表格数据,支持Pandas,还可处理列表、元组等可迭代数据结构
# 但仅用于显示数据,不提供诸如排序、过滤等数据框专有的功能
st.table(df)

st.write("🌹 这里可以放置与“Table”相关的信息和数据。")

elif st.sidebar.button("☆ Metric"):
st.subheader("Metric")

col1, col2, col3 = st.columns(3)
col1.metric("Temperature", "70 °F", "1.2 °F")
col2.metric("Wind", "9 mph", "-8%")
col3.metric("Humidity", "86%", "4%")

st.write("🌹 这里可以放置与“Metric”相关的信息和数据。")

elif st.sidebar.button("☆ Dataframe"):
st.subheader("Dataframe")

random_data = np.random.rand(7, 10)
df = pd.DataFrame(
random_data,
columns=[f"Col{i}" for i in range(1, 11)]
)

# 表格形式呈现数据,支持Pandas的排序、过滤等特有功能
# 自动适应数据框大小,如果数据框太大,会自动启用滚动条
st.dataframe(df)

st.write("🌹 这里可以放置与“Dataframe”相关的信息和数据。")

elif category == "媒体":
if st.sidebar.button("❄ 视频"):
st.subheader("本地视频")

video_file = open(r"./file/show.mp4", "rb")
video_bytes = video_file.read()

# 显示视频的函数,支持多种视频来源,包括本地文件、URL和字节数据
# format:若设为None,将尝试根据文件扩展名自动识别视频格式
# start_time:视频开始播放的时间,单位为秒
st.video(
video_bytes, format="mp4", start_time=1
)

st.subheader("网络视频")

st.video(
"https://videos.pexels.com/video-files"
"/4376249/4376249-hd_1920_1080_24fps.mp4"
)

st.write("🌹 这里可以放置与“视频”相关的信息和数据。")

elif st.sidebar.button("❄ 图片"):
st.subheader("本地图片")

img = Image.open("./file/show.jpg")

# 显示图像的函数,接受多种格式,包括文件路径、URL、图像字节数据等
# caption:图像标题,字符串,如果多幅图像,应设为字符串列表
# use_column_width:如果设置为True,则使用列宽作为图像宽度
# clamp:是否将像素值压缩到有效域(0~255),仅对字节数组图像有效
# channels:图像通道类型,例如RGB、CMYK、Lab、灰度等
st.image(image=img, width=700)

st.subheader("网络图片")

st.image(
"https://img2.baidu.com/it/u=3645742772,1483764043"
"&fm=253&fmt=auto&app=120&f=JPEG?w=1422&h=800",
width=700
)

st.write("🌹 这里可以放置与“图片”相关的信息和数据。")

elif st.sidebar.button("❄ 音频"):
st.subheader("本地音频:《同簪》")

audio_file = open("./file/show.mp3", "rb")
audio_bytes = audio_file.read()
st.audio(audio_bytes, format="audio/mp3")

st.subheader("网络音频:《Fresh Focus》")

st.audio(
"https://freepd.com/music/Fresh%20Focus.mp3"
)

st.write("🌹 这里可以放置与“音频”相关的信息和数据。")

elif category == "图表":
if st.sidebar.button("✦ Map"):
st.subheader("Map")

data = {
# 纬度
"latitude": [24.435028, 24.537242, 24.679506],
# 经度
"longitude": [118.089404, 118.022565, 118.174976],
"name": [
"厦门市思明区演武西路世茂海峡大厦",
"厦门市马銮湾环湾带状公园",
"厦门方特梦幻王国"
]
}

# 显示地图及叠加的数据点,支持自动居中与自动缩放
# data:显示的点,lat、lon可以是DataFrame、数组等
# zoom:缩放等级
# 整个地球试图0、大洲国家1-5、省市县6-10、城市街道11-15
# 特定街道或建筑16-20、街道特定建筑细节(门牌号之类)21-22
# use_container_width:是否使用容器的整个宽度
st.map(data, zoom=10, use_container_width=True)

st.write("🌹 这里可以放置与“Map”相关的信息和数据。")

elif st.sidebar.button("✦ PyPlot"):
st.subheader("PyPlot")

# 设置点的个数
m = 20

# 总点数
n = 256 * m + 1

# 变量的取值范围
tx = np.linspace(0, 24 * np.pi, n)

# 初始化x和y数组
x = np.zeros(n)
y = np.zeros(n)

# 计算函数的值
for i in range(n):
t = tx[i]
x[i] = (
np.sin(t) * (np.exp(np.cos(t)) - 2 * np.cos(4 * t) - (np.sin(t / 12)) ** 5)
)
y[i] = (
np.cos(t) * (np.exp(np.cos(t)) - 2 * np.cos(4 * t) - (np.sin(t / 12)) ** 5)
)

fig = plt.figure(figsize=(8, 6), dpi=100)
plt.plot(x, y, color="orange")

# 显示图表
st.pyplot(fig)

st.write("🌹 这里可以放置与“PyPlot”相关的信息和数据。")

elif st.sidebar.button("✦ Bar_Chart"):
st.subheader("Bar_Chart")

data = pd.DataFrame(
np.random.randn(20, 3), columns=["a", "b", "c"]
)
st.bar_chart(data)

st.write("🌹 这里可以放置与“Bar_Chart”相关的信息和数据。")

elif st.sidebar.button("✦ Line_Chart"):
st.subheader("Line_Chart")

data = pd.DataFrame(
np.random.randn(20, 3), columns=["a", "b", "c"]
)
st.line_chart(data)

st.write("🌹 这里可以放置与“Line_Chart”相关的信息和数据。")

elif st.sidebar.button("✦ Area_Chart"):
st.subheader("Area_Chart")

data = pd.DataFrame(
np.random.randn(20, 3), columns=["a", "b", "c"]
)
st.area_chart(data)

st.write("🌹 这里可以放置与“Area_Chart”相关的信息和数据。")

elif st.sidebar.button("✦ Altair_Chart"):
st.subheader("Altair_Chart")

data = pd.DataFrame(
np.random.randn(20, 3), columns=["a", "b", "c"]
)
c = alt.Chart(data).mark_circle().encode(
x="a", y="b", size="c",
color="c", tooltip=["a", "b", "c"]
)
st.altair_chart(c, use_container_width=True)

st.write("🌹 这里可以放置与“Altair_Chart”相关的信息和数据。")

elif st.sidebar.button("✦ Plotly_Chart"):
st.subheader("Plotly_Chart")

df = px.data.iris()
fig = px.scatter(
df, x="sepal_width", y="sepal_length", color="species"
)
st.plotly_chart(fig)

st.write("🌹 这里可以放置与“Plotly_Chart”相关的信息和数据。")

elif st.sidebar.button("✦ Bokeh_Chart"):
st.subheader("Bokeh_Chart")

x = np.linspace(0, 10, 100)
y = np.sin(x)
p = figure(title="Bokeh图表")
p.line(x, y, legend_label="正弦波", line_width=2)
st.bokeh_chart(p)

st.write("🌹 这里可以放置与“Bokeh_Chart”相关的信息和数据。")

elif st.sidebar.button("✦ PyDeck_Chart"):
st.subheader("PyDeck_Chart")

data = pd.DataFrame(
np.random.randn(1000, 2) / [50, 50] + [37.76, -122.4],
columns=["lat", "lon"]
)

st.pydeck_chart(
pdk.Deck(
map_style=None,
initial_view_state=pdk.ViewState(
latitude=37.76, longitude=-122.4,
zoom=11, pitch=50,
),
layers=[
pdk.Layer(
"HexagonLayer", data=data,
elevation_range=[0, 1000],
radius=200, elevation_scale=4,
pickable=True, extruded=True,
get_position="[lon, lat]",
),
pdk.Layer(
"ScatterplotLayer", data=data,
get_radius=200, get_color="[200, 30, 0, 160]",
get_position="[lon, lat]",
),
],
)
)

st.write("🌹 这里可以放置与“PyDeck_Chart”相关的信息和数据。")

elif st.sidebar.button("✦ Graphviz_Chart"):
st.subheader("Graphviz_Chart")

dot = Digraph()
dot.node("A", "节点 A")
dot.node("B", "节点 B")
dot.node("C", "节点 C")
dot.node("D", "节点 D")
dot.node("E", "节点 E")
dot.node("F", "节点 F")
dot.edges(["AB", "AC", "AD", "CE", "CF"])
st.graphviz_chart(dot)

st.write("🌹 这里可以放置与“Graphviz_Chart”相关的信息和数据。")

elif st.sidebar.button("✦ Vega_Lite_Chart"):
st.subheader("Vega_Lite_Chart")

x = np.linspace(0, 10, 100)
y = np.sin(x)
df = pd.DataFrame({"x": x, "y": y})
st.vega_lite_chart(df, {
"mark": "line",
"encoding": {
"x": {"field": "x", "type": "quantitative"},
"y": {"field": "y", "type": "quantitative"}
}
})

st.write("🌹 这里可以放置与“Vega_Lite_Chart”相关的信息和数据。")

# 默认内容或其他内容
st.write(
"🌸 这里是主区域,"
"点击左侧项目进行查看后,按下R键可返回首页。"
)

3 交互

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
import datetime
import pandas as pd
import streamlit as st

# 创建页面的主要标题,通常是最大最显眼的标题
st.title("Streamlit交互")

# 创建侧边栏
st.sidebar.title("显示项目")

# 添加分类
category = st.sidebar.selectbox(
"", ["输入控件", "选择控件", "文件操作", "滑动控件"]
)

# 初始化session_state,防止页面操作后,程序自动返回首页
# session_state用于在不同页面之间传递和保存状态数据
# 使用session_state可以在不同页面之间共享和使用相同的变量值
# 从而实现多页面之间的交互和数据传递
if "selected_category" not in st.session_state:
st.session_state.selected_category = None


# 定义返回首页的功能
def go_home():
st.session_state.selected_category = None


# 监听键盘事件
if st.button("返回首页"):
go_home()

if category == "输入控件":

# 添加按钮作为分类项目的标题
if st.sidebar.button("❀ 日期选择框"):
st.session_state.selected_category = "日期选择框"

elif st.sidebar.button("❀ 时间选择框"):
st.session_state.selected_category = "时间选择框"

elif st.sidebar.button("❀ 颜色选择器"):
st.session_state.selected_category = "颜色选择器"

elif st.sidebar.button("❀ 数字输入框"):
st.session_state.selected_category = "数字输入框"

elif st.sidebar.button("❀ 单行文本输入"):
st.session_state.selected_category = "单行文本输入"

elif st.sidebar.button("❀ 多行文本输入"):
st.session_state.selected_category = "多行文本输入"

selected_category = st.session_state.selected_category

if selected_category == "日期选择框":
st.subheader("日期选择框")

# 创建日期选择框,允许选择日期
# label:必需,选择框的初始值,默认为空字符串
# value:可选,选择框的初始值,datetime.date类型,未提供则为None
# min_value:可选,选择框的最小值,未提供则不设限
# max_value:可选,选择框的最大值,未提供则不设限
# key:可选,在session_state中标识该控件的唯一键
# help:可选,为选择框提供帮助,鼠标悬停在组件上时显示
date = st.date_input(
label="请选择日期:", value=None,
min_value=None, max_value=datetime.date.today(),
key="date_input", help="请选择日期!"
)

st.write("选择的日期:", date)
st.write("🌹 这里可以放置与“日期选择框”相关的信息和数据。")

elif selected_category == "时间选择框":
st.subheader("时间选择框")

# 创建时间选择框,允许选择时间
# label:必需,选择框的初始值,默认为空字符串
# value:可选,选择框的初始值,datetime.time类型,未提供则为None
# key:可选,在session_state中标识该控件的唯一键
# step:可选,选择框的时间间隔,最小值为60,单位秒(s)
# help:可选,为选择框提供帮助,鼠标悬停在组件上时显示
time = st.time_input(
label="请选择时间:", value=None,
key="time_input", step=120, help="请选择时间!"
)

st.write("选择的时间:", time)
st.write("🌹 这里可以放置与“时间选择框”相关的信息和数据。")

elif selected_category == "颜色选择器":
st.subheader("颜色选择器")

# 创建颜色选择框,允许选择颜色
# label:必需,选择框的初始值,默认为空字符串
# value:可选,选择框的初始值,十六进制颜色代码,未提供则为None
# key:可选,在session_state中标识该控件的唯一键
# help:可选,为选择框提供帮助,鼠标悬停在组件上时显示
color = st.color_picker(
label="请选择颜色:", value="#00F500",
key="color_picker", help="请选择颜色!"
)

st.write("选择的颜色:", color)
st.write("🌹 这里可以放置与“颜色选择器”相关的信息和数据。")

elif selected_category == "数字输入框":
st.subheader("数字输入框")

# 创建数字输入框,允许输入数字
# label:必需,输入框的初始值,默认为空字符串
# value:可选,输入框的初始值,未提供则为None
# min_value:可选,输入框的最小值,未提供则不设限
# max_value:可选,输入框的最大值,未提供则不设限
# key:可选,在session_state中标识该控件的唯一键
# step:可选,输入框的步进值,可通过点击按钮调整,未提供则默认1
# help:可选,为输入框提供帮助,鼠标悬停在组件上时显示
num = st.number_input(
label="请输入数字:", value=0,
min_value=0, max_value=1000,
key="number_input", step=10, help="请输入数字!"
)

st.write("输入的数字:", num)
st.write("🌹 这里可以放置与“数字输入框”相关的信息和数据。")

elif selected_category == "单行文本输入":
st.subheader("单行文本输入")

# 创建文本输入框,允许输入文本信息
# label:必需,输入框的初始值,默认为空字符串
# value:可选,输入框的初始值,默认为空字符串
# max_chars:可选,输入框允许的最大字符数,未提供则不设限
# key:可选,在session_state中标识该控件的唯一键
# type:可选,输入框的类型,默认default、包括password、number
# help:可选,为输入框提供帮助,鼠标悬停在组件上时显示
text = st.text_input(
label="请输入文本:", value="",
max_chars=100, key="text_input",
type="default", help="请输入文本!"
)

st.write("输入的文本:", text)
st.write("🌹 这里可以放置与“单行文本输入”相关的信息和数据。")

elif selected_category == "多行文本输入":
st.subheader("多行文本输入")

# 创建文本输入框,允许输入文本信息
# label:必需,输入框的初始值,默认为空字符串
# value:可选,输入框的初始值,默认为空字符串
# height:可选,输入框的高度,未提供则依据内容自动调节,单位px
# max_chars:可选,输入框允许的最大字符数,未提供则不设限
# key:可选,在session_state中标识该控件的唯一键
# help:可选,为输入框提供帮助,鼠标悬停在组件上时显示
text = st.text_area(
label="请输入文本:", value="",
height=120, max_chars=200,
key="text_area", help="请输入文本!"
)

st.write("输入的文本:", text)
st.write("🌹 这里可以放置与“多行文本输入”相关的信息和数据。")

elif category == "选择控件":
if st.sidebar.button("☆ 单选框"):
st.session_state.selected_category = "单选框"

elif st.sidebar.button("☆ 复选框"):
st.session_state.selected_category = "复选框"

elif st.sidebar.button("☆ 下拉单选框"):
st.session_state.selected_category = "下拉单选框"

elif st.sidebar.button("☆ 下拉多选框"):
st.session_state.selected_category = "下拉多选框"

selected_category = st.session_state.selected_category

if selected_category == "单选框":
st.subheader("单选框")

# 创建单选框
# label:必需,选择框的标签
# options:必需,提供可供选择选项的列表、元组或字典
# index:可选,选择框的初始选择索引,默认0,即默认选中第一个
# format_func:可选,用于格式化选项的函数
# key:可选,在session_state中标识该控件的唯一键
# help:可选,为选择框提供帮助,鼠标悬停在组件上时显示
radio = st.radio(
label="请选择性别:", options=("男", "女", "保密"),
index=2, format_func=str,
key="radio", help="请选择性别!"
)

st.write("选择的性别:", radio)
st.write("🌹 这里可以放置与“单选框”相关的信息和数据。")

elif selected_category == "复选框":
st.subheader("复选框")

# 创建复选框
# label:必需,选择框的值
# value:默认False,设为True则选择框初始状态为选中
# key:可选,在session_state中标识该控件的唯一键
# help:可选,为选择框提供帮助,鼠标悬停在组件上时显示
checkbox = st.checkbox(
label="确认", value=False,
key="checkbox", help="请确认是否勾选!"
)

st.write("是否确认:", checkbox)
st.write("🌹 这里可以放置与“复选框”相关的信息和数据。")

elif selected_category == "下拉单选框":
st.subheader("下拉单选框")

# 创建下拉单选框
# label:必需,选择框的标签
# options:必需,提供可供选择选项的列表、元组或字典
# index:可选,选择框的初始选择索引,默认0,即默认选中第一个
# format_func:可选,用于格式化选项的函数
# key:可选,在session_state中标识该控件的唯一键
# help:可选,为选择框提供帮助,鼠标悬停在组件上时显示
selectbox = st.selectbox(
label="请选择性别:", options=("男", "女", "保密"),
index=2, format_func=str,
key="selectbox", help="请选择性别!"
)

st.write("选择的性别:", selectbox)
st.write("🌹 这里可以放置与“下拉单选框”相关的信息和数据。")

elif selected_category == "下拉多选框":
st.subheader("下拉多选框")

# 创建日期选择框,允许选择日期
# label:必需,选择框的标签
# options:必需,提供可供选择选项的列表、元组或字典
# default:可选,选择框的初始选择,默认None
# format_func:可选,用于格式化选项的函数
# key:可选,在session_state中标识该控件的唯一键
# help:可选,为选择框提供帮助,鼠标悬停在组件上时显示
multiselect = st.multiselect(
label="请选择水果:", options=(
"苹果", "香蕉", "草莓", "樱桃", "橘子", "西瓜"
),
default=None, format_func=str,
key="multiselect", help="请选择水果!"
)

st.write("选择的水果:", multiselect)
st.write("🌹 这里可以放置与“下拉多选框”相关的信息和数据。")

elif category == "文件操作":
if st.sidebar.button("❄ 文件上传"):
st.session_state.selected_category = "文件上传"

elif st.sidebar.button("❄ 文件下载"):
st.session_state.selected_category = "文件下载"

selected_category = st.session_state.selected_category

if selected_category == "文件上传":
st.subheader("文件上传")

# 文件上传
# label:必需,显示在文件上传控件前面的标签
# type:可选,可上传的文件类型,例如["png", "jpg"]
# 也可以是通配符字符串,如"image/*",不指定则允许任何类型
# accept_multiple_files:可选,默认False,是否可上传多个文件
# key:可选,在session_state中标识该控件的唯一键
# help:可选,提供帮助提示,鼠标悬停在组件上时显示
file = st.file_uploader(
label="请选择文件:", type=["png", "jpg"],
accept_multiple_files=False,
key="file_uploader", help="请选择文件!"
)

st.write("选择的文件:", file)
st.write("🌹 这里可以放置与“文件上传”相关的信息和数据。")

elif selected_category == "文件下载":
st.subheader("文件下载")

# 创建数据
data = {
"Name": ["Alice", "Bob", "Charlie"],
"Age": [25, 30, 35]
}
df = pd.DataFrame(data)

# 文件下载
# label:必需,下载按钮上显示的文本标签
# data:必需,要下载的数据,字符串、字节、DataFrame、数组等
# file_name:可选,下载时保存的文件名,可以包含扩展名
# mime:可选,MIME类型,例如"text/csv",未提供则自动推断
# key:可选,在session_state中标识该控件的唯一键
# help:可选,提供帮助提示,鼠标悬停在组件上时显示
file = st.download_button(
label="下载CSV", data=df.to_csv(index=False),
file_name="data.csv", mime="text/csv",
key="download_button", help="点击下载!"
)

st.write("是否下载:", file)
st.write("🌹 这里可以放置与“文件下载”相关的信息和数据。")

elif category == "滑动控件":
if st.sidebar.button("✦ 滑动条"):
st.session_state.selected_category = "滑动条"

elif st.sidebar.button("✦ 选择条"):
st.session_state.selected_category = "选择条"

selected_category = st.session_state.selected_category

if selected_category == "滑动条":
st.subheader("滑动条")

# 创建一个滑块,允许用户在一个范围内选择一个数值
# label:必需,滑块的标签,显示在滑块上方,用于标识用途
# value:可选,滑块的初始值,可以是单个数值或表示范围的元组
# min_value:可选,滑块的最小值,未提供则默认0
# max_value:可选,滑块的最大值,未提供则默认100
# step:可选,滑块的步进值,未提供则默认1
# format:可选,滑块的显示格式
# 例如包含"{:.2f}"之类的格式字符串,用于控制显示的小数位数
# key:可选,在session_state中标识该控件的唯一键
# help:可选,为滑块提供帮助,鼠标悬停在组件上时显示
slider = st.slider(
label="请滑动滑块:", value=0,
min_value=0, max_value=100, step=10,
key="slider", help="请滑动滑块!"
)

st.write("滑动的数字:", slider)
st.write("🌹 这里可以放置与“滑动条”相关的信息和数据。")

elif selected_category == "选择条":
st.subheader("选择条")

# 创建选择条(选择滑块)
# label:必需,显示在滑块控件前面的标签
# options:必需,可以是一个列表、元组、NumPy数组等
# value:可选,默认选中的值,或一个包含初始值的元组
# format_func:可选,自定义格式化函数
# 用于将options列表中的值转换为在界面上显示的文字
# key:可选,在session_state中标识该控件的唯一键
# help:可选,为选择条提供帮助,鼠标悬停在组件上时显示
slider = st.select_slider(
label="请选择颜色:", options=[
"红", "橙", "黄", "绿", "青", "蓝", "紫"
],
value="绿", format_func=str,
key="select_slider", help="请选择颜色!"
)

st.write("选择的颜色:", slider)
st.write("🌹 这里可以放置与“选择条”相关的信息和数据。")

# 提示用户如何返回首页
if st.session_state.selected_category is None:
st.write(
"🌸 这里是主区域,"
"点击左侧项目进行查看后,按下“返回首页”按钮可回到首页。"
)

4 多页面

  • 多页面
    • 多页面应用的基本结构:导航栏、页面内容、状态管理。
    • 函数:如果页面内容构建复杂,可以使用函数进行构建。
    • 文件分页(推荐):简化路由管理,易于部署,代码更加模块化,易于维护。

4-1 基本结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
import sys
import datetime
import pandas as pd
import streamlit as st
from streamlit import runtime
from streamlit.web import cli as stcli


def web_app():
st.title("Streamlit交互")

# 侧边导航栏
st.sidebar.title("显示项目")
category = st.sidebar.selectbox(
"", ["输入控件", "选择控件", "文件操作", "滑动控件"]
)

# 状态管理
if "selected_category" not in st.session_state:
st.session_state.selected_category = None

# 仅当不在首页时显示“返回首页”按钮
if st.session_state.selected_category is not None \
or "force_rerun" in st.session_state:
if st.button("返回首页"):

# 彻底删除状态
del st.session_state.selected_category

# # 清除强制更新状态
del st.session_state["force_rerun"]

# 立即刷新页面
st.rerun()

# 页面内容
if category == "输入控件":
if st.sidebar.button("❀ 日期选择框"):
st.session_state.selected_category = "日期选择框"

# 添加强制更新状态
st.session_state["force_rerun"] = True
st.rerun()

elif st.sidebar.button("❀ 时间选择框"):
st.session_state.selected_category = "时间选择框"
st.session_state["force_rerun"] = True
st.rerun()

elif st.sidebar.button("❀ 颜色选择器"):
st.session_state.selected_category = "颜色选择器"
st.session_state["force_rerun"] = True
st.rerun()

elif st.sidebar.button("❀ 数字输入框"):
st.session_state.selected_category = "数字输入框"
st.session_state["force_rerun"] = True
st.rerun()

elif st.sidebar.button("❀ 单行文本输入"):
st.session_state.selected_category = "单行文本输入"
st.session_state["force_rerun"] = True
st.rerun()

elif st.sidebar.button("❀ 多行文本输入"):
st.session_state.selected_category = "多行文本输入"
st.session_state["force_rerun"] = True
st.rerun()

if "selected_category" in st.session_state:
selected_category = st.session_state.selected_category

if selected_category == "日期选择框":
st.subheader("日期选择框")

date = st.date_input(
label="请选择日期:", value=None,
min_value=None, max_value=datetime.date.today(),
key="date_input", help="请选择日期!"
)

st.write("选择的日期:", date)
st.write("🌹 这里可以放置与“日期选择框”相关的信息和数据。")

elif selected_category == "时间选择框":
st.subheader("时间选择框")

time = st.time_input(
label="请选择时间:", value=None,
key="time_input", step=120, help="请选择时间!"
)

st.write("选择的时间:", time)
st.write("🌹 这里可以放置与“时间选择框”相关的信息和数据。")

elif selected_category == "颜色选择器":
st.subheader("颜色选择器")

color = st.color_picker(
label="请选择颜色:", value="#00F500",
key="color_picker", help="请选择颜色!"
)

st.write("选择的颜色:", color)
st.write("🌹 这里可以放置与“颜色选择器”相关的信息和数据。")

elif selected_category == "数字输入框":
st.subheader("数字输入框")

num = st.number_input(
label="请输入数字:", value=0,
min_value=0, max_value=1000,
key="number_input", step=10, help="请输入数字!"
)

st.write("输入的数字:", num)
st.write("🌹 这里可以放置与“数字输入框”相关的信息和数据。")

elif selected_category == "单行文本输入":
st.subheader("单行文本输入")

text = st.text_input(
label="请输入文本:", value="",
max_chars=100, key="text_input",
type="default", help="请输入文本!"
)

st.write("输入的文本:", text)
st.write("🌹 这里可以放置与“单行文本输入”相关的信息和数据。")

elif selected_category == "多行文本输入":
st.subheader("多行文本输入")

text = st.text_area(
label="请输入文本:", value="",
height=120, max_chars=200,
key="text_area", help="请输入文本!"
)

st.write("输入的文本:", text)
st.write("🌹 这里可以放置与“多行文本输入”相关的信息和数据。")

elif category == "选择控件":
if st.sidebar.button("☆ 单选框"):
st.session_state.selected_category = "单选框"
st.session_state["force_rerun"] = True
st.rerun()

elif st.sidebar.button("☆ 复选框"):
st.session_state.selected_category = "复选框"
st.session_state["force_rerun"] = True
st.rerun()

elif st.sidebar.button("☆ 下拉单选框"):
st.session_state.selected_category = "下拉单选框"
st.session_state["force_rerun"] = True
st.rerun()

elif st.sidebar.button("☆ 下拉多选框"):
st.session_state.selected_category = "下拉多选框"
st.session_state["force_rerun"] = True
st.rerun()

if "selected_category" in st.session_state:
selected_category = st.session_state.selected_category

if selected_category == "单选框":
st.subheader("单选框")

radio = st.radio(
label="请选择性别:", options=("男", "女", "保密"),
index=2, format_func=str,
key="radio", help="请选择性别!"
)

st.write("选择的性别:", radio)
st.write("🌹 这里可以放置与“单选框”相关的信息和数据。")

elif selected_category == "复选框":
st.subheader("复选框")

checkbox = st.checkbox(
label="确认", value=False,
key="checkbox", help="请确认是否勾选!"
)

st.write("是否确认:", checkbox)
st.write("🌹 这里可以放置与“复选框”相关的信息和数据。")

elif selected_category == "下拉单选框":
st.subheader("下拉单选框")

selectbox = st.selectbox(
label="请选择性别:", options=("男", "女", "保密"),
index=2, format_func=str,
key="selectbox", help="请选择性别!"
)

st.write("选择的性别:", selectbox)
st.write("🌹 这里可以放置与“下拉单选框”相关的信息和数据。")

elif selected_category == "下拉多选框":
st.subheader("下拉多选框")

multiselect = st.multiselect(
label="请选择水果:", options=(
"苹果", "香蕉", "草莓", "樱桃", "橘子", "西瓜"
),
default=None, format_func=str,
key="multiselect", help="请选择水果!"
)

st.write("选择的水果:", multiselect)
st.write("🌹 这里可以放置与“下拉多选框”相关的信息和数据。")

elif category == "文件操作":
if st.sidebar.button("❄ 文件上传"):
st.session_state.selected_category = "文件上传"
st.session_state["force_rerun"] = True
st.rerun()

elif st.sidebar.button("❄ 文件下载"):
st.session_state.selected_category = "文件下载"
st.session_state["force_rerun"] = True
st.rerun()

if "selected_category" in st.session_state:
selected_category = st.session_state.selected_category

if selected_category == "文件上传":
st.subheader("文件上传")

file = st.file_uploader(
label="请选择文件:", type=["png", "jpg"],
accept_multiple_files=False,
key="file_uploader", help="请选择文件!"
)

st.write("选择的文件:", file)
st.write("🌹 这里可以放置与“文件上传”相关的信息和数据。")

elif selected_category == "文件下载":
st.subheader("文件下载")

data = {
"Name": ["Alice", "Bob", "Charlie"],
"Age": [25, 30, 35]
}
df = pd.DataFrame(data)

file = st.download_button(
label="下载CSV", data=df.to_csv(index=False),
file_name="data.csv", mime="text/csv",
key="download_button", help="点击下载!"
)

st.write("是否下载:", file)
st.write("🌹 这里可以放置与“文件下载”相关的信息和数据。")

elif category == "滑动控件":
if st.sidebar.button("✦ 滑动条"):
st.session_state.selected_category = "滑动条"
st.session_state["force_rerun"] = True
st.rerun()

elif st.sidebar.button("✦ 选择条"):
st.session_state.selected_category = "选择条"
st.session_state["force_rerun"] = True
st.rerun()

if "selected_category" in st.session_state:
selected_category = st.session_state.selected_category

if selected_category == "滑动条":
st.subheader("滑动条")

slider = st.slider(
label="请滑动滑块:", value=0,
min_value=0, max_value=100, step=10,
key="slider", help="请滑动滑块!"
)

st.write("滑动的数字:", slider)
st.write("🌹 这里可以放置与“滑动条”相关的信息和数据。")

elif selected_category == "选择条":
st.subheader("选择条")

slider = st.select_slider(
label="请选择颜色:", options=[
"红", "橙", "黄", "绿", "青", "蓝", "紫"
],
value="绿", format_func=str,
key="select_slider", help="请选择颜色!"
)

st.write("选择的颜色:", slider)
st.write("🌹 这里可以放置与“选择条”相关的信息和数据。")

if st.session_state.selected_category is None:
st.write(
"🌸 这里是主区域,"
"点击左侧项目进行查看后,按下“返回首页”按钮可回到首页。"
)


def main():
if runtime.exists():
web_app()
else:
sys.argv = ["streamlit", "run", sys.argv[0]]
sys.exit(stcli.main())


if __name__ == "__main__":
main()

4-2 函数构建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
import sys
import datetime
import pandas as pd
import streamlit as st
from streamlit import runtime
from streamlit.web import cli as stcli


def date_input():
st.subheader("日期选择框")

date = st.date_input(
label="请选择日期:", value=None,
min_value=None, max_value=datetime.date.today(),
key="date_input", help="请选择日期!"
)

st.write("选择的日期:", date)
st.write("🌹 这里可以放置与“日期选择框”相关的信息和数据。")


def time_input():
st.subheader("时间选择框")

time = st.time_input(
label="请选择时间:", value=None,
key="time_input", step=120, help="请选择时间!"
)

st.write("选择的时间:", time)
st.write("🌹 这里可以放置与“时间选择框”相关的信息和数据。")


def color_picker():
st.subheader("颜色选择器")

color = st.color_picker(
label="请选择颜色:", value="#00F500",
key="color_picker", help="请选择颜色!"
)

st.write("选择的颜色:", color)
st.write("🌹 这里可以放置与“颜色选择器”相关的信息和数据。")


def number_input():
st.subheader("数字输入框")

num = st.number_input(
label="请输入数字:", value=0,
min_value=0, max_value=1000,
key="number_input", step=10, help="请输入数字!"
)

st.write("输入的数字:", num)
st.write("🌹 这里可以放置与“数字输入框”相关的信息和数据。")


def text_input():
st.subheader("单行文本输入")

text = st.text_input(
label="请输入文本:", value="",
max_chars=100, key="text_input",
type="default", help="请输入文本!"
)

st.write("输入的文本:", text)
st.write("🌹 这里可以放置与“单行文本输入”相关的信息和数据。")


def text_area():
st.subheader("多行文本输入")

text = st.text_area(
label="请输入文本:", value="",
height=120, max_chars=200,
key="text_area", help="请输入文本!"
)

st.write("输入的文本:", text)
st.write("🌹 这里可以放置与“多行文本输入”相关的信息和数据。")


def radio():
st.subheader("单选框")

radios = st.radio(
label="请选择性别:", options=("男", "女", "保密"),
index=2, format_func=str,
key="radio", help="请选择性别!"
)

st.write("选择的性别:", radios)
st.write("🌹 这里可以放置与“单选框”相关的信息和数据。")


def checkbox():
st.subheader("复选框")

checkbox = st.checkbox(
label="确认", value=False,
key="checkbox", help="请确认是否勾选!"
)

st.write("是否确认:", checkbox)
st.write("🌹 这里可以放置与“复选框”相关的信息和数据。")


def selectbox():
st.subheader("下拉单选框")

selectbox = st.selectbox(
label="请选择性别:", options=("男", "女", "保密"),
index=2, format_func=str,
key="selectbox", help="请选择性别!"
)

st.write("选择的性别:", selectbox)
st.write("🌹 这里可以放置与“下拉单选框”相关的信息和数据。")


def multiselect():
st.subheader("下拉多选框")

multiselect = st.multiselect(
label="请选择水果:", options=(
"苹果", "香蕉", "草莓", "樱桃", "橘子", "西瓜"
),
default=None, format_func=str,
key="multiselect", help="请选择水果!"
)

st.write("选择的水果:", multiselect)
st.write("🌹 这里可以放置与“下拉多选框”相关的信息和数据。")


def file_uploader():
st.subheader("文件上传")

file = st.file_uploader(
label="请选择文件:", type=["png", "jpg"],
accept_multiple_files=False,
key="file_uploader", help="请选择文件!"
)

st.write("选择的文件:", file)
st.write("🌹 这里可以放置与“文件上传”相关的信息和数据。")


def download_button():
st.subheader("文件下载")

data = {
"Name": ["Alice", "Bob", "Charlie"],
"Age": [25, 30, 35]
}
df = pd.DataFrame(data)

file = st.download_button(
label="下载CSV", data=df.to_csv(index=False),
file_name="data.csv", mime="text/csv",
key="download_button", help="点击下载!"
)

st.write("是否下载:", file)
st.write("🌹 这里可以放置与“文件下载”相关的信息和数据。")


def slider():
st.subheader("滑动条")

slider = st.slider(
label="请滑动滑块:", value=0,
min_value=0, max_value=100, step=10,
key="slider", help="请滑动滑块!"
)

st.write("滑动的数字:", slider)
st.write("🌹 这里可以放置与“滑动条”相关的信息和数据。")


def select_slider():
st.subheader("选择条")

slider = st.select_slider(
label="请选择颜色:", options=[
"红", "橙", "黄", "绿", "青", "蓝", "紫"
],
value="绿", format_func=str,
key="select_slider", help="请选择颜色!"
)

st.write("选择的颜色:", slider)
st.write("🌹 这里可以放置与“选择条”相关的信息和数据。")


def page_home():
st.title("Streamlit交互")


def home_tip():
st.write(
"🌸 这里是主区域,"
"点击左侧项目进行查看后,按下“返回首页”按钮可回到首页。"
)


def home_button():
# 只在需要时显示按钮
if "input_rendered" in st.session_state:
btn = st.button("返回首页")
if btn:
# 彻底删除状态
del st.session_state.input_rendered

# 立即刷新页面
st.rerun()


def render_selected_input():
# home_button()放这里首页也有按钮
# 解决方法看home_button()函数
home_button()

# 渲染所选控件
if "input_rendered" in st.session_state:
# home_button()放这里返回首页后也会出现按钮
# 解决方法看home_button()函数
# home_button()

if st.session_state.input_rendered == "❀ 日期选择框":
# home_button()放这里需要双击才会返回首页,单击无效
# 通常是因为状态更新后没有立即触发重新运行,使用st.rerun()
# home_button()

date_input()
elif st.session_state.input_rendered == "❀ 时间选择框":
time_input()
elif st.session_state.input_rendered == "❀ 颜色选择器":
color_picker()
elif st.session_state.input_rendered == "❀ 数字输入框":
number_input()
elif st.session_state.input_rendered == "❀ 单行文本输入":
text_input()
elif st.session_state.input_rendered == "❀ 多行文本输入":
text_area()
elif st.session_state.input_rendered == "☆ 单选框":
radio()
elif st.session_state.input_rendered == "☆ 复选框":
checkbox()
elif st.session_state.input_rendered == "☆ 下拉单选框":
selectbox()
elif st.session_state.input_rendered == "☆ 下拉多选框":
multiselect()
elif st.session_state.input_rendered == "❄ 文件上传":
file_uploader()
elif st.session_state.input_rendered == "❄ 文件下载":
download_button()
elif st.session_state.input_rendered == "✦ 滑动条":
slider()
elif st.session_state.input_rendered == "✦ 选择条":
select_slider()


def web_app():
page_home()

# 确保session_state中需要的变量存在
if "selected_category" not in st.session_state:
st.session_state.selected_category = None

st.sidebar.title("显示项目")
categories = ["输入控件", "选择控件", "文件操作", "滑动控件"]
selected_category = st.sidebar.selectbox(
"", categories,
index=categories.index(
st.session_state.selected_category
) if st.session_state.selected_category else 0
)

# 保存用户选择的类别
st.session_state.selected_category = selected_category

if selected_category:
# 显示内容基于选择的类别
if selected_category == "输入控件":
input_buttons = [
"❀ 日期选择框", "❀ 时间选择框", "❀ 颜色选择器",
"❀ 数字输入框", "❀ 单行文本输入", "❀ 多行文本输入"
]
for input_type in input_buttons:
if st.sidebar.button(input_type):
st.session_state.selected_input = input_type
# 记录当前渲染的输入类型
st.session_state.input_rendered = input_type

elif selected_category == "选择控件":
selection_buttons = [
"☆ 单选框", "☆ 复选框", "☆ 下拉单选框", "☆ 下拉多选框"
]
for selection_type in selection_buttons:
if st.sidebar.button(selection_type):
st.session_state.selected_input = selection_type
st.session_state.input_rendered = selection_type

elif selected_category == "文件操作":
file_buttons = ["❄ 文件上传", "❄ 文件下载"]
for file_action in file_buttons:
if st.sidebar.button(file_action):
st.session_state.selected_input = file_action
st.session_state.input_rendered = file_action

elif selected_category == "滑动控件":
slider_buttons = ["✦ 滑动条", "✦ 选择条"]
for slider_type in slider_buttons:
if st.sidebar.button(slider_type):
st.session_state.selected_input = slider_type
st.session_state.input_rendered = slider_type

render_selected_input()

# 仅首页展示提示
if "input_rendered" not in st.session_state:
home_tip()


def main():
if runtime.exists():
web_app()
else:
sys.argv = ["streamlit", "run", sys.argv[0]]
sys.exit(stcli.main())


if __name__ == "__main__":
main()

4-3 文件分页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
pages:
# 每个分页的URL都由文件名定义
# 可通过修改文件名前缀,对所有分页进行排序展示
- 1_Input_Controls.py
- 2_Slider_Controls.py
- 3_File_Operations.py
- 4_Selection_Controls.py

# 主脚本
- main.py

# 支持运行时进行页面的保存,保存后将重新运行该页面
# 更新侧边导航栏不会重新运行脚本,需要重启进行查看
# 所有分页在全局范围内共享相同的Python模块和session_state

(1) main.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import sys
import streamlit as st
from streamlit import runtime
from streamlit.web import cli as stcli


def web_app():
# set_page_config()在页面级别工作
# 设置的标题或图标,仅适用于当前页面
st.set_page_config(
page_title="Streamlit交互",
page_icon="👋",
)

st.title("Streamlit交互")

st.sidebar.success("Select a modules above.")

st.markdown(
"""
Streamlit is an open-source app framework.
It is built specifically for Machine Learning and Data Science projects.
**👈 Select a demo from the sidebar**
to see some examples of what Streamlit can do!
### Want to learn more?
- Check out [streamlit.io](https://streamlit.io)
- Jump into our [documentation](https://docs.streamlit.io)
- Ask a question in our [community
forums](https://discuss.streamlit.io)
"""
)

st.write(
"🌸 这里是主区域,"
"点击左侧项目进行查看后,按下“返回首页”按钮可回到首页。"
)


def main():
if runtime.exists():
web_app()
else:
sys.argv = ["streamlit", "run", sys.argv[0]]
sys.exit(stcli.main())


if __name__ == "__main__":
main()

(2) Input_Controls.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import datetime
import streamlit as st

st.set_page_config(page_title="输入控件", page_icon="✍")

st.markdown("# 输入控件")
st.sidebar.header("输入控件")


# 各页面的内容函数
def date_input():
date = st.date_input(
label="请选择日期:", value=None,
min_value=None, max_value=datetime.date.today(),
key="date_input", help="请选择日期!"
)
st.write("选择的日期:", date)
st.write("🌹 这里可以放置与“日期选择框”相关的信息和数据。")


def time_input():
time = st.time_input(
label="请选择时间:", value=None,
key="time_input", step=120, help="请选择时间!"
)
st.write("选择的时间:", time)
st.write("🌹 这里可以放置与“时间选择框”相关的信息和数据。")


def color_picker():
color = st.color_picker(
label="请选择颜色:", value="#00F500",
key="color_picker", help="请选择颜色!"
)
st.write("选择的颜色:", color)
st.write("🌹 这里可以放置与“颜色选择器”相关的信息和数据。")


def number_input():
num = st.number_input(
label="请输入数字:", value=0,
min_value=0, max_value=1000,
key="number_input", step=10, help="请输入数字!"
)
st.write("输入的数字:", num)
st.write("🌹 这里可以放置与“数字输入框”相关的信息和数据。")


def text_input():
text = st.text_input(
label="请输入文本:", value="",
max_chars=100, key="text_input",
type="default", help="请输入文本!"
)
st.write("输入的文本:", text)
st.write("🌹 这里可以放置与“单行文本输入”相关的信息和数据。")


def text_area():
text = st.text_area(
label="请输入文本:", value="",
height=120, max_chars=200,
key="text_area", help="请输入文本!"
)
st.write("输入的文本:", text)
st.write("🌹 这里可以放置与“多行文本输入”相关的信息和数据。")


# 页面选项和对应的标题及内容函数
page_options = {
"日期选择框": {
"title": "日期选择框",
"content": lambda: date_input(),
},
"时间选择框": {
"title": "时间选择框",
"content": lambda: time_input(),
},
"颜色选择器": {
"title": "颜色选择器",
"content": lambda: color_picker(),
},
"数字输入框": {
"title": "数字输入框",
"content": lambda: number_input(),
},
"单行文本输入": {
"title": "单行文本输入",
"content": lambda: text_input(),
},
"多行文本输入": {
"title": "多行文本输入",
"content": lambda: text_area(),
}
}

# 初始化Input_Controls页面特有的selected_category
if "input_controls_selected_category" not in st.session_state:
# 默认显示第一个选项
st.session_state.input_controls_selected_category = list(
page_options.keys()
)[0]

# 这里不需要删除session_state,只重定向回主页
if st.button("返回首页"):
st.switch_page("main.py")

# 侧边栏按钮生成
for page_name in page_options.keys():
if st.sidebar.button(f"❀ {page_name}"):
st.session_state.input_controls_selected_category = page_name
st.rerun()

# 页面内容显示
if "input_controls_selected_category" in st.session_state:
selected_category = st.session_state.input_controls_selected_category
st.subheader(page_options[selected_category]["title"])
page_options[selected_category]["content"]()

(3) Slider_Controls.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import streamlit as st

st.set_page_config(page_title="滑块控件", page_icon="🛹")

st.markdown("# 滑块控件")
st.sidebar.header("滑块控件")


# 各页面的内容函数
def slider():
slider = st.slider(
label="请滑动滑块:", value=0,
min_value=0, max_value=100, step=10,
key="slider", help="请滑动滑块!"
)
st.write("滑动的数字:", slider)
st.write("🌹 这里可以放置与“滑动条”相关的信息和数据。")


def select_slider():
slider = st.select_slider(
label="请选择颜色:", options=[
"红", "橙", "黄", "绿", "青", "蓝", "紫"
],
value="绿", format_func=str,
key="select_slider", help="请选择颜色!"
)
st.write("选择的颜色:", slider)
st.write("🌹 这里可以放置与“选择条”相关的信息和数据。")


# 页面选项和对应的标题及内容函数
page_options = {
"滑动条": {
"title": "滑动条",
"content": lambda: slider(),
},
"选择条": {
"title": "选择条",
"content": lambda: select_slider(),
}
}

# 初始化Slider_Controls页面特有的selected_category
if "slider_controls_selected_category" not in st.session_state:
# 默认显示第一个选项
st.session_state.slider_controls_selected_category = list(
page_options.keys()
)[0]

# 这里不需要删除session_state,只重定向回主页
if st.button("返回首页"):
st.switch_page("main.py")

# 侧边栏按钮生成
for page_name in page_options.keys():
if st.sidebar.button(f"✦ {page_name}"):
st.session_state.slider_controls_selected_category = page_name
st.rerun()

# 页面内容显示
if "slider_controls_selected_category" in st.session_state:
selected_category = st.session_state.slider_controls_selected_category
st.subheader(page_options[selected_category]["title"])
page_options[selected_category]["content"]()

(4) File_Operations.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import pandas as pd
import streamlit as st

st.set_page_config(page_title="文件操作", page_icon="📕")

st.markdown("# 文件操作")
st.sidebar.header("文件操作")


# 各页面的内容函数
def file_uploader():
file = st.file_uploader(
label="请选择文件:", type=["png", "jpg"],
accept_multiple_files=False,
key="file_uploader", help="请选择文件!"
)
st.write("选择的文件:", file)
st.write("🌹 这里可以放置与“文件上传”相关的信息和数据。")


def download_button():
data = {
"Name": ["Alice", "Bob", "Charlie"],
"Age": [25, 30, 35]
}
df = pd.DataFrame(data)

file = st.download_button(
label="下载CSV", data=df.to_csv(index=False),
file_name="data.csv", mime="text/csv",
key="download_button", help="点击下载!"
)
st.write("是否下载:", file)
st.write("🌹 这里可以放置与“文件下载”相关的信息和数据。")


# 页面选项和对应的标题及内容函数
page_options = {
"文件上传": {
"title": "文件上传",
"content": lambda: file_uploader(),
},
"文件下载": {
"title": "文件下载",
"content": lambda: download_button(),
}
}

# 需确保每个页面的selected_category都是独立管理的
# 初始化File_Operations页面特有的selected_category
if "file_operations_selected_category" not in st.session_state:
# 默认显示第一个选项
st.session_state.file_operations_selected_category = list(
page_options.keys()
)[0]

# 这里不需要删除session_state,只重定向回主页
if st.button("返回首页"):
st.switch_page("main.py")

# 侧边栏按钮生成
for page_name in page_options.keys():
if st.sidebar.button(f"❄ {page_name}"):
st.session_state.file_operations_selected_category = page_name
st.rerun()

# 页面内容显示
if "file_operations_selected_category" in st.session_state:
selected_category = st.session_state.file_operations_selected_category
st.subheader(page_options[selected_category]["title"])
page_options[selected_category]["content"]()

(5) Selection_Controls.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import streamlit as st

st.set_page_config(page_title="选择控件", page_icon="✅")

st.markdown("# 选择控件")
st.sidebar.header("选择控件")


# 各页面的内容函数
def radio():
radio = st.radio(
label="请选择性别:", options=("男", "女", "保密"),
index=2, format_func=str,
key="radio", help="请选择性别!"
)
st.write("选择的性别:", radio)
st.write("🌹 这里可以放置与“单选框”相关的信息和数据。")


def checkbox():
checkbox = st.checkbox(
label="确认", value=False,
key="checkbox", help="请确认是否勾选!"
)
st.write("是否确认:", checkbox)
st.write("🌹 这里可以放置与“复选框”相关的信息和数据。")


def selectbox():
selectbox = st.selectbox(
label="请选择性别:", options=("男", "女", "保密"),
index=2, format_func=str,
key="selectbox", help="请选择性别!"
)
st.write("选择的性别:", selectbox)
st.write("🌹 这里可以放置与“下拉单选框”相关的信息和数据。")


def multiselect():
multiselect = st.multiselect(
label="请选择水果:", options=(
"苹果", "香蕉", "草莓", "樱桃", "橘子", "西瓜"
),
default=None, format_func=str,
key="multiselect", help="请选择水果!"
)
st.write("选择的水果:", multiselect)
st.write("🌹 这里可以放置与“下拉多选框”相关的信息和数据。")


# 页面选项和对应的标题及内容函数
page_options = {
"单选框": {
"title": "单选框",
"content": lambda: radio(),
},
"复选框": {
"title": "复选框",
"content": lambda: checkbox(),
},
"下拉单选框": {
"title": "下拉单选框",
"content": lambda: selectbox(),
},
"下拉多选框": {
"title": "下拉多选框",
"content": lambda: multiselect(),
}
}

# 初始化Selection_Controls页面特有的selected_category
if "selection_controls_selected_category" not in st.session_state:
# 默认显示第一个选项
st.session_state.selection_controls_selected_category = list(
page_options.keys()
)[0]

# 这里不需要删除session_state,只重定向回主页
if st.button("返回首页"):
st.switch_page("main.py")

# 侧边栏按钮生成
for page_name in page_options.keys():
if st.sidebar.button(f"☆ {page_name}"):
st.session_state.selection_controls_selected_category = page_name
st.rerun()

# 页面内容显示
if "selection_controls_selected_category" in st.session_state:
selected_category = st.session_state.selection_controls_selected_category
st.subheader(page_options[selected_category]["title"])
page_options[selected_category]["content"]()

5 其他函数

  • 其他函数
    • 组件库参考:官网组件库组件库论坛(找到要用的组件后,先使用pip命令安装)。
    • 状态组件:展示当前程序的运行状态。
      • progress(进度加载)、spinner(等待状态)、balloons(页面底部飘气球,祝贺)。
      • info(提示)、error(错误)、warning(警告)、success(成功)、exception(异常)。
    • 缓存特性
      • 在页面进行输入等操作时,会触发整个应用代码的重新执行。
      • 如果应用代码中包含读取外部数据的操作,则十分损耗性能。
      • Streamlit提供了两个缓存装饰器,在渲染页面时会检查缓存。
      • 满足一定条件则直接使用缓存结果,而不会重新执行被装饰的函数或初始化资源。

5-1 表格编辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import sys
import pandas as pd
import streamlit as st
from streamlit import runtime
from streamlit.web import cli as stcli


def data_editor():
st.title("表格编辑")

df = pd.DataFrame([
{"command": "st.date_input", "rating": 1, "is_widget": True},
{"command": "st.time_input", "rating": 3, "is_widget": False},
{"command": "st.color_picker", "rating": 7, "is_widget": True},
{"command": "st.number_input", "rating": 9, "is_widget": False}
])

edited_df = st.data_editor(df)
favorite_command = edited_df.loc[
edited_df["rating"].idxmax()
]["command"]

st.markdown(
f"Your favorite command is **{favorite_command}**. 🎈"
)


def main():
if runtime.exists():
data_editor()
else:
sys.argv = ["streamlit", "run", sys.argv[0]]
sys.exit(stcli.main())


if __name__ == "__main__":
main()

5-2 状态组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import sys
import time
import streamlit as st
from streamlit import runtime
from streamlit.web import cli as stcli


def state_components():
st.title("状态组件")

# 进度加载
st.subheader("进度加载")
bar = st.progress(0)
for percent_complete in range(100):
# 模拟进度加载时间
time.sleep(0.01)
bar.progress(percent_complete + 1)
st.success("加载完成!")

# 等待状态
st.subheader("等待状态")
with st.spinner("请稍等..."):
# 模拟等待时间
time.sleep(2)
st.success("加载完成!")

# 气球效果
st.subheader("气球祝贺")
if st.button("放飞气球"):
st.balloons()

# 状态消息
st.subheader("状态消息")
st.info("提示消息")
st.error("错误消息")
st.warning("警告消息")
st.success("成功消息")
try:
1 / 0
except Exception as e:
st.exception(e)


def main():
if runtime.exists():
state_components()
else:
sys.argv = ["streamlit", "run", sys.argv[0]]
sys.exit(stcli.main())


if __name__ == "__main__":
main()

5-3 缓存特性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import sys
import time
import pandas as pd
import streamlit as st
from streamlit import runtime
from streamlit.web import cli as stcli


def cache_data():
st.title("缓存数据")

# cache_data:缓存函数的返回值
# 适用于缓存相对较小、不会随着时间变化的数据
@st.cache_data
def load_data():
# 模拟一个耗时的数据加载过程
time.sleep(2)
data = pd.DataFrame({
"A": range(1, 6),
"B": range(6, 11)
})
return data

st.write(
"st.cache_data:主要用于缓存计算结果,"
"例如DataFrame等,适合用于数据处理的场景。"
"在内存有限的情况下,如果要缓存大型数据集,"
"尽量使用st.cache_data,并注意数据的大小和复杂性。"
)
data = load_data()
st.write(data)


def cache_resource():
st.title("缓存资源")

# cache_resource:缓存一个可调用对象(通常代表外部资源)
# 例如:数据库连接、文件句柄或其他需要初始化和销毁的对象
@st.cache_resource
def load_model():
# 模拟一个耗时的模型加载过程
time.sleep(2)

# 实际情况中,这里是要加载的模型对象
model = "Loaded Machine Learning Model"
return model

st.write(
"st.cache_resource:主要用于缓存资源,"
"例如模型、数据库连接等,适合于资源初始化的场景。"
"对于不经常变动的资源,如模型,"
"使用st.cache_resource可以有效减少资源的重复初始化,"
"提高处理速度,同时也减少内存消耗。"
)
model = load_model()
st.write(model)


def main():
if runtime.exists():
cache_data()
cache_resource()
else:
sys.argv = ["streamlit", "run", sys.argv[0]]
sys.exit(stcli.main())


if __name__ == "__main__":
main()

5-4 接口内嵌

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import sys
import streamlit as st
from streamlit import runtime
from streamlit.web import cli as stcli
import streamlit.components.v1 as components


def interface_embed():
st.title("接口内嵌")

# 预留了st.components.v1.html接口,可解析html数据
# B站视频的分享按钮,有个“嵌入代码”,点击即可获取
components.html(
"""
<iframe src="//player.bilibili.com/player.html?
isOutside=true&aid=114051866689921&bvid=BV1pRAUe3Ewz
&cid=28540404046&p=1" scrolling="no" border="0"
frameborder="no" framespacing="0" allowfullscreen="true"
style="width:70%; height:60vh;"></iframe>
""",
# 在HTML标签内联样式中动态调整
# width:70%:设置视频宽度为父容器宽度的70%
# height:60vh:设置高度为浏览器可视区域(视窗)高度的60%

# 直接在components.html中设置尺寸参数,这里设置没效果
height=600, width=1000
)


def main():
if runtime.exists():
interface_embed()
else:
sys.argv = ["streamlit", "run", sys.argv[0]]
sys.exit(stcli.main())


if __name__ == "__main__":
main()

6 流程控制

  • 流程控制
    • st.stop():代码运行到st.stop()时停止,类似于debug中的断点。
    • st.form():表单,自带提交按钮,其他按钮则不能添加到表单内部。
    • st.form_submit_button():主要作用于st.form()函数,提交表单。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import sys
import streamlit as st
from streamlit import runtime
from streamlit.web import cli as stcli


def process_control():
st.title("流程控制(st.stop)")

verification_code = "12345"
user_code = st.text_input(
# 自定义的多个函数都会使用到st.text_input()进行验证码等输入
# 需添加key唯一标识符,否则报错StreamlitDuplicateElementId
"请输入验证码:", key="verification_control"
)

if user_code != verification_code:
st.error("验证码错误,请重试!")

# 让Streamlit应用停止而不向下执行
# 若验证通过后,再向下运行展示后续内容
st.stop()

st.success("验证码正确,继续显示内容!")
st.write("这里显示验证码通过后的内容...")


def form_submit():
st.title("表单提交(st.form)")

with st.form("form_submit"):
username = st.text_input("用户名:", key="username_form")
password = st.text_input(
"密码:", type="password", key="password_form"
)
submitted = st.form_submit_button("登录")

if submitted:
if username == "admin" and password == "12345":
st.success("登录成功!")
elif username != "admin":
st.error("用户名错误!")
elif password != "12345":
st.error("密码错误!")


def advanced_form():
st.title("综合应用(st.form_submit_button)")

# 验证码
verification_code = "12345"
user_code = st.text_input("请输入验证码:")

if user_code != verification_code:
st.error("验证码错误,请重试!")
st.stop()

st.success("验证码正确,继续显示内容!")

# 表单
with st.form("advanced_form"):
name = st.text_input("姓名:", key="name_advanced")
email = st.text_input("邮箱:", key="email_advanced")
age = st.number_input(
"年龄:", min_value=0, max_value=120,
value=25, key="age_advanced"
)

# form_submit_button:在form中使用,提交表单
submit_advanced = st.form_submit_button("提交")

if submit_advanced:
if name and email:
st.success("表单提交成功!")
st.write(f"姓名:{name}")
st.write(f"邮箱:{email}")
st.write(f"年龄:{age}")
else:
st.error("请填写姓名和邮箱!")


def main():
if runtime.exists():
process_control()
form_submit()
advanced_form()
else:
sys.argv = ["streamlit", "run", sys.argv[0]]
sys.exit(stcli.main())


if __name__ == "__main__":
main()

7 页面布局

  • 页面布局
    • Streamlit是自上而下渲染的,组件在页面的排列顺序与代码的执行顺序一致。
    • 除上下单栏式的简单页面布局,Streamlit还提供了其他多种多样的页面布局。
    • 例如:选项卡、侧边栏、并排多列、展开或折叠、插入多元素、插入单元素。

7-1 选项卡

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import sys
import numpy as np
import streamlit as st
from streamlit import runtime
from streamlit.web import cli as stcli


def layout_tab():
st.title("选项卡")
tab1, tab2, tab3, tab4, tab5, tab6 = st.tabs(
["猫咪", "小狗", "花花", "多列", "图表", "数据"]
)
data = np.random.randn(7, 1)
with tab1:
st.subheader("猫咪")
st.image(
"https://bpic.51yuansu.com/pic3/cover/04/05/60"
"/65905f9af41ee_800.jpg?x-oss-process=image"
"/resize,h_360,m_lfit/sharpen,100", width=360
)
with tab2:
st.subheader("小狗")
st.image(
"https://bpic.51yuansu.com/pic3/cover/02"
"/26/79/59bfa2ea69707_610.jpg", width=360
)
with tab3:
st.subheader("花花")
st.image(
"https://img0.baidu.com/it/u=2308563798,591107067&fm"
"=253&fmt=auto&app=120&f=JPEG?w=400&h=400", width=360
)
with tab4:
st.subheader("多列")
col1, col2, col3, col4 = st.columns(4)
col1.header("col1")
col2.header("col2")
col3.header("col3")
col4.header("col4")
with tab5:
tab5.subheader("图表选项卡")
tab5.line_chart(data)
with tab6:
tab6.subheader("数据选项卡")
tab6.write(data)


def main():
if runtime.exists():
layout_tab()
else:
sys.argv = ["streamlit", "run", sys.argv[0]]
sys.exit(stcli.main())


if __name__ == "__main__":
main()

7-2 侧边栏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import sys
import streamlit as st
from streamlit import runtime
from streamlit.web import cli as stcli


def layout_sidebar():
st.title("侧边栏")
st.markdown(
"""
Streamlit is an open-source app framework.
It is built specifically for Machine Learning and Data Science projects.
**👈 Select a demo from the sidebar**
to see some examples of what Streamlit can do!
### Want to learn more?
- Check out [streamlit.io](https://streamlit.io)
- Jump into our [documentation](https://docs.streamlit.io)
- Ask a question in our [community
forums](https://discuss.streamlit.io)
"""
)
st.write("👈 效果展示看左侧栏!")

# 使用对象表示法添加选择框
st.sidebar.selectbox(
"您希望如何联系您?",
("电子邮件", "家庭电话", "移动电话", "添加微信")
)

# 使用with语法添加单选按钮
with st.sidebar:
st.radio(
"选择一种运输方式:",
(
"邮政", "顺丰", "中通", "申通",
"圆通", "韵达", "德邦", "百世"
)
)


def main():
if runtime.exists():
layout_sidebar()
else:
sys.argv = ["streamlit", "run", sys.argv[0]]
sys.exit(stcli.main())


if __name__ == "__main__":
main()

7-3 并排多列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import sys
import numpy as np
import streamlit as st
from streamlit import runtime
from streamlit.web import cli as stcli


def layout_column():
st.title("并列显示")
col1, col2, col3 = st.columns(3)

with col1:
st.subheader("猫咪")
st.image(
"https://bpic.51yuansu.com/pic3/cover/04/05/60"
"/65905f9af41ee_800.jpg?x-oss-process=image"
"/resize,h_360,m_lfit/sharpen,100", width=200
)
with col2:
st.subheader("小狗")
st.image(
"https://bpic.51yuansu.com/pic3/cover/02"
"/26/79/59bfa2ea69707_610.jpg", width=200
)
with col3:
st.subheader("花花")
st.image(
"https://img0.baidu.com/it/u=2308563798,591107067&fm"
"=253&fmt=auto&app=120&f=JPEG?w=400&h=400", width=200
)


def layout_percent_column():
st.title("按百分比设置列大小")
col1, col2 = st.columns([3, 1])
data = np.random.randn(7, 1)

col1.subheader("图表宽容器")
col1.line_chart(data)

col2.subheader("数据窄容器")
col2.write(data)


def main():
if runtime.exists():
layout_column()
layout_percent_column()
else:
sys.argv = ["streamlit", "run", sys.argv[0]]
sys.exit(stcli.main())


if __name__ == "__main__":
main()

7-4 展开或折叠

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import sys
import streamlit as st
from streamlit import runtime
from streamlit.web import cli as stcli


def layout_expand():
st.title("展开或折叠")
st.bar_chart(
{"data": [1, 5, 2, 6, 2, 1, 5, 3, 2, 1]}
)

# 初始状态为折叠状态,不支持将expander()嵌套在另一个expander()内
with st.expander("查看说明"):
st.write(
"""
Streamlit is an open-source app framework.
It is built specifically for Machine Learning and Data Science projects.
**👈 Select a demo from the sidebar**
to see some examples of what Streamlit can do!
"""
)
st.image(
"https://t7.baidu.com/it/u=707159321,3778666071&fm=193"
)


def main():
if runtime.exists():
layout_expand()
else:
sys.argv = ["streamlit", "run", sys.argv[0]]
sys.exit(stcli.main())


if __name__ == "__main__":
main()

7-5 插入多元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import sys
import numpy as np
import streamlit as st
from streamlit import runtime
from streamlit.web import cli as stcli


def insert_multiple():
st.title("插入多元素")
with st.container():
st.subheader("容器内内容")

# 调用Streamlit命令
st.bar_chart(np.random.randn(50, 3))
st.subheader("容器外内容")


def insert_random():
st.title("容器内外元素无序")
container = st.container(border=True)
container.write("容器内容A")
container.write("容器内容B")
st.write("容器外内容")

# 再插入一个容器内元素,与容器外插入的元素无序
container.write("容器内容C")


def main():
if runtime.exists():
insert_multiple()
insert_random()
else:
sys.argv = ["streamlit", "run", sys.argv[0]]
sys.exit(stcli.main())


if __name__ == "__main__":
main()

7-6 插入单元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import sys
import time
import streamlit as st
from streamlit import runtime
from streamlit.web import cli as stcli


def insert_single():
st.title("动态插入单元素")
with st.empty():
for seconds in range(3):
st.write(f"⏳ 已过去 {seconds} 秒")
time.sleep(1)
st.write("✔️ 3 秒结束!")


def replace_clear():
st.title("元素替换并清除")
placeholder = st.empty()
placeholder.text("Hi~")
time.sleep(3)

# 替换text文本内容为line_chart图表
placeholder.line_chart({"data": [1, 5, 2, 6]})
time.sleep(3)

# 等待3秒再替换图表为文本内容
with placeholder.container():
st.write("This is one element.")

# 清除所有元素
placeholder.empty()


def main():
if runtime.exists():
insert_single()
replace_clear()
else:
sys.argv = ["streamlit", "run", sys.argv[0]]
sys.exit(stcli.main())


if __name__ == "__main__":
main()

Python Streamlit
https://stitch-top.github.io/2025/03/03/python/python17-python-streamlit/
作者
Dr.626
发布于
2025年3月3日 22:35:00
许可协议