PythonだけでWebができる「Streamlit」を使ってみたはなし

# はじめに

この記事は JSL (日本システム技研) Advent Calendar 2020 - Qiita 20日目の記事です。

毎年恒例、一人アニバーサリー記念です。:tada:
この歳になっても迷ってばかりの日々を送っております・・。

普段、開発の仕事をしなくなって久しいので、何を書くか悩みましたが
先日、参加した「[みんなのPython勉強会](https://startpython.connpass.com/event/195410/) 」 でnikkieさんが紹介していた`Streamlit`が面白そうなので使ってみた話をします。

# Streamlitとは
[Streamlit](https://www.streamlit.io/) は、Pythonコードでフロントエンド（Web）が書けるライブラリであり、サービスのようです。

# 今回のゴール
+ Streamlitの公式チュートアルをやりつつ、[Connpass API](https://connpass.com/about/api/) を
使って、直近のイベントデータを表示してみたいと思います。

# 各種バージョン

+ Python:3.8.0
+ Streamlit:3.9.2
+ Pandas:1.1.5

# インストール

```
$ pip install streamlit
```
# チュートリアルをいじってみる
## Hello App

```
$ streamlit hello
```
とすると、プロジェクトが作成されます。
ブラウザが起動し、以下のようなデモサイトを構築できます。

![Screen Shot 2020-12-14 at 9.47.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20512/21f1f0dc-ff5f-59ee-6967-3c7db34b073b.png)

## streamlitプロジェクトの作成

チュートリアルに従い以下のように`streamlit`や各種ライブラリをimportして

`streamlit run [ファイル名]`とするとブラウザが起動します。

```
import streamlit as st

import numpy as np
import pandas as pd

```

## インタラクティブに反映されることを確認する

このような感じにタイトルと、PandasのDataFrameに渡すだけで、インタラクティブにブラウザが更新されます！。

```
st.title('My first app')

st.write("Here's our first attempt at using data to create a table:")
st.write(pd.DataFrame({
    'first column': [1, 2, 3, 4],
    'second column': [10, 20, 30, 40]
}))
```

![Screen Recording 2020-12-14 at 10.48.50.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20512/ad296380-3e50-fba0-8d3e-cb12bd87955e.gif)

## Magic command

`write`関数以外にも`Magic commands`という機能が用意されていて、以下のように変数を書くだけでも`write`関数と同様の挙動になるようです。

```
df = pd.DataFrame({
  'first column': [1, 2, 3, 4],
  'second column': [110, 200, 300, 400]
})

df

x=10

x
```

こんな感じでゴリゴリ**Pythonだけ**で生成されていきます！

![Screen Shot 2020-12-14 at 11.23.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20512/b25b2799-f0a7-4b7f-5f28-31ab4935257e.png)

# Connpass APIからのデータ取得

ざっとチュートリアルをいじってみただけでも色々できそうなので、「Connpass API」から当社が運営する「[GEEKLAB.NAGANO](https://glnagano.connpass.com/)」のデータを取得してイベント情報の表示をしてみました。

```geeklab_eventlist.py 
import streamlit as st

import pandas as pd
import requests, io
from datetime import datetime, date, timedelta
from dateutil.relativedelta import relativedelta
from PIL import Image

st.title('ギークラボイベント開催一覧')

image_url = 'https://connpass-tokyo.s3.amazonaws.com/thumbs/72/9d/729d521ab794e98b4427e9040e8f2fe9.png'
image = Image.open(io.BytesIO(requests.get(image_url).content))
st.image(image, use_column_width=True)

today = datetime.today()
startdate = datetime.strftime(today, '%Y%m')
enddate = "201402"

target_date_set = ['全件'] 
target_date_set.append(startdate)

while startdate > enddate:
  dt = datetime.strptime(startdate, '%Y%m') - relativedelta(months=1)
  startdate = dt.strftime("%Y%m")
  target_date_set.append(startdate)

yyyymm = st.selectbox(
    'イベント開催年月',
    target_date_set
     )

count = st.slider('取得件数', 0, 100, 10)
keyword = st.text_input('キーワード', '')

r = requests.get(f'https://connpass.com/api/v1/event/?series_id=2591&count={count}&ym={yyyymm}&keyword={keyword}')

titles = []
event_date_set = []
participants = []
owners_name = []

for e in r.json()["events"]:
  titles.append(e["title"])

  dt = datetime.fromisoformat(e["started_at"])
  event_date_set.append(datetime.strftime(dt, '%Y/%m/%d'))
  participants.append(e["accepted"])
  owners_name.append(e["owner_display_name"])

df = pd.DataFrame({
  'タイトル': titles,
  '開催日': event_date_set,
  '参加者数': participants,
  '管理者':  owners_name
})
df.style.set_properties(**{'text-align': 'center'})

df
```

たったこれだけのPythonコードで、ここまで出来るのはスゴイ！！

![aaa.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20512/2be2f520-3667-319b-5b92-ba279ef2ddd5.gif)

# 制限事項
試している中で気づいた制限事項をまとめます。

+ 1ファイル当たり同一のwigetは定義できない
    + 例） `selectbox` を２つ定義する


# デプロイ 
`https://share.streamlit.io/`に`requirements.txt`を含めたGitHubリポジトリを紐付けてあげるとデプロイできます。
週単位で招待メールを通知されるようで、利用できるまで少し時間がかかります。

招待メールが来たら必要事項を入力しているだけで、[こんな感じ](https://share.streamlit.io/y-nakazawa/streamlit_demo/geeklab_eventlist.py
) にデプロイしてくれます。

![Screen Shot 2020-12-19 at 22.13.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20512/f26ce1c2-2959-a27f-beb9-206154eab8c0.png)

# さいごに
久々の勉強会参加から、`Streamlit`を触ってみましたが、使ってみて**「楽しい」**、**「スゴイ！！」**と思えるライブラリに出会えました。若干制限事項はあるものの、データの見えるかを手っ取り早くできる良い仕組みだと思いました。

なにより**Pythonオンリー**で書けるのが良い。

キャッチアップを個人でやり続けるのは、辛いので定期的に勉強会参加することの重要性を再認識した次第です！！。この場をお借りして、nikkieさんに感謝です！！