社内教育で簡単な汎用streamlitアプリ作成する

# まずは自己紹介
初めまして。某化学メーカーに勤務していながら、AIやプログラミング、AWSによるインフラ関係の業務をやっています。
バックグラウンドは生粋の化学っ子でしたが、

上司「○○君。パソコンできる？」
僕「まあ、検索したりWordやパワポあたりなら…」
上司「いいね！じゃあAIやってみようか！」
僕「阿保か？（わかりました！！！）」

というわけで、化学メーカーに研究職として入社するも、入社2年目にしてジョブチェンジを果たしました。
と言っても、最初の1年は敬遠し続けてたので、実際にハマるのはその1年後でしたが…
AIと言っても、機械学習のモデルをpythonで書いたり、AWSのsagemakerを使ってモデル作ったりする程度です。
他には、AWSのEC2やECS、VPCを使用したWebアプリケーションの実装らへんを最近手掛けているところです。
そんなこんなで、かれこれ1年2か月程度のAI・プログラミング歴となりました。

# この記事の目的
昨今、AIの進化が止まらず、たくさんの企業でAIを業務に取り入れる動きが見られます。
その競争に負けないためには、AIに対して抵抗感をなくしておくのはアリなのでは？と思い立ち

僕「上司さん、AIやpythonの基礎知識の教育しませんか？」
上司「全社向けにやってみようか」
僕「おいおいデカくなりすぎてないか？（わかりました！！！）」

ということで、若手向けに教育することになりました（入社4年目）。
そんな教育の中で、streamlitというpythonライブラリであるフレームワークを使用したWebアプリケーションを作成するので、それを備忘録として残しておこうといったのが目的です。

streamlitについて興味のある方は、下記公式ページを参考にどういったことができるか確認してみてください。

https://streamlit.io/

# どういったアプリを作るのか
化学メーカーで働いているということもあり、実験をしたらデータが出てきます。
そのデータをExcelで可視化するのが面倒だなと思ったことがあります。
他の社員からも簡単に可視化したいとの要望があったりもします。
そこで、
### 可視化が簡単にできるアプリを作ろう！！！
ということで、streamlitで簡単なアプリを作っていきます。

作成環境は以下です。
- vscode
- python（ver3.11）

# 実装していく
まずはvscodeでpythonファイルを作成します。このファイルの名前は正直適当でいいです。どんなアプリか把握できればいいと思います。今回は便宜上 'app.py' とします。

ターミナル上で以下のコマンドを入力してください。

```
$ pip install streamlit pandas plotly
```

streamlitと一緒に、データを読み込むためにpandas、可視化するためにplotlyをインストールします。
今回、plotlyを選択した理由は3次元プロットを作成したり、インタラクティブなグラフを作成したかったためです。

では、さっそくコードを書いていきましょう。

```python
import streamlit as st
import pandas as pd
import plotly.express as px
```
必要なライブラリをインポートします。
plotlyはgraph_objectでもよかったんですが、初心者にも書きやすいexpressを使います。

次に、ページの設定をしていきます。

```python
st.set_page_config(page_title='Graph',layout='wide')
```
ページのタブを"Graph"として、レイアウトをワイドモードに設定しました。

では、タイトルを書いていきます。
```python
st.title('Graph App')
st.subheader('データを可視化しよう！')
```

ここまで書いて、ターミナル上で以下のコマンドを入力してください。

```
$ streamlit run app.py
```
すると
![streamlit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/9198e2e5-89f7-7c77-9fe5-8d75e3f5792a.png)
このようにURLが2つターミナル上に出てきます。
上の「Local URL」をクリックして、アプリを開いてみてください。

![app2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/291e6fc2-4528-443f-d490-a31ff869d881.png)

開けていますね。
ここで右上の設定を開きましょう。
![se.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/24ad97c1-0277-ae8d-729b-44a6c491c01a.png)

設定の「Settings」を押して、
![app.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/48e7a15b-1a81-fcfa-620c-13392f4b5023.png)
「Run on save」にチェックを入れてください。
こうすることで、pythonファイルを保存すると自動でページが更新されるようになります。
いちいち、ファイルを編集する度にページを更新するの面倒なので…


いよいよ中身を書いていきます！！！

