Flaskを使ってみる

seabornを使ったグラフ表示


Flaskを使えばこのようにグラフもブラウザーで表示することができます。


このグラフはseabornを使って作成しました。
こちらにseaborn のインストール方法が公開されていますが、以下のパッケージが必須の依存関係になっています。
Mandatory dependencies
numpy (>= 1.9.3)
scipy (>= 0.14.0)
matplotlib (>= 1.4.3)
pandas (>= 0.15.2)

seabornについては色々なところで紹介されていますが、インストールは以下で行いました。
$ sudo apt install python-pip python-setuptools

$ sudo apt install python-matplotlib

$ pip install seaborn



seabornの動作確認のために以下のプログラムを実行します。
matplotlibのpyplotを使ってグラフを作成するサンプルです。
#!/usr/bin/python
#-*- encoding: utf-8 -*-
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt

def main():
   flip=1
   x = np.linspace(0, 14, 100)
   for i in range(1, 7):
      plt.plot(x, np.sin(x + i * .5) * (7 - i) * flip)

   plt.savefig("graph.png")

if __name__ == "__main__":
   main()

起動したディレクトリに「graph.png」ができます。


次に、以下の2行を追加します。
#!/usr/bin/python
#-*- encoding: utf-8 -*-
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import seaborn as sns

def main():
   sns.set(font="serif")
   flip=1
   x = np.linspace(0, 14, 100)
   for i in range(1, 7):
      plt.plot(x, np.sin(x + i * .5) * (7 - i) * flip)

   plt.savefig("graph.png")

if __name__ == "__main__":
   main()

起動したディレクトリに「graph.png」ができますが、seabornを使うと見た目がずいぶん変わります。


さらに、以下の1行を追加します。
#!/usr/bin/python
#-*- encoding: utf-8 -*-
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import seaborn as sns

def main():
   sns.set(font="serif")
   sns.set_style('whitegrid')
   flip=1
   x = np.linspace(0, 14, 100)
   for i in range(1, 7):
      plt.plot(x, np.sin(x + i * .5) * (7 - i) * flip)

   plt.savefig("graph.png")

if __name__ == "__main__":
   main()

起動したディレクトリに「graph.png」ができますが背景が変わります。


Seabornは、matplotlibをベースにしたPythonデータ視覚化ライブラリです。
今回はSeabornを使ってフォント、背景、軸情報だけを変更し、グラフそのものはmatplotlibを使っています。

こちらに matplotlibとseabornの見た目の比較が公開されています。
seabornについてはこ ちらにサンプルが公開されていますが、matplotlibよりも見た目がきれいなグラフを作ることができます。
日本語の解説がこちらに 有ります。



このプログラムをFlask対応に変更し、グラフをブラウザーで表示できるようにします。

<変更前のプログラム>
#!/usr/bin/python
#-*- encoding: utf-8 -*-
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import seaborn as sns

def main():
   sns.set(font="serif")
   flip=1
   x = np.linspace(0, 14, 100)
   for i in range(1, 7):
      plt.plot(x, np.sin(x + i * .5) * (7 - i) * flip)

   plt.savefig("graph.png")

if __name__ == "__main__":
   main()

<変更後のプログラム>
#!/usr/bin/python
#-*- encoding: utf-8 -*-
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import seaborn as sns
from flask import Flask, render_template
app = Flask(__name__)

@app.route("/")
def main():
   sns.set(font="serif")
   flip=1
   x = np.linspace(0, 14, 100)
   for i in range(1, 7):
      plt.plot(x, np.sin(x + i * .5) * (7 - i) * flip)

   plt.savefig("static/graph.png")
   plt.close()

   templateData = {
     'title' : 'flask + seaborn',
     'filename' : 'graph.png'
   }

   return render_template('graph.html', **templateData)

if __name__ == "__main__":
   app.run(host='0.0.0.0', port=8080, debug=True)

テンプレートファイル(graph.html)を準備します。
画像がキャッシュされないようにしています。
<!DOCTYPE html>
   <head>
      <meta http-equiv="Pragma" content="no-cache">
      <meta http-equiv="Cache-Control" content="no-cache">
      <title>seaborn with flask</title>
      <link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='style.css') }}"/>
   </head>

   <body>
      <h1>{{ title }}</h1>
      <img src="/static/{{ filename }}" alt={{ filename }}>
   </body>
</html>

変更後のプログラムを使ってWEBサーバを起動します。
WindowsPCなどでブラウザを起動し、アドレスバーにサーバーのIPアドレスとポート番号を指定すると
グラフがブラウザ上に表示されます。


このようにPythonで作ったプログラムは、簡単にブラウザー対応に変更することができます。



上のスクリプトは、一旦グラフをローカルのgraph.pngに保存し、それをテンプレートを使って表示していますが、以下の様にすると、
直接グラフを含むhtmlを作成することができます。
#!/usr/bin/python
#-*- encoding: utf-8 -*-
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot
import seaborn as sns
from matplotlib.backends.backend_agg import FigureCanvasAgg
import cStringIO
from flask import Flask, render_template, make_response
app = Flask(__name__)

@app.route("/")
def main():
   sns.set(font="serif")
   fig, ax = matplotlib.pyplot.subplots()
   flip=1
   x = np.linspace(0, 14, 100)
   for i in range(1, 7):
      ax.plot(x, np.sin(x + i * .5) * (7 - i) * flip)

   canvas = FigureCanvasAgg(fig)
   buf = cStringIO.StringIO()
   canvas.print_png(buf)
   data = buf.getvalue()

   response = make_response(data)
   response.headers['Content-Type'] = 'image/png'
   response.headers['Content-Length'] = len(data)
   return response

if __name__ == "__main__":
   app.run(host='0.0.0.0', port=8080, debug=True)

テンプレートを使わないので、見た目の感じがずいぶん変わります。


続く...