グラフ作成

チャート/グラフ作成用JavaScriptライブラリ

Webサイトにグラフを表示するにはチャート/グラフ作成用JavaScriptライブラリを使う。ここではChart.jsというライブラリを使ってグラフの作成方法を説明する。

例として「【Chart.js】時系列(タイムライン)のグラフを表示させる方法」という解説サイトに掲載されている体温グラフ(下記)を取り上げる。

図1.体温グラフ

この解説サイトに掲載されているHTMLを以下に示す(完全なHTMLにするために一部タグを補っている)。

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <!-- ライブラリ読込 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js" integrity="sha512-vBmx0N/uQOXznm/Nbkp7h0P1RfLSj0HQrFSzV8m7rOGyj30fYAOKHYvCNez+yM8IrfnW0TCodDEjRqf6fodf/Q==" crossorigin="anonymous"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.css" integrity="sha512-/zs32ZEJh+/EO2N1b0PEdoA10JkdC3zJ8L5FTiQu82LR9S/rOQNfQN7U59U9BC12swNeRAz3HSzIL2vpp4fv3w==" crossorigin="anonymous" />

    <!-- グラフ描画エリア -->
    <canvas id="myChart" ></canvas>

    <!-- 以下、スクリプト -->
    <!-- ライブラリ読込 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js" integrity="sha512-vBmx0N/uQOXznm/Nbkp7h0P1RfLSj0HQrFSzV8m7rOGyj30fYAOKHYvCNez+yM8IrfnW0TCodDEjRqf6fodf/Q==" crossorigin="anonymous"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.css" integrity="sha512-/zs32ZEJh+/EO2N1b0PEdoA10JkdC3zJ8L5FTiQu82LR9S/rOQNfQN7U59U9BC12swNeRAz3HSzIL2vpp4fv3w==" crossorigin="anonymous" />

    <!-- グラフ描画エリア -->
    <canvas id="myChart" ></canvas>

    <!-- 以下、スクリプト -->
    <script>
      var ctx = document.getElementById('myChart');
      var myChart = new Chart(ctx, {
        //線グラフ
        type: 'line',
        //データ
        data: {
          //各データの時間
          labels: ['09:30', '11:10', '13:00', '15:00', '18:30', '19:50'],
          //データセット
          datasets: [{
            label: '体温',
            data: [35.6, 35.8, 36.1, 35.5, 35.8, 36.0],
            borderColor: 'rgba(255, 99, 132, 1)', //線の色
            backgroundColor: 'rgba(255, 99, 132, 0.1)' //塗りつぶしの色
          }]
        },
        //グラフ設定
        options: {
          //凡例は非表示
          legend: {
            display: false
          },
          scales: {
            //X軸
            xAxes: [{
              //軸ラベル表示
              scaleLabel: {
                display: true,
                labelString: '時間'
              },
              //ここで軸を時間を設定する
              type: 'time',
              time: {
                parser: 'HH:mm',
                unit: 'hour',
                stepSize: 1,
                displayFormats: {
                  'hour': 'HH:mm'
                }
              },
              //X軸の範囲を指定
              ticks: {
                min: '09:00',
                max: '20:00'
              }
            }],
            //Y軸
            yAxes: [{
              //軸ラベル表示
              scaleLabel: {
                display: true,
                labelString: '体温'
              },
              //Y軸の範囲を指定
              ticks: {
                min: 34.0,
                max: 38.0
              }
            }]
          }
        }
      });
    </script>
  </body>
</html>

リスト1.体温グラフのHTML

リスト1に示したHTMLはグラフ表示する体温データ(時系列データ)を直接Javascriptに書き込んでいる(data.labelsに各データの時刻、data.datasets内のdataに対応する体温データが配列として書き込まれている)。

ここでの目標は、これらグラフ化したいデータを下記のようなスプレッドシートから読み込むことである。

図2.体温データ

GAS動的Webページ

上記の目的を達成するには、リスト1のHTMLを動的なWebページにする必要がある。ここではGASによる動的Webページでこれを実現する。

まず、GASエディタで[ファイル]から「HTML」を追加(+)して「体温グラフ.html」という名前でリスト1を保存する(下図)。

