Webアプリケーションは、CGI (Common Gate Interface)
と呼ばれるプログラムをHTTPサーバから呼び出して実行されます。
CGIプログラムはどの言語で書いても構いませんが、以下のインターフェースを持ちます。
また、HTML出力に、HTML5やCSS5、Javascriptを使うことで、動的・インターラクティブなアプリケーションを作成することが可能です。
しかしながら、上記のようなプログラムをHTML/CSS/Javascriptを使って作成するには多くの知識とプログラムコードが必要となり、現在では、単純なWebアプリを除き、CGI形式が使われることは少なくなりました。上記の機能は、"フレームワーク"と呼ばれるWebアプリ用ライブラリにまとめられ、複雑なHTML/CSS/Javasciptのコードを隠ぺいし、簡単にプログラムを作成できるようなっています。
本ページでは、pythonを使ってWebアプリを作る際のメモをまとめます。pythonのフレームワークとしてはDjangoが有名ですが、多機能である一方、習得に必要な学習コストが大きいという問題があります。一方で、Flaskは軽量で比較的簡単に習得可能であり、データ解析などのダッシュボードとして利用されるDashはFlaskで動いています。Plotlyはpythonの可視化ライブラリの一つで、matplotlibよりもインタラクティブなグラフを描くことができますが、Flask/Dash上で稼働するWebアプリとして利用さるように作られています。一方、FastAPIは最新のフレームワークの一部であり、軽量・高速という特長があり、今後は主流になっていくものと考えられます。
上記のことを考え、本ページでは以下の項目を扱います。
注意: .run_server()をdebugモードで走らせるとスクリプトが2重起動
(リロード) される。
ログファイルを出力するときなどはdebugモードをoffにする。
start_web_app.py
HTTPサーバの起動とWebアプリURLへのアクセスを自動的に行うプログラム。
Usage: pythyon start_web_app.py python_script server_IP serverr_Port
wait_time
サンプルデータ
xrd.xlsx
plot_excel_show.py
.show()を使ってplotlyのグラフをweb browserに表示する例
(Dashは使っていない)
Usage: python plot_excel_show.py
plot_excel_base.py
これ以下はPlotly Dashの例。
Excelファイルをアップロードし、Plotlyで描画する
Usage: python plot_excel_base.py
を実行した後、コンソールに表示されたURLにアクセスする。
あるいは
Usage: python start_web_app.py plot_excel_base.py 127.0.0.1 8050
plot_excel_xrange.py
Excelファイルをアップロードし、Plotlyで描画する。表示X範囲をinput
boxで設定し、ボタンを押してグラフを再描画する
Usage: python start_web_app.py plot_excel_xrange.py 127.0.0.1 8050
plot_excel_xrange_auto.py
Excelファイルをアップロードし、Plotlyで描画する。
グラフの表示範囲を変えるとinput
boxのX範囲に設定される。
input boxのX範囲を変更するとグラフを再描画する
Usage: python start_web_app.py plot_excel_xrange_auto.py 127.0.0.1 8050
plot_excel_details.py
plot_excel_base.py
に HTMLの折り畳み要素 <details>
とテーブルを入れたもの
Usage: python start_web_app.py plot_excel_details.py 127.0.0.1 8050
plot_tkProg.py
必要ライブラリ: tklib
tklib.tkapplication とstart_web_app.pyの機能を統合
(Windows限定)。
sever起動のスクリプトは別のコンソールで実行するようにした。
.run_server()のdebug modeをデフォルトでoffにした。
Usage: python plot_tkProg.py
一般的なWebフレームワークでは、フレームワークライブラリにHTTPサーバが用意されており、まずHTTPサーバを起動し、表示されたURLにアクセスすることでアプリを実行します。
Plotlyでは、plotly.graph_objects を利用して .show() を実行することにより、Plotly内部でHTTPサーバの立ち上げとアプリの実行を行ってくれるため、matplotlibと同様の使い方をすることができます。
以下のプログラム plotly_demo1.py を実行すると、 http://127.0.0.1:53763/ を起動してグラフを表示しました。
import numpy as np
import plotly.graph_objects as go
xs = np.linspace(0, 10, 100)
sins = np.sin(xs)
randoms = np.random.rand(100)
fig = go.Figure(data=[
go.Scatter(x=xs, y=sins, name="sin"),
go.Scatter(x=xs, y=randoms, name="random"),
])
fig.show()
次の例では、pythonプログラムは .run_server()を呼び出し、アクセスURLを表示したうえでHTTPサーバを起動します。
from dash import Dash, dcc, html, Input, Output
import plotly_express as px
app = Dash(__name__)
app.layout = html.Div([
html.H4('Analysis of Iris data using scatter matrix'),
dcc.Dropdown(
id="dropdown",
options=['sepal_length', 'sepal_width', 'petal_length', 'petal_width'],
value=['sepal_length', 'sepal_width'],
multi=True
),
dcc.Graph(id="graph"),
])
@app.callback(
Output("graph", "figure"),
Input("dropdown", "value"))
def update_bar_chart(dims):
df = px.data.iris() # replace with your own data source
fig = px.scatter_matrix(df, dimensions=dims, color="species")
return fig
app.run_server(debug=True)
このプログラムを実行すると、コンソールに以下の表示が出ます。
PS D:\> python .\plotly2.py
Dash is running on http://127.0.0.1:8050/
* Serving Flask app 'plotly2'
* Debug mode: on
Webブラウザを起動してhttp://127.0.0.1:8050/ にアクセスすると、以下のようなページが表示されます
上記のPlotly
Dashプリでは、上段のドロップボックスを変更することで、グラフの表示を変えることができます。
ドロップボックスの選択を変更した場合、callback関数を呼び出しますが、Dashではcallback関数の定義が高度にカプセル化されています。
また、Flask/Dashでは、callback関数の定義では、decolatorが使われています。
@app.callback(
Output("graph", "figure"),
Input("dropdown", "value"))
def update_bar_chart(dims):
df = px.data.iris()
fig = px.scatter_matrix(df, dimensions=dims, color="species")
return fig
pythonでは、@hogehoge というデコレータを関数 func
の定義の前に置くことで、func()呼び出しに hogehoge()
関数で定義した動作を追加できます
例えば次の例
def hogehoge(f):
def _wrapper(*args, **kwargs):
print(f'hogehoge._wrapper(): デコレータが呼び出されました: args={args} kwargs={kwargs}')
print(f'hogehoge._wrapper(): 関数 f を呼び出します')
v = f(*args, **kwargs)
print(f'hogehoge._wrapper(): 関数 f の戻り値: {v}')
return v
return _wrapper
@hogehoge
def func(*args, **kwargs):
print(f"funcが呼び出されました")
print(f" args=", *args)
print(f" kwargs=", kwargs)
return 1.0
func(3.0, a = 'abc')
は、
hogehoge(func)(3.0, a = 'abc')
# f = hogehoge(func) # <= hogehoge._wrapper()関数の参照が
f に入る
# f(3.0, a = 'abc') # <= hogehoge.wapper(*args, **kwargs)
関数が呼び出される。
# *args と **kwargsは func(3.0, a = 'abc') に渡された位置引数 3.0
とキーワード引数 {"a": 'abc'} に対応
と同じ動作をします(異なる書き方で同じ動作をすることを
Syntax sugar であるといいます)。
つまり、hogehoge(func)は hogehoge._wrapper() 関数を返すので、
hogehoge(func)(3.0, a = 'abc') により hogehoge._wrapper(3.0, a = 'abc')
が呼び出されます。
hogehoge._wrapper(3.0, a = 'abc') 内ではfunc(3.0, a = 'abc')を呼び出していますが、その前後に追加処理を行っています。
デコレータは、このような共通の追加処理を関数に追加するための仕組みです。
Plotly Dashの場合、@app.callback() の app は
app = Dash(__name__)
と、Dashの変数になっており、@app.callback の実体は Dashクラスで定義されている .callback() 関数です。
参照: https://qiita.com/NAKA_G/items/f34738df364af8cbd58e