Streamlit 入門: 表示、インプット、複数ページの構成方法

2022-10-10
2022-10-10

どんなもの?

Python で簡単な UI が作成可能なライブラリです。

フロントエンドも Python で簡単に構築したい方におすすめです。特に後述するwriteメソッドを使用した記述方法がめちゃめちゃ便利です。

インストールは以下で可能です。

pip install streamlit

基本的な使い方

streamlitの記法で書かれた Python ファイルをstreamlit run <.pyファイル>で実行するとブラウザに画面が表示されます。

詳しい使い方は後述します。

データフレームの表示

先日使用した自然言語処理系のファイルを入力とします 単純に表示するなら以下のように実行可能。

import pandas as pd
import streamlit as st
SOURCE_DATA_PATH = "./data/test.csv"
@st.cache
def get_data() -> pd.DataFrame:
    df = pd.read_csv(SOURCE_DATA_PATH)
    return df
df = get_data()
st.dataframe(data=df)

@st.cacheはそのままの意味で関数の出力をキャッシュしてくれます。

dataframe

グラフ表示

サンプルを表示してみました。

st.pyplotで matplotlib で作成した図を表示できるようです。

import matplotlib.pyplot as plt
import numpy as np
import streamlit as st
from matplotlib.figure import Figure
def create_test_hist() -> Figure:
    arr = np.random.normal(1, 1, size=100)
    fig, ax = plt.subplots()
    ax.hist(arr, bins=20)
    return fig
st.pyplot(create_test_hist())
graph

セレクトボックス、チェックボックス、ボタンなどインプット系

よく利用されそうなインプット系をまとめてみました。 markdown も使える方法があるのできれいに表示を整えられます。

こちらが作成した画面とコードです。

screen
import datetime
import streamlit as st
select_option = st.selectbox("セレクトボックス", ("選択肢1", "選択肢2", "選択肢3"))
st.write("You selected:", select_option)
st.markdown("---")
multiselect_ptions = st.multiselect(
    "複数選択", ["Green", "Yellow", "Red", "Blue"], ["Yellow", "Red"]  # default値
)
st.write("You selected:", multiselect_ptions)
st.markdown("---")
age = st.slider("年齢選択", 0, 130, 25)
st.write("年齢:", age, "歳")
st.markdown("---")
title = st.text_input("テキスト入力", "テキストを入力")
st.write("入力文字列:", title)
st.markdown("---")
d = st.date_input("When's your birthday", datetime.date(2019, 7, 6))
st.write("選択肢た日付:", d)
st.markdown("---")
if st.button("ボタン"):
    st.write("ボタン押下後")
else:
    st.write("ボタン押下前")

イベント処理を書いてみる

単純にボタン押下で処理が実行されるようにしてみます。

button はクリックされると bool 値を返すのでそれにしたがって表示が行われるようにします。

import pandas as pd
import streamlit as st
SOURCE_DATA_PATH = "./data/test.csv"
@st.cache
def get_data() -> pd.DataFrame:
    df = pd.read_csv(SOURCE_DATA_PATH)
    return df
df = get_data()
st.dataframe(data=df)
idx = st.text_input("enter index", "0")
# 指定した行の内容表示
if st.button("ボタン"):
    if idx == "":
        raise ValueError("Value is Empty. Enter int value")
    st.dataframe(data=df.iloc[int(idx)])

結果はこんな感じ

event

なんでも表示できる write

これまでも登場してますが、writeメソッドはなんでも表示できます。

しかも表示したい順に引数に入れておげるとその通りに表示されます。

例えば以下のようなことができます。

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import streamlit as st
from matplotlib.figure import Figure
def create_test_hist() -> Figure:
    arr = np.random.normal(1, 1, size=100)
    fig, ax = plt.subplots(figsize=[4, 2])
    ax.hist(arr, bins=20)
    return fig
idx = 10
df = pd.DataFrame({"a": [0, 1], "b": [2, 3]})
st.write(
    "## writeはなんでもいける",
    df,
    "Hello World",
    idx,
    {"hoge": "fuga", "aaa": "bbb"},
    create_test_hist(),
)
write

