2023年2月22日 星期三

Python 學習筆記 : 用 Streamlit 開發網頁應用程式 (一) 安裝套件

最近發現一個很棒的 Python 套件 Streamlit, 有別於傳統的 Flask 或 Django 等套件, Streamlit 只需要用 Python 就可以生成網頁, 完全不需要去管 HTML, CSS, Javascript, React 等前端技術, 對專注於學術研究者, 以及從事資料科學或機器學習專案的 Python 程式員來說真是一個福音, 就算沒有前端技術背景, 單純依靠 Python 也能端出美美的互動式網頁介面來呈現專案結果.  

Streamlit 簡介如下 :  
  • Streamlit 是一個開源的 Python 套件, 由 2018 年創立於舊金山的同名軟體公司所研發, 創辦人為 Adrien Treuille, Amanda Kelly, and Thiago Teixeira. 主要是為了解決資料科學家與機器學習專家在解釋與部署資料分析專案時所面對的網頁前後端技術挑戰, 讓他們只要使用 Python 即可解決互動式網頁 UI 需求, 可專注於資料驅動的應用專案本身而毋須分心於前後端網頁技術.
  • Streamlit 能與資料科學 & 機器學習常用套件 Numpy, Pandas, Matplotlib, Seaborn, Plotly, Scikit-learn, TensorFlow, PyTorch, ... 等串接整合, 所產出的網頁本身即具有互動 (interactive) 功能. 
  • Streamlit 主要是為了原型應用程式 (prototype application) 而開發, 使用者不需要具備前端網頁相關技術背景, 故可節省開發時間, 快速完成專案. 
  • Streamlit 提供 Streamlit Cloud 雲端平台 (https://streamlit.io/cloud) 可讓使用者佈署所開發的應用程式, 方便客戶線上體驗成果 (免費帳戶可發布三個應用程式). 
  • Streamlit 在前端使用了 React 技術 (與 Dash 一樣); 後端則是採用 Tornado 框架. 
參考官網 :


Streamlit 於 2019 年開放原始碼, 寄存於 GitHub :


參考書籍 : 
 
1. 安裝 Streamlit : 

使用 pip install 安裝 (目前是 1.17.0 版) : 

pip install streamlit

C:\Users\User>pip install streamlit   
Collecting streamlit
  Downloading streamlit-1.17.0-py2.py3-none-any.whl (9.3 MB)
     ---------------------------------------- 9.3/9.3 MB 2.4 MB/s eta 0:00:00
Requirement already satisfied: python-dateutil in c:\python37\lib\site-packages (from streamlit) (2.7.5)
Collecting pyarrow>=4.0
  Downloading pyarrow-11.0.0-cp37-cp37m-win_amd64.whl (20.6 MB)
     ---------------------------------------- 20.6/20.6 MB 5.0 MB/s eta 0:00:00
Requirement already satisfied: typing-extensions>=3.10.0.0 in c:\python37\lib\site-packages (from streamlit) (4.3.0)
Requirement already satisfied: cachetools>=4.0 in c:\python37\lib\site-packages (from streamlit) (4.1.1)
Collecting rich>=10.11.0
  Downloading rich-13.3.1-py3-none-any.whl (239 kB)
     ---------------------------------------- 239.0/239.0 kB 4.9 MB/s eta 0:00:00
Collecting blinker>=1.0.0
  Downloading blinker-1.5-py2.py3-none-any.whl (12 kB)
Requirement already satisfied: packaging>=14.1 in c:\python37\lib\site-packages (from streamlit) (20.7)
Requirement already satisfied: pandas>=0.21.0 in c:\python37\lib\site-packages (from streamlit) (1.2.5)
Requirement already satisfied: click>=7.0 in c:\python37\lib\site-packages (from streamlit) (8.1.3)
Requirement already satisfied: requests>=2.4 in c:\python37\lib\site-packages (from streamlit) (2.28.1)
Collecting toml
  Downloading toml-0.10.2-py2.py3-none-any.whl (16 kB)
Collecting watchdog
  Downloading watchdog-2.2.1-py3-none-win_amd64.whl (78 kB)
     ---------------------------------------- 79.0/79.0 kB 4.3 MB/s eta 0:00:00
Requirement already satisfied: numpy in c:\python37\lib\site-packages (from streamlit) (1.19.4)
Requirement already satisfied: importlib-metadata>=1.4 in c:\python37\lib\site-packages (from streamlit) (4.12.0)
Collecting pympler>=0.9
  Downloading Pympler-1.0.1-py3-none-any.whl (164 kB)
     ---------------------------------------- 164.8/164.8 kB 5.0 MB/s eta 0:00:00
Collecting semver
  Downloading semver-2.13.0-py2.py3-none-any.whl (12 kB)
Collecting gitpython!=3.1.19
  Downloading GitPython-3.1.30-py3-none-any.whl (184 kB)
     ---------------------------------------- 184.0/184.0 kB 3.8 MB/s eta 0:00:00
Requirement already satisfied: tornado>=5.0 in c:\python37\lib\site-packages (from streamlit) (6.0.4)
Collecting validators>=0.2
  Downloading validators-0.20.0.tar.gz (30 kB)
  Preparing metadata (setup.py) ... done
Requirement already satisfied: pillow>=6.2.0 in c:\python37\lib\site-packages (from streamlit) (8.1.0)
Requirement already satisfied: tzlocal>=1.1 in c:\python37\lib\site-packages (from streamlit) (2.0.0)
Collecting altair>=3.2.0
  Downloading altair-4.2.2-py3-none-any.whl (813 kB)
     ---------------------------------------- 813.6/813.6 kB 7.3 MB/s eta 0:00:00
Requirement already satisfied: protobuf<4,>=3.12 in c:\python37\lib\site-packages (from streamlit) (3.14.0)
Collecting pydeck>=0.1.dev5
  Downloading pydeck-0.8.0-py2.py3-none-any.whl (4.7 MB)
     ---------------------------------------- 4.7/4.7 MB 10.4 MB/s eta 0:00:00
Requirement already satisfied: jinja2 in c:\python37\lib\site-packages (from altair>=3.2.0->streamlit) (3.1.2)
Collecting toolz
  Downloading toolz-0.12.0-py3-none-any.whl (55 kB)
     ---------------------------------------- 55.8/55.8 kB ? eta 0:00:00
Requirement already satisfied: entrypoints in c:\python37\lib\site-packages (from altair>=3.2.0->streamlit) (0.3)
Requirement already satisfied: jsonschema>=3.0 in c:\python37\lib\site-packages (from altair>=3.2.0->streamlit) (3.2.0)
Requirement already satisfied: colorama in c:\python37\lib\site-packages (from click>=7.0->streamlit) (0.4.1)
Collecting gitdb<5,>=4.0.1
  Downloading gitdb-4.0.10-py3-none-any.whl (62 kB)
     ---------------------------------------- 62.7/62.7 kB 3.3 MB/s eta 0:00:00
Requirement already satisfied: zipp>=0.5 in c:\python37\lib\site-packages (from importlib-metadata>=1.4->streamlit) (3.1.0)
Requirement already satisfied: pyparsing>=2.0.2 in c:\python37\lib\site-packages (from packaging>=14.1->streamlit) (2.3.1)
Requirement already satisfied: pytz>=2017.3 in c:\python37\lib\site-packages (from pandas>=0.21.0->streamlit) (2018.9)
Requirement already satisfied: six>=1.9 in c:\python37\lib\site-packages (from protobuf<4,>=3.12->streamlit) (1.12.0)
Requirement already satisfied: certifi>=2017.4.17 in c:\python37\lib\site-packages (from requests>=2.4->streamlit) (2018.11.29)
Requirement already satisfied: charset-normalizer<3,>=2 in c:\python37\lib\site-packages (from requests>=2.4->streamlit) (2.1.1)
Requirement already satisfied: idna<4,>=2.5 in c:\python37\lib\site-packages (from requests>=2.4->streamlit) (2.8)
Requirement already satisfied: urllib3<1.27,>=1.21.1 in c:\python37\lib\site-packages (from requests>=2.4->streamlit) (1.24.1)
Requirement already satisfied: markdown-it-py<3.0.0,>=2.1.0 in c:\python37\lib\site-packages (from rich>=10.11.0->streamlit) (2.1.0)
Collecting pygments<3.0.0,>=2.14.0
  Downloading Pygments-2.14.0-py3-none-any.whl (1.1 MB)
     ---------------------------------------- 1.1/1.1 MB 10.1 MB/s eta 0:00:00
Requirement already satisfied: decorator>=3.4.0 in c:\python37\lib\site-packages (from validators>=0.2->streamlit) (4.3.2)
Collecting smmap<6,>=3.0.1
  Downloading smmap-5.0.0-py3-none-any.whl (24 kB)
Requirement already satisfied: MarkupSafe>=2.0 in c:\python37\lib\site-packages (from jinja2->altair>=3.2.0->streamlit) (2.1.1)
Requirement already satisfied: attrs>=17.4.0 in c:\python37\lib\site-packages (from jsonschema>=3.0->altair>=3.2.0->streamlit) (19.3.0)
Requirement already satisfied: pyrsistent>=0.14.0 in c:\python37\lib\site-packages (from jsonschema>=3.0->altair>=3.2.0->streamlit) (0.16.0)
Requirement already satisfied: setuptools in c:\python37\lib\site-packages (from jsonschema>=3.0->altair>=3.2.0->streamlit) (51.0.0)
Requirement already satisfied: mdurl~=0.1 in c:\python37\lib\site-packages (from markdown-it-py<3.0.0,>=2.1.0->rich>=10.11.0->streamlit) (0.1.2)
Building wheels for collected packages: validators
  Building wheel for validators (setup.py) ... done
  Created wheel for validators: filename=validators-0.20.0-py3-none-any.whl size=19567 sha256=59014cff92b0a382bbf5c7961643c276bca5c3d4a2de9df1d119090de8563028
  Stored in directory: c:\users\user\appdata\local\pip\cache\wheels\5f\55\ab\36a76989f7f88d9ca7b1f68da6d94252bb6a8d6ad4f18e04e9
Successfully built validators
Installing collected packages: watchdog, validators, toolz, toml, smmap, semver, pympler, pygments, pyarrow, blinker, rich, pydeck, gitdb, gitpython, altair, streamlit
  Attempting uninstall: pygments
    Found existing installation: Pygments 2.3.1
    Uninstalling Pygments-2.3.1:
      Successfully uninstalled Pygments-2.3.1
Successfully installed altair-4.2.2 blinker-1.5 gitdb-4.0.10 gitpython-3.1.30 pyarrow-11.0.0 pydeck-0.8.0 pygments-2.14.0 pympler-1.0.1 rich-13.3.1 semver-2.13.0 smmap-5.0.0 streamlit-1.17.0 toml-0.10.2 toolz-0.12.0 validators-0.20.0 watchdog-2.2.1

可見 Streamlit 本身其實才 10 MB 不到, 但依賴於許多其他 Python 套件 (例如依賴 Tornado 框架來建立後端環境). 

進入 Python IDLE 匯入 streamlit (通常取簡名 st) 後用 .__version__ 屬性檢查版本 :

D:\Python\test\streamlit>python  
Python 3.7.2 (tags/v3.7.2:9a3ffc0492, Dec 23 2018, 23:09:28) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import streamlit as st    
>>> st.__version__    
'1.17.0'   

注意, Streamlit 必須在 Python 3.7 以上環境才能運作. 


2. Streamlit 內建應用程式 hello 展示 : 

Streamlit 本身自帶了一個 hello 應用程式範例, 安裝完 Streamlit 后馬上就可以執行. 執行此內建 App 的方法是在命令列輸入 streamlit hello 即可 : 

C:\Users\User>streamlit hello   

  Welcome to Streamlit!

  If you’d like to receive helpful onboarding emails, news, offers, promotions,
  and the occasional swag, please enter your email address below. Otherwise,
  leave this field blank.

  Email:   (輸入郵件信箱或直接按 Enter)

  You can find our privacy policy at https://streamlit.io/privacy-policy

  Summary:
  - This open source library collects usage statistics.
  - We cannot see and do not store information contained inside Streamlit apps,
    such as text, charts, images, etc.
  - Telemetry data is stored in servers in the United States.
  - If you'd like to opt out, add the following to %userprofile%/.streamlit/config.toml,
    creating that file if necessary:

    [browser]
    gatherUsageStats = false


  Welcome to Streamlit. Check out our demo in your browser.

  Local URL: http://localhost:8501   
  Network URL: http://192.168.43.14:8501    

  Ready to create your own Python apps super quickly?
  Head over to https://docs.streamlit.io

  May you create awesome apps!

執行此應用程式后 Streamlit 會在用 Tornado 建立一個後端伺服器, 將應用程式放在預設埠 8501, 然後自動開啟瀏覽器頁籤來顯示此網頁 App :




Streamlit App 網頁分成左右兩邊, 左側邊框為 App 導覽 (可按 X 鈕隱藏); 右邊框用來顯示內容. 此 hello App 提供了四個展示頁面 (Animation/Plotting/Mapping/DataFrame ), 可點選左邊框的超連結啟動 : 







每個展示底下都有 Python 原始碼, 其長度都不長, 簡單幾行程式碼就能展現如此複雜頁面, 可見 Streamlit 確實能幫助資料科學與機器學習專案工程師快速展示原型成果, 不需要具備 HTML, CSS, Javascript, React, Flask 等網頁技術基礎. 

在命令列按 Ctrl + C 即可關閉伺服器停止執行 App. 


3. 撰寫自己的 Streamlit 應用程式 : 

撰寫 Streamlit App 首先需匯入此套件, 習慣上會取簡名 st :

import streamlit as st 

先來檢視 Streamlit 套件的成員內容, 以下使用一個自訂模組 members, 其 list_members() 函式會列出模組或套件中的公開成員 (即屬性與方法), 參考 :

Python 學習筆記 : 檢視物件成員與取得變數名稱字串的方法

d:\test\python>python   
Python 3.7.2 (tags/v3.7.2:9a3ffc0492, Dec 23 2018, 23:09:28) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import streamlit as st   
>>> import members    
>>> members.list_members(st)    
altair_chart <class 'method'>
area_chart <class 'method'>
audio <class 'method'>
balloons <class 'method'>
bar_chart <class 'method'>
beta_columns <class 'function'>
beta_container <class 'function'>
beta_expander <class 'function'>
bokeh_chart <class 'method'>
button <class 'method'>
cache <class 'function'>
camera_input <class 'method'>
caption <class 'method'>
case_converters <class 'module'>
checkbox <class 'method'>
code <class 'method'>
code_util <class 'module'>
color_picker <class 'method'>
columns <class 'method'>
commands <class 'module'>
config <class 'module'>
config_option <class 'module'>
config_util <class 'module'>
container <class 'method'>
cursor <class 'module'>
dataframe <class 'method'>
date_input <class 'method'>
delta_generator <class 'module'>
deprecation_util <class 'module'>
development <class 'module'>
download_button <class 'method'>
echo <class 'function'>
elements <class 'module'>
emojis <class 'module'>
empty <class 'method'>
env_util <class 'module'>
error <class 'method'>
error_util <class 'module'>
errors <class 'module'>
exception <class 'method'>
expander <class 'method'>
experimental_get_query_params <class 'function'>
experimental_memo <class 'streamlit.runtime.caching.memo_decorator.MemoAPI'>
experimental_rerun <class 'function'>
experimental_set_query_params <class 'function'>
experimental_show <class 'function'>
experimental_singleton <class 'streamlit.runtime.caching.singleton_decorator.SingletonAPI'>
experimental_user <class 'streamlit.user_info.UserInfoProxy'>
file_uploader <class 'method'>
file_util <class 'module'>
folder_black_list <class 'module'>
form <class 'method'>
form_submit_button <class 'method'>
get_option <class 'function'>
graphviz_chart <class 'method'>
header <class 'method'>
help <class 'method'>
image <class 'method'>
info <class 'method'>
js_number <class 'module'>
json <class 'method'>
latex <class 'method'>
line_chart <class 'method'>
logger <class 'module'>
map <class 'method'>
markdown <class 'method'>
metric <class 'method'>
multiselect <class 'method'>
number_input <class 'method'>
plotly_chart <class 'method'>
progress <class 'method'>
proto <class 'module'>
pydeck_chart <class 'method'>
pyplot <class 'method'>
radio <class 'method'>
runtime <class 'module'>
secrets <class 'streamlit.runtime.secrets.Secrets'>
select_slider <class 'method'>
selectbox <class 'method'>
session_state <class 'streamlit.runtime.state.session_state_proxy.SessionStateProxy'>
set_option <class 'function'>
set_page_config <class 'function'>
sidebar <class 'streamlit.delta_generator.DeltaGenerator'>
slider <class 'method'>
snow <class 'method'>
source_util <class 'module'>
spinner <class 'function'>
stop <class 'function'>
string_util <class 'module'>
subheader <class 'method'>
success <class 'method'>
table <class 'method'>
tabs <class 'method'>
text <class 'method'>
text_area <class 'method'>
text_input <class 'method'>
time_input <class 'method'>
title <class 'method'>
type_util <class 'module'>
user_info <class 'module'>
util <class 'module'>
vega_lite_chart <class 'method'>
vendor <class 'module'>
version <class 'module'>
video <class 'method'>
warning <class 'method'>
watcher <class 'module'>
write <class 'method'>

可見 Streamlit 提供了非常多函式來渲染網頁元件, 其中 write() 函式用來輸出一般文字, 只要兩行程式碼就可以輸出 Hello World 字串 :

# hello.py
import streamlit as st
st.write('Hello World')

將此兩行程式碼存成 hello.py, 然後開啟命令列視窗, 切換到此程式目錄下, 執行下列指令 :

streamlit run hello.py

D:\test\python\streamlit>streamlit run hello.py    

  You can now view your Streamlit app in your browser.

  Local URL: http://localhost:8501
  Network URL: http://192.168.2.109:8501

此指令會用預設瀏覽器開啟 8501 埠來顯示網頁, 結果如下 :




這就是 Streamlit 輸出的最簡單網頁. 檢視網頁原始碼可以發現網頁內容裡沒有 'Hello World', 那是由 Javascript 產生的 :




後續將逐一來測試這些渲染出各種網頁元件的函式.


2024-12-20 補充 :

最近在測試與 Streamlit 類似但更輕量的 Gradio 套件時找到另一個支援 Streamlit 的 Python web app 執行空間 :

 
你只要註冊 Hugging Face 免費帳號即可在此空間佈署 Streamlit web app, 它不會限制可佈署的 Web app 數量, 但免費帳戶只能使用分享主機 (無 GPU). 付費帳戶則可挑選不同等級主機與使用 GPU, 這比 Streamlit Cloud 雲端平台更好康. 用法參考 Gradio 筆記 :


沒有留言 :