Streamlit 快速构建交互式页面的python库
基礎(chǔ)介紹
streamlit 是什么
Streamlit是一個(gè)面向機(jī)器學(xué)習(xí)和數(shù)據(jù)科學(xué)團(tuán)隊(duì)的開(kāi)源應(yīng)用程序框架,通過(guò)它可以用python代碼方便快捷的構(gòu)建交互式前端頁(yè)面。streamlit特別適合結(jié)合大模型快速的構(gòu)建一些對(duì)話式的應(yīng)用,可以看到一些行業(yè)內(nèi)熱門(mén)的使用。
項(xiàng)目本身也比較成熟,release版本,start數(shù)量等都表明該項(xiàng)目持續(xù)打磨了很長(zhǎng)時(shí)間。
streamlit 簡(jiǎn)單示例
import streamlit as st
import numpy as np
import matplotlib.pyplot as plt
st.title('Sin')
# Get user input for frequency and amplitude
freq = st.slider('頻率', min_value=1, max_value=10, value=1)
# Create x values
x = np.linspace(0, 2*np.pi, 1000)
# Create y values
y = np.sin(freq * x)
# Plot the graph
fig, ax = plt.subplots()
ax.plot(x, y)
ax.set_title('Sine Wave')
ax.set_xlabel('X')
ax.set_ylabel('Y')
st.pyplot(fig)
運(yùn)行代碼
streanlit run sample_demo.py
streamlit 優(yōu)缺點(diǎn)
streamlit優(yōu)點(diǎn):
- 不需要掌握前端知識(shí)就能創(chuàng)建web頁(yè)面
 - 內(nèi)置很多機(jī)器學(xué)習(xí)交互的展示組件,更有利于算法工程師使用
 - 開(kāi)發(fā)速度快,修改方便
streamlit缺點(diǎn): - 前端界面固定,開(kāi)發(fā)者不能隨意調(diào)整控件位置
 - 只適合于少量頁(yè)面的項(xiàng)目,不適用于復(fù)雜網(wǎng)頁(yè)的網(wǎng)站前端
 
組件集合
streamlit 主要用于構(gòu)建前端頁(yè)面,有著豐富的前端組件。 streamlit 官方文檔:??https://docs.streamlit.io/library/get-started/main-concepts??
從官方文檔來(lái)看,主要的組件包括:
- 文本
 - 數(shù)據(jù)表格
 - 圖表
 - 輸入組件
 - 媒體組件
 - 布局和容器
 - 聊天框
 - 狀態(tài)展示
 - 控制流程
 
下面將常見(jiàn)的組件拿出來(lái),做一個(gè)集合。stremlit的一個(gè)頁(yè)面叫做一個(gè)app,可以將多個(gè)頁(yè)面組裝起來(lái),如下圖:
文字
數(shù)據(jù)表格
輸入組件
聊天
js和html 渲染
上文中已經(jīng)提到streamlit的組件排列方式是從上到下逐個(gè)渲染,無(wú)法做到html那樣靈活的調(diào)整組件的位置。但是stream還是提供了兩個(gè)函數(shù)可以支持對(duì)頁(yè)面css和js的修改。
對(duì)css的修改
streamlit中按鈕是沒(méi)有背景顏色的,如果想增加按鈕的底色,就可以對(duì)其css修改。如下:
import streamlit as st
st.button("點(diǎn)擊我")
hide_streamlit_style = """
       <style>
       .ef3psqc11 {background-color: yellowgreen}
       </style>
       """
st.markdown(hide_streamlit_style, unsafe_allow_html=True)
通過(guò)類名找到對(duì)應(yīng)的按鈕,然后準(zhǔn)備好css代碼,最后使用st.markdown函數(shù)將css渲染到頁(yè)面上。
這時(shí)就可以通過(guò)css 隱藏屬性來(lái)完成。根據(jù)按鈕的id找到按鈕,隱藏該組件。
hide_streamlit_style = """
        <style>
        #MainMenu {visibility: hidden;}
        footer {visibility: hidden;}
        </style>
        """
