コンテンツへスキップ

d3-format

JavaScriptで数値が期待通りに表示されないことに気づいたことはありませんか?例えば、単純なループで1/10を表示しようとすると

js
for (let i = 0; i < 10; ++i) {
  console.log(0.1 * i);
}

このような結果になります。

0
0.1
0.2
0.30000000000000004
0.4
0.5
0.6000000000000001
0.7000000000000001
0.8
0.9

バイナリ浮動小数点形式へようこそ!ಠ_ಠ

しかし、丸め誤差だけが数値フォーマットをカスタマイズする理由ではありません。数値の表は比較のために一貫してフォーマットされるべきです。上記の例では、0.0の方が0よりも優れています。大きな数値は桁区切り(例:42,000)または科学記法やメートル法表記(4.2e+4、42k)を使用する必要があります。通貨には固定精度($3.50)が必要です。報告された数値結果は有効桁数に丸める必要があります(4021は4000になります)。数値形式は読者のロケールに適したものにする必要があります(42.000,00または42,000.00)。その他もたくさんあります。

人間が理解しやすいように数値をフォーマットすることがd3-formatの目的であり、Python 3のフォーマット指定ミニ言語PEP 3101)をモデルにしています。上記の例を見直してみましょう。

js
const f = d3.format(".1f");
for (let i = 0; i < 10; ++i) {
  console.log(f(0.1 * i));
}

これで、このような結果になります。

0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9

しかし、d3-formatはnumber.toFixedのエイリアス以上のものです!さらにいくつかの例を挙げます。

js
d3.format(".0%")(0.123) // rounded percentage, "12%"
js
d3.format("($.2f")(-3.5) // localized fixed-point currency, "(£3.50)"
js
d3.format("+20")(42) // space-filled and signed, "                 +42"
js
d3.format(".^20")(42) // dot-filled and centered, ".........42........."
js
d3.format(".2s")(42e6) // SI-prefix with two significant digits, "42M"
js
d3.format("#x")(48879) // prefixed lowercase hexadecimal, "0xbeef"
js
d3.format(",.2r")(4223) // grouped thousands with two significant digits, "4,200"

詳細な仕様についてはlocale.formatを参照し、上記のフォーマットの意味を解読するにはd3.formatSpecifierを実行してみてください。

number.toLocaleStringも参照してください。

format(specifier)

js
const f = d3.format(".2f");

ソースコード · デフォルトロケールlocale.formatのエイリアスです。

formatPrefix(specifier, value)

js
const f = d3.formatPrefix(",.0", 1e-6);

ソースコード · デフォルトロケールlocale.formatPrefixのエイリアスです。

formatLocale(definition)

js
const enUs = d3.formatLocale({
  thousands: ",",
  grouping: [3],
  currency: ["$", ""]
});

ソースコード · 指定されたdefinitionに対してlocale.formatおよびlocale.formatPrefixメソッドを持つlocaleオブジェクトを返します。definitionには次のプロパティを含める必要があります。

  • decimal - 小数点(例:".")。
  • thousands - 桁区切り記号(例:",")。
  • grouping - 桁グループのサイズ配列(例:[3])。必要に応じて循環します。
  • currency - 通貨の接頭辞と接尾辞(例:["$", ""])。
  • numerals - オプション;数値0~9を置き換える10個の文字列の配列。
  • percent - オプション;パーセント記号(デフォルトは"%")。
  • minus - オプション;マイナス記号(デフォルトは"−")。
  • nan - オプション;非数値(デフォルトは"NaN")。

thousandsプロパティは、グルーピング定義が千以外のグループを許可するため、誤称です。

formatDefaultLocale(definition)

js
const enUs = d3.formatDefaultLocale({
  thousands: ",",
  grouping: [3],
  currency: ["$", ""]
});

ソースコード · d3.formatLocaleと同等ですが、d3.formatd3.formatPrefixを新しいロケールのlocale.formatlocale.formatPrefixに再定義します。デフォルトロケールを設定しない場合、米国英語がデフォルトになります。

locale.format(specifier)

js
const f = d3.format(".2f");

ソースコード · 指定された文字列specifierに対して新しいフォーマット関数を返します。返された関数は数値を唯一の引数として受け取り、フォーマットされた数値を表す文字列を返します。スペシファイアの一般的な形式は次のとおりです。

[​[fill]align][sign][symbol][0][width][,][.precision][~][type]

fillには任意の文字を使用できます。fill文字の存在は、その後に続くalign文字によって示されます。align文字は次のいずれかである必要があります。

  • > - フィールドを右寄せにします。(デフォルト動作)。
  • < - フィールドを左寄せにします。
  • ^ - フィールドを中央寄せにします。
  • = - >に似ていますが、符号と記号はパディングの左側に配置されます。