```python
uploaded_file = st.sidebar.file_uploader('csvファイルを読み込んでください',type='csv')

if uploaded_file:
    df = pd.read_csv(uploaded_file)
    st.dataframe(df)
```
今回はcsvファイルのデータを可視化するので、ファイルを読み込むためのウィジェットを作成します。
.sidebarとすることでサイドバーにウィジェットを作成することができます。
ここではcsvファイルを読み込ませたいのでtypeの指定を忘れずにしておきましょう。

読み込ませるデータは、ネットにあるサンプルデータでもよかったんですが、せっかくなので自力で作ってみました。
![data.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/37fc5ddb-d5ba-3b49-3438-cb95fe15a4f5.png)

ごめんなさい。
自力とか言いながらChatGPT様に頼りました。
さあ、これで準備は整ったのでcsvファイルをダウンロードして、実際にアプリにアップロードしてみましょう。![data表示.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/d2473439-9872-ae2e-d16a-9797b34ea88b.png)

表示されましたね。
このデータを使って、可視化していきましょう！

今回は、散布図、折れ線グラフ、棒グラフの3つを作成してみましょう。
y軸は複数選択できるようにし、グラフの比較を行えるようにしてみます。
散布図についてはz軸を選択した場合、3次元プロットを作成することにします。

```python
columns = df.columns.tolist()
x_column = st.selectbox('x軸を選択してください',columns)
y_column = st.multiselect('y軸を選択してください(複数選択可)',columns)
z_column = st.selectbox('z軸を選択してください',[None] + columns)
plot_type = st.radio('グラフの形式を選択してください',['scatter','line','bar'])
```

ここで、z_columnで[None]というリストを追加していますが、df.columnsに対して追加しようとした場合、TypeErrorが発生します。これは、私も自信はないのですが、df.columnsの型はただのリスト型ではない？ために起きているようです。そのため、リスト型へ変換して追加することでエラーコードを解消できます。

では、アプリの方を確認してみましょう。
![１.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/bf5fa6ca-1036-916b-bb36-591fe05f1a91.png)
できていますね。

z軸についてはデフォルトで「None」を選択し、カラムを選択したときに3次元プロットが作成されるようにしています。

それでは、最後にグラフを作成していきましょう。
```python
def create_plot(df,x_column,y_column,z_column,plot_type):
    if plot_type == 'scatter':
        if z_column :
            fig = px.scatter_3d(df,x_column,y_column[0],z_column)
        else:
            fig = px.scatter(df,x_column,y_column)
    if plot_type == 'line':
        fig = px.line(df,x_column,y_column)
    if plot_type == 'bar':
        fig = px.bar(df,x_column,y_column)
    
    return fig

st.plotly_chart(create_plot(df,x_column,y_column,z_column,plot_type))
```
今回はグラフの形式を条件分岐としています。散布図を選択したときに限り、z軸の有無で分岐させています。
また、私の勉強不足かもしれませんが、plotlyの3次元プロットでは各軸で1つのカラムしか渡せないのか、y軸を複数選択していた場合、エラーが発生します。
そのため、複数選択していた場合でもリストの1つ目を指定するようにしています。
（何かわかる方がいましたらご教授ください！）

では、アプリを確認してみましょう。
![２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/353e859a-b988-c1f7-b97e-eea806feff0f.png)

![３.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/61ce9917-d636-4168-93ee-540f1e4793ee.png)

ちゃんと比較もできて、3次元プロットも生成されてますね。
折れ線グラフは時系列データを可視化する際に使用するくらいかな？
~~棒グラフはなぜか積み立てになってしまうんですよねえ…
横に並べたい場合、どうすればいいか知ってる方いましたら教えていただけると嬉しいです（plotlyのドキュメント見ろ）。~~

引数に`barmode`を`group`で指定すれば横に並べられました！
```python
if plot_type == 'bar':
    fig = px.bar(df,x_column,y_column,barmode='group')
```
![４.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/07efaa02-031f-88bc-49f1-abac9dda890f.png)

そんなこんなで、データを可視化するアプリの完成です！ﾊﾟﾁﾊﾟﾁ

# おわりに
ここまで見ていただいた方、ありがとうございました！
調べればすぐに出てくるような内容ではありましたが、エンジニア歴が浅いため備忘録として残させてください( ；∀；)
これからも、インプットしたものは定期的にアウトプットしていこうと思います！
streamlitで作成した機械学習アプリなんか作れたらいいなあ…

ご指摘等ありましたら、どんどんお願いします！

ということで、今回はここまでにしておきます！
それでは！！！