図3.GASエディタ

そしてGAS本体である「コード.js」には以下のようなコードを書く。

function doGet() {
  return HtmlService.createTemplateFromFile("体温グラフ").evaluate(); 
}

リスト2.コード.jsに書くdoGetエントリ

書き終えたらアクセスできるユーザを「全員」にして新規デプロイする。デプロイされたウェブアプリのURLをブラウザで開けば図1の体温グラフが表示されるはずである。

これで、グラフHTMLをGASで実装することに成功した。あとは、グラフに使用するデータを決め打ちした固定値から図2のスプレッドシートから読み込めばよい。

まず、リスト2の「コード.js」にスプレッドシートから体温データを読み込む下記の処理を追加する。

// スプレッドシート「サンプルデータのスプレッドシート」のID
const HEALTH_RECORD_ID = '1buKfN...25Evb4';

/**
 * スプレッドシートから「体温」シートの体温データを読み込む
 */
function getBodyTemperature() {
  const spreadsheet = SpreadsheetApp.openById(HEALTH_RECORD_ID);
  const sheet = spreadsheet.getSheetByName('体温');
  const lastRow = sheet.getLastRow();
  const numColumns = sheet.getLastColumn();
  const data = sheet.getRange(1, 1, lastRow, numColumns).getValues();
  const results = {
    "body_temperature": [],
    "measuring_date_JST": []
  };
  
  for (let i = 1; i < lastRow; i++) {
    const measuring_date = data[i][0];
    results.measuring_date_JST.push(Utilities.formatDate(measuring_date, 'JST', 'HH:mm'));
    results.body_temperature.push(data[i][1]);
  }
  return results;
}

リスト3.体温データの読み込み関数getBodyTemperature

ここで、HEALTH_RECORD_IDは図2のスプレッドシートのIDである。関数getBodyTemperatureは、スプレッドシートから読み込んだ時系列体温データを連想配列として返す。具体的には、体温を計測した時刻をmeasuring_date_JSTという要素名の配列に、対応する体温データをbody_temperatureという要素名の配列にセットして返してくる。

HTMLにGASを埋め込む

リスト1のHTMLにGASを埋め込むにはタグ"<?"と"?>"で囲み、暗黙オブジェクト output を利用してHTMLに文字列を出力する(Google Apps Script の暗黙オブジェクト)。

まず、以下のようにリスト1の先頭でGASのスクリプトレットを追加する。

<?
  const results = getBodyTemperature();
  const body_temperature = results.body_temperature.join(',');
  const measuring_date_JST = "'" + results.measuring_date_JST.join("','") + "'";
?>

リスト4.体温グラフ.htmlに追加するスクリプトレット

これは、リスト3で定義した関数 getBodyTemperature() を呼び出して、スプレッドシートの体温計測時系列データを取得し、それをデータ配列要素の文字列にしているところである。

変数 body_temperature には「37.6, 36.8, 35.1, 34.5, 36.8, 35.0」といった文字列、変数 measuring_date_JST には「'09:30', '11:10', '13:00', '15:00', '18:30', '19:50'」といった文字列が格納されることになる。

あとは、このデータをリスト1の決め打ち配列に展開するだけである(下記)。

//データ
data: {
  //各データの時間
  labels: [<? output._ = measuring_date_JST ?>],
  //データセット
  datasets: [{
    label: '体温',
    data: [<? output._ = body_temperature ?>],
    borderColor: 'rgba(255, 99, 132, 1)', //線の色
    fill: false,
  }]
},

リスト5.データをGASスクリプトレットで置き換え

リスト5に示すように、HTML中にGASスクリプトレットを使って文字列(この場合は体温時系列データを表す配列要素)を埋め込むには暗黙オブジェクト output を利用する。

<? output._ = [埋め込む文字列あるいはそれを格納した変数] ?>

リスト6.文字列の埋め込み

最後に完成した「体温グラフ.html」を以下に再掲する。

<!--
  【Chart.js】時系列(タイムライン)のグラフを表示させる方法
  https://mat0401.info/blog/chartjs-timeline/
-->