signは次のいずれかになります。

  • - - ゼロまたは正の数値には何も表示せず、負の数値にはマイナス記号を表示します。(デフォルト動作)。
  • + - ゼロまたは正の数値にはプラス記号を表示し、負の数値にはマイナス記号を表示します。
  • ( - ゼロまたは正の数値には何も表示せず、負の数値には括弧で囲みます。
  •  (スペース) - ゼロまたは正の数値にはスペースを表示し、負の数値にはマイナス記号を表示します。

symbolは次のいずれかになります。

  • $ - ロケール定義に従って通貨記号を適用します。
  • # - 2進数、8進数、または16進数の表記の場合、それぞれ0b0o、または0xを接頭辞として付けます。

zero0)オプションはゼロパディングを有効にします。これにより、fill0に、align=に暗黙的に設定されます。widthは最小フィールド幅を定義します。指定しない場合、幅はコンテンツによって決定されます。comma,)オプションは、千の区切り記号など、グループ区切り記号の使用を有効にします。

typeに応じて、precisionは小数点以下の桁数(fおよび%型)または有効桁数(egrsp型)を示します。精度を指定しない場合、(なし)型を除くすべての型ではデフォルトで6になります。(なし)型はデフォルトで12です。精度は整数形式(bodxX型)と文字データ(c型)では無視されます。precisionFixedprecisionRoundを参照して、適切な精度を選択してください。

~オプションは、すべてのフォーマットタイプで無効な末尾のゼロを切り捨てます。これは、res%型と組み合わせて最も一般的に使用されます。例えば

js
d3.format("s")(1500) // "1.50000k"
js
d3.format("~s")(1500) // "1.5k"

使用可能なtype値は次のとおりです。

  • e - 指数表記。
  • f - 固定小数点表記。
  • g - 有効桁数に丸めた10進表記または指数表記。
  • r - 有効桁数に丸めた10進表記。
  • s - SI接頭辞が付いた10進表記(有効桁数に丸める)。
  • % - 100を掛け、パーセント記号付きの10進表記にします。
  • p - 100を掛け、有効桁数に丸め、パーセント記号付きの10進表記にします。
  • b - 2進表記(整数に丸める)。
  • o - 8進表記(整数に丸める)。
  • d - 10進表記(整数に丸める)。
  • x - 16進表記(小文字を使用、整数に丸める)。
  • X - 16進表記(大文字を使用、整数に丸める)。
  • c - 文字データ(テキスト文字列用)。

(なし)型は~g(デフォルトの精度は6ではなく12)の省略形としてもサポートされており、n型は,gの省略形です。gn(なし)型の場合、結果の文字列がprecision以下の桁数になる場合は10進表記が使用され、それ以外の場合は指数表記が使用されます。例えば

js
d3.format(".2")(42) // "42"
js
d3.format(".2")(4.2) // "4.2"
js
d3.format(".1")(42) // "4e+1"
js
d3.format(".1")(4.2) // "4"

locale.formatPrefix(specifier, value)

js
const f = d3.formatPrefix(",.0", 1e-6);

ソースコード · locale.formatと同等ですが、返された関数は、指定された数値参照valueに対して適切なSI接頭辞の単位に値を変換してから、固定小数点表記でフォーマットします。次の接頭辞がサポートされています。

  • y - ヨクト、10⁻²⁴
  • z - ゼプト、10⁻²¹
  • a - アット, 10⁻¹⁸
  • f - フェムト, 10⁻¹⁵
  • p - ピコ, 10⁻¹²
  • n - ナノ, 10⁻⁹
  • µ - マイクロ, 10⁻⁶
  • m - ミリ, 10⁻³
  • (なし) - 10⁰
  • k - キロ, 10³
  • M - メガ, 10⁶
  • G - ギガ, 10⁹
  • T - テラ, 10¹²
  • P - ペタ, 10¹⁵
  • E - エクサ, 10¹⁸
  • Z - ゼタ, 10²¹
  • Y - ヨッタ, 10²⁴

ロケール.formatsフォーマットタイプとは異なり、このメソッドは、各数値に対して接頭辞を動的に計算するのではなく、一貫したSI接頭辞を持つフォーマッタを返します。さらに、指定された指定子精度は、有効桁数ではなく、小数点以下の桁数(f固定小数点表記と同じ)を表します。例えば

js
const f = d3.formatPrefix(",.0", 1e-6);
f(0.00042); // "420µ"
f(0.0042); // "4,200µ"

このメソッドは、同じ単位で複数の数値をフォーマットして容易に比較する場合に便利です。precisionPrefix を参照して、適切な精度を選択してください。

formatSpecifier(指定子)

js
d3.formatSpecifier(".1f")

