グラフの一方の軸が対数スケールになっているグラフを「片対数グラフ (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>
次の式で表される確率分布を「正規分布」といいます。
これを平均 \(\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>