背景

最近组内用 Flask+前端 开发了个基于 web 的图片评分筛选可视化工具,用于 AI NVR 项目的人脸图片分类。

虽然我没有参与 AI NVR 的项目,但是对此类 web 应用比较感兴趣,本身最近也想学一下 Python 后端开发,又由于初版的工具功能还不完善,需要添加很多功能,所以想着优化一下。

本来打算是用最近比较火的 FastAPI 写的,跟 Flask 差不多,很多地方可以复用,但是上手之后开始写前端的时候,就在 html 和 js 上遇到了层层阻碍。毕竟没有系统地学过前端,每遇到一个问题都要网上查半天,效率实在低。

突然想起来以前折腾可视化时候遇到的一个工具:Stremlit,于是重新翻出来研究了一下,发现还是比较好用的,写篇博客记录一下。

Streamlit 简介

Stremlit 是一个开源的 Python 库,提供简便的 API 接口,可以快速构建界面美观、交互友好的 web 应用程序,比较常用于结果演示、信息数据可视化等领域。

安装

依赖 Python 3.6 - Python 3.8

pip intsall stremlit

运行

不同于一般 Python 脚本的运行,streamlit 运行需要使用以下命令:

stremlit run [filename].py

默认使用 8501 端口,运行后会自动打开浏览器访问http://localhost:8501

基本使用

前面提到 streamlit 的一大特点就是方便快捷(不用写前端),下面就介绍一下怎么用几行 Python 代码就在网页上添加各种元素。

各个函数对应的功能不多赘述,直接看效果即可。

文本显示

import streamlit as st

st.text('Fixed width text')
st.markdown('_Markdown_') # see *
st.latex(r''' e^{i\pi} + 1 = 0 ''')
st.write('Most objects') # df, err, func, keras!
st.write(['st', 'is <', 3]) # see *
st.title('My title')
st.header('My header')
st.subheader('My sub')
st.code('for i in range(8): foo()')

数据显示

import streamlit as st
import pandas as pd

my_dataframe = pd.DataFrame({
    "1": {"A": 1, "B": 2},
    "2": {"A": 11, "B": 22},
    "3": {"A": 'a', "B": 'b'}
})
st.dataframe(my_dataframe)
st.table(my_dataframe.iloc[0:1])
st.json({'foo': 'bar', 'fu': 'ba'})

交互控件

import streamlit as st

st.button('Hit me')
st.checkbox('Check me out')
st.radio('Radio', [1,2,3])
st.selectbox('Select', [1,2,3])
st.multiselect('Multiselect', [1,2,3])
st.slider('Slide me', min_value=0, max_value=10)
st.select_slider('Slide to select', options=[1,'2'])
st.text_input('Enter some text')
st.number_input('Enter a number')
st.text_area('Area for textual entry')
st.date_input('Date input')
st.time_input('Time entry')
st.file_uploader('File uploader')
st.color_picker('Pick a color')

状态和进度

import streamlit as st
import time

st.progress(50)
st.spinner()
with st.spinner(text='In progress'):
    time.sleep(5)
    st.success('Done')
st.balloons()
st.error('Error message')
st.warning('Warning message')
st.info('Info message')
st.success('Success message')
st.exception('Error')

图表

streamlit 本身支持的图表类型较少,仅有线形图、面积图、柱状图,且不支持坐标轴、标题自定义等功能。

但是,stremlit 支持嵌入很多功能丰富的第三方图表,包括 matplotlib、altair、seaborn 等,能够满足各类图表的绘制需求。

st.line_chart(data)
st.area_chart(data)
st.bar_chart(data)
st.pyplot(fig)
st.altair_chart(data)
st.vega_lite_chart(data)
st.plotly_chart(data)
st.bokeh_chart(data)
st.pydeck_chart(data)
st.deck_gl_chart(data)
st.graphviz_chart(data)
st.map(data)

仅展示了streamlit自带的基本图表

视频/音频/图片

st.image('test.png')
st.audio('test.mp3')
st.video('test.mp4')

布局管理

import streamlit as st

with st.beta_container():
    st.write('123')

cols = st.beta_columns(3)
with cols[0]:
    st.write('First col')
with cols[1]:
    st.write('Second col')
with cols[2]:
    st.write('Third col')

with st.beta_expander("展开"):
    st.write("展开的信息")

侧边栏

st.sidebar()将定义一个侧边栏,可以在侧边栏中添加各类控件

其他

streamlit 还支持页面主题自定义、应用发布、页面录制等功能,可自行探索使用。

贴一下 cheatsheet(这个 cheatsheet 也是用 streamlit 实现的)

实际应用

花了一段时间,写了一个图片分类的工具

  • 左侧使用侧边栏,slider控件用于设置各类筛选条件的范围,radio控件用于设置排序条件,button控件用于导出筛选后的图片,number_input控件用于对图片进行主观评分。

  • 中间显示当前的筛选条件,排序条件,筛选的图片结果,图片按照指定的列宽度布局,下方显示该图片的信息。

  • 最后还对各类图片参数的分布进行了统计,绘制了直方图。

  • 后台的筛选排序逻辑用 Pandas.dataFrame 实现,不多介绍。

虽然页面看上去还行,功能也基本可用,但性能实在是有点拉胯,2000张图片基本上要等待 10 秒左右才能完全加载出来,且由于每次修改筛选或排序条件,页面都要重新进行加载,所以使用起来体验还是很差,对于该需求来说,实用性不强。

性能瓶颈应该还是在大量图片的加载和显示,实测如果不显示图片能够做到页面秒响应。

总结

Streamlit 作为一个 Python Web 开发工具,优缺点都很明显

优点:

  • 上手简单,开发容易,不用写前端
  • 界面美观,功能较丰富

缺点:

  • 相比一般的后端开发框架,性能较差
  • 由于不能自己写前端,有一定的局限性

这次用 Streamlit 开发的图片分类工具使用体验不太能够接受,可能还是要考虑用其他工具开发,但 Steamlit 本身算是非常好用的工具了。

后续工作中如果有其他需求,适合用 Streamlit 进行开发的,再进行考虑吧。

参考

  • https://github.com/stremlit
  • https://docs.streamlit.io
  • https://streamlit.io/gallery