Vega Fold 变换详解将矩阵与交叉表数据重塑为键值对标准格式【免费下载链接】vegaA visualization grammar.项目地址: https://gitcode.com/gh_mirrors/ve/vegafold是 Vega 可视化语法Vega中用于数据整形的核心变换之一它把一个或多个数据字段折叠为统一的key与value两个属性从而将矩阵或交叉表cross-tabulation形式的宽表数据映射为长表标准格式是 pivot 变换的逆操作。读完本文你将掌握fold的参数语义、输入输出行为、底层实现原理以及它与pivot、flatten之间的适用边界能够直接在 Vega 规范中完成数据重塑。fold 变换是什么在数据可视化实践中原始数据常常以宽表形式存在一行代表一个实体多个属性列代表该实体在不同维度上的取值。例如某届奥运会的奖牌数据[ {country: USA, gold: 10, silver: 20}, {country: Canada, gold: 7, silver: 26} ]这里的gold、silver是两个并列的度量列。若要按奖牌类型进行分组、着色或堆叠就需要把它们折叠成一个键值对结构。fold变换正是为此设计它把fields参数指定的一个或多个数据字段折叠folding成两个属性——key属性存放原始数据字段名value属性存放该字段对应的数值。关键行为来自 fold.md 与 Fold.js该变换生成一条新的数据流其中每个输出数据对象由key、value两个属性以及输入数据对象的全部原始字段共同组成原始字段被完整保留因此折叠后的每一行仍然携带country等上下文信息便于后续按实体分组或关联从数据流角度这是一个一对多的展开N 个字段被折叠时每个输入元组会产生 N 个输出元组因而在 Vega 的变换元数据中被标记为{generates: true}即属于生成新数据的变换。变换参数fold变换接受两个参数参数定义与校验规则在 Fold.js 的Fold.Definition中声明属性类型必填说明fieldsField[]是指定要折叠的数据字段数组即哪些属性需要被展开为key/value对。对应源码中type: field, array: true, required: true。asString[]否折叠后key与value属性的输出字段名。默认值为[key, value]源码中约束其必须为长度为 2 的字符串数组length: 2。关于as的默认行为可以从源码得到精确印证Fold.jsconst as _.as || [key, value], k as[0], v as[1];当未指定as时输出字段名固定为key与value若指定了as例如as: [measure, amount]则折叠后的字段名将分别改为measure原字段名与amount原字段值。这一能力在需要把多个fold结果合并、或避免与已有字段名冲突时非常实用。使用示例以下配置折叠gold与silver两个字段{type: fold, fields: [gold, silver]}给定输入数据[ {country: USA, gold: 10, silver: 20}, {country: Canada, gold: 7, silver: 26} ]输出为[ {key: gold, value: 10, country: USA, gold: 10, silver: 20}, {key: silver, value: 20, country: USA, gold: 10, silver: 20}, {key: gold, value: 7, country: Canada, gold: 7, silver: 26}, {key: silver, value: 26, country: Canada, gold: 7, silver: 26} ]注意三点输出行数是输入行数 × 折叠字段数2 行 × 2 字段 4 行每一行都保留了country等全部原始字段同时还保留了gold/silver原始列因为 fold 是在原对象基础上派生新对象而非替换key记录的是字段名gold、silvervalue记录的是该字段在当前行的取值。在 Vega 规范中折叠后的数据可以直接接入后续变换链例如按key进行颜色编码、按country分组后堆叠。一个典型的应用是把宽表转成长表后再配合stack变换绘制堆叠条形图或分组条形图。源码级实现原理理解fold的底层实现有助于预判它在动态数据流中的行为。核心实现在 packages/vega-transforms/src/Fold.js整个变换只有约 30 行inherits(Fold, Transform, { transform(_, pulse) { const out pulse.fork(pulse.NO_SOURCE), fields _.fields, fnames fields.map(accessorName), as _.as || [key, value], k as[0], v as[1], n fields.length; out.rem this.value; pulse.visit(pulse.SOURCE, t { for (let i0, d; in; i) { d derive(t); d[k] fnames[i]; d[v] fieldsi; out.add.push(d); } }); this.value out.source out.add; return out.modifies(as); } });关键实现细节派生而非复制derive(t)来自vega-dataflow在输入元组t的基础上派生出新元组从而天然继承全部原始字段随后写入d[k] fnames[i]和d[v] fieldsi完成字段名与取值的注入。字段名通过accessorName从访问器中提取来自vega-util字段取值则调用fieldsi求值。增量式数据流处理out.rem this.value将上一次的输出标记为待移除随后对新到达的pulse.SOURCE元组逐一展开并out.add.push(d)最后把本次生成的元组记为this.value out.source out.add。这意味着每次数据更新时旧输出被整体替换、新输出被整体追加保证下游算子始终看到一致的折叠结果。字段访问器机制fields参数在解析阶段被编译为字段访问器type: field因此既支持简单字段名也支持嵌套字段路径如a.b。展开时对每个输入元组调用fieldsi等价于读取t[a.b]对应的嵌套值。元数据声明metadata: {generates: true}告知 Vega 运行时该变换会产生新的数据对象运行时据此安排依赖与缓存策略。与 pivot 互为逆操作文档明确指出fold是 pivot 的逆操作。pivot将字段的唯一值映射为输出流中的新字段列并对其余值做聚合而fold把多个字段折叠回key/value长表。两者组合可以完成宽 ↔ 长的双向转换fold{country: USA, gold: 10, silver: 20}→ 两行{key: gold, value: 10, country: USA}、{key: silver, value: 20, country: USA}pivot以groupby: [country]、field: type、value: count配置可将长表还原为{country: USA, gold: 10, silver: 20}这样的宽表见 pivot.md 的示例。二者的实现路径也不同pivot在源码层面直接继承Aggregate变换先收集字段全部唯一值再逐列生成聚合字段见 Pivot.js而fold是独立的轻量变换不涉及聚合。在实际项目中fold常作为进入图表前的整形步骤pivot则常用于聚合后出表的场景。与 flatten 的边界什么时候不用 foldfold只适用于字段集合在设计期已知的宽表数据即把若干个具名列折叠成键值对。如果你的数据对象包含的是数组类型字段应改用 flatten 变换——flatten将数组中的每个元素展开为独立数据对象flatten.md 中有单字段、多字段、附带索引等多种用法示例。二者的判别要点数据形态目标结构适用变换多列度量gold、silver、bronze...每列变为一行key/valuefold单列存数组foo: [1, 2, 3]每个数组元素变为一行flatten嵌套子对象且字段设计期已知提取子对象字段fold或project顺带一提在flatten的文档中也有对应的反向提示若数据包含的是设计期已知的嵌套子对象字段则可考虑fold或project。两者相互呼应构成了 Vega 中结构化数据整形的完整工具箱。测试用例如何验证行为仓库为fold提供了完整的单元测试packages/vega-transforms/test/fold-test.js。测试基于vega-dataflow的Dataflow与changeset机制覆盖三类数据流脉冲新增insert插入两行{a:!, b:5, c:7}与{a:?, b:2, c:4}折叠b、c后断言输出共 4 行且key/value/原始字段a的值均正确修改modify通过changeset().modify(data[1], b, 9)修改第二行b字段断言对应的折叠行value同步更新为 9移除remove通过changeset().remove(data[0])删除第一行断言输出缩减为 2 行。该测试同时印证了两个文档级事实一是每个输入元组按字段数展开二是原始字段被完整保留在输出中如断言d[0].a !。从导出路径看fold在 packages/vega-transforms/index.js 中以export {default as fold} from ./src/Fold.js对外暴露因此在 Vega 规范的数据变换type: fold和编程式 Dataflowdf.add(Fold, {fields, pulse})两种用法中均可直接使用。在 Vega 规范中的完整用法fold作为数据变换data transform需要放置在 Vega 规范的data定义中与其他变换串联。一个完整的示例骨架如下{ data: [ { name: medals, url: data/medals.json, transform: [ {type: fold, fields: [gold, silver, bronze], as: [medal, count]} ] } ], marks: [ { type: rect, from: {data: medals}, encode: { update: { y: {scale: y, field: country}, height: {scale: y, band: 1}, x: {scale: x, field: count}, fill: {scale: color, field: medal} } } } ] }这里将gold/silver/bronze三列折叠为medal字段名与count数值随后 mark 编码直接以medal驱动颜色标度、以count驱动位置标度——这正是折叠变换最典型的落地方式把需要作为分组维度的列标题变成数据值。小结fold将宽表数据多列度量重塑为key/value长表格式每个输入对象按折叠字段数展开为多行同时完整保留原始字段参数仅有fields必填与as可选默认[key, value]两个语义简单、易于组合它是pivot的逆操作二者共同支撑宽 ↔ 长数据转换对数组型字段应改用flatten源码实现基于 Dataflow 的派生与脉冲增量机制derivepulse.visit测试用例覆盖增、改、删三类更新行为可预期、可验证。掌握fold之后配合 pivot、flatten、project 等整形变换你就可以在 Vega 规范内部灵活完成绝大多数数据形态转换而无需在数据进入 Vega 之前额外编写预处理脚本。【免费下载链接】vegaA visualization grammar.项目地址: https://gitcode.com/gh_mirrors/ve/vega创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
Deepseek架构定位与实战:从LLM到Agent选型部署指南 很多人第一次接触Deepseek,都是打开网页版聊天框问几个问题就完事了。直到有读者跑来问我:“Deepseek到底算AI模型还是Agent?”我才意识到,大多数人对它的理解还停留在“对话玩具”这一层。这个问题的答案会直接影响你后续所有技术… · 2026/9/23 9:15:39
3个坑让Win7卡顿?源码解析系统之家官网win7优化实录 3个坑让Win7卡顿?源码解析系统之家官网win7优化实录 复制来的代码跑不通不知道怎么调?别急,这事儿我干过十年,太熟了。尤其是处理【系统之家官网win7】这类老旧环境下的性能问题时,光看表面报错没用,必须深入【源码解析】才能找到病根。今… · 2026/9/23 10:07:18
3个坑教你选对识别人脸库,实战项目避坑指南 3个坑教你选对识别人脸库,实战项目避坑指南 刚接手一个安防监控的实战项目,老板甩给我一段网上复制的 Python 代码,说是能识别人脸。我满怀信心跑了一下,报错: ImportError: cannot import name… · 2026/9/23 10:07:18
3个坑救活你的项目:联想超薄笔记本选型与源码解析实战 3个坑救活你的项目:联想超薄笔记本选型与源码解析实战 版本升级后 API 全变了,这是每个转岗开发者最崩溃的瞬间。昨天还在用旧版接口写逻辑,今天框架一升,报错满屏,连文档都找不到对应说明。别慌,这种“断崖式”的断层,往往藏在底层源码里。今天… · 2026/9/23 10:07:11
开放式代码审查实战:从流程设计到落地要点 1. 开放式代码审查的核心思路与方案取舍1.1 为什么我会把代码审查做成“开放”流程代码审查这件事,很多团队都在做,但多数做得特别“憋屈”。我见过太多团队把审查当成合并代码前的一道行政关卡:写完代码丢给组长,组长扫一眼回一句… · 2026/9/23 10:07:11
egg学习(一):用egg-mongoose连接本地MongoDB的配置骨架与验证 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/23 10:07:11
AI时代程序员的核心竞争力与工作流重构 1. 从代码搬运工到AI调教师:程序员角色的范式转移十年前我刚入行时,程序员的工作就是对着IDE疯狂敲键盘。现在打开GitHub Copilot,看着它自动补完整个函数时,我突然意识到:当AI能写80%的样板代码时,我们的价… · 2026/9/23 10:07:11
3招搞定手机怎么下载微信面试难题实战项目解析 3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29