4.1 数据转换
你的 Crime 数据是宽格式,可视化常需要长格式。转换函数一行解决。
Your Crime data is in wide format, but visualization often needs long format. A one-liner conversion function handles it.
你的原案例
Your Original Case
原 5.1 节用了 1985 美国 50 州犯罪数据(CSV),含 8 个犯罪指标列。
Section 5.1 used 1985 U.S. crime data (CSV) for the 50 states, with 8 crime-indicator columns.
嵌入陈为教材理论
Embedded Theory
- 长格式(long):每行一个观测,列 = 字段(如
{state, metric, value})。优点:方便过滤、分组、绑定到 d3 join。 - Long format (long): one observation per row, columns = fields (e.g.,
{state, metric, value}). Pros: easy to filter, group, and bind to a d3 join. - 宽格式(wide):每行一个实体,列 = 指标(如
{state, murder, robbery, ...})。优点:人眼读得懂、直观。 - Wide format (wide): one entity per row, columns = metrics (e.g.,
{state, murder, robbery, ...}). Pros: human-readable and intuitive. - 转换:
flatMap+ 循环键名 = 几行代码搞定。 - Conversion:
flatMap+ iterating over key names = a few lines of code. - d3.autoType:自动推断列类型(数字、日期、布尔),省得手动
+d.field。 - d3.autoType: auto-infers column types (number, date, boolean), saving you from manual
+d.field.
⭐ 关键代码
★ Key Code
⭐ 关键点 1:d3.csv 第二参 = 类型转换回调
★ Key Point 1: the second argument of d3.csv = the type-conversion callback
// ⭐ 自动类型推断(数字/日期/布尔)
const raw = await d3.csv('./data/crime.csv', d3.autoType);
console.log(raw[0]); // {state: 'Alabama', population: 3979000, murder: 350, ...}
⭐ d3.autoType 内部就是遍历每列、用 Number() / Date() / 字符串检测。能识别的就转、识别不了保持字符串。
★ d3.autoType internally walks each column using Number() / Date() / string detection. Recognized types are converted; unrecognized values stay as strings.
⭐ 关键点 2:宽 → 长(flatMap 模式)
★ Key Point 2: wide → long (the flatMap pattern)
// ⭐ flatMap:每行展开成多个观测
const long = raw.flatMap(d =>
['murder', 'robbery', 'burglary'].map(key => ({
state: d.state,
metric: key,
value: d[key]
}))
);
// 现在可以做:d3.group(long, d => d.metric)
⭐ flatMap 是 ES2019,是 "map + 一维 flatten" 的简写。比 map().flat() 链式更直观。
★ flatMap is ES2019, shorthand for “map + one-level flatten”. More intuitive than the map().flat() chain.