2024年4月: Python Web UIフレームワークで作るデスクトップアプリ

寺田 学@terapyonです。2024 年 4 月の「Python Monthly Topics」は、Python Web UIフレームワークの一つである Streamlit を使ってWindowsやmacOSのデスクトップアプリを作る方法を解説します。

目的・モチベーション

Pythonで自動化のスクリプトを作ったり、JupyterLabやColaboratoryでデータの可視化を行うことがあります。 これらを作成者以外の多くの方に利用してもらう方法として、Webシステムやデスクトップアプリとして提供する方法が考えられます。

Webシステムの構築やデスクトップアプリの作成となると、技術的なハードルがあります。 他には、時間的なコストに見合わないという状況もあり得ます。

Python Web UIフレームワークを使うことで、比較的少ないコードでWeb UIからスクリプトの実行や可視化をするアプリケーションを構築できます。さらにはデスクトップアプリ化することも可能です。

本記事では、PythonコードからマルチOS対応のデスクトップアプリを、Web技術を使用して作成する方法について紹介します。

全体像

本記事で取り扱う、技術スタックを紹介します。

  • プログラミング言語 ・・ Python

  • Python Web UIフレームワーク ・・ Streamlit

  • サーバーレス環境 ・・ stlite / Pyodide

  • デスクトップアプリ ・・ Electron

  • パッケージング・ビルド ・・ electron-builder

システムの全体像とステップ

Pythonでモジュールを作り、ビルド設定を package.json に記述することで、WindowsやmacOS、さらにはLinux用の deb / rpm といったインストール可能なパッケージを作ることができます。 これらのパッケージをローカルのOSにインストールすると、Pythonの環境がなくても、Web技術を使ったデスクトップアプリとして実行できます。

Web UIフレームワーク

Web UIフレームワークは、Webアプリケーションのユーザーインターフェース(UI)を構築するためのフレームワークです。 ここではPython Web UIフレームワークを定義し、どのような種類があるかを紹介します。

Python Web UIフレームワークの定義

Python Web UIフレームワークは、データサイエンスや機械学習の分野でのインタラクティブなWebアプリケーションを、簡単に開発できるものとして重宝されています。 Pythonコードが直接Webアプリケーションに変換されるため、フロントエンド技術の知識が少ない開発者でも簡単に使いこなすことができます。 データサイエンスや機械学習の分野だけでなく、Excelや画像の加工を自動化するスクリプトなどにも簡単にGUIを提供できます。

フレームワークに準備されている関数やメソッドを使って、Pythonのモジュールを作るだけでWebアプリケーションが作れるところが魅力です。 フロントエンド開発なしに、入力フォームから結果を表示するインタラクティブなWebアプリケーションを作ることができます。

Python Web UIフレームワークは、以下の特徴を持つことが一般的です。

  • Pythonのコードを書くことで、フロントエンド(HTML/CSS/JavaScript)コードを書かずにWeb UIが構築できる

  • バックエンドのAPI化やデータのシリアライズなどを意識せず、Pythonで書いたロジックを実行するWebアプリが作れる

  • フォーム入力からボタンクリックで結果を表示するようなインタラクティブなWebアプリが作れる

  • 可視化ライブラリとの親和性がよく、グラフ表現やさまざまな可視化ができる

Python Web UIフレームワークの種類

Python Web UIフレームワークは10種類以上あり、最近も新しいフレームワークがリリースされています。

主なものを紹介します。

ここでは、それぞれの特徴は割愛します。まずは、いくつかのサイトを見ていただき、デモなどで興味がわいたものにチャレンジをしていただければと思います。