ソースコード · 指定された指定子を解析し、フォーマット仕様ミニ言語に対応する公開されたフィールドと、指定子を再構築するtoStringメソッドを持つオブジェクトを返します。例えば、formatSpecifier("s") は以下を返します。

js
FormatSpecifier {
  "fill": " ",
  "align": ">",
  "sign": "-",
  "symbol": "",
  "zero": false,
  "width": undefined,
  "comma": false,
  "precision": undefined,
  "trim": false,
  "type": "s"
}

このメソッドは、フォーマット指定子の解析方法を理解し、新しい指定子を導出する場合に便利です。例えば、precisionFixed を使用してフォーマットする数値に基づいて適切な精度を計算し、新しいフォーマットを作成できます。

js
const s = d3.formatSpecifier("f");
s.precision = d3.precisionFixed(0.01);
const f = d3.format(s);
f(42); // "42.00";

new d3.FormatSpecifier(指定子)

js
new d3.FormatSpecifier({type: "f", precision: 1})

ソースコード · 指定された指定子オブジェクトを受け取り、フォーマット仕様ミニ言語に対応する公開されたフィールドと、指定子を再構築するtoStringメソッドを持つオブジェクトを返します。例えば、new FormatSpecifier({type: "s"}) は以下を返します。

js
FormatSpecifier {
  "fill": " ",
  "align": ">",
  "sign": "-",
  "symbol": "",
  "zero": false,
  "width": undefined,
  "comma": false,
  "precision": undefined,
  "trim": false,
  "type": "s"
}

precisionFixed(ステップ)

js
d3.precisionFixed(0.01) // 2

ソースコード · 指定された数値ステップ値に対して、固定小数点表記の推奨小数点精度を返します。ステップは、フォーマットされる値間の最小絶対差を表します。(フォーマットされる値もステップの倍数であると仮定します。)例えば、1、1.5、2という数値の場合、ステップは0.5となり、推奨精度は1となります。

js
const p = d3.precisionFixed(0.5);
const f = d3.format("." + p + "f");
f(1);   // "1.0"
f(1.5); // "1.5"
f(2);   // "2.0"

一方、1、2、3という数値の場合、ステップは1となり、推奨精度は0となります。

js
const p = d3.precisionFixed(1);
const f = d3.format("." + p + "f");
f(1); // "1"
f(2); // "2"
f(3); // "3"

注:%フォーマットタイプの場合は、2を引きます。

js
const p = Math.max(0, d3.precisionFixed(0.05) - 2);
const f = d3.format("." + p + "%");
f(0.45); // "45%"
f(0.50); // "50%"
f(0.55); // "55%"

precisionPrefix(ステップ, )

js
d3.precisionPrefix(1e5, 1.3e6) // 1

ソースコード · 指定された数値ステップと参照に対して、ロケール.formatPrefix で使用する推奨小数点精度を返します。ステップは、フォーマットされる値間の最小絶対差を表し、はどのSI接頭辞が使用されるかを決定します。(フォーマットされる値もステップの倍数であると仮定します。)例えば、1.1e6、1.2e6、1.3e6という数値の場合、ステップは1e5となり、は1.3e6とすることができ、推奨精度は1となります。

js
const p = d3.precisionPrefix(1e5, 1.3e6);
const f = d3.formatPrefix("." + p, 1.3e6);
f(1.1e6); // "1.1M"
f(1.2e6); // "1.2M"
f(1.3e6); // "1.3M"

precisionRound(ステップ, 最大値)

js
d3.precisionRound(0.01, 1.01) // 3

ソースコード · 指定された数値ステップ最大値に対して、有効桁数に丸めるフォーマットタイプに対する推奨小数点精度を返します。ステップは、フォーマットされる値間の最小絶対差を表し、最大値はフォーマットされる最大の絶対値を表します。(フォーマットされる値もステップの倍数であると仮定します。)例えば、0.99、1.0、1.01という数値の場合、ステップは0.01となり、最大値は1.01となり、推奨精度は3となります。

js
const p = d3.precisionRound(0.01, 1.01);
const f = d3.format("." + p + "r");
f(0.99); // "0.990"
f(1.0);  // "1.00"
f(1.01); // "1.01"

一方、0.9、1.0、1.1という数値の場合、ステップは0.1となり、最大値は1.1となり、推奨精度は2となります。

js
const p = d3.precisionRound(0.1, 1.1);
const f = d3.format("." + p + "r");
f(0.9); // "0.90"
f(1.0); // "1.0"
f(1.1); // "1.1"

注:eフォーマットタイプの場合は、1を引きます。

js
const p = Math.max(0, d3.precisionRound(0.01, 1.01) - 1);
const f = d3.format("." + p + "e");
f(0.01); // "1.00e-2"
f(1.01); // "1.01e+0"