AIでStreamlitのダッシュボードを標準の部品だけで作る手順|Streamlit in Snowflakeの検証
今回は、AIで月次売上ダッシュボードをStreamlit in Snowflakeの標準の部品だけで作りました。HTMLとCSSは1行も書いていません。
お題は「とある町中華」の月次売上を定点観測する1枚です。数字はダミーで、データは弊社のSnowflakeに置きました。手本はPCの1440×900で、寸法、色、文字を指定しています。
作成はAIが担当し、約14分かかりました。手本は先に用意してあったので、この時間は手本を作る時間を含みません。コードは197行です。見やすい1枚にはなりましたが、1画面には収まらず、採点役の2人とも必須条件を不合格としました。
この記事は弊社の検証記録で、StreamlitやSnowflakeの公式手順ではありません。
手本の画面

手本:先に用意した設計の画面(PC 1440×900)。この画面にどこまで近づけるかを測りました。数字はダミーです
完成した画面

図1:表示域の幅を1440にし、高さを広げて全体を撮った画面。数字はダミーです
月を変える操作は3通りです。プルダウン、前の月・次の月のボタン、月別売上の棒を押す操作で、どれも実際に押して切り替わることを確かめました。プルダウンは3回試して3回とも切り替わりました。
使った部品
| 場所 | 部品 |
|---|---|
| 題名と月の操作 | `st.columns`、`st.markdown`、`st.button`、`st.selectbox` |
| KPI 4枚 | `st.metric`(枠、前月比、推移線) |
| 月別売上 | `st.altair_chart`(積み上げ棒、棒を押して選ぶ) |
| 曜日×時間 | `st.altair_chart`(マスと数字) |
| 売れ筋 | `st.dataframe` の `ProgressColumn` |
| 滞在の長さ別 | `st.dataframe`、`st.metric` |
| 注記 | `st.caption` |
`st.metric`、`st.dataframe` は、Snowflakeのダッシュボードの例にも出てくる部品です。この例はHTMLもCSSも書いていません。
公式の例と違うところ
部品は標準ですが、アプリの置き方は公式の例と違います。
| 項目 | 公式の例 | 今回 |
|---|---|---|
| 動かす場所 | コンテナのランタイム | ウェアハウスのランタイム |
| データへのつなぎ方 | `st.connection(“snowflake”)` | `get_active_session()` |
| グラフ | Plotly | Altair |
コンテナのランタイムでは、キャッシュを見る人全員で共有できます。ウェアハウスのランタイムでは、セッションごとです(制限の一覧)。今回はコンテナのランタイムを試していません。
手順1 版を指定して色を決める
`environment.yml` でStreamlitの版を1.52.2に指定しました。色はCSSを書かず、`.streamlit/config.toml` のテーマで決めます。
[theme]
base = "light"
primaryColor = "#3D4070"
backgroundColor = "#F7F9FC"
secondaryBackgroundColor = "#FFFFFF"
textColor = "#1E2430"
ファイルはステージの `.streamlit/` の下に置きました。
手順2 KPIはst.metricに任せる
枠、前月比、推移線が1つの部品で出ます。この記事のコードは要点だけの抜粋です。
st.metric("売上", "207.5万円", delta="-3.9%", border=True,
chart_data=values, chart_type="line")
`values` は全10か月の値のリストです。前月比の矢印と色は、先頭の半角マイナスで決まるので、手本のU+2212のマイナスは使えませんでした。推移線の色も前月比の色に従うため、月によって赤か灰色になります。選んだ月の点も置けません。
手順3 棒を押して月を変える
Altairの棒グラフに選択を付けます。`on_select` に関数を渡すと、画面を描き直す前に月を変えられます。下の `bars` は月別の表、`on_bar` は選ばれた月を書き込む関数です。
pick = alt.selection_point(name="pick", fields=["MON"], on="click", toggle=False)
chart = alt.Chart(bars).mark_bar(size=40).encode(
x=alt.X("軸:N", sort=None),
y=alt.Y("sum(金額):Q", axis=None),
color="区分:N",
detail="MON:N",
).add_params(pick)
st.altair_chart(chart, on_select=on_bar, selection_mode="pick", key="bar")
初回は棒を押すと `KeyError: MON` のエラーになり、選択の結果に `MON` が入っていませんでした。`detail=”MON:N”` を足すと動きました。
棒の上の合計は、文字を重ねたグラフだと選択を受け取れないので、月の軸の文字に入れています。そのため合計は棒の下に出ます。
手順4 表はst.dataframeの列の設定で作る
金額と割合の棒は `ProgressColumn` で出します。▼の赤はpandasの `Styler` で付けました。行の高さは `row_height` で詰めています。下の `tbl` は売れ筋の表、`red` は▼に色を付ける関数、`top` は1位の金額です。
st.dataframe(tbl.style.map(red, subset=["前月"]), hide_index=True,
height=311, row_height=28,
column_config={"金額(円)": st.column_config.ProgressColumn(
format="localized", min_value=0, max_value=top, width=160)})
幅1440で見ると、最初は右の列が切れました。列の幅を数字で指定して直しています。
確かめたこと
全10か月の写真を撮り、KPI、月別売上の合計と営業日、曜日×時間、売れ筋、滞在の長さ別を採点役が正解値と比べました。数字の不一致は0件でした。長い品名は3か所で末尾が切れていて、切れた部分は読めていません。集計のSQLは、別の作り方で全月を確かめたものと同じです。
採点の結果
採点役はAIの2人です。作り手と製品名を伏せ、出来ばえを96点満点、手本の再現度を100点満点で採点しました。
| かかった時間 | 必須条件 | 出来ばえ(2人分) | 再現度(2人分) |
|---|---|---|---|
| 約14分 | 2人とも不合格 | 72/61 | 47/47 |
不合格の理由は2つです。スクロールが要ることと、長い品名が切れることです。品名は列の幅を160pxにした状態でも切れていて、さらに広げる直しは試していません。
時間には、画面を開く許可を人が出すのを待った分と、棒の不具合、表の幅の直しを含みます。
うまくいかないこと
1画面に収まりません
全体の高さが約1170pxになりました。KPIの推移線の高さと表の高さが効いていて、標準の部品だけでは詰めきれません。

図2:Snowsightの外枠の中で開いた画面。下は表示域の外です。数字はダミーです
Snowflakeの画面の外枠の分も差し引かれます。同じ環境で別のアプリを測ったときは、1440×900の窓でアプリに使える表示域は1383×806でした。
座標は指定できません
`st.columns` は比率で並べるので、手本の座標には合いません。差し色の4か所も置けません。
説明の箱はグラフだけです
月別売上と曜日×時間には説明の箱が出ます。表の行には出ません。

図3:月別売上の棒に乗せたときの説明の箱。数字はダミーです
まとめ
- 標準の部品だけで、KPI、グラフ、表、月の切り替えまで約14分で作れました。
- 色はテーマの設定で決められ、CSSは要りませんでした。
- 手本の座標どおりの配置と1画面への収まりは、標準の部品では届きませんでした。
関連する記事
- BIダッシュボードをAIで作る比較|プログラムを書く4通りと画面を操作する2通り
- AIでStreamlitのダッシュボードを作る手順(HTMLとCSSで手本に合わせる)
- AIでStreamlitのダッシュボードを標準の部品だけで作る手順
- Streamlit in Snowflakeは標準の部品とHTMLのどちらで作るか
- Streamlit in Snowflake で、セマンティックビューから月次画面を作る