st.markdown(hide_streamlit_style, unsafe_allow_html=True)
插入js
除了可以插入css之后,streamlit也支持插入js代碼,這個(gè)功能就賦予streamlit操作html頁(yè)面的能力。上面修改按鈕顏色的需求通過(guò)js也能實(shí)現(xiàn)。首先通過(guò)js找到按鈕,然后對(duì)元素的屬性賦值。
import streamlit as st
import streamlit.components.v1 as components
st.button("點(diǎn)擊我")
# hide_streamlit_style = """
#        <style>
#        .ef3psqc11 {background-color: yellowgreen}
#        </style>
#        """
# st.markdown(hide_streamlit_style, unsafe_allow_html=True)
js_btn = '''window.parent.document.getElementsByClassName("ef3psqc11")[0].style.backgroundColor = "bisque"'''
components.html(f'''<script>{js_btn}</script>''', width=0, height=0)
修改js使用的是import streamlit.components.v1 as components,和普通js不同的是需要在js前面加上window.parent,否則不能生效。
除了支持原生js之后,也支持jquery庫(kù)。
組件工作原理
使用streamlit構(gòu)建的頁(yè)面和html構(gòu)建的頁(yè)面在工作方式上有很大的不同,streamlit有自己的一套工作機(jī)制,具體來(lái)說(shuō)有如下兩點(diǎn)注意:
- streamlit 根據(jù)組件在代碼的位置,從上至下渲染組件
 - 點(diǎn)擊或觸發(fā)某一個(gè)控件之后,代碼會(huì)從上至下執(zhí)行一遍
 
會(huì)話狀態(tài)
在前文中提到streamlit中觸發(fā)一個(gè)按鈕會(huì)重新執(zhí)行整個(gè)文件,相當(dāng)于整個(gè)代碼重新執(zhí)行一遍,這樣帶來(lái)的一個(gè)副作用就是前后兩次操作不能互相傳遞數(shù)據(jù)。比如下圖中想要實(shí)現(xiàn)點(diǎn)擊確定按鈕,將輸入的內(nèi)容展示在最上面。
這個(gè)簡(jiǎn)單的需求反而不好實(shí)現(xiàn),因?yàn)辄c(diǎn)擊確定按鈕之后,整個(gè)程序重新執(zhí)行,輸入的用戶名和密碼已經(jīng)是上一次頁(yè)面的數(shù)據(jù),無(wú)法傳遞到下一次頁(yè)面渲染中。這時(shí)就需要會(huì)話狀態(tài)來(lái)解決這個(gè)問(wèn)題了。
首先解釋一下streamlit中的會(huì)話。在streamlit中一個(gè)tab頁(yè)表示一個(gè)會(huì)話,新開(kāi)tab頁(yè)或者刷新頁(yè)面都代表會(huì)話失效。會(huì)話機(jī)制提供了一種能力:在會(huì)話中,也就是一個(gè)tab中存在一個(gè)全局對(duì)象,支持插入、更新、刪除數(shù)據(jù),該對(duì)象在會(huì)話任何時(shí)機(jī)都可以使用。會(huì)話機(jī)制可以有效解決頁(yè)面渲染前后帶來(lái)的數(shù)據(jù)傳遞問(wèn)題。
下面看看通過(guò)會(huì)話機(jī)制如何解決數(shù)據(jù)傳遞
import streamlit as st
msg = ""
if "name" in st.session_state:
    msg = {"name": st.session_state.name, "passwd": st.session_state.passwd}
st.write(f"輸入的內(nèi)容是:{msg}")
name = st.text_input(label="用戶名:")
passwd = st.text_input(label="密碼:")
submit = st.button("確定")
if submit:
    st.session_state["name"] = name
    st.session_state["passwd"] = passwd
