d3-format
有没有注意到有时候 JavaScript 并不会像你预期的那样显示数字?比如,你尝试用一个简单的循环打印十分之一:
🌐 Ever noticed how sometimes JavaScript doesn’t display numbers the way you expect? Like, you tried to print tenths with a simple loop:
for (let i = 0; i < 10; ++i) {
console.log(0.1 * i);
}你得到了这个:
🌐 And you got this:
0
0.1
0.2
0.30000000000000004
0.4
0.5
0.6000000000000001
0.7000000000000001
0.8
0.9欢迎来到 二进制浮点数! ಠ_ಠ
🌐 Welcome to binary floating point! ಠ_ಠ
然而,四舍五入误差并不是自定义数字格式的唯一原因。数字表格应格式一致以便比较;如上所示,0.0比0更合适。大数字应有分组位数(例如 42,000)或者使用科学计数法或公制表示法(4.2e+4,42k)。货币应有固定精度($3.50)。报告的数值结果应四舍五入到有效数字(4021 变为 4000)。数字格式应适合读者所在的区域(42.000,00 或 42,000.00)。其重要性不止于此。
🌐 Yet rounding error is not the only reason to customize number formatting. A table of numbers should be formatted consistently for comparison; above, 0.0 would be better than 0. Large numbers should have grouped digits (e.g., 42,000) or be in scientific or metric notation (4.2e+4, 42k). Currencies should have fixed precision ($3.50). Reported numerical results should be rounded to significant digits (4021 becomes 4000). Number formats should appropriate to the reader’s locale (42.000,00 or 42,000.00). The list goes on.
d3-format 的目的是将数字格式化以便人类使用,它的设计借鉴了 Python 3 的 格式说明迷你语言 (PEP 3101)。回到上述示例:
🌐 Formatting numbers for human consumption is the purpose of d3-format, which is modeled after Python 3’s format specification mini-language (PEP 3101). Revisiting the example above:
const f = d3.format(".1f");
for (let i = 0; i < 10; ++i) {
console.log(f(0.1 * i));
}现在你得到这个:
🌐 Now you get this:
0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9但 d3-format 远不只是 number.toFixed 的别名!这里有更多的例子:
🌐 But d3-format is much more than an alias for number.toFixed! A few more examples:
d3.format(".0%")(0.123) // rounded percentage, "12%"d3.format("($.2f")(-3.5) // localized fixed-point currency, "(£3.50)"d3.format("+20")(42) // space-filled and signed, " +42"d3.format(".^20")(42) // dot-filled and centered, ".........42........."d3.format(".2s")(42e6) // SI-prefix with two significant digits, "42M"d3.format("#x")(48879) // prefixed lowercase hexadecimal, "0xbeef"d3.format(",.2r")(4223) // grouped thousands with two significant digits, "4,200"请参阅 locale.format 获取详细规范,并尝试在上述格式上运行 d3.formatSpecifier 以解码它们的含义。
🌐 See locale.format for a detailed specification, and try running d3.formatSpecifier on the above formats to decode their meaning.
另请参见 number.toLocaleString。
🌐 Also see number.toLocaleString.
格式(specifier)
🌐 format(specifier)
const f = d3.format(".2f");来源 · 默认语言环境下 locale.format 的别名。
formatPrefix(specifier, value)
const f = d3.formatPrefix(",.0", 1e-6);来源 · 在默认语言环境上,locale.formatPrefix 的别名。
formatLocale(定义)
🌐 formatLocale(definition)
const enUs = d3.formatLocale({
thousands: ",",
grouping: [3],
currency: ["$", ""]
});来源 · 返回指定 definition 的 locale 对象,并具有 locale.format 和 locale.formatPrefix 方法。definition 必须包含以下属性:
decimal- 小数点(例如,".")。thousands- 组分隔符(例如,",")。grouping- 组大小的数组(例如,[3]),根据需要循环使用。currency- 货币前缀和后缀(例如,["$", ""])。numerals- 可选;一个包含十个字符串的数组,用于替换数字 0-9。percent- 可选;百分号(默认为"%")。minus- 可选;减号(默认为"−")。nan- 可选;非数字值(默认为"NaN")。
请注意,thousands 属性是一个用词不当,因为分组定义允许分组单位不是千位。
🌐 Note that the thousands property is a misnomer, as the grouping definition allows groups other than thousands.
formatDefaultLocale(定义)
🌐 formatDefaultLocale(definition)
const enUs = d3.formatDefaultLocale({
thousands: ",",
grouping: [3],
currency: ["$", ""]
});Source · 等同于 d3.formatLocale,只是它还将 d3.format 和 d3.formatPrefix 重新定义为新语言环境的 locale.format 和 locale.formatPrefix。如果你不设置默认语言环境,它将默认使用 美国英语。
locale.format(specifier)
const f = d3.format(".2f");来源 · 为给定的字符串 specifier 返回一个新的格式化函数。返回的函数以一个数字作为唯一参数,并返回表示该数字的格式化字符串。specifier 的一般形式为:
[[fill]align][sign][symbol][0][width][,][.precision][~][type]填充字符可以是任意字符。填充字符的存在由紧随其后的对齐字符表示,该字符必须是以下之一:
🌐 The fill can be any character. The presence of a fill character is signaled by the align character following it, which must be one of the following:
>- 强制字段在可用空间内右对齐。(默认行为)。<- 强制场场在可用空间内左对齐。^- 强制场场在可用空间内居中。=- 像>,但在任何填充的左侧可以有任何符号和标志。
这个符号可以是:
🌐 The sign can be:
-- 零或正数没有符号,负数有一个负号。(默认行为。)+- 一个加号表示零或正数,一个减号表示负数。(- 零或正数不显示,负数用括号括起来。(space)- 零或正数的空间,以及负数的负号。
该符号可以是:
🌐 The symbol can be:
$- 根据语言环境定义应用货币符号。#- 对于二进制、八进制或十六进制表示法,分别以0b、0o或0x为前缀。
zero (0) 选项启用零填充;这会隐式地将 fill 设置为 0,并将 align 设置为 =。width 定义最小字段宽度;如果未指定,则宽度将由内容决定。comma (,) 选项启用使用分组分隔符,例如用于千位的逗号。
🌐 The zero (0) option enables zero-padding; this implicitly sets fill to 0 and align to =. The width defines the minimum field width; if not specified, then the width will be determined by the content. The comma (,) option enables the use of a group separator, such as a comma for thousands.
根据类型,精度要么表示小数点后的位数(类型 f 和 %),要么表示有效数字的位数(类型 、e、g、r、s 和 p)。如果未指定精度,默认值为除 (无)外的所有类型的 6, 默认为 12。对于整数格式(类型 b、o、d、x 和 X)和字符数据(类型 c),精度会被忽略。请参阅 precisionFixed 和 precisionRound 以获取选择适当精度的帮助。
🌐 Depending on the type, the precision either indicates the number of digits that follow the decimal point (types f and %), or the number of significant digits (types , e, g, r, s and p). If the precision is not specified, it defaults to 6 for all types except (none), which defaults to 12. Precision is ignored for integer formats (types b, o, d, x, and X) and character data (type c). See precisionFixed and precisionRound for help picking an appropriate precision.
~ 选项会修剪所有格式类型中不重要的末尾零。这通常与类型 r、e、s 和 % 一起使用。例如:
🌐 The ~ option trims insignificant trailing zeros across all format types. This is most commonly used in conjunction with types r, e, s and %. For example:
d3.format("s")(1500) // "1.50000k"d3.format("~s")(1500) // "1.5k"可用的 type 值有:
🌐 The available type values are:
e- 指数表示法。f- 定点符号。g- 小数或指数表示法,四舍五入到有效数字。r- 以十进制表示法,四舍五入为有效数字。s- 使用 SI 前缀 的十进制表示法,四舍五入到有效数字。%- 乘以 100,然后以百分号表示十进制数。p- 乘以 100,四舍五入为有效数字,然后以百分号表示十进制数。b- 二进制表示法,四舍五入为整数。o- 八进制表示法,四舍五入为整数。d- 以十进制表示法,四舍五入为整数。x- 十六进制表示法,使用小写字母,四舍五入为整数。X- 十六进制表示法,使用大写字母,四舍五入为整数。c- 字符数据,用于文本字符串。
类型 (无)也被支持作为 ~g 的简写(默认精度为 12 而非 6),而类型 n 是 ,g 的简写。对于 g、n 和 (无)类型,如果生成的字符串的数字不超过 precision,则使用十进制表示;否则,使用指数表示。例如:
🌐 The type (none) is also supported as shorthand for ~g (with a default precision of 12 instead of 6), and the type n is shorthand for ,g. For the g, n and (none) types, decimal notation is used if the resulting string would have precision or fewer digits; otherwise, exponent notation is used. For example:
d3.format(".2")(42) // "42"d3.format(".2")(4.2) // "4.2"d3.format(".1")(42) // "4e+1"d3.format(".1")(4.2) // "4"locale.formatPrefix(specifier, value)
const f = d3.formatPrefix(",.0", 1e-6);来源 · 等同于 locale.format,只不过返回的函数会在以固定小数格式进行格式化之前,将值转换为指定数字参考 value 的适当 SI 前缀 单位。支持以下前缀:
y- yocto, 10⁻²⁴z- zepto, 10⁻²¹a- atto,10⁻¹⁸f- 飞秒级,10⁻¹⁵p- pico,10⁻¹²n- 纳米,10⁻⁹µ- micro,10⁻⁶m- milli,10⁻³(none)- 10⁰k- kilo,10³M- mega,10⁶G- giga,10⁹T- tera,10¹²P- peta,10¹⁵E- exa,10¹⁸Z- zetta, 10²¹Y- yotta, 10²⁴
与使用 s 格式类型的 locale.format 不同,该方法返回一个具有一致 SI 前缀的格式化器,而不是为每个数字动态计算前缀。此外,对于给定的 specifier 的 precision 表示小数点后的位数(如同 f 定点表示法),而不是有效数字的位数。例如:
🌐 Unlike locale.format with the s format type, this method returns a formatter with a consistent SI prefix, rather than computing the prefix dynamically for each number. In addition, the precision for the given specifier represents the number of digits past the decimal point (as with f fixed point notation), not the number of significant digits. For example:
const f = d3.formatPrefix(",.0", 1e-6);
f(0.00042); // "420µ"
f(0.0042); // "4,200µ"当以相同单位格式化多个数字以便于比较时,此方法非常有用。请参阅 precisionPrefix 以获取选择适当精度的帮助。
🌐 This method is useful when formatting multiple numbers in the same units for easy comparison. See precisionPrefix for help picking an appropriate precision.
formatSpecifier(specifier)
d3.formatSpecifier(".1f")来源 · 解析指定的 specifier,返回一个对象,该对象具有对应于格式规范迷你语言的公开字段,以及一个用于重建 specifier 的 toString 方法。例如,formatSpecifier("s") 返回:
FormatSpecifier {
"fill": " ",
"align": ">",
"sign": "-",
"symbol": "",
"zero": false,
"width": undefined,
"comma": false,
"precision": undefined,
"trim": false,
"type": "s"
}这种方法对于理解格式说明符的解析方式以及派生新的说明符非常有用。例如,你可以使用 precisionFixed 根据你想要格式化的数字计算出合适的精度,然后创建一个新的格式:
🌐 This method is useful for understanding how format specifiers are parsed and for deriving new specifiers. For example, you might compute an appropriate precision based on the numbers you want to format using precisionFixed and then create a new format:
const s = d3.formatSpecifier("f");
s.precision = d3.precisionFixed(0.01);
const f = d3.format(s);
f(42); // "42.00";新的 d3.FormatSpecifier(specifier)
🌐 new d3.FormatSpecifier(specifier)
new d3.FormatSpecifier({type: "f", precision: 1})来源 · 给定指定的 specifier 对象,返回一个具有暴露字段的对象,这些字段对应于 格式说明小语言 并且具有一个重建 specifier 的 toString 方法。例如,new FormatSpecifier({type: "s"}) 返回:
FormatSpecifier {
"fill": " ",
"align": ">",
"sign": "-",
"symbol": "",
"zero": false,
"width": undefined,
"comma": false,
"precision": undefined,
"trim": false,
"type": "s"
}precisionFixed(step)
d3.precisionFixed(0.01) // 2来源 · 根据指定的数值 step 返回固定小数点表示法的建议小数位数。step 表示将被格式化的值之间的最小绝对差值。(假设要格式化的值也是 step 的倍数。)例如,给定数字 1、1.5 和 2,step 应为 0.5,建议的小数位数为 1:
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:
🌐 Whereas for the numbers 1, 2 and 3, the step should be 1 and the suggested precision is 0:
const p = d3.precisionFixed(1);
const f = d3.format("." + p + "f");
f(1); // "1"
f(2); // "2"
f(3); // "3"注意:对于 % 格式类型,减去二:
🌐 Note: for the % format type, subtract two:
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(step, value)
d3.precisionPrefix(1e5, 1.3e6) // 1来源 · 根据指定的数值 step 和参考 value,返回用于 locale.formatPrefix 的建议小数精度。step 表示将要格式化的数值之间的最小绝对差异,value 决定将使用哪个 SI 前缀。(假设要格式化的数值也是 step 的倍数。)例如,给定数字 1.1e6、1.2e6 和 1.3e6,step 应为 1e5,value 可以为 1.3e6,建议的精度为 1:
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(step, max)
d3.precisionRound(0.01, 1.01) // 3来源 · 返回针对格式类型的建议小数精度,这些格式类型会根据指定的数字 step 和 max 值四舍五入到有效数字。step 表示将要格式化的值之间的最小绝对差,而 max 表示将要格式化的最大绝对值。(假设要格式化的值也是 step 的倍数。)例如,给定数字 0.99、1.0 和 1.01,step 应为 0.01,max 应为 1.01,建议的精度为 3:
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:
🌐 Whereas for the numbers 0.9, 1.0, and 1.1, the step should be 0.1, the max should be 1.1, and the suggested precision is 2:
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 格式类型,减一:
🌐 Note: for the e format type, subtract one:
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"