2025年5月18日 星期日

Streamlit 學習筆記 : 使用者輸入元件 (二) 選項圓鈕

今天繼續測試使用者輸入元件之選項圓鈕 (radio), 此為單選元件, 實際上會渲染為 HTML 中 type 為 radio 的 input 元件. 

本系列所有測試文章參考 :


呼叫 Streamlit 的 radio() 函式並傳入會建立一組選項圓鈕元件, 當按下按鈕時傳回 True, 否則傳回 False, 其參數結構如下 : 

st.radio(label, options, index=0, format_func=str, key=None, help=None, on_change=None, args=None, kwargs=None, disabled=False, horizontal=False, captions=None)

參數說明如下表 :


 st.radio() 之參數  說明
label 元件標籤文字,顯示於 radio 上方(必填)
options 選項資料(list、tuple 或其他 iterable,必填)
index 預設選中選項的索引,預設為 0
format_func 格式化選項顯示用的函式,預設為 str
key 元件的唯一識別鍵,防止重複
help 當滑鼠移至元件上方時顯示的提示文字
on_change 選項變更時要呼叫的 callback 函式
args / kwargs 傳給 on_change 函式的位置參數 / 關鍵字參數
disabled 設為 True 時元件將無法互動
horizontal 設為 True 時選項會橫向排列,預設為垂直
captions 搭配圖片選項使用,提供對應的描述文字


其中 label 與 options 是必要之位置參數, label 是用來顯示在各選項上方的說明文字, options 則是列舉之選項文字, 可以是任何序列物件, 例如 list, tuple, Series 物件等. 

例如 : 


測試 1 : 只傳入必要參數 label 與 options [看原始碼] 

# st-radio-test-1.py
import streamlit as st

label='請選擇最喜歡的水果 : '
options=['蘋果', '葡萄', '桃子', '芒果']
selection=st.radio(label, options)
st.write("你選的是:", selection)

此例僅傳入必要參數 label 與 options, 被選擇之選項值會立即傳回來, 因此不需要用一個按鈕去取得傳回值, 結果如下 : 



可見預設選項是由上而下垂直排列, 如果要讓選項水平排列則要傳入 horizontal=True : 


測試 2 : 傳入 horizontal=True 使選項水平排列 [看原始碼] 

# st-radio-test-2.py
import streamlit as st

label='請選擇最喜歡的水果 : '
options=['蘋果', '葡萄', '桃子', '芒果']
selection=st.radio(label, options, horizontal=True)
st.write("你選的是:", selection)

結果如下 : 




Streamlit 的選項圓鈕的傳回值就是被選擇選項的顯示字串, 如果想要讓傳回值與顯示字串不同 (即 input 元件中設定 value 屬性), 就要利用 format_func 參數指定一個自訂函式來轉換, 例如上面範例的四種水果我們想讓傳回值是英文, 則 options 參數就要改用英文 :

options=['apple', 'grape', 'peach', 'mango']

然後再定義一個字典來讓 format_func 參數指定的一個自訂函式來查詢轉換為顯示值 : 

fruits={'apple': '蘋果', 'grape': '葡萄', 'peach': '桃子', 'mango': '芒果'} 

程式碼如下 : 


測試 3 : 利用 format_func 參數轉換選項之顯示字串 [看原始碼] 

# st-radio-test-3.py
import streamlit as st

label='請選擇最喜歡的水果 : '
options=['apple', 'grape', 'peach', 'mango']
fruits={'apple': '蘋果', 'grape': '葡萄', 'peach': '桃子', 'mango': '芒果'}
selection=st.radio(label, options, format_func=lambda x: fruits[x])
st.write("你選的是:", selection)

此例傳入的 options 是英文的水果名稱, 所以傳回值就是英文, 但顯示值則是被 format_func 所指定之 lambda 函式轉換成中文, 此匿名函式會走訪 options 串列, 並將其元素傳給 lambda 中的參數 x, 以此為鍵查詢 fruits 字典而傳回中文水果名作為選項的顯示文字, 結果如下 :



可見雖然選項是中文, 但傳回值卻是英文. 

上面範例也可以用 on_change 搭配 key 參數來做, 例如 : 


測試 4 : 利用 on_change 與 key 參數轉換選項之傳回值 [看原始碼] 

# st-radio-test-4.py
import streamlit as st

def on_radio_change():
    selected=st.session_state['fruit_choice']
    fruits={'蘋果': 'apple', '葡萄': 'grape', '桃子': 'peach', '芒果': 'mango'}
    st.write(f'你選的是:{fruits[selected]}')

