"BOKU"のITな日常

62歳・文系システムエンジニアの”BOKU”は日々勉強を楽しんでます

views.py(python)からデータを渡して、Chart.jsでRaderチャートを描く/Chart.js+django

Webアプリケーションでレーダーチャートを使う必要があって、Chart.jsの使い方とdjangoからのデータの受け渡し方法を調べました。

f:id:arakan_no_boku:20200123212917p:plain

 

はじめに

 

今回、描きたいのはこんな感じの「レーダーチャート」です。

f:id:arakan_no_boku:20200123213544p:plain

これをChart.jsで描くのは簡単でもあり、煩雑でもあります。

なぜかというと。

Chart.jsでレーダーチャートをデフォルトで描くだけなら簡単ですが、うすいグレー一色の非常にしょぼい・・グラフになってしまいます。

そこに色をつけて、フォントを大きくして、かつ目盛りを固定にする(デフォルトだと、目盛りが自動調整されるので意図した形になりません)には、それなりの設定をしないといけないです。

今回は、それなりに見える最小限の設定をやってみたいと思います。

 

HtmlとJavaScriptのソースと補足説明

 

まずHtmlです。

<canvas id="myChart"></canvas>

<script type="text/javascript" src="{% static "js/chart01.js" %}"></script>

これだけです。

IDは必須です。

処理の本体はJavaScriptで、chart01.jsという名前で保存している前提です。

本体のJavaScriptです。

let ctx = document.getElementById('myChart').getContext('2d');
let myRadarChart = new Chart(ctx, {
    type: 'radar',
    data: {
        labels: ['選択肢1', '選択肢2', '選択肢3', '選択肢4','選択肢5'],
        datasets: [{
            data: [8, 5, 5, 5, 6],
            backgroundColor: "rgba(255,0,0,0.2)", // 線の下の塗りつぶしの色
            borderColor: "red",                   // 線の色
            borderWidth: 2,                       // 線の幅
            pointStyle: "circle",                 // 点の形状
            pointRadius: 6,                       // 点形状の半径
            pointBorderColor: "red",              // 点の境界線の色
            pointBorderWidth: 2,                  // 点の境界線の幅
            pointBackgroundColor: "yellow",       // 点の塗りつぶし色
            pointLabelFontSize: 20,
            label: 'Aさん'
            }
        ]
    },
    options: {
        responsive: true,
        title: {                // タイトル
            display: true,      // 表示する
            fontSize: 20,       // タイトルのフォント
            text: 'レーダーサンプル'         // 表示するタイトル
        },
        legend: {
            position: 'bottom', // 凡例の表示位置
            labels: {
                fontSize: 20,   // 判例のフォントサイズ
            },
        },
        scale: {
            // スケールを隠す。
            display: true,      // メモリを表示する
            ticks: {            // 目盛り
                min: 0,         // 目盛りの最小値
                max: 10,        // 目盛りの最大値
                stepSize: 1,    // 目盛の間隔
                fontSize: 12,   // 目盛り数字の大きさ
                fontColor: "purple"  // 目盛り数字の色
            },
            pointLabels: {
                fontSize: 20    // チャートラベルのフォントサイズ
            },
            angleLines: {        // 軸(放射軸)
                display: true,
                color: "maroon"
            },
            gridLines: {         // 補助線(目盛の線)
                display: true,
                color: "lime"
            }
        },
    }
});

個人的には普通に使う最小限の設定かなと思っています。

ポイントを補足します。

ラベルを指定することで、選択肢の数が決まります。

labels: ['選択肢1', '選択肢2', '選択肢3', '選択肢4','選択肢5'],

 データは配列で渡します。

data: [8, 5, 5, 5, 6]

データの並び順は、ラベルの並び順に対応します。

体裁を整えるのに特に重要だと思っているのが、Scaleブロックの「ticks」と「pointLabels」です。

ticksは、チャートの目盛りを固定するための設定です。

