M.Hiroi's Home Page

JavaScript Programming

お気楽 Chart.js 超入門


Copyright (C) 2025 Makoto Hiroi
All rights reserved.

●片対数グラフ

グラフの一方の軸が対数スケールになっているグラフを「片対数グラフ (semilog graph)」といいます。極端に範囲の広いデータを扱うことができます。Chart.js でも片対数グラフを描画することができます。

リスト : 片対数グラフ

<div style="width:600px; background-color: white">
  <canvas id="mychart0"></canvas>
</div>
<script>
  const ctx0 = document.getElementById('mychart0');
  new Chart(ctx0, {
    type: 'line',
    data: {
      labels: [0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4],
      datasets: [{
        label: 'y = 10 ** x',
        data: [1, 3.162278, 10, 31.62278, 100, 316.2278, 1000, 3162.278, 10000],
      }]
    },
    options: {
      scales: {
        y: { type: 'logarithmic' }
      }
    }
  });
</script>

●積み上げ棒グラフ

積み上げ棒グラフとは同じ項目内のデータを上に積み上げたグラフのことです。次の表を見てください。

   : 2010 2015 2020 2025
---+---------------------
 A :  10   15   20   25
 B :  20   15   15   10
 C :  10   15   15   20

たとえば、ある会社の主力商品 A, B, C の売上高だとしましょう。これを棒グラフで表すと次のようになります。

リスト : 棒グラフ

<div style="width:600px; background-color: white">
  <canvas id="mychart1"></canvas>
</div>
<script>
  const ctx1 = document.getElementById('mychart1');
  new Chart(ctx1, {
    type: 'bar',
    data: {
      labels: ['2010', '2015', '2020', '2025'],
      datasets: [
      {
        label: '# A',
        data: [10, 15, 20, 25],
      },
      {
        label: '# B',
        data: [20, 15, 15, 10],
      },
      {
        label: '# C',
        data: [10, 15, 15, 20],
      }]
    },
    options: { }
  });
</script>

単純な棒グラフの場合、個々の商品の売上高の推移はわかりますが、A, B, C の合計値は明確ではありません。これを積み上げ棒グラフで表すと、次のようになります。

合計値でみると、売上高は右肩上がりであることが一目でわかります。

リスト : 積み上げ棒グラフ

<div style="width:600px; background-color: white">
  <canvas id="mychart2"></canvas>
</div>
<script>
  const ctx2 = document.getElementById('mychart2');
  new Chart(ctx2, {
    type: 'bar',
    data: {
      labels: ['2010', '2015', '2020', '2025'],
      datasets: [
      {
        label: '# A',
        data: [10, 15, 20, 25],
      },
      {
        label: '# B',
        data: [20, 15, 15, 10],
      },
      {
        label: '# C',
        data: [10, 15, 15, 20],
      }]
    },
    options: {
      scales: {
        x: {stacked: true},
        y: {stacked: true}
      }
    }
  });
</script>

●横棒グラフ

棒グラフ (bar chart) において、options のプロパティ indexAxis に 'y' をセットすると、棒グラフが水平方向に描画されます。

リスト : 横棒グラフ (1)

<div style="width:600px; background-color: white">
  <canvas id="mychart8"></canvas>
</div>
<script>
  const ctx8 = document.getElementById('mychart8');

  new Chart(ctx8, {
    type: 'bar',
    data: {
      labels: ['130-135', '135-140', '140-145', '145-150', '150-155', '155-160', '160-165', '165-170'],
      datasets: [{
        label: '# 度数',
        data: [1, 6, 12, 25, 32, 17, 6, 1],
        borderWidth: 1,
	categoryPercentage: 0.9
      }]
    },
    options: {
      indexAxis: 'y',
      scales: {
        x: {
          beginAtZero: true
        },
      }
    }
  });
</script>

y 軸にプロパティ reverse: true をセットすると、ラベルの順番を反転させることができます。

リスト : 横棒グラフ (2)

<div style="width:600px; background-color: white">
  <canvas id="mychart9"></canvas>
