1. Python超入門
すでにPython経験がある人はこの章を流し見でOK。
1.1 変数・型・表示
# 1_hello_python.py
name = "Enzo"
age = 12
pi = 3.14
print(name, age, pi)
1.2 条件分岐・ループ・関数
# 1_basics.py
def grade(score):
if score >= 90:
return "A"
elif score >= 80:
return "B"
return "C"
scores = [72, 88, 95]
for s in scores:
print(s, grade(s))
1.3 仮想環境とパッケージ
# 端末で:プロジェクト用ディレクトリへ移動して
python -m venv .venv
# Windows: .venv\Scripts\activate
# macOS/Linux: source .venv/bin/activate
pip install streamlit pandas numpy matplotlib altair
2. 最初のStreamlit(最短ルート)
2.1 Hello, Streamlit!
# 2_hello_streamlit.py
import streamlit as st
st.title("Hello, Streamlit! 🚀")
st.write("はじめてのWebアプリ")
起動:
streamlit run 2_hello_streamlit.py
2.2 再実行(Rerun)モデルを掴む
# 2_rerun_model.py
import streamlit as st
st.title("再実行モデル入門")
name = st.text_input("お名前", "")
st.write("こんにちは,", name or "名無しさん")
count = st.number_input("回数", 0, 10, 0)
if st.button("実行"):
st.success(f"実行しました x {count}")
st.info("入力やボタン操作のたびに、このスクリプトは最初から実行されます。")
3. 部品(ウィジェット)総ざらい
ここを押さえると一気に作れる幅が広がる。
代表カテゴリごとに最小コードでざっと使い心地を掴みます。
3.1 テキストと装飾
# 3_texts.py
import streamlit as st
st.title("タイトル")
st.header("見出し")
st.subheader("サブ見出し")
st.text("等幅テキスト")
st.markdown("**太字** *斜体* `コード`")
st.code("print('コードブロック')", language="python")
st.latex(r"\int x^2 dx")
st.caption("補足説明・注意書きに")
st.divider()
3.2 入力ウィジェット(単発入力)
# 3_inputs_basic.py
import streamlit as st
name = st.text_input("名前")
age = st.number_input("年齢", min_value=0, step=1)
agree = st.checkbox("規約に同意する")
color = st.selectbox("色", ["red", "green", "blue"])
many = st.multiselect("複数選択", ["A","B","C"])
day = st.date_input("日付")
tm = st.time_input("時間")
st.write(name, age, agree, color, many, day, tm)
3.3 ボタン・リンク・ダウンロード
# 3_buttons_links.py
import streamlit as st
if st.button("計算する", type="primary"):
st.success("計算しました!")
st.download_button("CSVをDL", data="a,b\n1,2\n", file_name="sample.csv")
st.link_button("ヘルプを見る", "https://docs.streamlit.io/")
3.4 フォーム(まとめて送信)
# 3_form.py
import streamlit as st
with st.form("profile"):
c1, c2 = st.columns(2)
with c1:
name = st.text_input("氏名")
age = st.number_input("年齢", 0, 120, 20)
with c2:
email = st.text_input("メール")
langs = st.multiselect("言語", ["Python", "JS", "Go"])
ok = st.form_submit_button("登録する")
if ok:
st.success(f"登録完了: {name}, {age}, {email}, {langs}")
3.5 チャットUI要素(下準備)
# 3_chat_primer.py
import streamlit as st
st.title("チャットUI(素振り)")
if "messages" not in st.session_state:
st.session_state.messages = []
for m in st.session_state.messages:
with st.chat_message(m["role"]):
st.write(m["content"])
if prompt := st.chat_input("メッセージを入力"):
st.session_state.messages.append({"role":"user","content":prompt})
with st.chat_message("user"):
st.write(prompt)
# ダミー応答
reply = f"「{prompt}」を受け取りました。"
st.session_state.messages.append({"role":"assistant","content":reply})
with st.chat_message("assistant"):
st.write(reply)
4. レイアウト:列・タブ・サイドバー・コンテナ
# 4_layouts.py
import streamlit as st
st.title("レイアウト図鑑")
# 列
c1, c2, c3 = st.columns([1,2,1])
with c1: st.metric("PV", 1234, 56)
with c2: st.line_chart({"x":[1,2,3,4], "y":[1,4,9,16]})
with c3: st.progress(0.6)
# タブ
tab1, tab2 = st.tabs(["📈 分析", "⚙️ 設定"])
with tab1: st.area_chart({"x":[1,2,3], "y":[3,2,5]})
with tab2: st.toggle("ダークモード")
# サイドバー
st.sidebar.header("メニュー")
st.sidebar.radio("ページ", ["ホーム","分析","設定"])
# エクスパンダー
with st.expander("詳細を開く"):
st.write("ここに補足情報")
5. データ表示・編集:dataframe / data_editor / column_config
5.1 表示:st.dataframe
# 5_dataframe.py
import streamlit as st
import pandas as pd
df = pd.DataFrame({
"city":["Tokyo","Osaka","Nagoya","Fukuoka"],
"temp":[18,17,16,20],
"hum":[0.55,0.60,0.58,0.65],
})
st.dataframe(df, use_container_width=True)
5.2 編集:st.data_editor
# 5_data_editor.py
import streamlit as st
import pandas as pd
df = pd.DataFrame({"task":["A","B","C"], "done":[False,False,True]})
edited = st.data_editor(df, num_rows="dynamic")
st.write("編集結果", edited)
5.3 列の表現力:column_config 概要
# 5_column_config.py
import streamlit as st
import pandas as pd
df = pd.DataFrame({
"name":["A","B"],
"link":["https://example.com","https://streamlit.io"],
"score":[0.8, 0.95],
})
cfg = {
"name": st.column_config.TextColumn("名前", help="任意のテキスト"),
"link": st.column_config.LinkColumn("リンク"),
"score": st.column_config.NumberColumn("スコア", min_value=0.0, max_value=1.0, step=0.01),
}
st.dataframe(df, column_config=cfg)
6. 可視化(標準+Altair/Matplotlib)
# 6_charts.py
import streamlit as st
import pandas as pd
import altair as alt
import matplotlib.pyplot as plt
df = pd.DataFrame({"x": range(1, 11)})
df["y"] = [v*v for v in df["x"]]
st.subheader("標準チャート")
st.line_chart(df, x="x", y="y")
st.area_chart(df, x="x", y="y")
st.bar_chart(df, x="x", y="y")
st.subheader("Altair")
chart = alt.Chart(df).mark_line().encode(x="x", y="y")
st.altair_chart(chart, use_container_width=True)
st.subheader("Matplotlib")
fig, ax = plt.subplots()
ax.plot(df["x"], df["y"])
ax.set_title("Matplotlib line")
st.pyplot(fig)
7. 状態管理・キャッシュ
7.1 セッション状態
# 7_session_state.py
import streamlit as st
if "count" not in st.session_state:
st.session_state.count = 0
st.write("カウント:", st.session_state.count)
if st.button("増やす"): st.session_state.count += 1
if st.button("リセット"): st.session_state.count = 0
7.2 キャッシュ(データ/リソース)
# 7_cache.py
import streamlit as st, time
@st.cache_data
def slow_sum(n):
time.sleep(1); return sum(range(n+1))
n = st.slider("n", 1000, 50000, 10000, step=1000)
st.write("結果:", slow_sum(n))
class Client:
def __init__(self, token): self.token = token
def call(self, x): return f"hello {x} with {self.token}"
@st.cache_resource
def get_client(): return Client("SECRET")
client = get_client()
st.write(client.call("world"))
8. ファイルI/O(アップロード・ダウンロード)
# 8_io.py
import streamlit as st, pandas as pd, io
uploaded = st.file_uploader("CSVを選択", type="csv")
if uploaded:
df = pd.read_csv(uploaded); st.dataframe(df)
csv = "name,score\nA,80\nB,90\n"
st.download_button("結果をDL", data=csv, file_name="result.csv", mime="text/csv")
9. 生成AIチャットUI(スケルトン→評価UI)
# 9_chat_app.py
import streamlit as st
st.title("チャットUI(骨組み)")
if "messages" not in st.session_state: st.session_state.messages=[]
for m in st.session_state.messages:
with st.chat_message(m["role"]): st.write(m["content"])
if prompt := st.chat_input("メッセージを入力"):
st.session_state.messages.append({"role":"user","content":prompt})
with st.chat_message("user"): st.write(prompt)
# ここで任意のLLM APIを呼ぶ
reply = f"ダミー応答: {prompt}"
with st.chat_message("assistant"): st.write(reply)
st.session_state.messages.append({"role":"assistant","content":reply})
# 9_review_feedback.py
import streamlit as st
st.title("応答の検証/修正")
if "answer" not in st.session_state: st.session_state.answer = "サンプル応答。改善してください。"
st.text_area("AIの応答", key="answer", height=120)
fb = st.feedback("thumbs")
if fb is not None: st.toast(f"フィードバック: {fb}")
10. ステータスと進捗の見せ方
# 10_status.py
import streamlit as st, time, random
with st.status("処理中...", expanded=True) as status:
st.write("前処理..."); time.sleep(0.5)
st.write("推論..."); time.sleep(1.0)
st.write("後処理..."); time.sleep(0.5)
status.update(label="完了!", state="complete")
st.success("成功しました") if random.random()>0.5 else st.warning("注意が必要です")
11. 秘密情報・接続
# .streamlit/secrets.toml
[api]
key = "YOUR_API_KEY"
# 11_secrets.py
import streamlit as st
api_key = st.secrets["api"]["key"]
st.write("APIキー長:", len(api_key))
接続はst.connectionを前提に定義して使い回します(SQL/Snowflakeなど)。
12. ページ分割・構成
myapp/
├─ Home.py
└─ pages/
├─ 1_📊_Dashboard.py
└─ 2_⚙️_Settings.py
# Home.py
import streamlit as st
st.title("ホーム")
st.write("左上のメニューからページを切り替えられます。")
13. テスト(UI操作を自動化)
# 13_counter.py
import streamlit as st
if "count" not in st.session_state: st.session_state.count = 0
st.write(f"カウント: {st.session_state.count}")
if st.button("増やす"): st.session_state.count += 1
# 13_test_counter.py
from streamlit.testing.v1 import AppTest
def test_counter():
at = AppTest.from_file("13_counter.py").run()
at.button[0].click().run()
assert any("カウント: 1" in t.value for t in at.text)
14. ミニプロジェクト集(すぐ使える雛形)
14.1 CSV探索ダッシュボード
# 14_csv_explorer.py
import streamlit as st, pandas as pd, io
st.title("CSV Explorer")
upl = st.file_uploader("CSVを選択", type="csv")
if upl: df = pd.read_csv(upl)
else:
st.info("サンプルを使用")
df = pd.read_csv(io.StringIO("city,temp,hum\nTokyo,18,0.55\nOsaka,17,0.60\nNagoya,16,0.58\nFukuoka,20,0.65\n"))
st.dataframe(df)
cols = st.multiselect("可視化列", [c for c in df.columns if df[c].dtype!="O"])
if cols: st.bar_chart(df[cols])
st.download_button("CSV保存", data=df.to_csv(index=False), file_name="export.csv")
14.2 生成AI風Q&Aボット
# 14_qa_bot.py
import streamlit as st; from datetime import datetime
st.title("Q&Aボット(ダミー)")
if "messages" not in st.session_state: st.session_state.messages=[]
if "system" not in st.session_state: st.session_state.system = "あなたは親切なアシスタントです。"
with st.expander("システム指示"): st.session_state.system = st.text_area("役割", st.session_state.system)
for m in st.session_state.messages:
with st.chat_message(m["role"]): st.write(m["content"])
if prompt := st.chat_input("質問を入力"):
st.session_state.messages.append({"role":"user","content":prompt})
with st.chat_message("user"): st.write(prompt)
reply = f"[{datetime.now().strftime('%H:%M:%S')}] {st.session_state.system} → 回答: {prompt[:20]}..."
with st.chat_message("assistant"): st.write(reply)
st.session_state.messages.append({"role":"assistant","content":reply})
14.3 KPIダッシュボード(多タブ)
# 14_kpi_tabs.py
import streamlit as st, pandas as pd
st.title("KPIダッシュボード")
tab1, tab2 = st.tabs(["月次", "週次"])
df = pd.DataFrame({"日付": pd.date_range("2023-01-01", periods=10),
"売上": [1000,1200,900,1500,1300,1800,1700,1600,1900,2000]})
with tab1: st.line_chart(df.set_index("日付"))
with tab2:
df["増減"] = df["売上"].diff()
st.bar_chart(df.set_index("日付")["増減"])
15. つまずきやすいポイント(チェックリスト)
- ボタンは押した瞬間だけTrue。継続値は
st.session_stateへ。 - 入力中の画面チラつきが嫌ならフォームでまとめて送信。
- 重い処理は
@st.cache_data/@st.cache_resourceで再利用。 - 表は表示→
st.dataframe、編集→st.data_editor。 - レイアウトは列→タブ→サイドバーの順で整理。
- 公開前に最小テストを1本用意して回帰を防止。
- 機密はsecrets.tomlに置いてコードに直書きしない。
付録A:よく使うスニペット
import streamlit as st, time
st.toast("保存しました ✅"); st.caption("補足テキスト"); st.divider()
bar = st.progress(0);
for i in range(100): time.sleep(0.01); bar.progress(i+1)
# HTMLを最小限で
import streamlit as st
st.html("<p style='color:tomato'>HTMLレンダリング</p>")
# カラム幅の使い分け
import streamlit as st
left, main = st.columns([1,3]);
with left: st.write("サイド");
with main: st.write("メイン")
おわりに
小さく作って、すぐ動かして、少しずつ磨いていきましょう。
困ったらこのファイルのサンプルをコピペして、あなたのデータに置き換えるだけでOKです。
良いアプリ作りを!🚀