初体验
官网很好看:传送门
快速安装:conda install -c conda-forge streamlit
后续可以在此环境下直接输入一个:streamlit hello
便会自动跳转一个本地网页:http://localhost:8501/
,有些像Jupyter:

然后自动跳转浏览器,有几个自带的Demo可以感受一下:

关闭进程只需要在终端输入Ctrl+C
即可。
可以把官网Demo复制到本地,在文件夹路径下开启终端,通过输入streamlit run test1.py
运行:
import streamlit as st
import time
import numpy as np
st.title('My first app~')
chart_data = pd.DataFrame(
np.random.randn(20, 3),
columns=['a', 'b', 'c'])
st.line_chart(chart_data)
st.button("Re-run")
如果有报错:AttributeError: module 'google.protobuf.descriptor' has no attribute '_internal_create_key'
进行:pip install --upgrade protobuf
入门操作
参考这个 Getting started.
跟着上面入门教程添加内容。页面上会根据每添加一个内容项在下面叠加一个模块。
当然,直接往下无脑叠加代码在下拉选框部分报错了!!!需要注意的是下面两个似乎不可同时使用:
# 叠加形式的下拉选框
# option = st.selectbox(
# 'Which number do you like best?',
# df['first column'])
# 'You selected: ', option
# 将下拉选框移动至左侧
option = st.sidebar.selectbox(
'Which number do you like best?',
df['first column'])
'You selected:', option
跟到现在的呈现形式:

这里Doc里面有句Most of the elements you can put into your app can also be put into a sidebar using this syntax: st.sidebar.[element_name]()
,说的是任何加入app(即是页面主体部分的内容)都可放入sidebar部分,只是将调用的模块前面添加.sidebar
即可。
水平布局:使用st.beta_columns(N)
设置app的同行左右依次相依,将这一行切分为N列:
left_column, right_column = st.beta_columns(2)
pressed = left_column.button('Press me?') # 左侧放置button按键
if pressed:
right_column.write("Woohoo!") # 若是按键点击,右侧出现文字
可折叠文本:beta_expander()
模块
expander = st.beta_expander("FAQ")
expander.write("Here you could put in some really, really long explanations...")
得到:

时间进度条:st.progress()
模块
# 添加一个占位 placeholder
latest_iteration = st.empty()
bar = st.progress(0)
for i in range(100):
# Update the progress bar with each iteration.
latest_iteration.text(f'Iteration {i+1}')
bar.progress(i + 1)
time.sleep(0.1)
至此,官网入门部分指引完毕。
基本功能
进入CookBook部分。
import streamlit as st
import pandas as pd
import numpy as np
st.title('My Second App~')
DATE_COLUMN = 'date/time'
DATA_URL = ('https://s3-us-west-2.amazonaws.com/streamlit-demo-data/uber-raw-data-sep14.csv.gz')
# Streamlit默认每次改动都会重新加载文件,加上此cache装饰器后可以让其在第一次时缓存,后续加载与本地缓存对比检测是否有变动
# cache是会进行代码遍历,检测套上该装饰器的函数的参数&函数体&嵌套子函数的所有与此函数相关的变化
# cache是累计式缓存,比如给某参数x用slider指定返回,每执行一次都会被记录一次值!
@st.cache
def load_data(nrows):
data = pd.read_csv(DATA_URL, nrows=nrows)
lowercase = lambda x: str(x).lower()
data.rename(lowercase, axis='columns', inplace=True)
data[DATE_COLUMN] = pd.to_datetime(data[DATE_COLUMN])
return data
data_load_state = st.text('Loading data...')
data = load_data(10000)
# data_load_state.text('Loading data...done!') # 只需要申明一次
data_load_state.text("Done! (using st.cache)")
# 是否展示数据
if st.checkbox('Show raw data'):
st.subheader('Raw data')
st.write(data)
hist_values = np.histogram(data[DATE_COLUMN].dt.hour, bins=24, range=(0,24))[0] # 将时间按照2小时绘制频率图
st.subheader('Time hisChart')
st.bar_chart(hist_values)
# Slider组件
hour_to_filter = st.sidebar.slider('hour', 0, 23, 17) # 此时并未关联某个模块
st.subheader('Map with Slider')
st.map(data[data[DATE_COLUMN].dt.hour == hour_to_filter])
得到:

