こんにちは。たぶん初投稿です。
今回はPythonコードだけでWebアプリが作れるStreamlitで
入力フォームを追加/削除できるUIを考えていきます。
環境
Python 3.10.6
Streamlit 1.11.1
概要
Streamlitでは文字列や数値などの入力フォームが用意されています。
公開されているStreamlitデモアプリを見ると、入力フォームの数は固定になっているものがほとんどです。
入力フォームの数を可変にしたい場合もあると思い、入力フォームの数をユーザ側の操作に応じて変更できるデモアプリをつくってみました。
できあがったもの
ソースコードは下記の通りです。
import streamlit as st
st.set_page_config("Unlimited forms demo")
if "list" not in st.session_state:
st.session_state.list = [0]
st.info("Sums the numbers entered.")
with st.form("form"):
st_input_area = st.container()
st_add_button_area = st.container()
if st_add_button_area.form_submit_button("ADD FORM"):
st.session_state.list.append(0)
if st_add_button_area.form_submit_button("REMOVE FORM"):
del st.session_state.list[-1]
for i in range(len(st.session_state.list)):
st.session_state.list[i] = st_input_area.number_input(f"Value {i+1}", step=1, key=i)
is_calc = st.form_submit_button("DONE")
if is_calc:
sum = 0
for _value in st.session_state.list:
sum += _value
st.success(f"Total: {sum}")
else:
pass # DO NOTHING
解説
Streamlitの動作の特徴
Streamlitの特徴として、UIを操作するとコードが再実行し直されます。
例えば、以下はボタンをクリックすると数字が加算されるプログラムです。
import streamlit as st
temp = 0
if st.button("+1"):
temp += 1
st.write(temp)
Streamlitの場合、ボタンを押すと
- 変数の宣言
- ボタンの押下に伴う処理
- 加算後の結果表示
が一度に行われます。
したがってボタンを何回クリックしても、そのたびに変数が再宣言されるため、常にボタンを1回押した値にしかなりません。
Streamlitにはそうした再実行に対処するためにst.session_stateという機能があります。
これは変数の値を保持し続ける機能です。
以下のように宣言をします。
if "var" not in st.session_state:
st.session_state.var = 0
st.session_stateを組み合わせることで、変数の再宣言が行われずにボタンを押すたびに数を足す動作ができるようになります。
import streamlit as st
if "temp" not in st.session_state:
st.session_state.temp = 0
if st.button("+1"):
st.session_state.temp += 1
st.write(st.session_state.temp)
デモアプリの解説
Streamlitの再実行とst.session_stateの説明をしました。
デモアプリではst.session_stateでlist(配列)を宣言し、listの要素数に応じた入力フォームを表示させています。
そしてユーザがlistの要素数を操作できるようにすることによって、
入力フォームの追加/削除を実現しています。
処理の流れとしては、
- listの要素数を操作
- 要素数に応じた入力フォームを表示
となります。
デモアプリでは要素の配置を
- 入力フォーム
- 要素数の操作UI
という順にしたかったため、st.container()というStreamlit要素の配置場所を操作できる機能を使って、
処理順は、要素数の操作→入力フォーム表示 で
表示順は、入力フォーム→要素数の操作 を実現しています。
さいごに
Streamlitで入力フォームをユーザが自由に追加/削除できるアプリを実装してみました。
Streamlitは簡単にWebアプリが実装できますが、そのぶん制約が多いです。
ただ機能を組み合わせてみることで柔軟なUIが実現できます。
(そこまでするならDjangoとかに手を出したほうがいい気もする)