サイドバー、タブ表示、展開などのレイアウト

サイドバーやタブを使うとより綺麗なページにできます。

import matplotlib.pyplot as plt
import numpy as np
import streamlit as st
from matplotlib.figure import Figure
def create_test_hist() -> Figure:
    arr = np.random.normal(1, 1, size=100)
    fig, ax = plt.subplots(figsize=[4, 2])
    ax.hist(arr, bins=20)
    return fig
# ページ情報、基本的なレイアウト
st.set_page_config(
    page_title="test streamlit",
    page_icon="🧊",
    layout="wide",
    initial_sidebar_state="expanded",
)
# サイドバー
select_option = st.sidebar.selectbox(
    "セレクトボックス", ("Email", "Home phone", "Mobile phone")
)
# タブ
tab1, tab2, tab3 = st.tabs(["data1", "data2", "data3"])
with tab1:
    st.write("expanderで要素を展開する")
    with st.expander("testグラフ"):
        st.write("テスト用のグラフ", create_test_hist())
with tab2:
    st.write("サイドバーで選択した値: ", select_option)

作成後のページはこのようになります。タブやサイドバーを設けることがかなりカスタマイズ性が向上します。

layout1layout3layout2

複数ページ、タブ表示などのレイアウトの方法

最後にこれまで作成したものを複数ページのように構成してみます。streamlit で複数ページのように構成するには、サイドバーのセレクトボックスで表示を切り替えるようにします。

import datetime
import matplotlib.pyplot as plt
import numpy as np
import streamlit as st
from matplotlib.figure import Figure
def create_test_hist() -> Figure:
    arr = np.random.normal(1, 1, size=100)
    fig, ax = plt.subplots(figsize=[4, 2])
    ax.hist(arr, bins=20)
    return fig
st.set_page_config(
    page_title="test streamlit",
    page_icon="🧊",
    layout="wide",
    initial_sidebar_state="expanded",
)
def intro() -> None:
    import streamlit as st
    st.write("# demo")
def input_test() -> None:
    import streamlit as st
    select_option = st.selectbox("セレクトボックス", ("選択肢1", "選択肢2", "選択肢3"))
    st.write("You selected:", select_option)
    st.markdown("---")
    multiselect_ptions = st.multiselect(
        "複数選択", ["Green", "Yellow", "Red", "Blue"], ["Yellow", "Red"]  # default値
    )
    st.write("You selected:", multiselect_ptions)
    st.markdown("---")
    age = st.slider("年齢選択", 0, 130, 25)
    st.write("年齢:", age, "歳")
    st.markdown("---")
    title = st.text_input("テキスト入力", "テキストを入力")
    st.write("入力文字列:", title)
    st.markdown("---")
    d = st.date_input("When's your birthday", datetime.date(2019, 7, 6))
    st.write("選択肢た日付:", d)
    st.markdown("---")
    if st.button("ボタン"):
        st.write("ボタン押下後")
    else:
        st.write("ボタン押下前")
def layouts_demo() -> None:
    import streamlit as st
    # タブ
    tab1, tab2, tab3 = st.tabs(["data1", "data2", "data3"])
    with tab1:
        st.write("expanderで要素を展開する")
        with st.expander("testグラフ"):
            st.write("テスト用のグラフ", create_test_hist())
    with tab2:
        st.write("サイドバーで選択した値: ", "なし")
    with tab3:
        st.write("## なし")
page_names_to_funcs = {
    "—": intro,
    "input Demo": input_test,
    "layout Demo": layouts_demo,
}
demo_name = st.sidebar.selectbox("Choose a demo", page_names_to_funcs.keys())
page_names_to_funcs[demo_name]()

以下のようにこれまでのデモを一つにまとめることができます。

multipage1multipage2

感想

st.writeが便利すぎる。これだけ覚えればかなりいろんな表示ができる。

サイドバーやタブ表示を使えばそれなりの情報量を扱うことも簡単そう。

簡単なユースケースなら streamlit で十分対応可能な印象。

一方で細かいレイアウトの調整方法がすぐ分からなかったりするので、カスタマイズ性を求めるなら普通のフロントエンドフレームワークを使ってもいいかもしれない。