Ps: map方法需要有字段列名为lon、lat或全称形式。
后续几个篇章值得注意的是:这个模块可以和前端语法Html+JS等自定义组件搭配使用(网不好 看不到...)。
至此,tutorial部分完结。
再谈cache
import streamlit as st
import time
@st.cache(suppress_st_warning=True)
def expensive_computation(a, b):
st.write("Cache miss: expensive_computation(", a, ",", b, ") ran")
time.sleep(2) # This makes the function take 2s to run
return {"output": a * b} # 👈 Mutable object
a = 2
b = 21
res = expensive_computation(a, b)
st.write("Result:", res)
res["output"] = "result was manually mutated" # 👈 Mutated cached value
st.write("Mutated result:", res)
这个部分首次运行没啥问题,一眼看出结果,如果rerun一次便会报错,因为Streamlit的缓存机制限制,Doc里有个caching_issues话题,推荐使用import copy
方法deepcopy一个出来。
然后若是清理缓存,终端下输入:streamlit cache clear
即可。
Session属性
由于每次交互操作都会导致StreamLit都会重运行,那如何维持会话状态呢?比如我想尝试一下每次点击累加,但rerun就会让程序每次都是在初始值的基础上变化。。。
这个用起来还有生疏,而且暂时没具体应用场景。先不做进一步记录。
import streamlit as st
st.title('Counter Example using Callbacks')
if 'count' not in st.session_state:
st.session_state.count = 0 # 或st.session_state['count']
def increment_counter():
st.session_state.count += 1
st.button('Increment', on_click=increment_counter)
st.write('Count = ', st.session_state.count)
最后,贴一张官网介绍Streamlit的模型逻辑图:

真的很喜欢这款产品,交互设计很赞👍
页面布局
通常情况下,Streamlit默认居中展示,感觉比例是30%-40%-30%分布,所以若是不添加一些Widgets组件的情况下会显得两边很空。
方法一:右上角Setting

这一操作等同于:st.set_page_config(layout="wide")
但是这样设置后得到的又太宽了...
方法二:通过Markdown语法配置
st.markdown(
f"""
<style>
.reportview-container .main .block-container{{
max-width: {1800}px;
padding-top: {10}rem;
padding-right: {10}rem;
padding-left: {10}rem;
padding-bottom: {10}rem;
}}
.reportview-container .main {{
color: white;
background-color: black;
}}
</style>
"""
,unsafe_allow_html=True,
)
方法三:通过st.beta_container
等方式进行布局
严格意义上来讲,这个并不是进行区域扩展的方法,只是将默认区域再分块,类似于前端HTML中的div用法。
import streamlit as st
from string import ascii_uppercase, digits
from random import choices
st.header('Test Layout')
img_base = "https://www.htmlcsscolor.com/preview/128x128/{0}.png"
colors = (''.join(choices(ascii_uppercase[:6] + digits, k=6)) for _ in range(100))
with st.beta_container():
left_col, right_col = st.beta_columns(2)
left_col.image(img_base.format('D32166'), use_column_width=True) # 若是不进行配置,间距大会比较丑
right_col.write('placeholder')
with st.beta_container():
for col in st.beta_columns(3):
col.image(img_base.format(next(colors)), use_column_width=True)
with st.beta_container():
for col in st.beta_columns(9):
col.image(img_base.format(next(colors)), use_column_width=True)
得到:

可以看到各个container还是垂直布局,只是在不同的container中,水平分开了好几个。
Ace Editor
可以在页面内同步进行编辑的插件,可以看下参考资源5,挺好玩(但是网路不行时候加载不全...)
import streamlit as st
from streamlit_ace import st_ace
st.set_page_config(layout="wide")
st.header('Test Layout')
def main():
with st.beta_container():
left_col, right_col = st.beta_columns(2)
with right_col:
content = st_ace(language='python', key="ace")
with left_col:
st.write(content)
# st.write([*streamlit_ace.LANGUAGES])
if __name__ == "__main__":
main()
一个初步的带编辑器的界面,但是似乎配置编译器语言未成功:

其实还不如配合VS Code来得好,花里胡哨的,下回再看...
2021.7.15 填坑待续...
参考资源
1.Welcome to Streamlit Doc -- 跟着这个上往下走就行,有问题查查API部分
2.discuss 社区 -- 网不好进不去
3.New layout options for Streamlit
4.Lay your app
5.Streamlit-ace插件 -- 官方Demo
6.Streamlit:快速数据可视化界面工具:2021.9.15补充 这篇博文写得挺详细