本記事では、Streamlitを使って解説します。Streamlitは、現在、Snowflakeというデータクラウド基盤サービスの会社が持つオープンソースライブラリです (https://www.snowflake.com/blog/snowflake-to-acquire-streamlit/?lang=ja)。 大変人気のあるWeb UIフレームワークです。さらに、@stlite/desktopというライブラリを使うことで、本記事で紹介するデスクトップアプリを作ることが可能です。

サーバーサイドWebフレームワークとの違い

Python Web UIフレームワークは、サーバーサイドWebフレームワークとは異なる特徴を持っています。 PythonのサーバーサイドWebフレームワークとしては、DjangoやFlask、FastAPIが有名です。 これらのフレームワークは、Webアプリケーションを作るためのフレームワークで、データベースの操作や、ユーザーからのリクエストを受け取って処理を行い、結果を返すということを行います。 また、HTMLやCSS、JavaScriptなどのフロントエンド技術を使って、Webページを作る必要があります。 フロントエンドを作る際には、専用のテンプレートを用いたり、JavaScriptを使って動的なページを作ることがあります。

自由度が高く、複雑な処理を行うことができる一方で、開発に時間がかかることがあります。 一つの入力フォームを作り、その結果を表示するだけのアプリケーションを作る場合、サーバーサイドWebフレームワークを使うのはオーバースペックです。

アプリを作る

ここからStreamlitを使ってアプリを作っています。

アプリの説明

本記事では、Excelファイルをアップロードし、2次元マトリックスを表示するアプリを作ります。

  • 名称: st-matrix-chart

  • 目的: Streamlitで二次元のマトリックスを表示する

  • 機能: Excelのデータから列を選択し、プライオリティ・マトリックスのような二次元可視化を行う

アップロードされたファイルをWeb画面上で確認します。ここでは pandas を活用しています。

可視化は plotly.express を使ってグラフを表示します。

完成後の画面は以下のようになります。

起動後のページ

起動後のページ

グラフ表示

グラフ表示

アップロード可能なExcelフォーマットは以下のとおりです。

「名称」「カテゴリID」「優先度」「コスト」「期待度」の5列あり、名称以外の各項目は、数値で入力します。

Excelのデータイメージ

アプリに必要なファイル構成

ここでは、Streamlitで構築するWebアプリに必要な構成を説明します。 次節のデスクトップアプリ化を念頭に置いたファイル構成を作ります。

必要なファイルとフォルダ構成

st-matrix-chart/
  | st_matrix_chart/
  |   | streamlit_app.py
  | package.json
  | requirements.txt

パッケージ名である st-matrix-chart をルートとして説明します。

まず、フォルダを作ります。これはデスクトップ化に必要なものです。フォルダ名はアプリケーション名が慣例的に使われていますが、任意の名称で構いません。また、Pythonのパッケージとしてインポートできるように英数字とアンダースコア(_)で名称を決めましたが必須ではありません。ここでは、 st_matrix_chart としました。 次に、st_matrix_chartフォルダ内に、 streamlit_app.py モジュールを作ります。このモジュールがStreamlitのメインのモジュールとなります。 なお、デスクトップアプリ化に利用する、 stlite では、現状モジュール名が固定化されていますので、必ずstreamlit_app.pyというモジュールを作ります。

次に、 package.json を空ファイルとして準備します。これはデスクトップ化に必要なファイルですので、ファイルの準備のみをしておきます。

最後に、 requirements.txt を準備します。これはPythonの関連パッケージを記載するファイルとなります。内容は以下のようにしてください。

streamlit
pandas
openpyxl
plotly

関連パージと用途は以下のとおりです。

  • streamlit ・・Web UIフレームワーク

  • pandas ・・データ加工

  • openpyxl ・・Excelファイルの読み込み

  • plotly ・・可視化フレームワーク

環境設定

必須条件は以下のとおりです。

  • Python 3.11 (3.8以上)

  • Streamlit 1.31以上

  • その他のPythonパッケージ: pandas, openpyxl, plotly

  • npm or yarn (node v18以降)

Pythonは3.11をお勧めします。これは、このあと行う、デスクトップ化で利用するstliteの現行の最新バージョン(厳密には内部のPyodide)がPython 3.11相当で動作するからです。

仮想環境とパッケージインストール

Pythonの標準の仮想環境 venv を準備します。

% cd st-matrix-chart
% python3 -m venv venv
% source venv/bin/activate

Pythonパッケージをインストールします。

(venv) % pip install -r requirements.txt

ここまでで、Streamlitを使ったWebアプリの環境構築が完了しました。

アプリの構築

アプリの構築は、 streamlit_app.py モジュールにコーディングします。 今回のアプリは、機能が小さいので、サブモジュールを使わずにすべて1つのモジュールで完結します。

ファイルの読み込み部分

以下のコードでExcelファイルの読み込みを行います。

pandasのDataFrame化したものを保持するためのキャッシュ機構が含まれています。

続いて、タイトルなどの表示部分と、ファイルのアップロードウィジェットを使ったファイルのアップロード機能を提供しています。

Streamlitの重要な特徴として、フォームなどの状態が変化した場合にモジュールを読み直し再実行するという点があります。 画面上選択肢が変更されると、モジュールすべてが再実行され、再計算が行われます。 これらを防ぐために、このモジュールの最初の①にて、再実行時にデータが失われないような工夫を行っています。

ファイルのアップロードについては、専用の機能が準備されていますので、ドラッグ&ドロップにも対応したウィジェットが設定可能です。

import streamlit as st
import pandas as pd

@st.cache_data  # ① キャッシュデコレータ
def get_data(file) -> pd.DataFrame:
    df = pd.read_excel(file)
    return df

st.title("Excelから2次元マトリックスを表示")  # ② タイトル表示

# ファイルの読み込み
st.subheader("Excelファイルをアップロードします。")
uploaded_file = st.file_uploader("Excelファイル", type="xlsx")  # ③ アップロードウィジェット

コードの中で重要なポイントを説明します。

  • ①: st.cache_data デコレータで関数の実行結果をキャッシュするようにしています。この関数では、ファイルオブジェクトからpandasのDataFrameに変換をしています。

  • ②: st.title を使って、タイトルを表示しています。Streamlitには多様な表示や機能があります (https://docs.streamlit.io/develop/api-reference/text)。

  • ③: st.file_uploader でファイルのアップロードウィジェットを表示しています。

DataFrame化

次に、アップロードされたExcelから、pandasのDataFrame化を行い、表形式でデータの確認ができるようにします。

uploaded_file = st.file_uploader("Excelファイル", type="xlsx")
# ここまでは上記のコード

# DataFrame化
if uploaded_file:
    df = get_data(uploaded_file)  # ① ファイルからDataFrameを作る
    st.write(uploaded_file.name)  # ② ファイル名の表示
    st.dataframe(df)  # ③ 表形式で表示

コードを説明します。

  • ①: キャッシュ化している get_data() 関数を使って、ファイルからDataFrameを作ります。

  • ②: ここでは、アップロードされたファイル名を表示しています。

  • ③: st.dataframe でDataFrameを表形式で表示します。

DataFrameの表示は以下のようになります。

DataFrameの確認

可視化に使うカラムを選択

可視化に使う設定を行います。

今回の可視化は2次元のマトリックスをバブルチャートとして出力します。 以下の項目をDataFrameのカラム名から選択します。

  • 表示名: マウスオーバー時に表示されるオブジェクトを表す名称(文字列)

  • 円の大きさ: バブルチャートの円の大きさを設定(数値)

  • 色: 円の色を決定(数値)

  • 横軸: マトリックスのX軸(数値)

  • 縦軸: マトリックスのY軸(数値)

ここで選ばれたものが、可視化ライブラリ上で要求されるデータ型になっていない場合は、ウォーニングやエラーが表示されることがあります。

    st.dataframe(df)
    ...  # ここまでは上記のコード

    columns = df.columns.to_list()
    name = st.selectbox("表示名", columns)  # ① 表示名に使うカラムを選択
    color = st.selectbox("色", columns)  # ② 色でカテゴライズに使うカラムを選択
    size = st.selectbox("円の大きさ", columns)  # ③ 円の大きさを決めるカラムを選択
    x_columns = st.selectbox("横軸", columns)  # ④ 横軸のカラムを選択
    y_columns = st.selectbox("縦軸", columns)  # ⑤ 縦軸のカラムを選択
  • ①: st.selectbox で表示名に使うカラムを選択します。

  • ②: st.selectbox で色を決めるカテゴライズに使うカラムを選択します。データ型が数値である必要があります。

  • ③: st.selectbox で円の大きさに使うカラムを選択します。データ型が数値である必要があります。

  • ④: st.selectbox で横軸(X軸)に使うカラムを選択します。データ型が数値である必要があります。

  • ⑤: st.selectbox で縦軸(Y軸)に使うカラムを選択します。データ型が数値である必要があります。

グラフの表示用の選択画面は以下のようになります。

グラフの表示要素の選択

可視化部分

plotly.expressを使った可視化部分です。 Streamlitでは可視化のオブジェクトを直接表示する機能があります。 なお、横軸と縦軸が同じものが選ばれている時には、表示をしないようにしています。

import plotly.express as px  # インポート文を追加
...

    y_columns = st.selectbox("縦軸", columns)
    ...  # ここまでは上記のコード
    if x_columns and y_columns:  # ① X軸、Y軸ともに選択済みなのかを確認 
        if x_columns == y_columns:  # ② X軸とY軸に同じカラムが選ばれていたらエラー表示
            st.error("横軸と縦軸が同じです。")
        else:
            fig = px.scatter(
                df,
                x=x_columns,
                y=y_columns,
                size=size,
                color=color,
                hover_name=name,
            )  # ③ バブルチャートのグラフを生成
            st.plotly_chart(fig)  # ④ グラフを画面表示
  • ①: 横軸と縦軸にデータが入力されていることを確認しています。

  • ②: 横軸と縦軸が同じ場合は st.error でエラーを出力しています。

  • ③: plotly.expressscatter を使ってバブルチャートを生成しています。

  • ④: st.plotly_chart を使ってscatterオブジェクトを画面表示しています。

コード全体

streamlit_app.pyモジュールのコードすべてを掲載します。 今回作るアプリのコード部分の全てになります。

50行以下のコードで、ファイルのアップロードから、アップロードデータの確認、可視化に必要な条件の設定ができ、インタラクティブなグラフを表示するアプリケーションに仕上がりました。

import streamlit as st
import pandas as pd
import plotly.express as px


@st.cache_data
def get_data(file) -> pd.DataFrame:
    df = pd.read_excel(file)
    return df


st.title("Excelから2次元マトリックスを表示")

# ファイルの読み込み
st.subheader("Excelファイルをアップロードします。")
uploaded_file = st.file_uploader("Excelファイル", type="xlsx")

# DataFrame化
if uploaded_file:
    df = get_data(uploaded_file)
    st.write(uploaded_file.name)
    st.dataframe(df)

    #  可視化に使うカラムを選択
    columns = df.columns.to_list()
    name = st.selectbox("表示名", columns)
    color = st.selectbox("色", columns)
    size = st.selectbox("円の大きさ", columns)
    x_columns = st.selectbox("横軸", columns)
    y_columns = st.selectbox("縦軸", columns)

    # 可視化
    if x_columns and y_columns:
        if x_columns == y_columns:
            st.error("横軸と縦軸が同じです。")
        else:
            fig = px.scatter(
                df,
                x=x_columns,
                y=y_columns,
                size=size,
                color=color,
                hover_name=name,
            )
            st.plotly_chart(fig)

PythonのWeb UIフレームワーク及びStreamlitの良さをご理解いただけたでしょうか。

ローカル環境で実行

ローカル環境で以下のコマンドを実行すると、Streamlitのアプリが起動します。

(venv) % streamlit run st_matrix_chart/streamlit_app.py

コンソールに以下のように表示されます。


  You can now view your Streamlit app in your browser.

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

アプリの起動とともにブラウザが開いて、アプリケーションが表示されたと思います。 この段階で、動作の検証を行い、より自分にあったアプリに仕上げていきましょう。

デスクトップアプリ化

デスクトップアプリ化は、 @stlite/desktop を使います。

stliteは、Pythonで書かれたStreamlitのコードをサーバーサイドまで含めてブラウザ上で実行するものです。 内部では、Pythonのコードを WebAssembly 化する Pyodide が使われています。

stliteでは、Pythonの実行環境がなくても、WebブラウザでPyodideを経由して、Pythonのコードが実行できます。 すべてのPythonコードが実行できるというわけではありませんが、多くのライブラリがPyodideへの対応を進めています。 詳細は、Pyodideの公式ドキュメントを確認してください。

本記事では、Webブラウザで動作することにとどまらず、OS上のデスクトップアプリ化を行います。 @stlite/desktopは、 Electron を使ってデスクトップアプリ化を行います。

Electronは、Web技術を使ってデスクトップアプリを作るためのフレームワークです。 Node.jsとChromiumを使って、HTML、CSS、JavaScriptでアプリを作ることができます。 著名なアプリには、Visual Studio Code、Slack、Discordなどがあります。 なお、@stlite/desktopは、 electron-builder でパッケージングを行います。

デスクトップ化の設定と環境設定

Nodeの環境を準備します。ここでは、すでに Node v20系がインストールされいる前提で進めます。

package.jsonの準備

空のファイルを準備していた package.json に設定を書きます。

これは、Nodeで関連パッケージのインストールを行ったり、ビルドを行うためのものです。 @stlite/desktopのドキュメント にある雛形を元にしています。

{
    "name": "st-matrix-chart",  // ① アプリ名
    "version": "0.1.0",
    "homepage": "https://github.com/terapyon/st-matrix-chart",  // ② URLを設定
    "author": {  // ③ 名前とメールアドレスを設定
        "name": "Manabu TERADA",
        "email": "terapyon@example.com"
    },
    "main": "./build/electron/main.js",
    "scripts": {
      "dump": "dump-stlite-desktop-artifacts",
      "serve": "cross-env NODE_ENV=production electron .",
      "pack": "electron-builder --dir",
      "dist": "electron-builder",
      "postinstall": "electron-builder install-app-deps"
    },
    "build": {
      "files": ["build/**/*"],
      "directories": {
        "buildResources": "assets"
      }
    },
    "devDependencies": {  // ④ 関連パッケージのバージョンを確認
      "@stlite/desktop": "^0.52.0",
      "cross-env": "^7.0.3",
      "electron": "^28.2.1",
      "electron-builder": "^24.9.1"
    }
  }

主な変更点を説明します。

  • ①: nameはパッケージの名称を指定します。任意の名称に変更することができます。

  • ②: homepageはパッケージのURLを指定します。リポジトリのURLでも構いません。

  • ③: authorには、nameとemailを設定します。

  • ④: devDependenciesの内容は変更は不要です。ただし、新たなバージョンが出ていることもありますので必要に応じてバージョンを上げていきます。

インストール

以下のコマンドで、必要なパッケージをインストールします。

% npm install

ビルド

ここからは、実際にデスクトップアプリをビルドしていきます。

最初に dumpを行います。 これは、必要なファイル群をパッケージングしています。

% npm run dump st_matrix_chart -- -r requirements.txt

動作確認は以下のコマンドを実行すると、ローカルでアプリが立ち上がり動作検証が行えます。 動作に問題がないかを確認しましょう。

% npm run serve

以下のような画面が表示されます。

serve起動時の画面

最後に、アプリケーションのビルドです。

Windows環境で以下のコマンドを実行すると、dist フォルダに、Windows用の exe ファイルが出力されます。

> npm run dist -- --win

macOS環境で以下のコマンドを実行すると、 dist フォルダに、macOS用の dmg ファイルが出力されます。

% npm run dist -- --mac

Linux環境で以下のコマンドを実行すると、dist フォルダに debrpm ファイルが出力されます。

% npm run dist -- --linux deb rpm

それぞれの環境でビルドされたパッケージをインストールし、実行することができます。 出来上がったファイルを配布しインストールすることで、Pythonの実行環境がないPCでもアプリケーションを使うことができます。

なお、 npm run dist コマンドは、electron-builderコマンドラインインターフェースのエイリアスとなります(package.jsonの scripts.distフィールドで定義)。詳細は公式ドキュメント electron-builderのCLI を参照してください。

まとめ

本記事では、Streamlitで簡単にWebアプリケーションを作るところから、デスクトップアプリにビルドするところまでを駆け足で紹介しました。 実際のアプリケーションを作る場合は、アイコンを設定したり細かな配慮が必要になります。 また、ビルドについてもGitHub ActionsなどのCI/CDツールを使い自動ビルドをすることになろうかと思います。

今回は、Pythonのコードから簡単にデスクトップアプリができることを紹介しました。 詳細は、公式ドキュメントやほかの記事などを参考に自身のアプリを作ってみていただければと思います。

参考用公式ドキュメント