メインコンテンツへスキップ
見出し画像

Pythonライブラリ(Webアプリ):Streamlit

    1.概要

     StreamlitはWebアプリ所謂ホームページを簡単に作成できるライブラリです。Webアプリ用ライブラリは他にもありそれぞれ特徴がありますが個人的にはStreamlitが最強でした学びやすく簡単で実践投入できた。
     参考用のアウトプットはstreamlit cloudに挙げていますどのようなアウトプットかご確認ください。。

    【Webアプリ一覧】
    ●Flask:軽量かつ簡単に使いやすい。
    ●Dash:データの可視化が得意
    ●Django:詳細なウェブアプリを作れるけど難しい
    ●Streamlit:簡単かつ爆速でウェブアプリが作成可能

    2.Webアプリ使用の目的

     Streamlitの使用目的に関して、私の場合は下記のとおりです。

    ●CLIでなくGUIで好きなタイミングで|スクリプト自分で書いたコードを実行したい《ボタンを
    ポチってPythonコードを実行》(実行するタイミングが不定期な処理)。
    ●チームで簡単に共有できるシステムが作りたい。(チームの人へのPython教育の労力をなくしたい)
    ●チームで利用する時に使用者のPCに環境構築なしで使用したい(同上)

    画像

    3.参考資料

     Streamlitの参考資料は公式ドキュメントが絶対ベストです。初心者の時私は今もですはチートシートを見ながらやれば何とかいきます(こちらでも確認可)。

    画像1

     Update情報に関しては公式Twitter、Youtube、blogでフォロー可能です。

    🎉 It's the 2-year anniversary of Streamlit. And...🥁🥁...today we're launching Streamlit 1.0! Check out what's included and what's coming next. 🚀

    📖 Read more: https://t.co/3gYo0y0AA1
    💻 Roadmap app: https://t.co/aS23B8zpby#datascience #ml #opensource

    Volume up 😎 pic.twitter.com/YDIvvv1rr2

    — streamlit (@streamlit) October 5, 2021

     簡単なチュートリアルに関してはいまにゅさんのYoutube動画はおすすめです。ただしStreamlitのAPIはVersion1.0で結構追加されたため、1. 動画のStreamlitのVersionが古く一部のAPIは使用できないものがある、2. 最新のAPIの説明まではないです。ただし使い方が分かれば公式ドキュメントで十分作成可能です。

    4.基礎

     Streamlitの操作・使い方を紹介します。非常に多くのコードが追加できるため、私が使用した分だけ記載していきます。不明な個所は公式Docsを確認すれば簡単に理解できると思います。

     なお説明用コードは「note_streamlit.py」ファイルに記載していきます。

    画像

    4-1.Streamlit立ち上げ:streamlit run f.py

     ファイル内にstreamlitのコードを記載します。

    [In]
    import streamlit as st
    
    st.title('note記事作成') #タイトルを作成
    
    #文字列を記載
    """
    noteでstreamlitの紹介記事を作成します。下記に記載していく予定です。
    """

     次にターミナルで「streamlit run ファイル名」で実行します。これだけでWebアプリが立ち上がります。

    画像

     あとはコードを追記すれば記載したコードによるテキスト・ウィジェット・グラフなどがWebアプリに表示実装されます。

    【参考】
     同一接続環境(社内LANや同じWifiを接続している端末)で、実行時にターミナルに表示されるURL(例:http://192.900.2.999:8501)をブラウザに入力するとその端末でも作成したWebアプリを共有することができます。
    (※ChromeやFirefoxはいけますがおそらくIEは使えません。)

    4-2.テキスト・文字の入力や表示

    4-2-1.テキスト表示

     コードに記載した文字列をWebアプリに表示します。

    ●Magic commands:4-1.で使用した3つの'で囲うことで文字列を表示させる(個人的には可読性が落ちるため不使用)
    ●st.title('string'):タイトル文字を作成HTMLのh1タグ
    ●st.write('string'):普通の文字列を表示する場合に使用
    ●st.markdown('string'):マークダウン記法で文字を表示数式、リンク、強調文字などしたい場合に使用=>数式記載時はエスケープシーケンスに注意\を一個多く記載

    画像

    4-2-2.データ入力(Interactive Widgets)

     Webアプリ側にデータを入力してその値を抽出できます。また入力値を変数に格納できるため、その変数を別の個所で利用できます。

    ●st.number_input('title', value=初期, step=刻み値, format=型)
    :数値入力のBOX作成
    ●st.text_input('title', value='初期値'):テキスト入力BOX作成

    画像

    4-3.データ表示

    4-3-1.表形式・JSONデータ:st.dataframe, st.table

     テーブルやJSONデータをきれいな形で表示します。

    ●st.dataframe(df):Webアプリ内で動かすことができる表
    ●st.table(df)
    :Webアプリで操作できない表
    ●st.json(json):jsonデータを表示(参考用のため下記未記載)

    画像

    4-3-2.メディアデータ:st.image(path)

     画像、音声や動画ファイルを表示できます(画像データはここ)。

    ●st.image(filepath):画像データをWebアプリ内に表示
    ●st.audio(data)
    :音声データを表示(未使用のため紹介のみ)
    ●st.video(data):動画データを表示(未使用のため紹介のみ)

    画像

    4-3-3.コード表示:st.echo()

     Webアプリの中でコード表示ができます。

    画像

    4-4.ウィジェット

    4-4-1.ボタン・選択ボックス

     ボタンを選択=>処理させたい場合などに使用します。

    ●st.button(title):ボタンを押すと処理を実行する
    ●st.checkbox(title)
    :チェックボックスを選択する(radioボックスだと選択肢を記憶できないときに使用しています)
    ●st.radio(title, list):ラジオボックスで複数選択肢から1個選択
    ●st.selectbox(title, list):セレクトボックスで複数の選択肢から1個だけ選択
    ●st.multiselect(title, list, default='list:初期値の選択'):セレクトボックスで複数の選択肢から複数の選択肢を選択可能

    画像

    4-4-2.ファイルのUpload/Download

    【ファイルのアップロード:st.file_uploader('title')】
     
    アップロードは下記で実行できます。留意点は下記の通りです。

    【留意点】
    ●変数に格納する場合は初期値がNoneとなる。
    ●アップロードしてほしいファイルはわかるようにすること。

    画像

    【ファイルのダウンロード:st.download_button()※Ver.>=1.0.0】
     
    ファイルのダウンロードボタンを作成できます(参照リンク)。

    [In]
    #ファイルダウンローダ作成
    csv_financde = df_stocktable.to_csv().encode('utf-8')
    st.download_button(
        label='CSVダウンロード',
        data=csv_financde,
        file_name='Yahoo株価ランキング.csv',
        mime='text/csv'
    )
    画像

     なおDLボタンはversion1.0で実装されており、それ以前のVersionでDL実装すると下記コードになります(もう思い出せないので参考までに※最後にexporttab_pyxl()関数を実行)。

    [In]
    def app():
        @st.cache
        #DataFrameをBytes型に変換
        def to_excel(df):
            output = BytesIO()
            writer = pd.ExcelWriter(output, engine='xlsxwriter')
            df.to_excel(writer, sheet_name='Sheet1')
            writer.save()
            processed_data = output.getvalue()
            return processed_data
    
        #to_excelで変換したBytes型Dfをエンコードしてダウンロード
        def get_table_download_link(df, filename):
            """Generates a link allowing the data in a given panda dataframe to be downloaded
            in:  dataframe
            out: href string
            """
            val = to_excel(df)
            b64 = base64.b64encode(val)  # val looks like b'...'
            return f'<a href="data:application/octet-stream;base64,{b64.decode()}" download="{filename}">Download Excel file</a>' # decode b'abc' => abc
    
        #ダウンローダーのボタンを作成_DataFrame用
        def exporttab_df(module, excelfile, text4input, text4button, DeorAV):
            st.markdown('### ```計算結果の出力(Excel)```')
            #2カラム(st.beta_columns)がベータのため、リスクヘッジ用
            # st.write('ファイル名の語尾につけたい名称を下記に記載してください。')
            # name_pj = st.text_input(text4input)
            #ベータ型のため上の記載を残しておく
            column_L, column_R = st.beta_columns(2)
            name_pj = column_L.text_input(text4input)
            filename = f'output.xlsx'
            column_R.write('出力されるファイル名')
            column_R.write(filename)
    
            Flag_export = st.button(text4button)
            if Flag_export:
                df_cal = module.main(excelfile=excelfile)
                st.markdown(get_table_download_link(df_cal, filename=filename), unsafe_allow_html=True)
    
        #OpenpyxlのwbをBytesで読み込みダウンロード
        def get_table_download_link_pyxl(wb, filename):
            stream = save_virtual_workbook(wb)
            b64 = base64.b64encode(stream) 
            return f'<a href="data:application/octet-stream;base64,{b64.decode()}" download="{filename}">Download Excel file</a>' # decode b'abc' => abc
    
        #ダウンローダーのボタンを作成_Openpyxl用
        def exporttab_pyxl(wb, text4input, text4button):
            st.markdown('### ```計算結果の出力(Excel)```')
            column_L, column_R = st.beta_columns(2)
            name_pj = column_L.text_input(text4input)
            filename = f'output.xlsm'
            column_R.write('出力されるファイル名')
            column_R.write(filename)
    
            Flag_export = st.button(text4button)
            if Flag_export:
                st.markdown(get_table_download_link_pyxl(wb=wb, filename=filename), unsafe_allow_html=True)

    4-5.レイアウト設定

     Webアプリ内でのUI改善のためのレイアウト設計が可能です。

    4-5-1.カラム・コンテナ:st.columns(), st.empty()

     レイアウト分割や処理内容をページ上部に表示したりできます。

    ●st.columns(int):レイアウトを並べて表示させる(version1.0より前ではst.beta_columns(int)のため注意)
    ●st.container()
    :空のエリアをとっておく->下で処理したコードの結果を上に持っていく(下記では省略)
    ●st.empty():st.container()の1行ver.

    画像

    4-5-2.サイドバー:st.sidebar.api

     st.sidebar.apiと記載することでサイドバーに表示できます(apiの部分を各コードに置換してください)。

    画像

    4-6.Webカメラ(st.camera_input)

     Version1.4.0で追加されたwebカメラを接続する機能です。下記コードを記載するだけでWebカメラを使用できます。

    [In]
    img_file = st.camera_input("Webcam image")
    if img_file is not None:
        st.image(img_file)
    
    [Out]
    下図赤枠
    画像

    4-7.グラフ表示(altair)

     追って(量が多い場合は別記事で作成予定)

    5.便利機能

    5-1.キャッシュ(@st.cache)

     (ちゃんと理解はできてないが)Pythonデコレーターの@cacheと同様に関数やクラスの前に記載することでキャッシュをためることができる。つまり1回関数を処理したら出力が同じ場合はその関数を処理しないため処理速度が向上します。
     Streamlitは更新ごとに上からコードが処理されるため重い処理があると動作が遅くなるのでキャッシュ機能は便利です。

    [In]※下記関数は参考であり、そのまま処理してもエラーになります。
    @st.cache
    def to_excel(df): #DataFrameをBytes型に変換
        output = BytesIO()
        writer = pd.ExcelWriter(output, engine='xlsxwriter')
        df.to_excel(writer, sheet_name='Sheet1')
        writer.save()
        processed_data = output.getvalue()
        return processed_data

    6.応用

    6-1.複数ページの統合

     複数ページのアプリを一つのスクリプトで実行したい場合を説明します。下記の通り3つのappフォルダにそれぞれapp.pyスクリプトが入っています。

    画像

    【mainapp.py】
    メインのスクリプトでは下記処理をします。
    ①モジュールpythonファイルがあるフォルダをimportできるようにフォルダのパスを通す
    ②モジュールからスクリプトをインポートする
    ③サイドバーに表示する名称とスクリプトを辞書で格納する
    ④サイドバーのタイトル、リスト名称、モジュール関数実行処理を記載する

    [In]
    import streamlit as st
    import sys, os
    
    #パッケージ(ライブラリ)のパス設定:相対参照で使用するためにパスを通す
    sys.path.append(os.path.join(os.getcwd(),'01_app1'))
    sys.path.append(os.path.join(os.getcwd(),'02_app2'))
    sys.path.append(os.path.join(os.getcwd(),'03_app3'))
    
    
    #各パッケージからモジュールをインポートする
    import app1
    import app2
    import app3
    
    
    # ページ一覧の設定:Streamlitのサイドバーに表示
    PAGES = {
        "01. app1": app1,
        "02. app2": app2,
        "03. app3": app3, 
    }
    
    #選択したページを開く処理:Streamlit main.appの動作設定
    st.sidebar.title('各種アプリの選択')
    selection = st.sidebar.radio("アプリ一覧", list(PAGES.keys()))
    page = PAGES[selection]
    page.app()

    【スクリプト側(app.py)】
     実行する処理を"def app():"関数内に記載する(上記page.app()の関数)。

    画像

    【結果(OUTPUT):streamlit run mainapp.py】
     メインスクリプトを実行するとサイドバーにそれぞれのページが選択でき、ラジオボックスを選択するとほしいページが確認できる。

    画像

    6.クラウドへのデプロイ

     作成したアプリをStreamlitのクラウドへデプロイできます。誰でもアクセスできるような状態にする。デプロイするためには事前①streamlit cloudへの登録、②GitHubアカウントへの登録が必要となります。

     フォルダ構成は下記の通りであり、①app1.py:基礎コード、②app2.py:株価可視化を作成しました6-1.の2ページレイアウト。

    画像
    [mainapp.py]
    import streamlit as st
    import sys, os
    
    #パッケージ(ライブラリ)のパス設定:相対参照で使用するためにパスを通す
    sys.path.append(os.path.join(os.getcwd(),'01_基礎コード表示'))
    sys.path.append(os.path.join(os.getcwd(),'02_株価取得アプリ'))
    
    
    #各パッケージからモジュールをインポートする
    import app1
    import app2
    
    
    # ページ一覧の設定:Streamlitのサイドバーに表示
    PAGES = {
        "01_基礎コード表示": app1,
        "02_株価取得アプリ": app2,
    }
    
    #選択したページを開く処理:Streamlit main.appの動作設定
    st.sidebar.title('アプリの選択')
    selection = st.sidebar.radio("アプリ一覧", list(PAGES.keys()))
    page = PAGES[selection]
    page.app()

    6-1.requirements.txtの作成

     外部ライブラリインストール用のrequirements.txtを作成します。エラーが生じないようにライブラリのVersionを指定して記載します。

    [requirements.txt]
    streamlit==1.3.1
    pandas==1.3.4
    numpy==1.20.3
    matplotlib==3.4.3
    pandas-datareader
    mplfinance
    japanize-matplotlib

    6-2.GitHubにレポジトリ作成

     GitHubに公開用のレポジトリを作成します。

    画像
    画像

    6-3.GitHubのレポジトリにPush

     GitHubのレポジトリにファイルをPushします。

    [ターミナル]
    git init #ローカルレポジトリの登録
    git config --global user.name "<ユーザー名>" #ユーザー名の登録(エラー時) 
    git config --global user.email <メールアドレス> #メールアドレスの登録(エラー時)
    git remote set-url origin https://<ユーザ名>@github.com/<ユーザ名>/<リポジトリ名>.git #(エラー時)
    git remote add origin https://github.com/KIYO-GitHub/note_streamlit_KIYO.git #リモートレポジトリの登録
    git add . #ファイルをステージへ移動
    git commit -m 'commitメッセージ' #コミット
    git push origin master #リモートレポジトリへPush
    画像

     Pushでエラーが出て地味に大変だったので参考までに

    6-4.Streamlit Cloudへのデプロイ

     最後にstreamlit Cloudから「New app」を選択して、作成したレポジトリとファイルを選択したらデプロイ完了です。

    画像

     参考用にデプロイしたコードは下記より確認できます。


    参考資料

    Streamlit/Python Drawable Canvas - Element Selection (React JS)

    With Streamlit component you can render canvas and draw on top of it. I explain how to implement object selection and pass data from React to Streamlit.

    Video: https://t.co/sRveQoZerN#Python #React pic.twitter.com/2tvh9vGsYl

    — Andrej Baranovskij (@andrejusb) November 6, 2022

    あとがき

     自分で作ったスクリプトをチームで共有する時に下記を検討して頓挫しましたが、その中でStreamlitは救世主でした。

    ①Pyinstallerでexeファイル化:ファイルが重くなるし、そもそも特定ライブラリ(多分xgboostが原因)を含むスクリプトはexe化できなかった。
    ②チームメンバーにPythonを教育:覚える気がなさそうだし多分仕事が増えるとか思ってる?PCの環境構築やってくれないし、新しいメンバー入ってきたときに教えられる人がいない私は今の会社に一生いる気ないしとチームが動かなくなるリスクが出てきた。
    ③Excelのマクロで実行:私にはExcelでの機械学習のハードルが高かった。
    ④その他Webアプリ:Flaskは挑戦したのですが応用するスキルがなくほしいアプリが作れなかった。Djangoは無理。

     ただ当時StreamlitだけでできないことはあきらめていたのですがExcelだけでファイルを処理したいFastAPIと組み合わせることでできることを最近知ったので今からStreamlitを学ぶ人はFastAPIも合わせて学ぶことをお勧めします。
     なおエッジデバイス別のPCを用意してでstreamlitを常時立ち上げておけば、接続URLをブラウザにお気に入り登録するだけで簡単に接続可能になります。

     将来的には自動工程管理ツール(API連携)を作りたいのだけどStreamlitでは厳しいのかな・・・・

     
     

    KIYO

     
     
    普段は製造業で企画/開発/設計しております。記事はプログラミング・機械学習、IoT関係の記事をメインで作成し、なるべく1つの記事で知りたいことを網羅していきます。内容は学術的より実装・アウトプット(ほしくなるもの)を重視して作成しています。 面白そうな仕事があればやりたいです!

    あなたへのおすすめ