label='請選擇最喜歡的水果 : '
options=['蘋果', '葡萄', '桃子', '芒果']
st.radio(label, options, key='fruit_choice', on_change=on_radio_change)

此例中的 options 使用中文, 故在呼叫 st.radio() 時其顯示文字與傳回值都是中文水果名, 但我們另外傳入 key 參數與 on_change 參數, on_change 用來指定一個自訂函式來處理選項切換事件, key 則是為被選擇之選項設定一個獨一無二的鍵名, 它與被選擇的選項值會存入 st.session_state 字典中, 因此在切換事件處理函式中可以用 st.session_state[key] 取得選項圓鈕的傳回值, 然後從 fruits 字典中取得其英文, 結果如下 :




與上面範例不同的是, 初始化時不會顯示預設被選取項目, 而是要在選取動作發生時才會更新選取結果. 也可以在 on_change 事件發生時利用 args 參數攜帶引數給事件處理函式, 例如 : 


測試 5 : 利用 args 參數攜帶引數給 on_change 事件處理函式 [看原始碼] 

# st-radio-test-5.py
import streamlit as st

def on_radio_change(name):
    selected=st.session_state['fruit_choice']
    fruits={'蘋果': 'apple', '葡萄': 'grape', '桃子': 'peach', '芒果': 'mango'}
    st.write(f'{name} 選的是:{fruits[selected]}')

label='請選擇最喜歡的水果 : '
options=['蘋果', '葡萄', '桃子', '芒果']
st.radio(label, options, key='fruit_choice', on_change=on_radio_change, args=('Tony',))

注意, args 參數型態為 tuple, 因此若只有一個元素後面必須有一個逗號. on_change 事件處理函式用一個參數來接收 args 傳遞的引數 (如果有兩個引數就兩個參數接收, 依序), 結果如下 :



也可以使用 kwargs 參數傳送, 例如 : 


測試 6 : 利用 kwargs 參數攜帶引數給 on_change 事件處理函式 [看原始碼] 

# st-radio-test-6.py
import streamlit as st

def on_radio_change(name=None):
    selected=st.session_state['fruit_choice']
    fruits={'蘋果': 'apple', '葡萄': 'grape', '桃子': 'peach', '芒果': 'mango'}
    st.write(f'{name} 選的是:{fruits[selected]}')

label='請選擇最喜歡的水果 : '
options=['蘋果', '葡萄', '桃子', '芒果']
st.radio(label, options, key='fruit_choice', on_change=on_radio_change, kwargs={'name': 'Tony'})

此例與上面 args 的範例差別僅是 kwargs 使用字典傳送而已, 結果如下 :




有些應用場景可能需要同時使用 args 與 kwargs, 這時事件處理函式中的接收參數必須 args 位置參數在前 (依序), kwargs 關鍵字參數在後 (可以不依序). 

下面是兩個 st.radio 元件連動的範例, 當變更第一個 st.radio 時, 第二個 st.radio 的選項也會動態改變 :


測試 7 : 兩個連動的 st.radio 選擇器 [看原始碼] 

# st-radio-test-7.py
import streamlit as st

st.subheader('連動的 st.radio 選單測試')
# 圖片尺寸選項
food_options={
    '米食': ['炒飯', '蛋包飯', '咖哩飯'],
    '麵食': ['炒麵', '烏龍麵', '鍋燒麵']
    }
# 初始化 session 狀態變數 : 預設=米食之炒飯
if 'main_sel' not in st.session_state:
    st.session_state.main_sel='米食'  # 預設米食
if 'item_sel' not in st.session_state:
    st.session_state.item_sel=food_options['米食'][0]  # 預設炒飯
# 主食選單(更新連動食譜選單)
main=st.radio(
    '選擇主食',
    ['米食', '麵食'],
    index=['米食', '麵食'].index(st.session_state.main_sel)
    )
# 當主食選項更改時更新狀態變數
if main != st.session_state.main_sel:  
    st.session_state.main_sel=main  # 更新主食狀態
    st.session_state.item_sel=food_options[main][0]  # 更新品項狀態為第一個被選取
# 品項選單 (會依主食動態變化)
item_sel=st.radio(
    '選擇品項',
    food_options[st.session_state.main_sel],  # 依據主食設定品項的選項
    index=food_options[st.session_state.main_sel].index(st.session_state.item_sel)
    )
st.session_state.item_sel=item_sel  # 更新食譜狀態
st.write(f'{st.session_state.main_sel}:{st.session_state.item_sel}'

此例利用 st.session_state 字典來記錄兩個選項園鈕的即時選項狀態, 當主選擇器 (主食) 變更選項時, 副選擇器 (品項) 的選項也隨之變更, 結果如下 :




沒有留言 :