qtatsuの週報

初心者ですわぁ

Django + Chart.jsなら、django-chartjsライブラリを使おう

前書き

最近、業務でDjango + Chart.jsを使ったシステムを作成しました。 Chart.jsは綺麗なグラフを簡単に作成することができ、またドキュメントも充実しています。しかしグラフ一つ作るためのパラメータが非常に多く、Django側から送ったデータをjavascriptで埋めていくのが大変でした。 かといってDjango側でChart.js用のJSONを自分で組み立てるのは厳しいと感じ、諦めていました。

ところが、Chart.js描画のためのデータを送るバックエンド側として、Django-chartjsというライブラリがあるということを最近知りました。

こちらを利用すると、DjangoからChart.jsに必要な各種データ、ラベル、オプションをViewのメソッド別に整理して定義することができるようでした。

フロントはAjaxを書いて、new Chart(ctx, {type: 'xxx', data:data})とするだけで良さそうです。

公式ドキュメントは無い様なのですが、実装されているBaseとなるViewは直感的に使うことができ、またデモ用のサンプルコードが公式GitHubに充実していて、簡単に導入できそうでした。

公式GitHub

GitHub - peopledoc/django-chartjs: Django Class Based Views to generate Ajax charts js parameters.

公式GitHubのデモ用のサンプルコード

django-chartjs/demo at master · peopledoc/django-chartjs · GitHub

実際に使ってみました。基本的には、上述の公式GitHubのREADMEに載っている例を変更して使います。

所感

少ないコード量で記述が可能ですが、その反面デフォルト値を利用することで簡略化を実現しているように感じました。 デフォルトの挙動をカスタムするほど、(仕方ないことですが)当然コード量は増えていく感じです。ソースコードは決して難しいものでは無いので、良く読んでメソッドをオーバーライドする必要があります。

色の変更

色の変更は、以下の2種類のメソッドをオーバーライドすることで実現できるようです。

get_colorsメソッド

RGBを指定したタプルのリストをここで定義します。順番と数は定義したラベルと合わせて使うことが多いと思いますが、数は多くても少なくても大丈夫です(next_colorメソッドを利用する場合)。

next_colorメソッドに定義したリストを渡し、returnします。next_colorメソッドは特殊なジェネレーターを返します。nextし続け最後までくると、渡したリストの最初に戻ります。ですので指定した色を使い果たしてまだラベルが残っていれば、また最初の色から順番に適応していきます。

get_dataset_optionsメソッド

get_colorsメソッドが返した色をもとに、チャートの各部品の色を指定するメソッドです。 デフォルトではbackgroundColorのみ透明度を0.5にしたグラフを描画します。この部分を好きな様に変更すれば、自由にグラフを描画できます。

以下の例では、グラフを濃い目の赤/緑/青に変更しています。

from chartjs.colors imoport next_color
# .....(略)........

class lineChartJSONView(BaseLineChartView):

# .....(略).........
    def get_colors(self):
        # 赤 / 緑 / 青 
        l = [(200, 0, 0), (0, 200, 0), (0, 0, 200)]
        return next_color(l)

    def get_dataset_options(self, index, color):
        default_opt = {
            # 棒グラフの色が濃くなるように、透明度を0.5 -> 0.9に変更
            "backgroundColor": "rgba(%d, %d, %d, 0.9)" % color,
            
            "borderColor": "rgba(%d, %d, %d, 1)" % color,
            "pointBackgroundColor": "rgba(%d, %d, %d, 1)" % color,
            "pointBorderColor": "#fff",
        }
        return default_opt

options属性の付加

BaseLineChartViewは、Chart.jsにおけるoptionsを設定できません。optionsを設定したい場合は、BaseLineOptionsChartViewを利用し、get_options関数で設定したいoptionsの一覧をdictとしてreturnします。

また、BaseLineOptionsChartViewを使う際にはフロント側も変更する必要があります。

$.get('{% url "cms:line_chart_json" %}', function (data) {
  const ctx = 'myChart';
  // dataとoptionsを以下の様に取り出す必要がある。
  new Chart(ctx, {type: 'bar', data: data.data, options: data.options});
});

サブタイトルをグラフの上に表示し、画質を10倍にしてみます。

また、get_labels, get_providers, get_dataメソッドはBaseLineChartViewと全く同じように記述します。 (BaseLineOptionsChartViewは、BaseLineChartViewを継承して作成されています)

class lineChartJSONView(BaseLineOptionsChartView):
# ...........(略)..................
    def get_options(self):
        options = {
            "title": {"display": True, "text": "サブタイトル"},
            "devicePixelRatio": 10,
        }
        return options

補足: 利用可能なview

デモ用サンプルコードをみると

from chartjs.util import date_range, value_or_null
from chartjs.views.columns import BaseColumnsHighChartsView
from chartjs.views.lines import (
    BaseLineChartView,
    BaseLineOptionsChartView,
    HighchartPlotLineChartView,
)
from chartjs.views.pie import HighChartDonutView, HighChartPieView

どうやらChart.js用のViewとHighChart用のViewがありそうです。

また、Chart.js用のViewとしてはLineChartと名前がついているViewしか見当たりません。 ですが、このViewでLineChart以外も記述できます。Chart.jsでは、フロント側でtypeを指定しますが、そこでlinebarを指定すれば形式を変更できます。

Chart.jsで利用するViewは

  1. BaseLineCharView
  2. BaseLineOptionsChartView

この二種類の様です。

ソースコードchartjs/views/lines.pyに存在し、割とシンプルなコードなので読めばすぐわかります。 BaseLineOptionsChartViewは、その名の通りoptions属性を付加できる、というだけです。

(念の為)ソースコードの完全なパスは、以下の様にして得られます。

$ python -c "import chartjs; print(chartjs.__path__)"