36
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

StreamlitでPythonデータ分析ダッシュボードをサクッと作ってAWSにデプロイ

Last updated at Posted at 2020-04-12

はじめに

データを可視化して直観的に分析できるダッシュボードを作ってWebアプリとして公開したいです。
でもhtmlやcssやjsは面倒なのでいじりたくないです。
そんなとき、Streamlitなら面倒なことを一切抜きにして、Pythonスクリプト1つでデータ分析ダッシュボードを作成することができます。
この記事には、

  • アプリ作成の過程(インストール、データ準備、ダッシュボード作成)
  • AWS EC2インスタンスにデプロイしてみた手順

を残していきます。
こんな時期なので、題材としてはヤフー・データソリューションで公開されている東京23区内の人の往来が確認できるデータを眺めて、新型コロナ対策の影響を確認してみます。

アプリ作成

Streamlitのインストール

StreamlitはOSSです。
GitHub:https://github.com/streamlit/streamlit

インストールは以下でOK。

pip install streamlit

以下のコマンドを実行すると、ローカルでデモアプリを立ち上げてブラウザで確認することができます(ブラウザが勝手に立ち上がります)。

streamlit hello

image.png

使い方については、公式のチュートリアルページがわかりやすいです。
こちらの解説記事もどうぞ。

【追記】
こちらも参考になります。

データ準備

こんな時期なので、新型コロナ対策が東京都内の人流にどんな影響を与えているのか見てみたくなりますよね。
それっぽいデータを探してみたところ、ヤフーデータソリューション
「東京23区滞在人口推計値の日別遷移(全体・来訪者・住人)」データが
オープンデータとして公開されていました(2020年4月10日現在)。
今回はこれをいい感じに可視化してみることにします。