</div>
<script>
  const ctx9 = document.getElementById('mychart9');

  new Chart(ctx9, {
    type: 'bar',
    data: {
      labels: ['130-135', '135-140', '140-145', '145-150', '150-155', '155-160', '160-165', '165-170'],
      datasets: [{
        label: '# 度数',
        data: [1, 6, 12, 25, 32, 17, 6, 1],
        borderWidth: 1,
	categoryPercentage: 0.9
      }]
    },
    options: {
      indexAxis: 'y',
      scales: {
        x: {
          beginAtZero: true
        },
        y: {
          reverse: true,
        },
      }
    }
  });
</script>

同様に、indexAxis: 'y' を指定すると、積み上げ棒グラフも水平方向に描画することができます。

リスト : 横棒グラフ (3)

<div style="width:600px; background-color: white">
  <canvas id="mychart10"></canvas>
</div>
<script>
  const ctx10 = document.getElementById('mychart10');
  new Chart(ctx10, {
    type: 'bar',
    data: {
      labels: ['2010', '2015', '2020', '2025'],
      datasets: [
      {
        label: '# A',
        data: [10, 15, 20, 25],
      },
      {
        label: '# B',
        data: [20, 15, 15, 10],
      },
      {
        label: '# C',
        data: [10, 15, 15, 20],
      }]
    },
    options: {
      indexAxis: 'y',
      scales: {
        x: {
          stacked: true,
          beginAtZero: true
        },
        y: {stacked: true}
      }
    }
  });
</script>

●複数軸と複合グラフ

2 つのグラフを描画するとき、それらの値が大きく異なると、同一スケールではわかりにくくなります。この場合、左側の y 軸だけではなく、右側の y 軸にもスケールを設定すると便利です。たとえば、2024 年度東京都月別平均気温と降水量 を折れ線グラフで表してみましょう。

リスト : 複数軸

<div style="width:600px; background-color: white">
  <canvas id="mychart11"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
<script>
  const ctx11 = document.getElementById('mychart11');
  new Chart(ctx11, {
    type: 'line',
    data: {
      labels: ['2024-01', '2024-02', '2024-03', '2024-04', '2024-05', '2024-06', 
               '2024-07', '2024-08', '2024-09', '2024-10', '2024-11', '2024-12'],
      datasets: [
      {
        label: '降水量',
        data: [36, 78.5, 188.5, 115.5, 201.5, 350.0, 206.5, 381.0, 111.5, 174.5, 82.0, 0.5]
      },
      {
        label: '平均気温',
        data: [7.1, 8.0, 9.6, 17.1, 20.0, 23.1, 28.7, 29.0, 26.6, 20.6, 13.7, 8.1],
        yAxisID: 'y2',
      },],
    },
    options: { 
      scales: {
        x: {
          type: 'time',
          time: { unit: 'month' }
        },
        y: {
          title: {
            display: true,
            text: '降水量 (mm)',
          },
          beginAtZero: true
        },
        y2: {
          title: {
            display: true,
            text: '平均気温 (℃)',
          },
          position: 'right',
          min: 0,
          max: 40
        },
      }
    }
  });
</script>

次は降水量を棒グラフに変更してみましょう。2 種類以上の異なるチャートを表示するグラフを「複合チャート (Mixed chart)」といいます。

リスト : 複合チャート

<div style="width:600px; background-color: white">
  <canvas id="mychart12"></canvas>
</div>
<script>
  const ctx12 = document.getElementById('mychart12');
  new Chart(ctx12, {
    data: {
      labels: ['2024-01', '2024-02', '2024-03', '2024-04', '2024-05', '2024-06', 
               '2024-07', '2024-08', '2024-09', '2024-10', '2024-11', '2024-12'],
      datasets: [
      {
        type: 'bar',
        label: '降水量',
        data: [36, 78.5, 188.5, 115.5, 201.5, 350.0, 206.5, 381.0, 111.5, 174.5, 82.0, 0.5]
      },
      {
        type: 'line',
        label: '平均気温',
        data: [7.1, 8.0, 9.6, 17.1, 20.0, 23.1, 28.7, 29.0, 26.6, 20.6, 13.7, 8.1],
        yAxisID: 'y2',
      },],
    },
    options: { 
      scales: {
        x: {
          type: 'time',
          time: { unit: 'month' }
        },
        y: {
          title: {
            display: true,
            text: '降水量 (mm)',
          },
          beginAtZero: true
        },
        y2: {
          title: {
            display: true,
            text: '平均気温 (℃)',
          },
          position: 'right',
          min: 0,
          max: 40
        },
      }
    }
  });
