📈

Chart.jsで左右のy軸の間隔(ticks)を揃える

2024/12/03に公開

Chart.jsのMulti Axisのチュートリアルで、const NUMBER_CFG = {count: DATA_COUNT, min: 0, max: 1000};と乱数を変更すると、次のように出てくることがあります。

左側が7等分、右側が10等分で表示されているため、視覚的に分かりにくいかと思います。Chart.jsが与えられたデータをもとに「nice」な見た目になるように調整してくれた結果なのですが、ここに手を加えていこうと思います。


完成例

ソースコード
手を加えたソース,これをSetupの部分のコードと差し替える
const DATA_COUNT = 7;
const NUMBER_CFG = {count: DATA_COUNT, min: 0, max: 100};

function generateRandomIntegers(cfg) {
  const {count, min, max} = cfg;
  const numbers = [];
  for (let i = 0; i < count; i++) {
    numbers.push(Math.floor(Math.random() * (max - min + 1)) + min);
  }
  return numbers;
}

const labels = Utils.months({count: 7});
const dataset1Data = generateRandomIntegers(NUMBER_CFG);
const dataset2Data = generateRandomIntegers(NUMBER_CFG);

const data = {
  labels: labels,
  datasets: [
    {
      label: 'Dataset 1',
      data: dataset1Data,
      borderColor: 'rgb(255, 99, 132)',
      backgroundColor: 'rgba(255, 99, 132, 0.5)',
      yAxisID: 'y',
    },
    {
      label: 'Dataset 2',
      data: dataset2Data,
      borderColor: 'rgb(54, 162, 235)',
      backgroundColor: 'rgba(54, 162, 235, 0.5)',
      yAxisID: 'y1',
    }
  ]
};

const maxY = getNextRoundedValue(Math.max(...dataset1Data));
const maxY1 = getNextRoundedValue(Math.max(...dataset2Data));

function getNextRoundedValue(value) {
  const valueStr = value.toString();
  const firstDigit = parseInt(valueStr[0]);
  const newFirstDigit = firstDigit + 1;
  const zeros = '0'.repeat(valueStr.length - 1);
  const result = parseInt(newFirstDigit + zeros);
  return result;
}

const config = {
  type: 'line',
  data: data,
  options: {
    responsive: true,
    interaction: {
      mode: 'index',
      intersect: false,
    },
    stacked: false,
    plugins: {
      title: {
        display: true,
        text: 'Chart.js Line Chart - Multi Axis'
      }
    },
    scales: {
      y: {
        type: 'linear',
        display: true,
        position: 'left',
        min: 0,
        max: maxY,
        ticks: {
          count: 11,
        }
      },
      y1: {
        type: 'linear',
        display: true,
        position: 'right',
        min: 0,
        max: maxY1,
        ticks: {
          count: 11,
        },

        // grid line settings
        grid: {
          drawOnChartArea: false, // only want the grid lines for one axis to show up
        },
      },
    }
  },
};

1:最大値をキリの良い数字で決める

今回は縦軸の最大値を以下のようにしました。このやり方である必要はないので、要件ややりたいことに応じてロジックを作れば良いです。

  1. ランダムな整数を生成するように変更する。
  2. データ内で最大の値を取得する。
  3. 最大の値の先頭の位に1を足し、それ以外の数字は0にする。

例: 4321->5000, 123456->200000, 334->400


// Copilot君に出してもらったコード
function generateRandomIntegers(cfg) {
  const {count, min, max} = cfg;
  const numbers = [];
  for (let i = 0; i < count; i++) {
    numbers.push(Math.floor(Math.random() * (max - min + 1)) + min);
  }
  return numbers;
}

const dataset1Data = generateRandomIntegers(NUMBER_CFG);
const dataset2Data = generateRandomIntegers(NUMBER_CFG);

const maxY = getNextRoundedValue(Math.max(...dataset1Data));
const maxY1 = getNextRoundedValue(Math.max(...dataset2Data));

// Copilot君に出してもらったコード
function getNextRoundedValue(value) {
  const valueStr = value.toString();
  const firstDigit = parseInt(valueStr[0]);
  const newFirstDigit = firstDigit + 1;
  const zeros = '0'.repeat(valueStr.length - 1);
  const result = parseInt(newFirstDigit + zeros);
  return result;
}

2:configを設定する

options.scales.{AxisID}(今回だとy,y1)の項目で以下のように設定します。それぞれ

  • min: 軸の最小値
  • max: 最大値
  • ticks.count: 軸のメモリの本数、分割したい数+1で設定

ticks.countは今回10分割したいので11としています。

min: 0,
max: maxY // or maxY1,
ticks: {
    count: 11,
},

まとめ

軸の分割数を左右揃えて見やすくしたい場合、options.scales.ticks.countを揃えるとできます。その際軸の最大値を割り切れる数字で設定することで、綺麗に表示できるようになります。


最大値を特に明示しないとデータ内の最大値が参照される(左)

Discussion