【Streamlit】初体验

初体验

官网很好看:传送门

快速安装: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补充 这篇博文写得挺详细

posted @ 2021-07-13 16:38  喜庆97  阅读(2017)  评论(0编辑  收藏  举报