【Streamlit入門】Streamlitのよく使うメソッドと実装例

## Streamlitの基本
### Streamlitの概要
`Streamlit`は動的かつ簡易的なWebアプリケーションを作成するにあたって有用な`Python`のライブラリです。

https://streamlit.io/

`Streamlit`を用いることでグラフなどを画面からの入力に基づいて動的に変化させることができるのでデモの作成などに用いられることが多いです。


### Streamlitのインストールとサンプルコードの実行
`Streamlit`は下記を実行することでPyPIから入手することができます。

```
$ pip install streamlit
```

次に`Streamlit`のサンプルコードを実行します。

```python:sample.py
import streamlit as st

st.title('Hello Streamlit!')
```

上記のようなコードを`sample.py`に保存し、下記のコマンドを実行することで`Streamlit`の動作確認を行うことができます。

```
$ streamlit run sample.py
```

・実行結果
```
  You can now view your Streamlit app in your browser.

  Local URL: http://localhost:8501
  Network URL: http://192.168.2.126:8501

gio: http://localhost:8501: Operation not supported
```

実行後にブラウザから`http://localhost:8501`にアクセスすると下記のような画面が確認できます。

![Streamlit1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/d5dd71a9-14be-4e86-9b2f-58f6f91d23e0.png)

上記の画面が出力されていれば`Streamlit`のインストールは成功しているので詳しい実装例については次節で取り扱います。

### Streamlitのよく使うメソッド
#### 画面出力
| メソッド名 | 概要 |
| --- | --- |
| `st.title` |  |
| `st.header` |  |
| `st.subheader` |  |
| `st.text` |  |
| `st.write` |  |
| `st.dataframe` | データフレームの出力(`pandas`) |


#### 画面からの入力
| メソッド名 | 概要 |
| --- | --- |
| `st.button` | ボタン |
| `st.checkbox` | チェックボックス |
| `st.radio` | ラジオボタン |
| `st.selectbox` | Select Box |
| `st.slider` | スライドで値を指定 |
| `st.textinput` | テキスト入力 |



## 実装例
### 基本的な関数のグラフの出力
```python
import pandas as pd
import streamlit as st
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier, plot_tree

sns.set_theme()


def plot_linear(coef0, coef1):
    fig, ax = plt.subplots()
    x = np.linspace(-2.5, 2.5, 100)
    y = coef1 * x + coef0
    plt.plot(x, y)
    st.pyplot(fig)

def plot_quadratic(coef0, coef1, coef2):
    fig, ax = plt.subplots()
    x = np.linspace(-2.5, 2.5, 100)
    y = coef1*x**2 + coef2*x + coef0
    plt.plot(x, y)
    st.pyplot(fig)

def plot_cubic(coef0, coef1, coef2, coef3):
    fig, ax = plt.subplots()
    x = np.linspace(-2.5, 2.5, 100)
    y = coef1*x**3 + coef2*x**2 + coef3*x + coef0
    plt.plot(x, y)
    st.pyplot(fig)

def plot_exp(coef1):
    fig, ax = plt.subplots()
    x = np.linspace(-2.5, 2.5, 100)
    y = coef1**x
    plt.plot(x, y)
    st.pyplot(fig)

def plot_log(coef1):
    fig, ax = plt.subplots()
    x = np.arange(0.1, 10.1, 0.01)
    if coef1 == "2":
        y = np.log2(x)
    elif coef1 == "e":
        y = np.log(x)
    elif coef1 == "10":
        y = np.log10(x)
    plt.plot(x, y)
    st.pyplot(fig)


st.header("Graph Type")
option_radio = st.radio(
    "", 
    ["linear", "quadratic", "cubic", "exp", "log"]
)
st.write("Option: {}".format(option_radio))

if option_radio == "linear":
    coef1 = st.slider("Select a slope", -5, 5, 0)
    coef0 = st.slider("Select a intercept", -5, 5, 0)
    plot_linear(coef0, coef1)
elif option_radio == "quadratic":
    coef1 = st.slider("Select a coef1", -5, 5, 0)
    coef2 = st.slider("Select a coef2", -5, 5, 0)
    coef0 = st.slider("Select a coef0", -5, 5, 0)
    plot_quadratic(coef0, coef1, coef2)
elif option_radio == "cubic":
    coef1 = st.slider("Select a coef1", -5, 5, 0)
    coef2 = st.slider("Select a coef2", -5, 5, 0)
    coef3 = st.slider("Select a coef3", -5, 5, 0)
    coef0 = st.slider("Select a coef0", -5, 5, 0)
    plot_cubic(coef0, coef1, coef2, coef3)
elif option_radio == "exp":
    coef1 = st.slider("Select a coef1", 0.01, 5.0, 2.0)
    plot_exp(coef1)
elif option_radio == "log":
    coef1 = st.radio(
        "Basis value", 
        ["2", "e", "10"]
    )
    plot_log(coef1)
```

・実行結果(ブラウザの画面)
![Streamlit2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/14b7fac1-621c-42fa-9ee5-88052e79319b.png)


### 決定木の構築結果の可視化
```python
import streamlit as st
import matplotlib.pyplot as plt

from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier, plot_tree


iris = load_iris()
X, y = iris.data, iris.target
 
model = DecisionTreeClassifier()
model.fit(X, y)

def plot_model():
    fig, ax = plt.subplots()
    plot_tree(model)
    st.pyplot(fig)

if st.button('Plot Tree'):
    plot_model()
```

・実行結果(ブラウザの画面)
![Streamlit3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/9c0e31fc-9000-4f6c-8266-edffbf804a25.png)


### グラフとNetworkX
```python
import pandas as pd
import streamlit as st
import numpy as np
import networkx as nx
import matplotlib.pyplot as plt
import seaborn as sns

sns.set_theme()


st.title("Visualize Graph by using NetworkX")

num_nodes = st.number_input("Input a number of nodes", value=7)
e0 = st.text_input("Input(node1-node2,node1-node3,...)", "1-2,1-3,1-4,1-7,2-6,5-7")
e1 = e0.split(",")

edges = []

for i in range(len(e1)):
    e2 = e1[i].split("-")
    edges.append(tuple([int(e2[0]), int(e2[1])]))


def plot_graph():
    fig, ax = plt.subplots()
    G = nx.DiGraph()
    G.add_nodes_from(list(range(1, num_nodes+1)))
    G.add_edges_from(edges)
    nx.draw(G, with_labels=True, font_weight="bold")
    st.pyplot(fig)
    
if st.button("Plot graph"):
    plot_graph()
```

・実行結果(ブラウザの画面)
![Streamlit_NetworkX.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936087/0774eea3-4268-449d-a69a-e5b8cd05002b.png)