Matplotlib で描画したグラフを SVG 化して Django で表示する方法

Django アプリケーション内で、データベースから取得したデータをグラフにして表示したいと思ったので方法を調べました。

ざっくりですが、取得した情報を元にグラフの SVG 画像を作成、そしてページに表出する方法を記載します。

  1. テンプレートに img タグを追加
  2. urls.py に URL ディスパッチャを追加
  3. views.py に SVG 描画の処理を追加

1. テンプレートに img タグを追加

テンプレートファイルのグラフを表示したい場所に img タグを追加し、URL 逆引きで URL ディスパッチャを呼び出します。

<img src="{% url 'sample_django_app:yt_trend_svg' %}">

今回は sample_django_app の yt_trend_svg というディスパッチャを呼び出しています。

2. urls.py に URL ディスパッチャを追加

urls.py の urlpatterns リストの中に下記を追加し、yt_trend_svg が呼び出されたら views.py の get_trend_svg 関数を呼び出す様設定しています。

path('chart/', views.get_trend_svg, name="yt_trend_svg"),

3. views.py に SVG 描画の処理を追加

ビューで get_trend_svg 関数を定義し、データの取得、グラフの作成、SVG への変換をして最後に HttpResponse を返します。

処理の流れは下記の通りです。

  1. URL ディスパッチャからget_trend_svg が呼び出される
  2. YtTrendChannel モデルからデータを取り出す
  3. x と y のリストを作成
  4. make_chart 関数に x と y を渡しグラフを作成
  5. convert_to_svg 関数でグラフを SVG に変換
  6. HttpResponse として SVG を返す
import io
from django.http import HttpResponse
import matplotlib
matplotlib.use('Agg') # Matplotlib の backend を指定
import matplotlib.pyplot as plt

# 1. ルーターから get_trend_svg が呼び出される
def get_trend_svg(request):
    
    def make_chart(x, y):
        # setting up plots
        plt.bar(x, y, color='#00d5ff')
        plt.title("My Chart", color='#3407ba')
        plt.xlabel("channel")
        plt.ylabel("views")

    def convert_to_svg():
        # convert the plots to SVG
        buffer = io.BytesIO() # バッファを作成
        plt.savefig(buffer, format='svg', bbox_inches='tight') # バッファに一時保存
        s = buffer.getvalue() # バッファの内容を s に渡す
        buffer.close() # バッファはクローズ
        return s # s を返す
    
    # 2. YtTrendChannel モデルからデータを取り出す
    channels = YtTrendChannel.objects.filter(data_date='20210104').order_by('channel_name')[:10]

    # 3. x と y のリストを作成
    x = [channel.channel_name for channel in channels]
    y = [int(channel.view_count) for channel in channels]

    # 4. make_chart 関数に x と y を渡しグラフを作成
    make_chart(x, y)

    svg = convert_to_svg() # 5. グラフを SVG に変換
    plt.cla()
    
    # 6. HttpResponse として SVG を返す
    return HttpResponse(svg, content_type='image/svg+xml')

convert_to_svg 関数の中でコメントを色々書いていますが、メモリ上に一時ファイルを保存できるため、実ファイルが作られなくて済むんだそうです。

すると下記の様にチャートが表示されます。表示がだいぶ崩れてますがこれは後ほど調整するということで。。。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です