streamlit とは
Python で Web アプリケーションを作成できるオープンソースのライブラリ。
インストール〜アプリ起動
ライブラリのインストール:
$ pip install streamlit
サンプルアプリの実装:
# sample.py
import streamlit as st
st.title('streamlit Tutorial')
st.header('This is a header')
st.subheader('This is a subheader')
st.text('Hello World!')
input_num = st.number_input('Input a number', value=0)
result = input_num ** 2
st.write('Result: ', result)
アプリの起動:
$ streamlit run sample.py
→ http://localhost:8501 にアクセス
使い方
st.write の色々
Markdown 表記にも対応:
st.write('# This is h1')
st.write('## This is h2')
st.write('### This is h3')
st.write('**太字の例**')
st.write('~~取消線の例~~')
リスト・辞書の表示:
st.write(['apple', 'orange', 'banana'])
st.write({'apple': 100, 'orange': 50, 'banana': 200})
import pandas as pd
df = pd.DataFrame({
'name': ['Tom', 'John'],
'age': [19, 22],
'birthPlace': ['U.K.', 'Australia']
})
st.write(df)
入力フォーム
# 数値入力を受け取るボックスとデフォルト値を設定
n_input = st.number_input('Input a number', value=0)
st.write('Result: ', n_input**2)
# テキスト入力ボックス
text_input = st.text_input('Input', 'Input some text here.')
# テキストエリア
text_area = st.text_area('Text Area', 'Input some text here.')
ファイルのアップロード
import pandas as pd
uploaded_file = st.file_uploader("Choose a file")
if uploaded_file is not None:
st.write(uploaded_file)
# アップロードされたファイルを読み込んで操作
data = pd.read_csv(uploaded_file)
st.write(data)
ボタン・チェックボックス
if st.button('My Button'):
st.write('Hello World!')
if st.checkbox('My Checkbox'):
st.write('Task 1 is done.')
opt_radio = st.radio(
'My Radio Button',
['A', 'B', 'C']
)
opt_select = st.selectbox(
'My Select Box',
['A', 'B', 'C']
)
opt_multiselect = st.multiselect(
'My Multi Select Box',
['A', 'B', 'C', 'D'],
default=['A', 'C'] # デフォルトの設定
)
# スライダー
value = st.slider('Select a value', 0, 100, 50) # min, max, default
if value < 30:
# 値が30以下になったらテキストを表示
st.write('value = {} < 30'.format(value))
# 両側スライダー、日付型
import datetime
d_min = datetime.date(1900, 1, 1)
d_max = datetime.date(2000, 12, 31)
d_lower = datetime.date(1930, 1, 1)
d_upper = datetime.date(1970, 12, 31)
values = st.slider('期間を指定してください', d_min, d_max, (d_lower, d_upper), format='YYYY-MM-DD (ddd)')
st.write('values: left = {}, right = {}'.format(values[0], values[1]))
グラフの描画
matplotlib を利用してグラフを描画できる。
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
y1 = x**2
y2 = x*7
fig, ax = plt.subplots()
ax.plot(x, y1, label=r'$y=x^2$')
ax.plot(x, y2, label=r'$y=7x$')
plt.legend()
plt.grid()
st.pyplot(fig)
地図
# 緯度経度のフィールド名は lat, lon でも可
points = [
{'latitude': 35.689521, 'longitude': 139.691704}, # 東京都
{'latitude': 34.686316, 'longitude': 135.519711} # 大阪府
]
st.map(points)
Latex 数式
st.latex(r'''
\sum_{k=0}^{n-1} a r^k =
a \left(\frac{1-r^{n}}{1-r}\right)
''')
コンテナ
with st.container(height=100):
st.write('Inside container')
for i in range(10):
st.write(i)
st.write('Outside container')
展開
with st.expander('中身を見る'):
st.write('expander の中身')
カラム分割
col1, col2, col3, empty = st.columns([1,2,1,6]) # 比率を指定して分割
col1.write('カラム1に文字列を表示します')
col2.write(['カ', 'ラ', 'ム', '2'])
if col3.button('ボタン'):
col3.write('ボタンがクリックされました')
水平区切り線
st.write('AAAAA')
st.divider()
st.write('BBBBB')
サイドバー
st.sidebar.write('サイドバー')
side_slider = st.sidebar.slider('width', 0, 100, 30)
タブ
tab_a, tab_b, tab_c = st.tabs(['A', 'B', 'C'])
with tab_a:
st.write('This tab is A')
with tab_b:
st.write('This tab is B')
with tab_c:
st.write('This tab is C')
処理が長引く場合の wait 表示
import time
if st.button('Slow process'):
with st.spinner('処理中です。しばらくお待ち下さい'):
st.write('Processing...')
time.sleep(3)
st.write('Done!')
空のウィジット
- 空っぽのウィジットを生成して場所を確保しておき、ボタン押下などのユーザ行動をトリガーにその位置に表示させる
- 作ってあったウィジットを画面から消す
といったことができる。
例えば以下の例では、
- 初期状態:数値を入力するフォームと「submit」ボタン
- ボタンを押下したとき:フォームの数値のみが画面に表示され、フォームとボタンは消失
widget_out = st.empty()
widget_in = st.empty()
btn = st.empty()
num = widget_in.number_input('Input a number', value=0)
if btn.button('submit'):
widget_in.empty()
widget_out.write(num)
btn.empty()
TIPS
ページ全体の設定
streamlit.set_page_config
を使えば、
- ブラウザタブに表示されるページタイトル
- ファビコン
- 画面の表示領域の幅
- サイドバーの開閉の初期状態
などを設定できる。
import streamlit as st
st.set_page_config(
page_title='My Sample Page',
page_icon='📕',
layout='wide',
initial_sidebar_state='expanded',
menu_items={
'Get Help': 'https://hkawabata.github.io/technical-note/note/Language/Python/Library/streamlit',
'About': 'https://streamlit.io/',
'Report a bug': 'http://example.com'
}
)
データの保持
streamlit はボタンを押したときなどのタイミングで全てのデータがリセットされるため、通常の変数の値は保持されない。
→ 例えば「ボタンを押すたびにカウンタを1大きくする」といったことができない。
これを解決するには session_state
の機能を使う:
import streamlit as st
# 変数の定義(ボタンが押された回数)
count = 0
if 'count' not in st.session_state:
st.session_state.count = 0
# ボタンを表示し、クリックされた回数を表示する
if st.button('クリックしてください'):
count += 1
st.session_state.count += 1
st.write(f'クリック回数: {count}(通常の変数)')
st.write(f'クリック回数: {st.session_state.count}(session_state)')
キャッシュ
import streamlit as st
import time
import datetime
@st.cache_resource
def get_result_of_heavy_process(arg):
# 時間がかかる処理
time.sleep(1)
return arg * 10
def try_once(arg):
t = datetime.datetime.now()
r = get_result_of_heavy_process(arg)
print(f'result = {r}, ', datetime.datetime.now() - t)
try_once(4)
try_once(4)
try_once(7)
result = 40, 0:00:01.006119
result = 40, 0:00:00.000730 # キャッシュが効いてすぐに結果が返る
result = 70, 0:00:01.007979 # 初めての引数で関数を呼び出したので3秒かかる
次に ttl
(キャッシュの有効時間)を設定してみる:
@st.cache_resource(ttl='5s') # 5秒でキャッシュが切れる設定
def get_result_of_heavy_process(arg):
# 時間がかかる処理
time.sleep(1)
return arg * 10
def try_once(arg):
t = datetime.datetime.now()
r = get_result_of_heavy_process(arg)
print(f'result = {r}, ', datetime.datetime.now() - t)
try_once(4)
try_once(4)
time.sleep(6)
try_once(4)
time.sleep(3)
try_once(4)
time.sleep(3)
try_once(4)
result = 40, 0:00:01.009000
result = 40, 0:00:00.002509 # キャッシュが効いてすぐに結果が返る
result = 40, 0:00:01.007050 # 有効期限切れで再処理
result = 40, 0:00:00.000667 # まだ有効期限内なのですぐ結果が返る
result = 40, 0:00:01.006122 # 有効期限切れで再処理
→ キャッシュされた値への再アクセスがあっても、キャッシュの残り時間はリセットされない模様
他にも st.cache_resource(max_entries=n)
とすると、キャッシュする件数を n
件に制限できる(これを超えると古いものから削除)