<?
  const results = getBodyTemperature();
  const body_temperature = results.body_temperature.join(',');
  const measuring_date_JST = "'" + results.measuring_date_JST.join("','") + "'";
?>

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <!-- ライブラリ読込 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js" integrity="sha512-vBmx0N/uQOXznm/Nbkp7h0P1RfLSj0HQrFSzV8m7rOGyj30fYAOKHYvCNez+yM8IrfnW0TCodDEjRqf6fodf/Q==" crossorigin="anonymous"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.css" integrity="sha512-/zs32ZEJh+/EO2N1b0PEdoA10JkdC3zJ8L5FTiQu82LR9S/rOQNfQN7U59U9BC12swNeRAz3HSzIL2vpp4fv3w==" crossorigin="anonymous" />

    <!-- グラフ描画エリア -->
    <canvas id="myChart" ></canvas>

    <!-- 以下、スクリプト -->
    <script>
      var ctx = document.getElementById('myChart');
      var myChart = new Chart(ctx, {
        //線グラフ
        type: 'line',
        //データ
        data: {
          //各データの時間
          labels: [<? output._ = measuring_date_JST ?>],
          //データセット
          datasets: [{
            label: '体温',
            data: [<? output._ = body_temperature ?>],
            borderColor: 'rgba(255, 99, 132, 1)', //線の色
            fill: false,
          }]
        },
        //グラフ設定
        options: {
          //凡例は非表示
          legend: {
            display: true
          },
          scales: {
            //X軸
            xAxes: [{
              //軸ラベル表示
              scaleLabel: {
                display: true,
                labelString: '時間'
              },
              //ここで軸を時間を設定する
              type: 'time',
              time: {
                parser: 'HH:mm',
                unit: 'hour',
                stepSize: 1,
                displayFormats: {
                  'hour': 'HH:mm'
                }
              },
              //X軸の範囲を指定
              ticks: {
                min: '09:00',
                max: '20:00'
              }
            }],
            //Y軸
            yAxes: [{
              //軸ラベル表示
              scaleLabel: {
                display: true,
                labelString: '体温'
              },
              //Y軸の範囲を指定
              ticks: {
                min: 34.0,
                max: 38.0
              }
            }]
          }
        }
      });
    </script>
  </body>
</html>

リスト6.体温グラフ.htmlの完成形

保存して新規デプロイすると完成する。ここをクリックすると完成した体温グラフが確認できる。試しにスプレッドシートのデータを修正してグラフが変化するか確認するとよい。

x軸のスケール

体温グラフ(図1)のx軸は時間スケールになっている。chart.jsで時系列のグラフを作成するときのx軸の設定方法については「chart.jsで時系列のグラフ」を参考にするとよい。

また、時間軸の日付書式はMoment.jsに従っている。

x軸の範囲

x軸の範囲は次のようにして動的に変更できる。

//0:00〜23:59
function setTicks() {
  myChart.options.scales.xAxes[0].ticks.min = "0:00";
  myChart.options.scales.xAxes[0].ticks.max = "23:59";
  myChart.update();
}

リスト7.x軸の範囲を変更する


Bootstrap

画面レイアウトを整えるためにBootstrapを用いた。Bootstrap4.5のスターターテンプレートを「体温グラフ.html」に組み込んだ。それがこれ

ボタンを配置するためにコンテナを利用してレイアウトを作成した。

<div class="container-fluid">
  <!-- ボタン -->
  <div class="row">
    <div class="col">
      <button type="button" class="btn btn-primary btn-block">Primary</button>
    </div>
    <div class="col">
      <button type="button" class="btn btn-secondary btn-block">Secondary</button>
    </div>
    <div class="col">
      <button type="button" class="btn btn-success btn-block">Success</button>
    </div>
  </div>
  <!-- グラフ描画エリア -->
  <div class="row">
    <div class="col">
      <canvas id="myChart" ></canvas>
    </div>
  </div>
</div>

リスト8.Bootstrapによるコンテナレイアウト

Chart.jsでグラフのサイズを動的に決定する方法についてはこのサイトに書いてある。非常に複雑なため,まだ実装していない。

0 件のコメント:

コメントを投稿