ここで最小と最大を指定しない場合のデフォルトだと、与えたデータの最小値が中心の目盛りになるなど動的に調整されてしまうので、グラフの形が変わってしまいます。

あと、pointlabelsはこの赤枠の部分のフォントです。

f:id:arakan_no_boku:20200123225532p:plain

この情報は意外にないので、自分も最初わからなくて苦労しました。

あと。

色の指定ですが、以下のようなカラーコード表を参照します。

W3C基本16色は「red」のように名前でも指定できるので、今回はそれを使いました。

www.netyasun.com

 

あとは、ソースのコメントに書いてます。

 

djangoからデータを受け渡す

 

上記でグラフは表示できます。

でも、データとかをJavaScriptに直書きしてる限り、何の役にも立ちません(笑)

djangoからその辺を受け渡すようにします。

今回のターゲットは。

  • labels: ['選択肢1', '選択肢2', '選択肢3', '選択肢4','選択肢5'],
  • data: [8, 5, 5, 5, 6],
  • label: 'Aさん'
  • text: 'レーダーサンプル'

の4か所です。

これらをdjangopythonプログラムから、以下のようにして渡します。

from django.shortcuts import render


def chart_do(request):
    c = {
        'chart_labels': "'選択肢1', '選択肢2', '選択肢3', '選択肢4','選択肢5'",
        'chart_data': "8, 5, 5, 5, 6",
        'chart_title': "レーダーサンプル",
        'chart_target': "Aさん"
    }
    return render(request, 'chart01.html', c)

dataやlabelsは、javascript側では配列データでしたが、一旦受け渡しのためにカンマ区切りの文字列にしています。

理由は、プログラム側の編集も楽で、シンプルでわかりやすいから・・です(笑)。

上記のHTML部分は、chart01.htmlという名前で以下のように受け取る想定です。 

<div class="container">
    <div class="row my-4">
        <canvas id="myChart"></canvas>
    </div>
    <input type="hidden" id="chart_labels" name="chart_labels" value="{{ chart_labels}}">
    <input type="hidden" id="chart_title" name="chart_title" value="{{ chart_title}}">
    <input type="hidden" id="chart_target" name="chart_target" value="{{ chart_target}}">
    <input type="hidden" id="chart_data" name="chart_data" value="{{ chart_data}}">
</div>
<script type="text/javascript" src="{% static "js/chart01.js" %}"></script>

hiddenタグを配置して、valuepython側の変数を受け取っています。

あとは、このhiddenタグの情報をJavaScript側で受け取ればよいです。

受け取る部分だけ抜粋します。

let title = document.getElementById('chart_title').value;
let target = document.getElementById('chart_target').value;
let dstr = String(document.getElementById('chart_data').value);
let darr = dstr.split(',');
let dlabel = String(document.getElementById('chart_labels').value);
let larr = dlabel.split(',');

IDでvalueを取得して、dataとlabelsの部分はStringでうけとって、カンマをデリミタにしてsplitをかけて配列データに変換してます。

あとは。

  • labels: larr,
  • data: darr,
  • label: target
  • text: title

のようにリテラルの部分を変数に置き換えます。

これで実行して、リテラルで指定した時と同じグラフが表示できれば、OKですね。

f:id:arakan_no_boku:20200124014351p:plain

よしよし。

 

参考にしたサイトなど

 

日本語ドキュメントは充実してます。

misc.0o0o.org

サンプルもあります。

これでソースの表示をすると

www.chartjs.org

 あと、英語ですが本家の方です。

内容的には日本語版とほぼ同じみたいですけど。

www.chartjs.org

 

最後にソース全文です

 

pythondjango)のソース+JavaScriptです。

djangoの実行方法とかは特にここでは説明しません。

インストールとか基本的なところは、こちらのカテゴリの一連の流れに則ってます。

arakan-pgm-ai.hatenablog.com

 

views.py 

from django.shortcuts import render


