Streamlitでデータを可視化する


概要

  • データをインタラクティブに可視化できるWebアプリを作りたい
  • D3.jsなどを生で使うのはちょっと重たい(技術力的に)
  • そもそもWeb系の知識が謙遜抜きでほぼ0(Vue?React?なにそれ美味しいの?)
  • じゃあStreamlit使ってみよう

環境構築

こんな記事読まずに公式ドキュメントを読もうぜ。

インストール

pipでインストールします。

$ pip install streamlit

動作確認

$ streamlit hello

これでローカルに8063番ポート(デフォルト設定)でwebサーバが立ちます。
ということで、ブラウザでhttp://localhost:8063/にアクセスするとサンプルページを確認できます。

ちなみに、streamlitをimportしたpythonファイルでWebアプリを立ち上げたい場合には、以下のようにrunの後にpythonファイルを指定します。

$ streamlit run [python-file]

基本的な書式

公式ドキュメントが充実しているのでそちらを参照されるのが速いです。

ここでは雰囲気だけ。

テキスト

見出しは、streamlit.headersubheaderで指定できます。
文章は、streamlit.textや、streamlit.writeで書くことができます。
また、Markdownも使えます(streamlit.markdown)。

例えば

st.title('Sample page')
st.markdown('''
チョコボールの内容量

- ピーナッツ
  - 28g
''')

データフレーム(表)

pandas.DataFrameを使って表を描けます。
streamlit.tablestreamlit.dataframeを使います。st.dataframeは特定の条件でセルをハイライトできたり、ソートできたりと高機能です。

例えば

def rand_df(r=10, c=5):
    df = pd.DataFrame(
        np.random.randn(r, c),
        columns=('col %d' % i for i in range(c)))
    return df
dataframe = rand_df(c=3, r=2)
st.dataframe(dataframe)

グラフ

チャートなどの描画はstreamlitでチャートを描く方法とmatplotlibのfigureオブジェクトなどを描画する方法があります。

例えば

dataframe = ...
st.line_chart(dataframe)

デフォルトでカラム毎の折れ線グラフが描画されます。また、マウスホイールの操作で拡大/縮小ができたり、ドラッグすることで位置を動かしたりできます。(インタラクティブ!)

また、matplotlibに慣れている場合はstreamlit.pyplotでfigureオブジェクトを描画することもできます。当然seabornなども使えます。

fig = plt.Figure(figsize=(6,2))
ax = fig.subplots(1,1)
dataframe.plot(ax=ax)
st.pyplot(fig)

ただしこれだと拡大/縮小などはできないです(当然ですが)。
他にもbokehのチャートを描画できたりもしますし、いろいろサポートされているので公式ドキュメントを(以下略)

Widget

データの選択などが行える各種のWidgetが用意されています。

例えば

lst_flavors = ['ピーナッツ', 'いちご']
select_taste = st.selectbox('Flavor', lst_flavors)

プルダウンで選択項目が出てきます。
様々なものが用意されているので、ドキュメントを確認してください。

サイドバー

st.sidebar.xxxと指定するとサイドバーが左端に現れます。xxxには上記のコマンドがそのまま使えます。

例えば

st.sidebar.header('サイドバー')
p = st.sidebar.slider('確率の設定', min_value=0.0, max_value=1.0, value=0.8)
st.sidebar.write(f'設定値は {p} です')

こんな感じ。

キャッシュ

streamlitはWidgetなどで要素に変更があると、pythonファイルを上から順に全て実行しなおします。そのため、変更した要素に関係なくても、ちょっと重たい計算などをしていると毎回その処理が走ります。

そこで、関係する要素に変更が無ければキャッシュを利用するようにしたいです。
streamlitでは、@st.cacheデコレータを使います。

例えば

@st.cache
def rand_df(r=10, c=5):
    df = pd.DataFrame(
        np.random.randn(r, c),
        columns=('col %d' % i for i in range(c)))
    return df
dataframe = rand_df(c=7)

こうすれば、Widgetなどに変更があっても dataframeは更新されません。

サンプルソースコード

上で記載した例をそのまま使って、ただのサンプルなWebアプリを作ってみます。
e.g. sample.py

import numpy as np
import pandas as pd
import streamlit as st
import matplotlib.pyplot as plt

# テキストの描画
st.title('Sample page')
st.header('Header')
st.markdown('''
チョコボールの内容量

- ピーナッツ
  - 28g
- いちご
  - 25g
''')

@st.cache
def rand_df(r=10, c=5):
    df = pd.DataFrame(
        np.random.randn(r, c),
        columns=('col %d' % i for i in range(c)))
    return df
dataframe = rand_df(c=3, r=10)

# 表の描画
st.dataframe(dataframe.head(n=3))
# チャートの描画
st.line_chart(dataframe)
# widget
lst_flavors = ['ピーナッツ', 'いちご']
select_taste = st.selectbox('Flavor', lst_flavors)
# Sidebar
st.sidebar.header('サイドバー')
p = st.sidebar.slider('確率の設定', min_value=0.0, max_value=1.0, value=0.8)
st.sidebar.write(f'設定値は {p} です')

ローカルにテストサーバを立ててブラウザで確認してみます。

streamlit run src/sample2.py

これでこんな感じのアプリができます

おしまい

参考