目盛りの自動生成アルゴリズム比較
グラフの軸に表示する目盛り(ticks)は、どうやって決まっているのでしょうか?
「0 から 100 まで、5 つくらい目盛りを表示したい」という要求は単純に見えますが、実際には「読みやすい数値」「適切な間隔」「データ範囲のカバー」といった複数の要件のバランスを取る必要があります。
この記事では、目盛り生成アルゴリズムの観点から、主要なグラフライブラリ(D3.js、Recharts、ECharts)を比較します。
目盛り生成の難しさ
グラフの軸目盛りは、ただの数値の羅列ではありません。良い目盛りは以下の特徴を持っています。
- 読みやすい数値: 5、10、100 のような切りの良い数
- 適切な間隔: データの範囲を適切にカバーしている
- 適度な密度: 多すぎず少なすぎない
しかし、これらの要件はしばしば矛盾します。
データの範囲がちょうどきりの良い数になることは稀です。例えば以下のようなケースがあります。
- 売上データの範囲が ¥127〜¥2,847,293
- 温度データの範囲が-3.7°C〜24.3°C
- アクセス数の範囲が 127〜8,942
このような「半端な数値」をそのまま軸の範囲として使うと、読みやすい目盛りを生成するのが難しくなります。
例えば、min=3、max=47 の範囲で、読みやすい目盛りを 5 つくらい作りたい場合を考えてみましょう。10 刻みの目盛り[10, 20, 30, 40, 50]を作ると読みやすいですが、最小値 3 をカバーできません。一方、データの最小値 3 から最大値 47 までをきっちり含めると[3, 14, 25, 36, 47]のような半端な目盛りになってしまいます。
この問題を解決するため、多くのライブラリは「範囲の調整」という戦略を取ります。データ範囲を少し拡張して(3〜47 → 0〜50)、きれいな目盛りとデータのカバレッジを両立させるのです。
各ライブラリの比較
D3.js: プリミティブな API を提供
D3 は目盛り生成のためのプリミティブな API を提供しています。
scale.ticks(count)
指定された範囲内で、読みやすい目盛りを生成します。ただし、問題があります。
例えば、domain を [3, 47] として ticks(5) を呼ぶと、[10, 20, 30, 40] のような目盛りが生成されます。読みやすい数値(10 刻み)ですが、最小値 3 と最大値 47 が範囲外になってしまいます。
scale.nice()
この問題を解決する方法の 1 つとして、nice() で domain を拡張できます。[3, 47] を [0, 50] に拡張することで、ticks() が生成する目盛りが必ずデータ範囲をカバーするようにします。
ただし、nice() は必須ではありません。他にも解決方法があります。
- domain を最初から [0, 50] のように手動で設定する
- データの最小値・最大値にパディングを追加してから範囲を設定する
- tickValues で目盛りを明示的に指定する
D3 は開発者に選択を委ねており、状況に応じて適切な方法を選べます。scale.nice().ticks() はその中でも便利な組み合わせの 1 つです。
Recharts: 厳密な目盛り数の遵守
Recharts は内部的に独自のアルゴリズム(getNiceTickValues)を使用しています。最初から範囲の拡張が組み込まれているため、D3 のnice()と同じような処理が自動的に行われます。
**重要な特徴として、Recharts は希望した目盛り数を厳密に守ります。**これは複合軸グラフ(左右に Y 軸がある)で便利です。左右の目盛り数が揃っていれば、グリッド線の高さも自動的に揃うためです。
D3 や ECharts は「5 つくらい」という目安として扱い、4 つや 6 つになることもありますが、Recharts は指定された数をできるだけ正確に守ろうとします。
ECharts: バランス重視
ECharts も範囲の拡張と読みやすい目盛りの生成を自動で行います。内部的にはintervalScaleNiceTicksという関数を使い、精度を保ちながらきれいな間隔を計算します。
Recharts と異なり、目盛り数を厳密に守ることはありません。
そのため、alignTicks を true にすると場合によっては次のように右Y軸の温度表示に中途半端な数値が出現します。

実際の挙動を比較する
例えば、min=3、max=47、希望目盛り数=5 のような「半端な範囲」を指定した場合、以下のような違いがあります。
| ライブラリ | 挙動 |
|---|---|
| D3 (nice) | 範囲を 0〜50 に拡張して、[0, 10, 20, 30, 40, 50]のような目盛りを生成 |
| D3 (nice なし) | [10, 20, 30, 40]のような目盛りを生成し、データ範囲をカバーできない |
| Recharts | 自動的に範囲を調整して、データをカバーする目盛りを生成 |
| ECharts | 独自のインターバル計算により、バランスの取れた目盛りを生成 |
Recharts や ECharts は、このような範囲の調整が最初から組み込まれているため、ユーザーが意識しなくても正しく動作します。D3 は柔軟性が高い反面、nice()を明示的に呼ぶ必要があります。
可視化ツール
これらの違いを実際に体験できる比較ツールを作成しました。パラメータをリアルタイムで変更しながら、各ライブラリの目盛り生成を視覚的に比較できます。
実際に触ってみると、各ライブラリの特性がよくわかります。
まとめ
グラフの目盛り生成で最も重要なのは、データの範囲を適切にカバーしつつ、読みやすい目盛りを提供することです。
今回比較した目盛り生成アルゴリズムには、大きく2つのアプローチがありました。
目盛り数を柔軟に調整する(D3、ECharts)
読みやすさを最優先し、希望した目盛り数は目安として扱います。4つや6つになることもありますが、常にきれいな数値(10、20、50など)を生成できます。
目盛り数を厳密に守る(Recharts)
希望した目盛り数を必ず守ります。これにより、複合軸グラフで左右のY軸の目盛り数が一致し、グリッド線がきれいに揃います。一方で、状況によっては多少読みにくい数値になることもあります。
どちらのアプローチにも利点があり、用途によって使い分けることができます。











