アイソモカ

知の遊牧民の開発記録

開発記録 191219 Thu (Flaskで作った画像を表示)

前々回 191214 と 前回 191215 の続き。

Flask を使って、アップロードした dat ファイルのデータをグラフにして表示します。

 

UNIXコマンド:cpで上書きするか確認してくれ

$ cp file.py file1.py でファイルをコピーして、file1.py を編集したぞー実行するぞ!という時にターミナル上で▲を押していたら、もう一回$ cp file.py file1.py を実行してしまうこと、あるよね。ぼくだけ?

今のところ取り返しのつかないことにはなっていないけど、がっかりしちゃう。

$ cp -i file.py file1.py

とオプションをつけて実行すると、ファイルが既にある時には overwrite file1.py? (y/n [n]) と確認してくれる。

~/.bash_profileエイリアスを書いた。

alias cp='cp -i'

再発防止。

 

勉強会の宿題③ ブラウザにグラフを表示

前々回は、Flask を使って、ブラウザから dat ファイルをアップロードし、ファイルを読んでヘッダを表示できるようになった。 前回は、Pandas と Matplotlib を使って、dat ファイルからデータをグラフ化できるようになった。 今回はそれの合わせ技。

画像を埋め込む方法、 static/

ファイルの指定方法が全然分からなくて、かなり苦戦した。普通のHTMLを書く時のように path を指定したら、ダメだった。

画像を埋め込むには、 static/ という静的ファイル置き場ディレクトリを使うのが良いっぽい。

参考 👉 [Python] 軽量WebフレームワークのFlaskに入門(準備、起動、HTML、静的ファイル、GET、POSTなど) - YoheiM .NET

html ファイルのほうには

<img src="{{image}}" alt="graph">

と書き、main.py の return render_template()の中で

image = url_for('static', filename=plot_mhdata(filename))

と渡してやると、なんかうまくいった (このplot_mtdata(filename) は、ファイル名を渡すとグラフの pngファイル名を返す自作関数)。

python コード

全部載せる。前々回のmain.pyに、前回の plotmhdata.pyを足して、画像埋め込みを加えた感じ。 拡張子の確認とかはしていません。自分用なので。

# main.py
import os
import pandas as pd

from flask import Flask, request, url_for, render_template
app = Flask(__name__)
UPLOAD_FOLDER = './uploads'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

import matplotlib.pyplot as plt
from matplotlib import rc
font = {"family": "Noto Sans CJK JP"}
rc('font', **font)

@app.route('/', methods = ['GET', 'POST'])
def top():
    if request.method == 'GET':
        return render_template('upload_file.html')
    else:
        if 'file' in request.files:
            file = request.files['file']
            if file:
                filename = file.filename
                file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
                return render_template('dataplot.html', \
                    filename = filename, \
                    table = read_file(filename), \
                    image1 = plot_mhdata(filename),\
                    image = url_for('static', filename=plot_mhdata(filename)))


# dat ファイルの最初に読み飛ばす行が何行あるか数える関数
def getHeaderRow(filename):
    with open(UPLOAD_FOLDER+'/'+filename) as file:
        for i, l in enumerate(file):
            if l == '[Data]\n':
                return i+1
    return False


# ヘッダの表を返す関数
def read_file(filename):
    headerrow = getHeaderRow(filename)
    if headerrow:
        df = pd.read_csv(UPLOAD_FOLDER+'/'+filename, skiprows = headerrow, header = 0)
    return df.head().to_html() 


# グラフを描いてpngファイル名を返す関数
def plot_mhdata(filename):
    xcol = 3
    ycol = 4

    headerrow = getHeaderRow(filename)
    if headerrow:
        df = pd.read_csv(UPLOAD_FOLDER+'/'+filename, skiprows = headerrow, header = 0)
        plt.figure()
        df.plot(title = filename.split('/')[-1], \
                 x = df.columns.values[xcol], \
                 y = df.columns.values[ycol])
        plt.savefig('static/'+filename+'_'+str(xcol)+'_'+str(ycol)+'.png')
        plt.close('all')

        imgname = filename+'_'+str(xcol)+'_'+str(ycol)+'.png'
    else:
        imgname = ''

    return imgname


if __name__ == '__main__':
    app.run(debug=True, threaded=True)

html ファイル

{{table|safe}} というふうに |safeを入れると、 python から渡した文字列にも html コードを適用してくれる。これがないと、そのまま表示されてまう(この前教えてもらった)。

<!-- dataplot.html -->
<!doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>
            データ読み込み結果
        </title>
    </head>
    <body>
        <h1> データを読み込みました </h1>
        データ:{{filename}} <br>
        先頭の5行 
        {{table|safe}}

        グラフ <br>
        {{image1}}
        <img src="{{image}}" alt="graph">
    </body>
</html>

結果:ブラウザにヘッダ表とグラフを表示

ヘッダとグラフは モザイクとスタンプで隠してしまいました。借り物のデータなので。すいません。

f:id:piijey:20191219213939j:plain
結果

「どの行をグラフ化するか選べるようにする」というのもやりたかったんですが、 次は言語処理100本ノックか統計やりたいと思います。