Django アプリケーション内で、データベースから取得したデータをグラフにして表示したいと思ったので方法を調べました。
ざっくりですが、取得した情報を元にグラフの 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 を返します。
処理の流れは下記の通りです。
- URL ディスパッチャからget_trend_svg が呼び出される
- YtTrendChannel モデルからデータを取り出す
- x と y のリストを作成
- make_chart 関数に x と y を渡しグラフを作成
- convert_to_svg 関数でグラフを SVG に変換
- 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 関数の中でコメントを色々書いていますが、メモリ上に一時ファイルを保存できるため、実ファイルが作られなくて済むんだそうです。
すると下記の様にチャートが表示されます。表示がだいぶ崩れてますがこれは後ほど調整するということで。。。
