MatplotlibのグラフをDjangoで使ってみた

MatplotlibのグラフをDjangoで使ってみた
えびかずき
えびかずき

こんにちは、えびかずきです。

今回はMatplotlibのグラフをDjangoで使う方法について説明します!


最近Django開発にハマっている筆者ですが、Matplotlibでのグラフ描画に割とハマってしまったので、実装手順を備忘録として残しおきます。

こんな人におすすめ:
・DjangoのテンプレートにMatplotlibのグラフを表示させたい。

結論としては、views.pyでMatplotlibのグラフをsvg化してレスポンスを渡します。

では順を追って手順を見ていきましょう!

開発環境

OS:MacOS Catalina 10.15(ローカルサーバー)
IDE:PyCharm 
Python:3.7.3
Django:2.2.2
Matplotlib:3.3.0
PostgreSQL:10.3

概要

今回の作業の流れは下図のとおりです。

グラフを表示させたいテンプレートにurlを埋め込んで、views.pyでグラフを描画する関数を定義してレスポンスを返します。

最終的には下のようにテンプレートによって出力されたページにMatplotlibのグラフを表示することが目標です。

テンプレートの編集(.html)

まずは、テンプレートを編集します。

グラフを埋め込みたい場所へ、<img>タグとしてグラフ埋め込んでおきます。

#テンプレート追記例
#diary_list.html

app_name = 'diary'
<img src="{% url 'diary:plot' %}" width=600 height=600>

ルーティングの設定(urls.py)

次にルーティングです。

urlリクエストをviews.pyへ受け渡すためのルーティングを設定してやります。

#urls.pyの追記例

app_name = 'diary' #アプリケーション名

urlpatterns = [
    ・
    ・
    path('plot/', views.get_svg, name='plot')
]

ビューファイルの編集(views.py)

最後にビューファイルの編集です。

Matplotlibでグラフを描画してSVG化し、returnとしてHttpResponseを返します。

#views.py追記例

import matplotlib
#バックエンドを指定
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import io
from django.http import HttpResponse

#グラフ作成
def setPlt():
    x = ["07/01", "07/02", "07/03", "07/04", "07/05", "07/06", "07/07"]
    y = [3, 5, 0, 5, 6, 10, 2]
    plt.bar(x, y, color='#00d5ff')
    plt.title(r"$\bf{Running Trend  -2020/07/07}$", color='#3407ba')
    plt.xlabel("Date")
    plt.ylabel("km")

# SVG化
def plt2svg():
    buf = io.BytesIO()
    plt.savefig(buf, format='svg', bbox_inches='tight')
    s = buf.getvalue()
    buf.close()
    return s

# 実行するビュー関数
def get_svg(request):
    setPlt()  
    svg = plt2svg()  #SVG化
    plt.cla()  # グラフをリセット
    response = HttpResponse(svg, content_type='image/svg+xml')
    return response

これで、テンプレートにグラフが表示されるようになりました!

Matplotlibのエラー対策

Matplotlibはバックエンド指定しないとエラーが発生する場合があります。

筆者の環境では下のようなエラーが出ました。

UserWarning: Starting a Matplotlib GUI outside of the main thread will likely fail.
plt.bar(x, y, color=’#00d5ff’)

Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘NSWindow drag regions should only be invalidated on the Main Thread!’

これに対しては、

下のようにバックエンドを『Agg』に指定してMatplotlibを実行することで解決することができました。

#views.py

import matplotlib

#バックエンドを指定
matplotlib.use('Agg')
import matplotlib.pyplot as plt

まとめ

今回は、MatplotlibのグラフをDjangoで使う方法について説明しました。

もしエラーに出くわしたら、Matplotlibのバックエンドを指定してみましょう。

参考サイト

今回の記事はこちらのサイトを参考にさせていただきました。

Djangoカテゴリの最新記事