pyhaya’s diary

機械学習系の記事をメインで書きます

Django で Chart.js を使ってグラフを描く

DjangoPython を使うことで簡単に Web アプリケーションを作ることができることから非常に人気のあるフレームワークです。しかし、高度なアニメーションなどは Python だけでは表現することが難しく、JavaScript の力を借りることが多い印象を受けます。この記事では、グラフ描画でよく用いられる Chart.js を Django のプロジェクト内で使う方法について紹介したいと思います。特に、Python 側で処理したデータを JavaScript に渡して、Chart.js で描画するという部分について書きます。

開発環境

Django と Chart.js を結ぶ django-chartjs というライブラリがありますが、正直ここまでやらなくていいという感じを受けたので今回はこのライブラリ無しで実装を進めます。

準備

Django プロジェクトの準備はこれまでに何度か書いていますので、割愛します。詳しく知りたい方は以下の記事の「準備」までを参考にして作ってみてください。
pyhaya.hatenablog.com

Chart.js を使ってみる

ひとまず、Django の存在は最初にはできるだけ意識せず、HTML と JavaScript を使って適当なグラフを作ってみます。

{% load static %}
<html lang="ja">
    <header>
        <meta charset="utf-8">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.js"></script>
        <script type="text/javascript" src="{% static 'visualize/js/draw.js' %}" defer></script>
    </header>
    <body>
        <div style="width: 50%; heigh: 50%;">
            <canvas id="graph"></canvas>
        </div>
    </body>
</html>

グラフだけを表示する HTML です。JavaScript のコードは

var ctx = document.getElementById("graph");

var myLineChart = new Chart(ctx, {
  type: "line",
  data: {
    labels: [
        "Jan.", "Feb.", "Mar.", "Apr.", "May", "Jun.", "Jul.", "Aug.",
        "Sep.", "Oct.", "Nov.", "Dec."
    ],
    datasets: [
      {
        data: [1, 2, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121],
        borderColor: "salmon",
        backgroundColor: "rgba(0,0,0,0)",
      },
    ],
  },
  options: {
    title: {
      display: false,
    },
    scales: {
      yAxes: [
        {
          ticks: {
            suggestedMax: 130,
            suggestedMin: 0,
            stepSize: 10,
            callback: function (value, index, values) {
              return value;
            },
          },
        },
      ],
    },
  },
});

x軸を labels に書いて、y軸の値を dataset に書いて、それ以外の軸の設定を options に書くというチュートリアルに載っていそうなコードです。

Django からデータを渡してグラフを描画する

では次に、Django からデータをもらってグラフを書くということをしてみます。これはユーザーがなにか操作をしてグラフを更新するような状況で、グラフにプロットされている値が不変でない状況です。

Django では HTML には context という形でデータを渡すことができます。そのため、JavaScript のコードを HTML 内の script タグの中に全部入れるという解決策がまず思い浮かびます。しかし、JavaScript のコードが長くなると、ソースコードがごちゃごちゃになってしまいます。そこで、データを JavaScript の変数に受け渡すところだけ script タグ内に入れるようにすればコードはスッキリします。

{% load static %}
<html lang="ja">
    <header>
        <meta charset="utf-8">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.js"></script>
        <script type="text/javascript" src="{% static 'visualize/js/draw.js' %}" defer></script>
        <script type="text/javascript">var data = {{ data }}</script>
    </header>
    <body>
        <div style="width: 50%; heigh: 50%;">
            <canvas id="graph"></canvas>
        </div>
    </body>
</html>

var data = {{ data }}Django から JavaScript へデータの受け渡しが行われます。

var ctx = document.getElementById("graph");

var myLineChart = new Chart(ctx, {
  type: "line",
  data: {
    labels: [
        "Jan.", "Feb.", "Mar.", "Apr.", "May", "Jun.", "Jul.", "Aug.",
        "Sep.", "Oct.", "Nov.", "Dec."
    ],
    datasets: [
      {
        data: data,  // ここで data を使っている
        borderColor: "salmon",
        backgroundColor: "rgba(0,0,0,0)",
      },
    ],
  },
  options: {
    title: {
      display: false,
    },
    scales: {
      yAxes: [
        {
          ticks: {
            suggestedMax: 130,
            suggestedMin: 0,
            stepSize: 10,
            callback: function (value, index, values) {
              return value;
            },
          },
        },
      ],
    },
  },
});

肝心の Python コードは

views.py

from django.shortcuts import render
from django.views import View

# Create your views here.
class Index(View):
    def get(self, request):
        context = {"data": [i*i for i in range(12)]}
        return render(request, "visualize/index.html", context)

です。これで画面をリフレッシュすると先程のグラフと同様のグラフが表示されます。
f:id:pyhaya:20200930222012p:plain