- 数据可视化
【免费下载链接】vega
A visualization grammar.
本篇指南围绕 Vega 官方示例 bar-chart.vg.json 展开:一个仅 95 行 JSON 的柱状图规范,却完整覆盖了数据声明、band/linear 双尺度映射、坐标轴、rect 与 text 双重标记、以及基于信号(signal)的悬停高亮与数值 Tooltip 交互。读完本文,你将能够逐行理解 Vega 顶层规范的结构,掌握enter/update/hover编码集、band尺度与生产规则(production rules)的用法,并具备把任意结构相似的数据改造成可交互柱状图的能力。
对应的完整教程位于 docs/tutorials/bar-chart/index.md,本文以其为核心骨架,并结合 packages/vega-scale、packages/vega-parser 等源码做纵深解读。
示例规范一览
先通读完整的 Vega 规范(docs/examples/bar-chart.vg.json):
{ "$schema": "https://vega.github.io/schema/vega/v6.json", "description": "A basic bar chart example, with value labels shown upon pointer hover.", "width": 400, "height": 200, "padding": 5, "data": [ { "name": "table", "values": [ {"category": "A", "amount": 28}, {"category": "B", "amount": 55}, {"category": "C", "amount": 43}, {"category": "D", "amount": 91}, {"category": "E", "amount": 81}, {"category": "F", "amount": 53}, {"category": "G", "amount": 19}, {"category": "H", "amount": 87} ] } ], "signals": [ { "name": "tooltip", "value": {}, "on": [ {"events": "rect:pointerover", "update": "datum"}, {"events": "rect:pointerout", "update": "{}"} ] } ], "scales": [ { "name": "xscale", "type": "band", "domain": {"data": "table", "field": "category"}, "range": "width", "padding": 0.05, "round": true }, { "name": "yscale", "domain": {"data": "table", "field": "amount"}, "nice": true, "range": "height" } ], "axes": [ { "orient": "bottom", "scale": "xscale" }, { "orient": "left", "scale": "yscale" } ], "marks": [ { "type": "rect", "from": {"data":"table"}, "encode": { "enter": { "x": {"scale": "xscale", "field": "category"}, "width": {"scale": "xscale", "band": 1}, "y": {"scale": "yscale", "field": "amount"}, "y2": {"scale": "yscale", "value": 0} }, "update": { "fill": {"value": "steelblue"} }, "hover": { "fill": {"value": "red"} } } }, { "type": "text", "encode": { "enter": { "align": {"value": "center"}, "baseline": {"value": "bottom"}, "fill": {"value": "#333"} }, "update": { "x": {"scale": "xscale", "signal": "tooltip.category", "band": 0.5}, "y": {"scale": "yscale", "signal": "tooltip.amount", "offset": -2}, "text": {"signal": "tooltip.amount"}, "fillOpacity": [ {"test": "datum === tooltip", "value": 0}, {"value": 1} ] } } } ] }规范由六大顶层组件构成:可视化尺寸、数据、信号、尺度、坐标轴、标记。下面逐一拆解。
可视化尺寸:width、height、padding 与 autosize
"width": 400, "height": 200, "padding": 5, "autosize": "pad"width/height定义的是数据矩形(data rectangle)的大小,即数据绘图区域;坐标轴、图例等额外组件会占用更多空间。padding定义图表内容与视图边界之间的留白。autosize决定最终图表尺寸如何确定:"pad"(默认):额外扩展空间以容纳所有标记(包括坐标轴、图例),数据矩形大小不变。若标记超出数据矩形边界,视图组件可能变得很大。"fit":尝试将整张图(数据矩形、坐标轴、图例,但不含 padding)放入给定的width/height内,Vega 会收缩数据矩形来容纳坐标轴与图例;某些情况下(如图例过高)可能发生裁剪。"none":禁用自动尺寸调整,总尺寸仅由width+height+padding决定。
从源码看,autosize、padding、width、height都属于内建信号(built-in signals)。在 packages/vega-parser/src/parsers/view.js 的collectSignals中,它们被统一收集:优先取顶层 spec 属性值,未定义时才回落到 config 中的对应配置;随后布局阶段由ViewLayout运算符(同文件 L54-L60)消费autosize信号完成最终布局。这意味着autosize等属性既可以直接写死,也可以声明为信号引用,实现动态尺寸。
数据:内联 values、URL 与数据变换
"data": [ { "name": "table", "values": [ {"category": "A", "amount": 28}, {"category": "B", "amount": 55}, {"category": "C", "amount": 43}, {"category": "D", "amount": 91}, {"category": "E", "amount": 81}, {"category": "F", "amount": 53}, {"category": "G", "amount": 19}, {"category": "H", "amount": 87} ] } ]data是数据定义数组,每个数据集合必须有唯一的name。本示例使用values直接内联定义数据:每条记录包含字符串字段category(类别标签)与数值字段amount(数值)。
Vega 中的数据来源有三种方式(三者只能选其一):
values:直接内联;url:从网络加载(支持 JSON、CSV 等格式);source:由先前定义的数据集派生(例如经变换得到的新数据集)。
数据集还可通过transform属性挂接一系列数据变换(过滤、聚合、布局等)。关于数据与变换的完整说明见 docs/docs/data.md 与 docs/docs/transforms.md。
尺度:band 尺度与线性尺度的分工
"scales": [ { "name": "xscale", "type": "band", "domain": {"data": "table", "field": "category"}, "range": "width", "padding": 0.05, "round": true }, { "name": "yscale", "domain": {"data": "table", "field": "amount"}, "nice": true, "range": "height" } ]尺度(scale)将数据值映射为视觉值(像素位置、颜色等)。本示例定义了两个尺度:
- xscale(band 尺度):
type: "band"显式指定为序数 band 尺度,将有序的类别域(A–H)映射到水平像素范围。range: "width"是 Vega 提供的便捷写法,等价于[0, 400](由画布宽度决定)。padding: 0.05在条带之间加入 5% 的间隔;round: true让柱条对齐到像素边界,避免亚像素模糊。 - yscale(线性尺度):未显式写
type,因为linear是默认类型(见 packages/vega-scale/src/scales/types.js 中Linear = 'linear'的定义)。其域取自amount字段的最小/最大值,range: "height"等价于[200, 0](Y 轴方向反转)。nice: true让域值更“友好”——例如原始域[0, 94.345]会被圆整为[0, 100],刻度更易读。
关于 band 尺度的底层行为,可参考 packages/vega-scale/src/scales/scaleBand.js:它基于 d3 的序数尺度扩展而来,通过paddingInner/paddingOuter(padding会同时设置二者)计算step与bandwidth,round为真时对步长、起点与带宽取整(见该文件 L27-L36)。band: 1即取满整个条带宽度;若改用band: 0.5则只取条带的一半。
补充说明:
- 每个尺度必须有唯一名称(嵌套在
group标记内的尺度可以重名覆盖已定义尺度,属高级用法)。 domain既可以是静态值数组,也可以像本例一样从数据动态求取。- 默认情况下定量尺度会自动包含 0;如需禁用,在尺度定义中加入
"zero": false。 range也可显式定义为数组:二元数值数组用于空间映射,更长的数组(如["#ffa804", ...]十六进制色值)可用于序数尺度的自定义调色板。
坐标轴:最小定义与定制技巧
"axes": [ { "orient": "bottom", "scale": "xscale" }, { "orient": "left", "scale": "yscale" } ]坐标轴用于将尺度可视化为刻度与标签。一条轴定义最少需要两个属性:orient(方位)与scale(所可视化的尺度)。这里底部为 xscale,左侧为 yscale。
教程中还演示了进一步的定制(对应 docs/tutorials/bar-chart/bar-chart-axes.vg.json):
"axes": [ { "orient": "bottom", "scale": "xscale" }, { "orient": "right", "scale": "yscale", "tickCount": 5, "offset": 6 } ]tickCount: 5:请求大约 5 个刻度(默认约 10 个);orient: "right":将 Y 轴移到图表右侧;offset: 6:沿垂直方向平移轴的位置(本例向右偏移 6 像素)。
更完整的轴配置说明见 docs/docs/axes.md。
标记与编码集:rect 柱条 + hover 高亮
{ "type": "rect", "from": {"data":"table"}, "encode": { "enter": { "x": {"scale": "xscale", "field": "category"}, "width": {"scale": "xscale", "band": 1}, "y": {"scale": "yscale", "field": "amount"}, "y2": {"scale": "yscale", "value": 0} }, "update": { "fill": {"value": "steelblue"} }, "hover": { "fill": {"value": "red"} } } }标记(mark)是可视化的基本图形元素。每个标记必须有type(rect、area、line、symbol等)和from(指明数据来源;若不提供from,则创建单个标记实例)。
标记属性的视觉编码通过encode下的命名编码集完成,标准编码集有:
| 编码集 | 作用 |
|---|---|
enter | 标记首次创建时设置的属性 |
exit | 标记即将移除时的属性 |
update | 数据变化时更新的属性 |
hover | 鼠标悬停时设置的属性 |
执行顺序上,enter先被求值,随后是update,二者共同画出柱状图;鼠标悬停时求值hover将柱条染红;鼠标移出后再次求值update恢复steelblue。注意:若省略update集,悬停后柱条会永久保持红色——因为hover属性不会被自动还原。
再细看enter集中的四个定位属性:
"x": {"scale": "xscale", "field": "category"}, "width": {"scale": "xscale", "band": 1}, "y": {"scale": "yscale", "field": "amount"}, "y2": {"scale": "yscale", "value": 0}x:柱条左边缘,由xscale映射category字段得到;width:柱条宽度,取 band 尺度的完整条带(band: 1);y/y2:分别指定柱顶与柱底两个端点,y2用写死的数值 0 经yscale映射,确保柱底始终贴零线。使用双端点而非y+height的好处是不必关心哪个值更大——Vega 会自动正确处理位置;同理也可使用x/x2(横向柱状图、时间线常用)。
除标准图形标记外,Vega 还支持group标记(docs/docs/marks/group.md)用于嵌套标记与小多图(small multiples),group 内部可定义自己的尺度与坐标轴。更完整的标记体系见 docs/docs/marks.md。
信号:用 Tooltip 信号驱动交互
"signals": [ { "name": "tooltip", "value": {}, "on": [ {"events": "rect:pointerover", "update": "datum"}, {"events": "rect:pointerout", "update": "{}"} ] } ]信号(signal)是 Vega 的动态变量:表达式会在其他信号变化或输入事件发生时被自动重新求值。每个信号必须有唯一name和初始value。
本示例的tooltip信号跟踪当前高亮柱条对应的数据对象(datum):
rect:pointerover(指针移入矩形标记)时,update求值datum,即该标记的底层数据记录;rect:pointerout(指针移出)时,update求值为空对象{}。
事件语法rect:pointerover属于事件流选择器(event stream selector)的简写形式,详见 docs/docs/event-streams.md(其中也包含mouseover等指针事件的说明)。
用信号驱动 text 标记
接着,用一个单实例 text 标记把 Tooltip 数值渲染出来(注意:该标记没有from属性,只创建一个实例):
{ "type": "text", "encode": { "enter": { "align": {"value": "center"}, "baseline": {"value": "bottom"}, "fill": {"value": "#333"} }, "update": { "x": {"scale": "xscale", "signal": "tooltip.category", "band": 0.5}, "y": {"scale": "yscale", "signal": "tooltip.amount", "offset": -2}, "text": {"signal": "tooltip.amount"}, "fillOpacity": [ {"test": "datum === tooltip", "value": 0}, {"value": 1} ] } } }x/y:直接从tooltip信号取值,经对应尺度映射定位:band: 0.5将文本置于条带中心,offset: -2让文本略微上移;text:显示tooltip.amount数值;fillOpacity:使用生产规则(production rules)——一组 if-then-else 视觉编码规则链。当tooltip为空对象时,datum === tooltip为false(空对象不等于任何数据记录),走第二个规则取不透明度 1……实际上这里更常见的写法是判断tooltip是否有值:教程早期版本使用isNaN(tooltip.amount)判断,即指针不在柱条上时tooltip为空对象、tooltip.amount为NaN,此时文本完全透明(不透明度 0);否则不透明度为 1,文本可见。
信号可被用于规范的任意位置:数据变换、尺度、标记编码等,详见 docs/docs/signals.md。
延伸练习与下一步
在 Vega Editor 中粘贴完整规范即可实时编辑预览(对应源文件 docs/examples/bar-chart.vg.json)。建议尝试以下练习:
- 调整尺度与坐标轴:改
tickCount、orient、padding、nice等参数观察变化; - 将竖向柱状图改为横向柱状图(提示:用
x/x2双端点配合band尺度在 Y 轴方向排布,轴方位相应调整); - 用结构相似的新数据集(字段名为
category与amount)替换values,观察图表是否自动适配; - 把
hover高亮改成update中基于条件测试的填充色,体验生产规则与编码集之间的取舍。
更进一步的参考:数据与变换见 docs/docs/data.md 与 docs/docs/transforms.md;完整顶层规范说明见 docs/docs/specification.md;尺度、坐标轴、标记的详细文档分别在 docs/docs/scales.md、docs/docs/axes.md、docs/docs/marks.md。
- 数据可视化
【免费下载链接】vega
A visualization grammar.
相关推荐
Flet BarChart 柱状图控件完全指南:从交互式柱状图到事件驱动的自定义悬停效果
Flet BarChart 柱状图控件完全指南:从交互式柱状图到事件驱动的自定义悬停效果 flet_charts 是 Flet 生态中专门用于数据可视化的扩展包
前端跨平台桌面应用移动开发Vega 官方教程全解析:从交互式柱状图到机场航线地图的完整实战
Vega 官方教程全解析:从交互式柱状图到机场航线地图的完整实战 Vega 是一个用于创建交互式可视化声明的可视化语法(visualization gramma
数据可视化Paper2Slides多模态RAG:图像、表格、公式的智能处理
Paper2Slides多模态RAG:图像、表格、公式的智能处理 Paper2Slides是一款革命性的开源工具,通过多模态RAG(检索增强生成)技术,实现从学
人工智能AI 应用RAG后端前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考