</script>

●折れ線グラフの塗りつぶし

折れ線グラフ (line chart) において、プロパティ fill を true に設定すると、x 軸と折れ線グラフの間を塗りつぶします。fill に 'end' を指定すると、折れ線グラフと画面の上端 (end) の間を塗りつぶします。'start' を指定すると画面の下端と折れ線グラフの間を塗りつぶします。

リスト : 折れ線グラフの塗りつぶし

<div style="width:600px; background-color: white">
  <canvas id="mychart3"></canvas>
</div>
<script>
  let xs = [];
  for (let i = -2; i <= 2; i += 0.25) xs.push(i);
  const ctx3 = document.getElementById('mychart3');
  new Chart(ctx3, {
    type: 'line',
    data: {
      labels: xs,
      datasets: [{
        label: 'y = x**2 - 1',
        data: xs.map(x => x ** 2 - 1),
        fill: true
      }, {
        label: 'y = x**3 - 4x',
        data: xs.map(x => x ** 3 - 4*x),
        fill: 'end'
      }, {
        label: 'y = x**4 - 6x**2 + 4',
        data: xs.map(x => x ** 4 - 6 * x**2 + 4),
        fill: 'start'
      }]
    },
    options: {
      lineTension: 0.4
    }
  });
</script>
リスト : 折れ線グラフの塗りつぶし (2)

<div style="width:600px; background-color: white">
  <canvas id="mychart4"></canvas>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.js"></script>
<script>
  const ctx = document.getElementById('mychart4');
  new Chart(ctx4, {
    type: 'line',
    data: {
      labels: xs,
      datasets: [{
        label: 'y = x**2 - 1',
        data: xs.map(x => x ** 2 - 1),
        fill: 2
      }, {
        label: 'y = x**3 - 4x',
        data: xs.map(x => x ** 3 - 4*x),
      }, {
        label: 'y = x**4 - 6x**2 + 4',
        data: xs.map(x => x ** 4 - 6 * x**2 + 4),
      }]
    },
    options: {
      lineTension: 0.4
    }
  });
</script>

●タイトルと凡例

グラフのタイトルは options.plugins のプロパティ title で指定します。

リスト : タイトル

<div style="width:600px; background-color: white">
  <canvas id="mychart13"></canvas>
</div>
<script>
  const ctx13 = document.getElementById('mychart13');
  new Chart(ctx13, {
    type: 'bar',
    data: {
      labels: ['2024-01', '2024-02', '2024-03', '2024-04', '2024-05', '2024-06', 
               '2024-07', '2024-08', '2024-09', '2024-10', '2024-11', '2024-12'],
      datasets: [
      {
        label: '降水量',
        data: [36, 78.5, 188.5, 115.5, 201.5, 350.0, 206.5, 381.0, 111.5, 174.5, 82.0, 0.5],
      }],
    },
    options: { 
      plugins: {
        title: {
          display: true,
          text: '2024 年度東京都降水量',
          font: {
            size: 16,
          }
        },
      },
      scales: {
        x: {
          type: 'time',
          time: { unit: 'month' }
        },
        y: {
          beginAtZero: true,
        },
      }
    }
  });
</script>

凡例の詳細は options.plugins のプロパティ legend で指定します。

リスト : 凡例

<div style="width:600px; background-color: white">
  <canvas id="mychart14"></canvas>
</div>
<script>
  const ctx14 = document.getElementById('mychart14');
  new Chart(ctx14, {
    type: 'bar',
    data: {
      labels: ['2024-01', '2024-02', '2024-03', '2024-04', '2024-05', '2024-06', 
               '2024-07', '2024-08', '2024-09', '2024-10', '2024-11', '2024-12'],
      datasets: [
      {
        label: '降水量',
        data: [36, 78.5, 188.5, 115.5, 201.5, 350.0, 206.5, 381.0, 111.5, 174.5, 82.0, 0.5],
      }],
    },
    options: { 
      plugins: {
        title: {
          display: true,
          text: '2024 年度東京都降水量',
          font: {
            size: 16,
          },
          position: 'bottom',
        },
        legend: {
          position: 'bottom',
        },
      },
      scales: {
        x: {
          type: 'time',
          time: { unit: 'month' }
        },
        y: {
          beginAtZero: true,
        },
      }
    }
  });