【出典:ヤフー・データソリューション(https://ds.yahoo.co.jp/report/, 2020/04/09)】
データは毎日更新されています。ここでは、2020年4月9日までのデータを用いています。

元データはエクセル形式で、日毎の東京23区の住人数・来訪者数・全体数が含まれます。
これが月毎に別々のシートに保存されているので、予めcsvに変換しておきます。

これをそれぞれ読み込み、一つにまとめます。

import numpy as np
import pandas as pd

data_02 = pd.read_csv('東京23区推移0409_2月.csv')
data_03 = pd.read_csv('東京23区推移0409_3月.csv')
data_04 = pd.read_csv('東京23区推移0409_4月.csv')

data_all = pd.concat([data_02, data_03.iloc[:, 2:], data_04.iloc[:, 2:]], axis=1)
data_all.head()
エリア 対象分類 2月1日 2月2日 2月3日 2月4日 2月5日 2月6日 2月7日 2月8日 ... 3月30日 3月31日 4月1日 4月2日 4月3日 4月4日 4月5日 4月6日 4月7日 4月8日
0 東京23区全体 全体 10485000 10164000 11676000 11687000 11659000 11690000 11691000 10471000 ... 11393000 11388000 11288000 11263000 11256000 10021000 9737000 11212000 11104000 10859000
1 NaN 住人 8921000 8921000 8921000 8921000 8921000 8921000 8921000 8921000 ... 8949000 8949000 8924000 8924000 8924000 8924000 8924000 8924000 8924000 8924000
2 NaN 来訪者 1564000 1243000 2755000 2766000 2738000 2769000 2770000 1550000 ... 2444000 2439000 2364000 2339000 2332000 1097000 813000 2288000 2180000 1935000
3 千代田区 全体 454900 356900 1028900 1039900 1031900 1043900 1041900 453900 ... 857000 855000 819500 802500 791500 266500 195500 775500 731500 624500
4 NaN 住人 54900 54900 54900 54900 54900 54900 54900 54900 ... 56000 56000 55500 55500 55500 55500 55500 55500 55500 55500

エリア、対象分類をMultiIndexとして整理し、出力します。

data_all.fillna(method='ffill', inplace=True)
data_all.set_index(['エリア', '対象分類'], inplace=True)

data_all.to_csv('tokyo_0409.csv', index=True, header=True)

最終的なデータはこんな感じ。

data_all.head(7)
2月1日 2月2日 2月3日 2月4日 2月5日 2月6日 2月7日 2月8日 2月9日 2月10日 ... 3月30日 3月31日 4月1日 4月2日 4月3日 4月4日 4月5日 4月6日 4月7日 4月8日
エリア 対象分類
東京23区全体 全体 10485000 10164000 11676000 11687000 11659000 11690000 11691000 10471000 10149000 11523000 ... 11393000 11388000 11288000 11263000 11256000 10021000 9737000 11212000 11104000 10859000
住人 8921000 8921000 8921000 8921000 8921000 8921000 8921000 8921000 8921000 8921000 ... 8949000 8949000 8924000 8924000 8924000 8924000 8924000 8924000 8924000 8924000
来訪者 1564000 1243000 2755000 2766000 2738000 2769000 2770000 1550000 1228000 2602000 ... 2444000 2439000 2364000 2339000 2332000 1097000 813000 2288000 2180000 1935000
千代田区 全体 454900 356900 1028900 1039900 1031900 1043900 1041900 453900 356900 958900 ... 857000 855000 819500 802500 791500 266500 195500 775500 731500 624500
住人 54900 54900 54900 54900 54900 54900 54900 54900 54900 54900 ... 56000 56000 55500 55500 55500 55500 55500 55500 55500 55500
来訪者 400000 302000 974000 985000 977000 989000 987000 399000 302000 904000 ... 801000 799000 764000 747000 736000 211000 140000 720000 676000 569000
中央区 全体 441000 367000 849000 857000 852000 861000 863000 440000 370000 793000 ... 733000 728000 701000 691000 684000 307000 256000 675000 641000 563000

ダッシュボード作成

ここから、実際にダッシュボードを作っていきます。
Streamlitでは、ダッシュボードを1つのPythonスクリプトのみで作ることができます。
今回はstreamlit_app.pyとしてスクリプトを書いていきます。

データの中身をラインチャートで表示します。
セレクトボックスで対象地域を指定し、その地域の住人・来訪者・全体数の時系列推移を見ることができる仕様にします。

streamlit_app.py
import numpy as np
import pandas as pd
import streamlit as st
import plotly.graph_objects as go

st.title('東京23区滞在人口推計値の日別遷移')
st.write('【出典:ヤフー・データソリューション】')

data_all = pd.read_csv('data/tokyo_0409.csv')
erea_list = data_all['エリア'].unique()

data_all.set_index(['エリア', '対象分類'], inplace=True)

# 値を縦持ちに変更
data_all = data_all.T
# 日付をdatetime型に変換
data_all.index = map(lambda x: '2020年'+x, data_all.index)
data_all.index = pd.to_datetime(data_all.index, format='%Y年%m月%d日')
data_all.index.name = '月日'

# 表示エリアをセレクトボックスで選択
selected_erea = st.sidebar.selectbox(
    '表示するエリアを選択:',
    erea_list
)

# グラフ表示
st.write(f'## 表示中:{selected_erea}')
data_plotly = data_all[(selected_erea)]
data_plot = [
    go.Scatter(x=data_plotly.index,
               y=data_plotly['住人'],
               mode='lines',
               name='住人'),
    go.Scatter(x=data_plotly.index,
               y=data_plotly['来訪者'],
               mode='lines',
               name='来訪者'),
    go.Scatter(x=data_plotly.index,
               y=data_plotly['全体'],
               mode='lines',
               name='全体')]
layout = go.Layout(
    xaxis={"title": "日付"},
    yaxis={"title": "人数"}
)
st.plotly_chart(go.Figure(data=data_plot, layout=layout))


image.png

streamlitモジュールのst.write()メソッドなどを使って、
画面に表示する文字列やテーブル、グラフを定義していきます。

また、対話的な処理として、st.selectbox()で対象地域の選択肢を表示し、
ユーザが選択した値を返り値としてselected_ereaに持つことで、
対応する地域の情報をグラフ描画しています。
st.sidebarで画面左側のサイドバーに要素を配置できて、ちょっと見た目がいい感じに。

グラフ表示には、st.line_chart()など簡便なメソッドが用意されていますが、
日付等をうまく扱えなさそうだったので、
今回はPlotlyで対話的なグラフを作成してそれを描画するst.plotly_chart()を使っています。

その他にStreamlitの特徴的な機能としては、
st.map()で地図上にデータをプロットできたり、
st.progress()で時間がかかる処理に対してプログレスバーを表示できたりします。
このあたりも使って作り込んでみたかったですが、今回は割愛。

htmlをまったく意識せずに、短いPythonスクリプトだけで画面を作っていけるのは便利ですね。

AWSにデプロイ

想定されている使い方としては、手元のデータをサクッと確認したり結果をチームで共有したり、
っていうくらいかと思いますが、せっかくなのでAWS EC2インスタンスにデプロイしてテスト公開してみます。

手順:
1: AWS EC2無料枠のt2.microインスタンスを立てる
2: インスタンス内でアプリ実行

streamlit run streamlit_app.py

3: (必要に応じて)ドメイン取得
 今回は無料ドメインサービスのfreenomで適当なドメイン名onedata.gaを取得しました。
 (「.tk」、「.ml」、「.ga」、「.cf」、「.gq」ドメインが無料で取得できます)

4: streamlitのconfigファイル編集
~/.streamlitフォルダ内にある設定ファイル(config.toml)に、
アクセス用のアドレスとして取得したドメイン名を記入しておきます。

[browser]
gatherUsageStats = false
serverAddress = "onedata.ga"

[server]
port = 8501

5: 80番から8501番へポート転送
streamlitはデフォルトでは8501番ポートで通信を受け付けます。
ドメイン名でポート指定せずアクセスするためにデフォルトの80番ポートからアクセスできるようにしたいのですが、
そのためにはアプリ実行時にroot権限が必要になります。
そこでここでは、iptablesをいじって80番ポートへのアクセスを8501番ポートへ転送することで対応します。

sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8501

6: 80番ポートの開放
EC2ダッシュボードのセキュリティグループ>インバウンドルールを編集し、80番ポートを開放しておきます。

作ったアプリがこちら↓
http://onedata.ga
(20230326追記:EC2料金節約のため停止中です)

実装↓
https://github.com/tkmz-n/streamlit_app

まとめ

Streamlitを使ってオープンデータを可視化する簡単なデモアプリを作成し、
AWSにデプロイして公開するまでをやってみました。

データを見ると、東京23区内の人の往来は3月末あたりから徐々に減りつつあることが確認できます。
新型コロナの一刻も早い収束を目指して、引き続きおうちに籠もりましょう。

36
47
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
36
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?