数据处理 — d3-array 与格式化工具¶
这一章讲什么: 数据绑上图形之前,通常要先加工:挑出最大最小值来定比例尺的范围、 排序、求和取平均、把一张平表折叠成嵌套结构。这一份拆解决 d3-array 的数据处理全家桶 和 d3-format / d3-time-format 两套格式化工具(生成数据、分箱、分组在下一章)。 原书的讲法是「控制台一行行试」——每个函数都配了可复制的真实输出。
1. 主线例子:四个小数据集走全程¶
原书给了一组贯穿全章的演示数据,每个函数都在它们身上跑1:
numArray = [9, 2, 12, 9, 71] —— 数字数组
strArray = ['9', '2', '12', '9', '71', 'Y', null] —— 同样的数,但存成字符串,外加两个捣乱项
tasks = [
{task: 'Debugging', cost: 1.40, priority: 1, date: …},
{task: 'Reviewing', cost: 0.60, priority: 2, date: …},
{task: 'Editing', cost: 0.25, priority: 5, date: …},
{task: 'Testing', cost: 0.10, priority: 1, date: …}
] —— 对象数组(四个任务)
taskmap = new Map(tasks.map(e => [e.task, e])) —— 同样的数据装进 Map
numset = new Set(numArray) —— 去重后的集合 {9,2,12,71}
str = "953zyx2" —— 一个字符串
图说:数字、字符串、对象、Map、Set、字符串六种形态,用来展示「任何可迭代对象都能吃」。
为什么需要这一整章?因为原生 JavaScript 的数组工具在这三类场景会翻车:
Math.min(strArray) 遇字符串得 NaN、原生 sort() 默认按字典序排数字、
原生方法只认数组不认 Map/Set/字符串。d3-array 的对应函数修了这三个坑2。
2. 核心原理¶
2.1 最值:min / max / extent / minIndex¶
| 函数 | 返回 |
|---|---|
d3.min(集合, 访问器?) |
最小值(自然序) |
d3.max(集合, 访问器?) |
最大值 |
d3.extent(集合, 访问器?) |
[min, max] 二元数组——配比例尺 domain 的标配 |
d3.minIndex / d3.maxIndex |
最值所在的下标(没有则 -1) |
为什么不用 Math.min? 对着主线例子看3:
d3.min(numArray) // 2 —— 数字按数值比,没问题
d3.min(strArray) // '12' —— 字符串按字典序比:'1' 开头的 '12' 排在 '2' 前面!
Math.min(strArray) // NaN —— 原生版本想把 'Y' 转成数字,失败,全盘皆 NaN
图说:d3.min 遇到 null/NaN 直接跳过;字典序的坑在求「数值最小」时是静默错误——
你的图不会报错,只是 domain 错得离谱。
对象数组要用访问器(accessor)告诉它比哪个字段,两种等价写法4:
d3.min(tasks.map(d => d.cost)) // 0.1 —— 先 map 出数组再求值
d3.min(tasks, d => d.cost) // 0.1 —— 访问器直接传,更省一步
d3.min(taskmap, d => d[1].cost) // 0.1 —— Map 的元素是 [键, 值] 二元组,所以取 d[1]
警告框里的那个坑值得背下来:想顺手用访问器做类型转换时,别让它改变数据的「可比较性」5:
d3.min(strArray, d => +d) // 0 ← 错了!
// 原因:+null 会先被转成 0,null 就不再被忽略,0 成了最小值
d3.min(strArray, d => (d == null) ? null : +d) // 2 ← 显式挡住 null 才对
extent 一次拿两头,是配比例尺 domain 时最高频的调用:d3.extent(numArray) 返回 [2, 71]6。
它同样吃 Map、Set、字符串:d3.extent(str) 把字符串拆成字符按字典序比,得 [2, 'z']——
单字符的 '2' 也能和 'z' 比,比较时按各自的自然序7。
2.2 排序与选择:比较器的世界¶
数字有自然序,对象没有。要「取出最贵的那个任务对象」而不是「最贵的价钱」,
就需要比较器(comparator):一个 (a, b) => 负数/0/正数 的函数,返回值的符号表示先后。
| 函数 | 干什么 |
|---|---|
d3.ascending(a, b) / d3.descending(a, b) |
升/降序比较器(处理 null) |
d3.least(集合, 比较器?) / d3.greatest |
返回元素本身(不是字段值) |
d3.leastIndex / d3.greatestIndex |
最元素的下标 |
d3.rank(集合, 访问器?或比较器?) |
返回每个元素的「名次」数组 |
d3.quickselect(数组, k) |
原地重排,使 数组[k] 恰好是第 k 小(比全排序快) |
numArray.sort((a,b) => d3.descending(a,b)) // [71,12,9,9,2]
numArray.sort(d3.descending) // 简写,等价
tasks.sort((a,b) => d3.ascending(a.cost, b.cost)) // 对象按字段排
d3.least(tasks, (a,b) => d3.ascending(a.priority, b.priority))
// → {task: 'Debugging', …, priority: 1} ← 返回整个对象!
图说:least/greatest 加访问器时返回的是字段值(least(tasks, d=>d.priority) 得 1);
加比较器时才能拿到「整条记录」——这个区别在「找记录」时是要命的。
d3.rank 返回名次数组:d3.rank(numArray) 得 [1,0,3,1,4]——
9 排第 1(从 0 计)、2 排第 0、12 排第 3、9 又是第 1、71 排第 4;
对象数组不给比较依据就全体名次 0:d3.rank(tasks) 得 [0,0,0,0],补上访问器 d => d.date 才有意义8。
2.3 求和与统计¶
| 函数 | 返回 |
|---|---|
d3.sum(集合, 访问器?) |
总和(跳过 null/NaN/undefined) |
d3.cumsum(集合, 访问器?) |
累积和数组:第 i 项是前 i 项之和 |
d3.fsum / d3.fcumsum |
高精度版(慢,对付浮点误差) |
new d3.Adder() |
累加器对象:adder.add(x) 喂数,+adder 取值 |
d3.count |
数值个数(不是总个数!) |
d3.mode |
众数 |
d3.mean / d3.median / d3.variance / d3.deviation |
均值/中位数/方差/标准差 |
主线例子的实跑结果9:
d3.sum(strArray) // 103 —— 'Y' 和 null 被跳过,纯数字求和
d3.sum(tasks, d => d.cost) // 2.35 —— 四个任务的成本总和
d3.cumsum(tasks, d => d.cost) // [1.4, 2, 2.25, 2.35] —— 逐项累加
d3.count(numArray) // 5
d3.count(strArray) // 5 —— 'Y' 和 null 不算数
d3.count(tasks) // 0 —— 对象是「不是数」,除非给访问器
d3.count(tasks, d => d.cost) // 4
d3.mean(numArray) // 20.6
d3.median(numArray) // 9
d3.variance(numArray) // 807.3
d3.deviation(numArray) // 28.41302518212378
d3.fsum 的存在理由:JavaScript 的浮点数加法有舍入误差,0.1 + 0.2 !== 0.3;
fsum 用补偿算法算出精确和,代价是慢10。d3.Adder() 是同一个思路的对象版:
numArray.forEach(d => acum.add(d)) 之后 +acum 得 10311。
2.4 集合运算与 every/some¶
d3.difference([3,6,9], [2,4,6,8,10]) // Set{3,9} —— 在 a 不在 b
d3.union([5,10], [3,6,9], [2,4,6,8,10]) // Set{2,3,4,5,6,8,9,10} —— 并集(去重)
d3.intersection([2,4,6,8,10], [3,6,9]) // Set{6} —— 交集
d3.disjoint([5,10], [3,6,9]) // true —— 两集合无交集
d3.superset([1,2,3,4,5,6], [2,4,6]) // true —— a 包含 b
d3.subset([3,6], [1,2,3,4,5,6]) // true —— a 含于 b
d3.difference("dinosaur", "pterosaur") // Set{'d','i','n'} —— 字符串也能当集合
返回值是 JavaScript 的 Set。d3.every/d3.some 与原生数组方法同名不同家:
不是数组方法、可作用于任何可迭代对象(d3.some('abc-def', ch => …) 直接吃字符串)12。
2.5 d3 版「原生方法」:三个关键差异¶
d3.filter / map / reduce / reverse / sort 与原生同名,但原书列出了三条差异13:
- 吃任何可迭代对象(字符串、Map、Set),不用先
Array.from转换; - 不改原集合——原生
sort()/reverse()是原地修改,d3 版返回新数组; - 默认自然序——
d3.sort(numArray)数字按数值排得[2,9,9,12,71], 原生numArray.sort()按字典排得[12,2,71,9,9]——经典翻车现场。
array = [8,2,3,5]
sorted = d3.sort(array) // array 还是 [8,2,3,5],sorted 是 [2,3,5,8]
sorted = array.sort() // 原生:array 自己也变了
d3.sort(集合, 比较器) // 也可传多个访问器做多级排序
2.6 数组变换:merge / permute / cross / pairs / zip / transpose¶
六个变换函数,各解决一类「数组的数组」问题14:
| 函数 | 干什么 | 例子 |
|---|---|---|
d3.merge(二维可迭代) |
拍平一层 | merge([[3,4],[5,6]]) → [3,4,5,6] |
d3.permute(数组, 下标数组) |
按下标重排 | permute([33,65,86,49],[3,2,0,1]) → [49,86,33,65] |
d3.cross(a, b, 归并?) |
笛卡尔积 | cross([1,2],[9,8,7]) → [[1,9],[1,8],…] 6 组 |
d3.pairs(数组, 归并?) |
相邻两两配对 | pairs([3,4,5,6]) → [[3,4],[4,5],[5,6]] |
d3.zip(多个数组) |
按下标对齐合并(裁齐) | zip([1,2,3],[4,5,6],[9,8,7,6]) → [[1,4,9],[2,5,8],[3,6,7]] |
d3.transpose(矩阵) |
转置 | transpose([[1,2,3],[4,5,6],[9,8,7]]) → 行列互换 |
cross 的典型用途:替掉嵌套循环——画网格坐标、棋盘格(exercise 7.2 就是棋盘),
cross([1,2],[9,8,7],(a,b)=>a*b) 直接给每个格子算好值15。
pairs 是画折线的原料:点列变线段列,pairs([3,4,5,6],(a,b)=>a+b) 得 [7,9,11]16。
merge 与原生 flat() 的取舍:merge 吃任意可迭代对象但遇非可迭代元素会报错,
flat() 只认数组但更宽容更快——现代代码里原书也承认 flat/flatMap 通常是更好的选择17。
permute 允许重复和省略下标:d3.permute("aardvark",[2,0,3,0,2]).join('') 得 'radar'18。
2.7 二分查找与分位数¶
bisect 家族:在有序数组里找插入位置或最近元素,多数时候 D3 内部自用(坐标轴找刻度)。
sorted1 = d3.sort(numArray) // [2,9,9,12,71]
d3.bisectLeft(sorted1, 8) // 1 —— 8 该插在 1 号位(插在所有 8 之前)
d3.bisectRight(sorted1, 8) // 1 —— 不存在,左右一致
d3.bisectLeft(sorted1, 9) // 1 —— 9 已存在:左插,挤在已有 9 之前
d3.bisectRight(sorted1, 9) // 3 —— 右插,挤在已有 9 之后(下标 3)
d3.bisectCenter(sorted1, 41) // 3 —— 离 41 最近的是 12(下标 3)
d3.bisectCenter(sorted1, 42) // 4 —— 离 42 最近的是 71(下标 4)
图说:bisectLeft/Right 只在「值已存在」时有别;配合 splice 就是有序的数组插入。
quantile(分位数):把一个排好序的数列切成等大的组,返回切点的值。
p 取 0–1:0.25/0.5/0.75 三个切点把数据四等分(四分位数),0.5 就是中位数19:
sorted2 = [2,19,24,67,69,72,81,88,91,94,98,99]
d3.quantile(sorted2, 0.25) // 56.25
d3.quantile(sorted2, 0.50) // 76.5 ← 中位数
d3.quantile(sorted2, 0.75) // 91.75
分位数的实战价值原书点了两条:压缩大数据(一万个数的 100 个分位点就能画出保留趋势的简化图)、 给分箱当阈值(下一章的分箱就会用到)20。
3. 格式化:让数字和日期说读者的话¶
数字 123456789.9876 直接打印出来,读者要数好一会儿逗号。
d3.format(说明符) 造一个格式化函数,说明符是一个紧凑的模板字符串,语法借自 C/Python 的 printf 传统21:
formatPercent = d3.format(".2%") // 百分比,2 位小数
formatUnit = d3.format(".3s") // SI 公制单位(k/M/G/µ)
formatMoney = d3.format("$,.2f") // 货币 + 千分位 + 定点 2 位小数
formatPercent(0.23478) // "23.48%"
formatUnit(0.0000045367) // "4.537µ"
formatMoney(123456789.9876) // "$123,456,789.99"
图说:.2% 的数会先乘 100;.3s 选合适数量级并保留 3 位有效数字;
$ 是货币符号(会因地区而变),, 是千分位,.2f 是两位小数的定点数。
locale(地区设置)是这套工具的另一半:同样的 formatMoney,在巴西葡萄牙语环境里
小数点变逗号、千分位变点号:R$ 123.456.789,99。两种用法:自己拼定义对象
({decimal, thousands, grouping, currency} 四个属性)传给 d3.formatDefaultLocale(),
或从 CDN 加载现成地区文件(如 de-DE.json)22。
日期是平行的一套:d3.timeFormat("%Y-%m-%d") 造格式化器,d3.timeParse(同模板) 造反向的解析器;
ISO8601 标准格式有直达车 d3.isoParse("2024-01-14")。模板里的指令以 % 开头:
%A 星期全名、%d 补零的日、%B 月全名、%Y 四位年、%H 24 小时……
配合地区文件,%c/%x/%X 三个指令输出各地区习惯的完整日期、短日期、时间写法23。
解析失败返回 null——这个「安静的 null」是日期处理里最常见的 bug 来源,用前记得验24。
4. 作者的判断与证据¶
| 判断 | 性质 | 依据 |
|---|---|---|
| 「d3 版函数优于原生」 | 有边界的经验法则 | 三条理由(可迭代、不改原、自然序)都给了反例边界,如 flat() 更快13 |
| 「分位数可压缩大数据」 | 使用建议 | 配了万级数据 → 百级阈值的具体场景20 |
| 「高精度求和更慢」 | 性能事实 | fsum/fcumsum 与 Adder 的取舍照实写10 |
5. 边界与局限¶
- 本章是工具箱巡览,不是教程:17 个随机分布、全部分位数变体都只给名字和图, 细节让读者查官方文档25。
d3.format说明符的完整语法原书明确不展开(「beyond the scope of this book」)26。- 时区处理只有 UTC 系列函数一句带过;夏令时原书明说不处理(
count()不考虑 DST)27。 - 格式化函数的输出依赖运行环境的默认地区,同一行代码在德文系统上结果不同——团队项目里建议显式设 locale。
判断(我们的,不是书里的): d3-array 的存在理由是 JavaScript 标准库的三个历史遗留缺陷 (可迭代协议普及晚、sort 默认字典序、类型强制转换多),随着语言演进,这个模块的很大一部分 正在退化成「兼容性封装」——d3.sort 对 d3 自身的意义(与 scale/axis 的自然序约定一致) 大于它对用户的意义。学它的正确姿势是记住差异点,而不是背 API 表。 如果错,会错在: 可迭代对象原生方法的支持度如果继续扩大、或 TC39 给 sort 加自然序选项, d3-array 的差异化会继续萎缩——但「跳过脏数据」这一条(原生 Math.min 做不到)依然独一份。
6. 可带走的¶
主线例子一行收束: [9,2,12,9,71] 六个函数轮一遍——min 2、max 71、extent [2,71]、
sum 103、mean 20.6、median 9;同名字符串数组 min 得 '12'(字典序),Math.min 直接 NaN。
d3.min/max/extent(集合, 访问器)吃任何可迭代对象,跳过 null/NaN,默认自然序;extent一次拿[min,max],是配 scale domain 的标配;- 访问器里做
+d转换要小心 null 变 0 的坑; least/greatest + 比较器返回整条记录;+ 访问器只返回字段值;cumsum累积和、fsum/fcumsum高精度(慢)、Adder对象累加;d3.count数的是数值个数,不是元素个数;- 集合运算返回 Set;
difference/union/intersection/disjoint/superset/subset; d3.sort等五件套:不改原集合、自然序、可迭代——与原生 sort 的三大差异;cross替嵌套循环、pairs产折线原料、zip/transpose对位合并;bisectLeft/Right在有序数组找插入位(值已存在时左右有别);quantile切等分点;d3.format(".2%")等说明符格式化数字,locale 决定小数点/千分位/货币样式;timeParse/timeFormat模板互逆,解析失败返回 null。
7. 原文地图¶
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| 章节目标与样本数据 | Working with Data | text/14-ch07-chapter-7-working-with-data.txt:2(搜「preparing your data」) · text/14-ch07-chapter-7-working-with-data.txt:35(搜「numArray = [9, 2, 12, 9, 71]」) |
| min/max 与字符串陷阱 | Working with Data | text/14-ch07-chapter-7-working-with-data.txt:77(搜「d3.min(iterable,accessor)」) · text/14-ch07-chapter-7-working-with-data.txt:101(搜「// 2」) · text/14-ch07-chapter-7-working-with-data.txt:108(搜「NaN」) |
| 访问器与 null 警告 | Working with Data | text/14-ch07-chapter-7-working-with-data.txt:119(搜「d => d.cost」) · text/14-ch07-chapter-7-working-with-data.txt:130(搜「// 0」) · text/14-ch07-chapter-7-working-with-data.txt:136(搜「d == null」) |
| extent 与各集合类型 | Working with Data | text/14-ch07-chapter-7-working-with-data.txt:143(搜「[2,71]」) · text/14-ch07-chapter-7-working-with-data.txt:150(搜「[2, 'z']」) |
| 比较器家族与 rank | Working with Data | text/14-ch07-chapter-7-working-with-data.txt:172(搜「d3.ascending(a,b)」) · text/14-ch07-chapter-7-working-with-data.txt:206(搜「[1,0,3,1,4]」) · text/14-ch07-chapter-7-working-with-data.txt:229(搜「highest-priority task」) · text/14-ch07-chapter-7-working-with-data.txt:234(搜「quickselect」) |
| 求和与统计 | Working with Data | text/14-ch07-chapter-7-working-with-data.txt:242(搜「d3.sum(iterable,accessor)」) · text/14-ch07-chapter-7-working-with-data.txt:259(搜「// 103」) · text/14-ch07-chapter-7-working-with-data.txt:265(搜「[9,11,23,32,103,103,103]」) · text/14-ch07-chapter-7-working-with-data.txt:307(搜「// 5」) · text/14-ch07-chapter-7-working-with-data.txt:320(搜「// 20.6」) |
| fsum 与 Adder | Working with Data | text/14-ch07-chapter-7-working-with-data.txt:247(搜「full precision」) · text/14-ch07-chapter-7-working-with-data.txt:272(搜「new d3.Adder()」) |
| 集合运算 | Working with Data | text/14-ch07-chapter-7-working-with-data.txt:332(搜「d3.difference(a」) · text/14-ch07-chapter-7-working-with-data.txt:352(搜「{3,9}」) · text/14-ch07-chapter-7-working-with-data.txt:369(搜「dinosaur」) |
| d3 版原生方法三差异 | Working with Data | text/14-ch07-chapter-7-working-with-data.txt:385(搜「d3.filter(iterable, test)」) · text/14-ch07-chapter-7-working-with-data.txt:416(搜「array = [8,2,3,5]」) · text/14-ch07-chapter-7-working-with-data.txt:428(搜「[12, 2, 71, 9, 9]」) |
| merge/permute/cross/pairs | Working with Data | text/14-ch07-chapter-7-working-with-data.txt:440(搜「d3.merge」) · text/14-ch07-chapter-7-working-with-data.txt:481(搜「[3,2,0,1]」) · text/14-ch07-chapter-7-working-with-data.txt:491(搜「[1,9], [1,8]」) · text/14-ch07-chapter-7-working-with-data.txt:502(搜「[3,4], [4,5]」) |
| zip/transpose | Working with Data | text/14-ch07-chapter-7-working-with-data.txt:516(搜「d3.zip(arrays)」) · text/14-ch07-chapter-7-working-with-data.txt:526(搜「last 6 discarded」) |
| bisect 家族 | Working with Data | text/14-ch07-chapter-7-working-with-data.txt:541(搜「d3.bisect(array,x」) · text/14-ch07-chapter-7-working-with-data.txt:569(搜「sorted1 = d3.sort」) · text/14-ch07-chapter-7-working-with-data.txt:583(搜「bisectCenter」) |
| 分位数 | Working with Data | text/14-ch07-chapter-7-working-with-data.txt:556(搜「d3.quantile(iterable」) · text/14-ch07-chapter-7-working-with-data.txt:591(搜「sorted2 = [2,19,24」) · text/14-ch07-chapter-7-working-with-data.txt:601(搜「compress large datasets」) |
| d3.format 与说明符 | Working with Data | text/14-ch07-chapter-7-working-with-data.txt:639(搜「d3.format(specifier)」) · text/14-ch07-chapter-7-working-with-data.txt:651(搜「.2%」) · text/14-ch07-chapter-7-working-with-data.txt:705(搜「23.48%」) |
| locale | Working with Data | text/14-ch07-chapter-7-working-with-data.txt:661(搜「decimal points will be commas」) · text/14-ch07-chapter-7-working-with-data.txt:665(搜「pt_BR」) · text/14-ch07-chapter-7-working-with-data.txt:676(搜「de-DE.json」) |
| 日期格式化与解析 | Working with Data | text/14-ch07-chapter-7-working-with-data.txt:734(搜「d3.timeFormat(specifier)」) · text/14-ch07-chapter-7-working-with-data.txt:766(搜「timeParse」) · text/14-ch07-chapter-7-working-with-data.txt:774(搜「return null」) · text/14-ch07-chapter-7-working-with-data.txt:781(搜「%A」) |
| 章小结 | Working with Data | text/14-ch07-chapter-7-working-with-data.txt:1732(搜「Summary」) |
-
出处:「Working with Data」第 35–48 段(
text/14-ch07-chapter-7-working-with-data.txt:35,搜「numArray = [9, 2, 12, 9, 71]」;:45,搜「taskmap = new Map」)。六个数据集定义照原书转写;它们被复制到全局上下文以便控制台实验,见第 61–63 段。 ↩ -
出处:「Working with Data」第 92–96 段(
text/14-ch07-chapter-7-working-with-data.txt:93,搜「ignore undefined, null, and NaN」;:425,搜「natural order as default」)。「Math.min 遇字符串得 NaN」的机理(想把 'Y' 转成数字失败)见第 108–111 段。 ↩ -
出处:「Working with Data」第 101–111 段(
text/14-ch07-chapter-7-working-with-data.txt:101,搜「d3.min(numArray)」;:102,搜「'12'」;:108,搜「Math.min(strArray)」)。 ↩ -
出处:「Working with Data」第 115–123 段(
text/14-ch07-chapter-7-working-with-data.txt:115,搜「0.1」;:123,搜「d[1].cost」)。 ↩ -
出处:「Working with Data」第 125–138 段(
text/14-ch07-chapter-7-working-with-data.txt:130,搜「// 0」;:136,搜「d == null」)。原文:「This is because +null was coerced to 0 before the accessor was called.」 ↩ -
出处:「Working with Data」第 140–150 段(
text/14-ch07-chapter-7-working-with-data.txt:143,搜「[2,71]」)。「for example, to set up a scale's domain」是原书给的典型场景。 ↩ -
出处:「Working with Data」第 150–155 段(
text/14-ch07-chapter-7-working-with-data.txt:150,搜「[2, 'z']」;:153,搜「split into individual characters」)。 ↩ -
出处:「Working with Data」第 204–216 段(
text/14-ch07-chapter-7-working-with-data.txt:206,搜「[1,0,3,1,4]」;:211,搜「[0,0,0,0]」)。 ↩ -
出处:「Working with Data」第 259–323 段(
text/14-ch07-chapter-7-working-with-data.txt:259,搜「103」;:265,搜「[1.4,2,2.25,2.35]」;:307,搜「// 5」;:320,搜「20.6」)。逐值照原书注释。 ↩ -
出处:「Working with Data」第 247–249、268–269 段(
text/14-ch07-chapter-7-working-with-data.txt:247,搜「full precision」;:269,搜「though they are slower」)。 ↩↩ -
出处:「Working with Data」第 270–280 段(
text/14-ch07-chapter-7-working-with-data.txt:272,搜「new d3.Adder()」;:280,搜「result = +acum」)。 ↩ -
出处:「Working with Data」第 330–376 段(
text/14-ch07-chapter-7-working-with-data.txt:352,搜「{3,9}」;:369,搜「dinosaur」;:375,搜「abc-def」)。 ↩ -
出处:「Working with Data」第 379–431 段(
text/14-ch07-chapter-7-working-with-data.txt:385,搜「d3.filter(iterable, test)」;:416,搜「array = [8,2,3,5]」;:425,搜「natural order as default」;:428,搜「[12, 2, 71, 9, 9]」)。 ↩↩ -
出处:「Working with Data」第 434–530 段(
text/14-ch07-chapter-7-working-with-data.txt:440,搜「d3.merge」;:516,搜「d3.zip」)。各函数输出值均照原书注释。 ↩ -
出处:「Working with Data」第 488–498 段(
text/14-ch07-chapter-7-working-with-data.txt:491,搜「[1,9], [1,8]」;:497,搜「replace nested loops」)。 ↩ -
出处:「Working with Data」第 499–509 段(
text/14-ch07-chapter-7-working-with-data.txt:502,搜「[3,4], [4,5]」;:508,搜「a+b」)。 ↩ -
出处:「Working with Data」第 469–477 段(
text/14-ch07-chapter-7-working-with-data.txt:471,搜「flat() and flatMap()」;:469,搜「1 is not iterable」)。 ↩ -
出处:「Working with Data」第 478–486 段(
text/14-ch07-chapter-7-working-with-data.txt:481,搜「[3,2,0,1]」;:486,搜「radar」)。 ↩ -
出处:「Working with Data」第 565–597 段(
text/14-ch07-chapter-7-working-with-data.txt:569,搜「[2,9,9,12,71]」;:570,搜「index 1」;:574,搜「index 3」;:591,搜「sorted2 = [2,19,24」;:595,搜「56.25」)。 ↩ -
出处:「Working with Data」第 599–603 段(
text/14-ch07-chapter-7-working-with-data.txt:601,搜「compress large datasets」)。 ↩↩ -
出处:「Working with Data」第 632–697 段(
text/14-ch07-chapter-7-working-with-data.txt:639,搜「d3.format(specifier)」;:651,搜「.2%」;:689,搜「based on print formatting」)。 ↩ -
出处:「Working with Data」第 660–682 段(
text/14-ch07-chapter-7-working-with-data.txt:665,搜「pt_BR」;:676,搜「de-DE.json」;:682,搜「123.456.789,99 €」)。 ↩ -
出处:「Working with Data」第 728–815 段(
text/14-ch07-chapter-7-working-with-data.txt:734,搜「d3.timeFormat(specifier)」;:760,搜「%A %d %B %Y」;:780,搜「Day of week」;:804,搜「d3.timeFormat('%c')」)。 ↩ -
出处:「Working with Data」第 774 段(
text/14-ch07-chapter-7-working-with-data.txt:774,搜「return null」)。 ↩ -
出处:「Working with Data」第 930–937 段(
text/14-ch07-chapter-7-working-with-data.txt:931,搜「17 generators」;:936,搜「beyond the scope of this book」)。 ↩ -
出处:「Working with Data」第 723–724 段(
text/14-ch07-chapter-7-working-with-data.txt:723,搜「beyond the scope」)。 ↩ -
出处:「Working with Data」第 1224 段(
text/14-ch07-chapter-7-working-with-data.txt:1224,搜「daylight savings time」)。原文:「The interval considers the correct number of days in each month and leap years (but not daylight savings time).」 ↩