def chart_do(request):
    c = {
        'chart_labels': "'選択肢1', '選択肢2', '選択肢3', '選択肢4','選択肢5'",
        'chart_data': "8, 5, 5, 5, 6",
        'chart_title': "レーダーサンプル",
        'chart_target': "Aさん"
    }
    return render(request, 'chart01.html', c)

urls.py

from django.contrib import admin
from django.urls import path
from . import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('demo07/', views.chart_do, name='chart01'),
]
   

base.html

{% load static %}
{% bootstrap_css %}
{% bootstrap_javascript jquery='full' %}
{% load widget_tweaks %}

<!doctype html>
<html lang="jp">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  	{% block header %}
	{% endblock %}
    <title>{% block title %}デモ用テンプレート{% endblock %}</title>
  </head>
  <body>
    <nav class="navbar navbar-dark bg-primary text-white">
        <h3 >サンプル (django3.0 & bootstrap4)</h3>
    </nav>

    <div class="container">
	    {% block content %}
	    {% endblock %}
    </div>    
   </body>
</html>   

chart01.html

{% extends 'base.html' %}
{% load static %}
{% bootstrap_css %}
{% bootstrap_javascript jquery='full' %}
{% load widget_tweaks %}

{% block header %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.min.js"></script>
{% endblock %}

{% block title %}
  サンプルその1
{% endblock %}

{% block content %}
<div class="container">
    <div class="row my-4">
        <canvas id="myChart"></canvas>
    </div>
    <input type="hidden" id="chart_labels" name="chart_labels" value="{{ chart_labels}}">
    <input type="hidden" id="chart_title" name="chart_title" value="{{ chart_title}}">
    <input type="hidden" id="chart_target" name="chart_target" value="{{ chart_target}}">
    <input type="hidden" id="chart_data" name="chart_data" value="{{ chart_data}}">
</div>
<script type="text/javascript" src="{% static "js/chart01.js" %}"></script>
{% endblock %}
    

chart01.js

let ctx = document.getElementById('myChart').getContext('2d');
let title = document.getElementById('chart_title').value;
let target = document.getElementById('chart_target').value;
let dstr = String(document.getElementById('chart_data').value);
let darr = dstr.split(',');
let dlabel = String(document.getElementById('chart_labels').value);
let larr = dlabel.split(',');
let myRadarChart = new Chart(ctx, {
    type: 'radar',
    data: {
        labels: larr,
        datasets: [{
            data: darr,
            backgroundColor: "rgba(255,0,0,0.2)", // 線の下の塗りつぶしの色
            borderColor: "red",                   // 線の色
            borderWidth: 2,                       // 線の幅
            pointStyle: "circle",                 // 点の形状
            pointRadius: 6,                       // 点形状の半径
            pointBorderColor: "red",              // 点の境界線の色
            pointBorderWidth: 2,                  // 点の境界線の幅
            pointBackgroundColor: "yellow",       // 点の塗りつぶし色
            pointLabelFontSize: 20,
            label: target
            }
        ]
    },
    options: {
        responsive: true,
        title: {                // タイトル
            display: true,      // 表示する
            fontSize: 20,       // タイトルのフォント
            text: title         // 表示するタイトル
        },
        legend: {
            position: 'bottom', // 凡例の表示位置
            labels: {
                fontSize: 20,   // 判例のフォントサイズ
            },
        },
        scale: {
            // スケールを隠す。
            display: true,      // メモリを表示する
            ticks: {            // 目盛り
                min: 0,         // 目盛りの最小値
                max: 10,        // 目盛りの最大値
                stepSize: 1,    // 目盛の間隔
                fontSize: 12,   // 目盛り数字の大きさ
                fontColor: "purple"  // 目盛り数字の色
            },
            pointLabels: {
                fontSize: 20    // チャートラベルのフォントサイズ
            },
            angleLines: {        // 軸(放射軸)
                display: true,
                color: "maroon"
            },
            gridLines: {         // 補助線(目盛の線)
                display: true,
                color: "lime"
            }
        },
    }
});

こんな感じです。

ではでは。