streamlit run text_input.py 
st.session_state 就是會(huì)話機(jī)制的全局變量,在按鈕點(diǎn)擊之后向st.session_state中更新數(shù)據(jù),當(dāng)新一輪循環(huán)開(kāi)始時(shí)判斷st.session_state中是否有name屬性,如果存在name數(shù)據(jù)表明會(huì)話中有數(shù)據(jù),讀取數(shù)據(jù)展示出來(lái)。
st.session_state支持即支持字典的數(shù)據(jù)管理方式,也支持屬性的管理方式。也就是說(shuō)獲取一個(gè)數(shù)據(jù),st.session_state["data"] 和  st.session_state.data都是支持的
避坑指南
在實(shí)際使用streamlit中也有到一些讓人困惑的事情,下面列舉出來(lái)避免有人同樣踩坑。
不同按鈕的監(jiān)聽(tīng)方式會(huì)影響組件渲染順序
按鈕有兩種監(jiān)聽(tīng)方式,分別是監(jiān)聽(tīng)按鈕變量和綁定回調(diào)函數(shù)
# 按鈕監(jiān)聽(tīng)方法1
submit = st.button()
if submit:
    pass 
# 按鈕監(jiān)聽(tīng)方法2
submit = st.button(on_click=handler_click)
這兩種監(jiān)聽(tīng)方式有不同的組件渲染順序。具體來(lái)說(shuō)是:
- 使用監(jiān)聽(tīng)按鈕方式,點(diǎn)擊按鈕之后程序重新執(zhí)行所有代碼,執(zhí)行到按鈕時(shí)進(jìn)入監(jiān)聽(tīng)代碼片段
 - 使用回調(diào)函數(shù),點(diǎn)擊按鈕之后先執(zhí)行回調(diào)函數(shù),再重新執(zhí)行所有代碼
 
如下獲取輸入框信息,就會(huì)發(fā)現(xiàn)獲取的是button出現(xiàn)時(shí)input輸入框的狀態(tài),而不是最新的狀態(tài)
import streamlit as st
def get_username_passwd(username, password):
    st.write("username:", username, "password:", password)
with st.form("登錄頁(yè)面"):
    username = st.text_input("用戶名")
    password = st.text_input("密碼")
    # 使用on_click的方法,獲取的是button出現(xiàn)時(shí)input輸入框的狀態(tài),而不是最新的狀態(tài)。逆天bug
    submitted = st.form_submit_button("登錄", on_click=get_username_passwd, args=(username, password))
元素沒(méi)有固定ID
在streamlit中生成的頁(yè)面沒(méi)有固定的class name 或 id。在不同環(huán)境下可能生成不一樣的class name。所以通過(guò)js或css修改頁(yè)面的方法往往不能通用,因?yàn)轭惷麜?huì)發(fā)生變化。
可靠的獲取元素的方法是使用 data-testid="stFormSubmitButton"中的 data_testid。
但是如果頁(yè)面中有多個(gè)相同屬性的 data-testid,那么這種方式也不可靠。
使用建議
來(lái)自三體人的吶喊:
不要在大型項(xiàng)目中使用!
不要在大型項(xiàng)目中使用!
不要在大型項(xiàng)目中使用!
streamlit調(diào)整布局是一件痛苦的事情。個(gè)人真實(shí)感受:如果說(shuō)做項(xiàng)目想蓋房子,做普通項(xiàng)目是用水泥磚頭蓋房子,用streamlit像是用積木蓋房子,感覺(jué)碰一下就倒了。
streamlit更適合用在功能單一,頁(yè)面較少,沒(méi)有頁(yè)面跳轉(zhuǎn)的項(xiàng)目上。各種封裝好的組件能夠快速實(shí)現(xiàn)一個(gè)最小可行性產(chǎn)品(MVP),避免算法工程師在前端頁(yè)面花費(fèi)太長(zhǎng)時(shí)間。
總結(jié)
以上是生活随笔為你收集整理的Streamlit 快速构建交互式页面的python库的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
                            
                        - 上一篇: 对普通人来说,基因测序对我们的健康保障到
 - 下一篇: 亚马逊雨林碳吸收能力到达临界值!产生碳的