寺田 学
2024年4月には、
今回はStreamlitにフォーカスを当てて、よく使う機能を紹介します。Streamlitにはたくさんの機能があり、公式ドキュメント APIリファレンスを見ても、どの機能から使って良いのかわからないという声がありました。今回は、筆者目線でよく使うであろう機能に絞って紹介します。
Streamlitとは
StreamlitはPythonで構築できるWeb用のフレームワークです。Pythonのモジュールを定義することで、インタラクティブなWebアプリを簡単に構築できるという特徴があります。
PythonのWebフレームワークにはDjangoやFlask、FastAPIなどがあります。これらはサーバサイドフレームワークやMVCフレームワークと呼ばれています。StreamlitはDjangoやFlaskとは違い、Web UIに特化したフレームワークです。筆者は
フレームワークの違いについては、先に紹介した2024年4月公開の
Streamlitは、細かなデザインやフロントエンドの処理を自由に表現することよりも、簡単にWebアプリを作ることにフォーカスしたフレームワークです。特にデータ系の表現や、簡単に動的な動きを実現できることに魅力があります。
環境設定から起動方法
最初に、Streamlitの開発及び起動方法を紹介します。
開発環境
今回は、Python 3.
執筆時点
Pythonの仮想環境であるvenv
を準備して、Streamlitをインストールします。ここでは、macOSのターミナルで実行をしています。venvは、WindowsやLinuxでも利用可能です。
venvの準備と有効化が終わりましたので、Streamlitをインストールします。
ここまでで、Streamlitの準備が終わりました。
Streamlitと一緒に、pandasなど多くの依存パッケージがインストールされます。
起動方法
Streamlitを起動するには以下のように実行します。その際にPythonモジュールを指定します。
タイトルだけを表示するアプリ
app.
アプリを起動するとデフォルトブラウザが立ち上がり、以下のように表示されます。
サンプルアプリ ―ランダム選択アプリ
ここから、
アプリケーションの内容は以下のとおりです。
タイトル | 文字列から単語を選択するアプリ |
---|---|
説明 | 入力された文字列をスペース区切りで分割し、ボタンを押したら1つが選ばれる |
入力 | 1行文字入力 |
結果 | 1つの単語 |
モジュール | choice_ |
ランダム選択アプリのコード
Streamlitのコードは以下のとおりです。
以下、choice_
- st.
text_ input() - 1行入力
(textの入力) を定義し、入力されたものを変数 text
に格納
- 1行入力
- text.
replace(" ", " ").split(" ") - Pythonの文字列メソッド
replace()
で全角スペースを半角に置き換え - その後、同じく文字列メソッド
split()
で半角スペースで文字列を分割してリストを作成 - 上記の結果を変数
words
に格納
- Pythonの文字列メソッド
- st.
write() - アプリ上
(ブラウザ上) に表示するための機能を使って分割された文字列を表示 - st.
write()が与えられるデータに沿って、データの内容を表示 - st.
write()の詳細は次項にて説明します
- アプリ上
- st.
button() - クリック可能なボタンを設置
if
文のあとにボタンを設置することで、ボタンが押されたときにifブロックが実行できるように設定
- random.
choice() - Pythonのrandomモジュールの
choice()
を使ってリストの中から1つを選択可能に
- Pythonのrandomモジュールの
ランダム選択アプリを実行した結果は以下のとおりです。
今回は、
st.write()
st.
文字列を渡せば文字列をそのまま出力してくれます。今回のサンプルコードでは、リストもst.
に渡しています。リストの場合はリスト用の表示になっていることがわかったかと思います。
このst.
一方でStreamlitには、DataFrameを表示するst.
や、画像を表示するst.
といった専用の機能が存在します。専用の機能には、表示する大きさなどの引数があります。専用の機能を用いることで、表示をより細かく制御することができます。
サンプルアプリ ―サイコロを2つ振り結果を表示するアプリ
ここからは、もう少し複雑なアプリを作っていきます。アプリケーションの内容は以下のとおりです。
タイトル | サイコロを2つ振った結果を表示するアプリ |
---|---|
説明 | サイコロ2個を何度か振って結果を表形式で表示し、棒グラフで結果を表示する |
モジュール | dice_ |
ステップ |
|
「サイコロを2つ振り結果表示アプリ」の最初のコード
ここでは最初のコードとして、上記のステップの3まで実行
以下、dice_
dices = []
- サイコロを振った結果を格納する空リストを定義
random.
randint(1, 6) - 1から6までの整数をランダムに生成
dices.
append() - 各出目と合計値をタプルで保存
pd.
DataFrame() - DataFrame化する。これは次の表示で表形式で表示するため
st.
dataframe(df) - DataFrameを表形式で出力
- データをCSV形式でダウンロードしたり、検索する機能がUI上に表示される
実行結果を以下に示します。
このままででは狙い通りのアプリができていません。実行して何度か
これは、Streamlitの特徴である
「サイコロを2つ振り結果表示アプリ」に状態保持機能を入れる
先ほどまでのコードでは、ボタンを押すたびにモジュールが再実行されます。結果を保持しようとしていたdices = []
が毎回初期化されてしまい、アプリケーションが狙い通りの動きができませんでした。
毎回初期化されないようにする方法はいくつか存在します。
- セッションにデータを保持する
- 関数化してキャッシュ化する
- コードの一部だけを再実行する
今回は、セッションにデータを保持する方法で解決します。
なお、関数化してキャッシュ化するには@st.
や@st.
を用います。詳しくは、公式ドキュメント キャッシュ を参照してください。
また、コードの一部を再実行する方法としては、Streamlit 1.
セッションにデータを保持 するには、st.
を使います。
セッションを使った変更後のコードを見てみましょう。
import random
import streamlit as st
import pandas as pd
if "dices" not in st.session_state: # セッションデータの初期化
st.session_state.dices = []
st.title("2つのサイコロを振るアプリ")
if st.button("サイコロを振る"):
dice1 = random.randint(1, 6)
dice2 = random.randint(1, 6)
dice_sum = dice1 + dice2
st.session_state.dices.append((dice1, dice2, dice_sum)) # セッションにappend
st.write(f"1つ目のサイコロ: {dice1} / 2つ目のサイコロ: {dice2}")
df = pd.DataFrame(st.session_state.dices, columns=["1つ目のサイコロ", "2つ目のサイコロ", "合計"])
st.dataframe(df)
st.write("試行回数: ", len(st.session_state.dices))
変更点は以下のとおりです。
"dices" not in st.
session_ state - st.
session_ stateにdicesが存在するかを確認
- st.
st.
session_ state. dices = [] - st.
session_ stateにdicesが存在しないときは、空リストで初期化
- st.
st.
session_ state. dices. append() - st.
session_ stateのdicesにデータを追記
- st.
- DataFrame化、試行回数表示の変更
動作を確認してみます。
ボタンが押されるたびにDataFrameの表が増え、試行回数も増えていることがわかりました。
「サイコロを2つ振り結果表示アプリ」にグラフを表示
Streamlitには、グラフを表現する機能があります。ここでは、Streamlitの標準機能を用いてグラフ化します。ここでは、2つのサイコロの和がボタンが押されるごとにどのようになるかの回数を、棒グラフで表現してみます。
グラフを表示するには、先ほどまでのコードに以下の2行を追加するだけです。
if st.button("結果を表示"):
st.bar_chart(df["合計"].value_counts())
ここでは
st.
bar_ chart() - 棒グラフを表示
df["合計"].value_
counts() - 定義済みDataFrameから、"合計"カラムを取得し、合計値が同じ回数をカウント
以下は、30回サイコロを振った結果を表示しました。
「サイコロを2つ振り結果表示アプリ」に複数回のサイコロをまとめて振る
このアプリの完成形として、
import random
import streamlit as st
import pandas as pd
if "dices" not in st.session_state:
st.session_state.dices = []
st.title("2つのサイコロを振るアプリ")
multiple = st.toggle("複数回振る", False) # 複数回振るかのトグルスイッチ
if not multiple:
if st.button("サイコロを振る"):
dice1 = random.randint(1, 6)
dice2 = random.randint(1, 6)
dice_sum = dice1 + dice2
st.session_state.dices.append((dice1, dice2, dice_sum))
st.write(f"1つ目のサイコロ: {dice1} / 2つ目のサイコロ: {dice2}")
else:
n = st.slider("回数", 1, 1000, 500) # 回数をスライダーで入力
if st.button("サイコロを振る"):
for _ in range(n):
dice1 = random.randint(1, 6)
dice2 = random.randint(1, 6)
dice_sum = dice1 + dice2
st.session_state.dices.append((dice1, dice2, dice_sum))
st.write(f"{n}回振りました。")
if st.session_state.dices and st.button("リセット"): # 過去のデータを削除する機能
st.session_state.dices = []
df = pd.DataFrame(st.session_state.dices, columns=["1つ目のサイコロ", "2つ目のサイコロ", "合計"])
st.dataframe(df)
st.write("試行回数: ", len(st.session_state.dices))
if st.button("結果を表示"):
st.bar_chart(df["合計"].value_counts())
追加した機能を説明します。
st.
toggle("複数回振る", False) - トグルスイッチを設置し、複数回振るモードかを設定
- 第2引数はデフォルト値で
False
とし、1回ずつ振るモードがデフォルト
st.
slider("回数", 1, 1000, 500) - 数値を入力するスライダーを準備
- 第2引数と第3引数で範囲を指定、1から1000回までが選択可能
- 第4引数でデフォルト値を設定、500回がデフォルト
st.
session_ state. dices and st. button("リセット") - 過去の振ったサイコロの記録を削除する機能を設置
- セッションにデータがあった場合のみ
「リセット」 ボタンを表示 - リセットをクリックすると、ifブロックが実行され、セッションを初期化
完成したアプリは以下のようになります。
その他のStreamlitの機能
ここでは、今回のアプリで使用しなかった機能の中から、Streamlitのその他の機能を紹介します。
入力
さまざまな入力ウィジェットが準備されています。詳細は、公式ドキュメント Widget を参照してください。
この中からいくつかを紹介します。
- テキストエリア
st.
text_ area - 複数行の文字列を入力
- セレクトボックス
st.
selectbox - リストから一つを選択
- マルチセレクト
st.
multiselect - リストから複数を選択
- ファイルアップロード
st.
file_ uploader - ファイルをアップロード
- ドラッグ&ドロップに対応
- 日付入力
st.
date_ input - カレンダーから日付を選択
- ダウンロードボタン
st.
download_ button - ボタンをクリックすると、ファイルがダウンロード
出力
出力方法もさまざまなものが準備されています。
- テキスト
- 公式ドキュメント Text elements
- タイトル、ヘッダー、マークダウンなど
- データ
- 公式ドキュメント Data elements
- DataFrame、データの編集、統計テーブルなど
- チャート
- 公式ドキュメント Chart elements
- シンプルがグラフ、地図、MatplotlibやPlotryの利用
- メディア
- 公式ドキュメント Media elements
- 画像、音声、ビデオなど
- 状態表示やメッセージ
- 公式ドキュメント Display progress and status
- シンプルなメッセージ表示、プログレスバーやトーストメッセージなど
レイアウト
サイドバーやカラムの設定、タブ切り替えにも対応しています。詳細は、公式ドキュメント Layouts and Containers を参照してください。
筆者がよく使うのは2つです。
- タブ化
st.
tabs - 複数の機能をタブで切り替える
- サイドバー
st.
sidebar - 情報や補足的な設定をサイドバーに設置
デプロイ
Streamlitはサーバ系のアプリケーションです。サーバにデプロイすることでURLを持ち、Webブラウザからインターネット経由で利用することができます。
今回は、Streamlitをホストするサービスを利用してデプロイします。
Streamlit Cloud
Streamlit公式のホスティング環境です。
- Community Cloud | Streamlit
- URL:https://
streamlit. io/ cloud
Streamlit Cloudは以下の特徴があります。
- 無料
- 簡単にデプロイできる
- 認証などの機能がない
Streamlit Cloudを利用するには、ログインアカウントを作り、ダッシュボード にアクセスします。
ここでは、GitHubでアプリケーションを管理している前提で、アプリをデプロイする手順を紹介します。
- ダッシュボードの右上の
Create app
をクリック - 「Do you already have an app?」
と聞かれるので、 「Yup, I have an app」 を選択 - GitHubのオーガニゼーションを選択し、認証
- その後、以下の通り入力
- Repository:GitHubのレポジトリのURLをペースト
- Branch:ここでは
“main” を選択 - Main file path:アプリのモジュールを選択
- App URL (optional):今回は
「st-sample-gihyo-202410」 と入力
- Deployボタンをクリック
デプロイされ、App URLに入力したURLが表示されます。
今回は、以下にサイコロを振るアプリをデプロイしました。
- サイコロを振るアプリ
- URL:https://
st-sample-gihyo-202410. streamlit. app/
その他の選択肢
Streamlit Cloud以外に、HuggingFace Spacesを活用する方法もあります。HuggingFace SpacesにはGPUの利用が可能な有料プランがあります。
筆者は何度かHuggingFace Spacesを利用してアプリをホストしています。普段は無料プランでホスティングしておいて、利用が多くなるときやGPUが必要なタイミングだけ有料プランに変更する、といった柔軟な運用ができることに魅力を感じています。
また、独自の環境へのデプロイには、サーバにPythonをセットアップし、Streamlitを起動するスクリプトを書いてホスティングする方法があります。他には、Dockerを使ってホスティングすることも可能です。
まとめ
今回は、PythonのWeb UIフレームワークの1つであるStreamlitを使い始めるための基本機能の紹介を行いました。Webアプリ化すると、Pythonスクリプトで作っていたものをGUIから実行可能なプログラムにできます。このような用途にもStreamlitは活用できると思います。みなさんもぜひ挑戦してみてください。