</script>

●正規分布

次の式で表される確率分布を「正規分布」といいます。

\( f(x) = \dfrac{1}{\sqrt{2\pi}\sigma} \exp \left(-\dfrac{(x - \mu)^2}{2σ^2}\right) \)

これを平均 \(\mu\)、分散 \(\sigma^2\) の正規分布といい、\(N(\mu, \sigma^2)\) と略記します。特に、\(N(0, 1)\) を「標準正規分布」といいます。正規分布は次の図に示すような釣鐘状の曲線 (ベル・カープ) になります。

リスト : 正規分布 (1)

<div style="width:600px; background-color: white">
  <canvas id="mychart5"></canvas>
</div>
<script>
  function norm(x, m, s2) {
    return (1 / Math.sqrt(2 * Math.PI * s2)) * Math.exp(- ((x - m) ** 2) / (2 * s2));
  }
  let xs1 = [];
  for (let i = -5; i <= 5; i += 0.25) xs1.push(i);
  const ctx5 = document.getElementById('mychart5');
  new Chart(ctx5, {
    type: 'line',
    data: {
      labels: xs1,
      datasets: [
      {
        label: 'N(0, 1)',
        data: xs1.map(x => norm(x, 0, 1)),
      },
      {
        label: 'N(1, 2)',
        data: xs1.map(x => norm(x, 1, 2)),
      },
      {
        label: 'N(-2, 0.5)',
        data: xs1.map(x => norm(x, -2, 0.5)),
      }, ]
    },
    options: {
      radius: 0,
      lineTension: 0.4
    }
  });
</script>

青線が N(0, 1)、赤線が N(1, 2)、黄線が N(-2. 0.5) です。正規分布は、平均値のデータが一番多く、分散の値が小さいほど平均値にデータが集まるので、ベル・カーブの頂点が高くなります。分散の値が大きくなると、ベル・カーブの頂点は低くなり裾野が広がります。ようするに、分散の値だけで正規分布の形が決まるわけです。

正規分布の場合、\(-\sigma \lt x \lt \sigma\) の確率が 68.26 % で、\(-2\sigma \lt x \lt 2\sigma\) の確率が 95.44 % になります。したがって、下図のように標準正規分布では \(-1 \lt x \lt 1\) の確率が 68.26 % で、\(-2 \lt x \lt 2\) の確率が 95.44 % になります。

リスト : 正規分布 (2)

<div style="width:600px; background-color: white">
  <canvas id="mychart6"></canvas>
</div>
<script>
  const ctx6 = document.getElementById('mychart6');
  new Chart(ctx6, {
    type: 'line',
    data: {
      labels: xs1,
      datasets: [
      {
        label: 'N(0, 1)',
        data: xs1.map(function(x) {
                if (x <= -1 || x >= 1) {
                  return norm(x, 0, 1);
                } else {
                  return null;
                }
              }),
      },
      {
        label: 'N(0, 1)',
        data: xs1.map(function(x) {
                if (x >= -1 && x <= 1) {
                  return norm(x, 0, 1);
                } else {
                  return null;
                }
              }),
        fill: true
      },
    ]},
    options: {
      radius: 0,
      lineTension: 0.4
    }
  });
</script>
リスト : 正規分布 (3)

<div style="width:600px; background-color: white">
  <canvas id="mychart7"></canvas>
</div>
<script>
  const ctx7 = document.getElementById('mychart7');
  new Chart(ctx7, {
    type: 'line',
    data: {
      labels: xs1,
      datasets: [
      {
        label: 'N(0, 1)',
        data: xs1.map(function(x) {
                if (x <= -2 || x >= 2) {
                  return norm(x, 0, 1);
                } else {
                  return NaN;
                }
              }),
      },
      {
        label: 'N(0, 1)',
        data: xs1.map(function(x) {
                if (x >= -2 && x <= 2) {
                  return norm(x, 0, 1);
                } else {
                  return undefined;
                }
              }),
        fill: true
      },
    ]},
    options: {
      radius: 0,
      lineTension: 0.4
    }
  });
</script>

初版 2025 年 3 月