AntV
蚂蚁企业级数据可视化解决方案,让人们在数据世界里获得视觉化思考能力
AntV 旗下产品有:
G2
:统计图表S2
:多维表格G6
:关系图X6
:流程图L7
:地图
移动端:
F2
:移动统计图F6
:移动关系图F7
:移动地图
G2
G2 是一个简洁的渐进式语法,主要用于制作基于网页的可视化。它提供了一套函数风格式、声明形式的 API 和组件化的编程范式,希望能帮助用户能快速完成报表搭建、数据探索、可视化叙事等多样化的需求。
介绍一下 G2 的核心概念:
- 标记(Mark):绘制数据驱动的图形
- 转换(Transform):派生数据
- 比例尺(Scale):将抽象的数据映射为视觉数据
- 坐标系(Coordinate):对空间通道应用点变换
- 视图复合(Composition):管理和增强视图
- 动画(Animation):数据驱动的动画和连续的形变动画
- 交互(Interaction): 操作视图并且展现详细信息
js
<div id="chart"></div>
(() => {
/**实例化图表
* @getContainer() 获取Chart容器
* @render() 渲染图表
* @clear() 清空图表
* @destroy() 销毁图表
*/
const chart = new G2.Chart(
{
// 挂在容器
container: 'chartId'||document.createElementById('chart'),
height: 360,
width:800,
paddingLeft: 50,
}
);
// 生命可视化
let facet = chart
.point() // 点阵图
.data({ // 获取数据
type: "fetch",
value:
"https://gw.alipayobjects.com/os/antvdemo/assets/data/scatter.json",
})
// 标记是 G2 中最小的视觉单元,G2 中的所有图表都是由不同标记构成的。
.encode("x", "weight");
.encode('y', 'height')
// 视图复合用于制作多视图图表。
facet
.rect() //柱形图
// 增加颜色编码
.encode("color", "gender")
//转换会改变数据和标记的展现形式,多用于数据分析
.transform({ type: "binX", y: "count" })
.transform({ type: "stackY" })
//比例尺用于控制标记的视觉样式。
.scale("color", { range: ["steelblue", "orange"] })
.scale("y", { nice: true })
//坐标系会改变图表的展示形式。
.coordinate({ type: "polar" })
.axis("y", { title: false })
.style("insetLeft", 1)
//交互可以按需探索数据。
.interaction("brushXHighlight", true);
// 动画支持分组动画和关键帧动画。
const keyframe = chart
.timingKeyframe()
.attr("direction", "alternate")
.attr("iterationCount", 4);
keyframe
.interval()
.attr("padding", "auto")
.data(data)
.encode("x", "gender")
.encode("color", "gender")
.encode("key", "gender")
.transform({ type: "groupX", y: "count" });
// 渲染可视化
chart.render();
// 挂载图表的容器
return chart.getContainer();
})();
参考选项:https://g2.antv.antgroup.com/spec/overview
标记 mark
在 G2 中没有图表的概念,而是把标记(Mark)作为基本的视觉组成单元,任何一个图表都是多个标记组合而成的。和传统的绘制系统不同,标记提供了绘制抽象数据的能力。标记是一个模版,会生成一系列数据驱动的图形,其中每个图形对应一个或者多个数据项(Data Item)。
标记是视图树中叶子节点,也是 G2 中的“一等公民”:G2 中最重要的概念,一个标记由如下核心概念构成:
js
({
type: "mark",
data: [],
encode: {},
scale: {},
transform: [],
layout: {},
coordinate: {},
style: {},
viewStyle: {},
animate: {},
state: {},
label: {},
title: {},
axis: {},
legend: {},
tooltip: {},
scrollbar: {},
slider: {},
interaction: {},
theme: {},
});
绘制数据驱动的图形。
- interval - 通常用来绘制柱、条形图,饼图等相关图表。
- point - 主要用于绘制散点图,利用点的粒度来分析数据的分布情况。
- line - 根据一系列的点,绘制折线,通常用来绘制折线图。
- area - 通常用来绘制我们常见的面积图,通过填充,可以更好突出趋势堆积信息。
- cell - 根据 x, y 将空间划分成一个子空间,然后进行可视化绘制,常见于一些方块图,如日历图、聚合热力图等。
- rect - 使用两组 x,两组 y 来定位一个矩形区域,常用于直方图、矩阵树图等。
- link - 标记使用两个用 (x, y) 定位的点,绘制一条带方向的直线。通过指定 x,y 通道为长度为 2 的字段数组即可。
- vector - 用 start,end 两个点来表示一个向量,通常用于绘制具备向量含义的数据,比如风向量场等。
- box - 用来绘制箱线图,通常用来展示一组数据分布情况的统计图。
- boxplot - 用来绘制箱线图,并且内置数据的聚合操作。
- text - 通过指定文本的样式通道,可以在画布上绘制和数据绑定的文本字符。
- image - 利用 src 通道在画布上绘制图片。
- shape - 使用自定义函数灵活绘制自定义图形。
- lineX - 指定 x 通道来绘制垂直于 x 轴的辅助线,常用于绘制平均值或其他聚合数据辅助线。
- lineY - 指定 y 通道来绘制垂直于 y 轴的辅助线,常用于绘制平均值或其他聚合数据辅助线。
- range - 使用一组 x(x1, x2) 和一组 y(y1, y2) 来定位一个矩形区域,常用于绘制高亮指定区域的辅助区域。
- rangeX - 使用一组 x(x1, x2) 来定位一个垂直于 x 轴的矩形区域,常用于绘制高亮指定区域的辅助区域。
- rangeY - 使用一组 y(y1, y2) 来定位一个垂直于 y 轴的矩形区域,常用于绘制高亮指定区域的辅助区域。
- polygon - 利用多组 (x, y) 数据点,在画布中绘制闭合的多边形,通常结合一些社区布局算法使用。
- wordCloud - 绘制词云图。
- density - 渲染核密度数据,多用于小提琴图。
- heatmap - 接受热力数据,多用于绘制热力图。
mark组成部分
- data - 可视化的数据
- encode - 编码信息,用于指定视觉元素属性和数据之间的关系
不同的标记有不同的通道,但是也有一些通用的通道,一些常见的和绘制相关的通用通道如下:
js
x - x 位置
y - y 位置
z - z 位置
color - 颜色,填充色或者边框色,由形状决定
opacity - 透明度,填充透明度或者边框透明度,由样式决定
shape - 形状
size - 大小,不同的标记有不同的函数
series - 系列,用于分成系列
key - 唯一标记,用于数据更新
// API
// 第一种
chart.interval().encode('x', 'name').encode('y', 'value');
// 第二种
chart.interval().encode({ x: 'name', y: 'value' });
- scale - 映射规则:将抽象数据映射为视觉数据,它是抽象数据和视觉数据的桥梁。如果说编码决定了标记的哪些通道需要被可视化,那么比例尺决定了这些通道该如何被可视化。
js
// API 形式
// 第一种方式
chart.scale("x", { padding: 0.5 }).scale("y", {
type: "log", // 指定类型
domain: [10, 100], // 指定定义域
range: [0, 1], // 指定值域
});
// 第二种方式
chart.scale({
x: { padding: 0.5 },
y: {
type: "log", // 指定类型
domain: [10, 100], // 指定定义域
range: [0, 1], // 指定值域
},
});
- transform - 转化通道值:去转换数据和标记的选项,主要用于分析数据。标记转换的本质是一个函数,这个函数会筛选 、修改 、聚合和产生新的通道值。
js
// API
// 第一种方式 StackY 转换堆叠了条形图 y 和 y1 通道绑定的列数据
chart.interval().transform({ type: "stackY" }).transform({ type: "sortX" });
// 第二种方式
chart.interval().transform([{ type: "stackY" }, { type: "sortX" }]);
- layout - 布局算法配置:用于指定一些有特定布局函数标记的布局方法的参数,比如 Snakey, WordCloud, ForceGraph 等。
js
({
type: "sankey",
layout: {
nodeAlign: "center",
nodePadding: 0.03,
},
});
// API
chart.sankey().layout({ nodeAlign: "center", nodePadding: 0.03 });
- coordinate - 坐标系变换:标记的位置通道 x 和 y 会经过比例尺的映射到 [0, 1] 的范围,这之后会使用坐标系将点转换为画布坐标,从而改变标记的空间展示形式。
js
({
type: 'interval',
coordinate: { type: 'polar' },
});
// API
chart.interval().coordinate({ type: 'polar' });
//每一个视图只能拥有一个坐标系。坐标系除了本身的属性之外,还包含一系列坐标系变换(Coordinate Transform)
({
type: 'polar', // 类型
innerRadius: 0.6, // 本身的属性
outerRadius: 0.8,
transform: [{ type: 'transpose' }], // 坐标系变换
});
chart.line().coordinate({ type: 'polar' });
chart.area().coordinate({ type: 'radial' });
// 和下面的情况等价:
chart.line();
chart.area():
- style - 视觉样式:用来控制标记和视图的视觉样式
- view${Style} - 设置视图区域的样式
- plot${Style} - 设置绘制区域的样式
- main${Style} - 设置主区域的样式
- content${Style} - 设置内容区域的样式
js
style: {
// 设置视图样式
viewFill: '#4e79a7',
plotFill: '#f28e2c',
mainFill: '#e15759',
contentFill: '#76b7b2',
},
// 设置mark样式
style: { shape: 'point', fill: '#59a14f' },
// API
// 第一种方式
chart
.interval()
.style('stroke', 'black')
.style('strokeWidth', 2)
.viewStyle('viewFill', 'red')
.viewStyle('contentFill', 'yellow');
// 第二种方式
chart
.interval()
.style({
stroke: 'black',
strokeWidth: 2,
})
.viewStyle({
viewFill: 'red',
contentFill: 'yellow',
});
- viewStyle - 视图的视觉样式
- animate - 动画属性
标记是通过 mark.animate 指定动画属性的,一共有三个部分的动画可以指定:
enter - 新增的图形 update - 更新的图形 exit - 删除的图形 而每部分的动画有以下的属性:
type - 种类 duration - 持续时间 delay - 延迟时间 easing - 缓动函数
js
// API
// 第一种方式
chart
.interval()
.animate('enter', { type: 'scaleInX', duration: 100, delay: 10 })
.animate('update', { type: 'morphing' });
// 第二种方式
chart.interval().animate({
enter: {
type: 'scaleInX',
duration: 100,
delay: 10,
},
update: {
type: 'morphing',
},
});
.animate('enter', {
type: 'scaleInY', // 指定入场动画的类型
duration: 1000, // 指定入场动画的执行时间
});
//动画属性可以作为一种通道,也可以编码数据
.encode('enterDuration', (d) => d.endTime - d.startTime) // 计算持续时间,并且编码
.encode('enterDelay', 'startTime'); // 指定出现的时间,并且编码
/**
* 上面的动画都是过渡动画,不涉及到数据的更新,G2 也提供了制作关键帧动画的能力。
* 使用 chart.timingKeyframe 创建一个时间容器,用于放置一系列视图,它会对这些视图中
* 有关系的图形元素应用平滑的过渡效果。而对应关系通过 key 和 groupKey 两个通道指定。
*/
// 参考 css animation 的描述
const keyframe = chart
.timingKeyframe() // 创建容器
.attr('iterationCount', 2) // 迭代次数
.attr('direction', 'alternate') // 方向
.attr('duration', 1000); // 持续时间
keyframe
.interval()
.transform({ type: 'groupX', y: 'mean' })
.data(data)
.encode('x', 'gender')
.encode('y', 'weight')
.encode('color', 'gender')
.encode('key', 'gender'); // 指定 key
keyframe
.point()
.data(data)
.encode('x', 'height')
.encode('y', 'weight')
.encode('color', 'gender')
.encode('shape', 'point')
.encode('groupKey', 'gender'); // 指定 groupKey
- state - 状态样式:用来控制标记的状态样式。
目前一共有 4 个内置状态:
- active - 高亮时候的样式
- inactive - 没有高亮时候的样式
- selected - 选择时候的样式
- unselected - 没有选择时候的样式
js
// API
// 第一种方式
chart
.interval()
.state("active", { fill: "red", stroke: "blue", strokeWidth: 2 })
.state("inactive", { fill: "#aaa" })
.state("selected", { fill: "red", stroke: "blue", strokeWidth: 2 })
.state("unselected", { fill: "#aaa" })
.interaction("elementSelect"); // 设置选择交互
// 第二种方式
chart.interval().state({
active: { fill: "red", stroke: "blue", strokeWidth: 2 },
inactive: { fill: "#aaa" },
});
- label - 数据标签:是给图表添加标注的手段之一。可以给标记添加多个标签:
js
// 第一种方式
chart
.interval()
.label({
text: 'genre', // 指定绑定的字段
dy: -15, // 指定样式
})
.label({
text: 'sold', // 指定绑定的字段
fill: '#fff', // 指定样式
dy: 5,
});
// 第二种方式
chart.interval().label([
{
text: 'genre', // 指定绑定的字段
dy: -15, // 指定样式
},
{
text: 'sold', // 指定绑定的字段
fill: '#fff', // 指定样式
dy: 5,
},
]);
// 在 View 层级可以通过 labelTransform 声明标签转化:
// 第一种方式
chart
.labelTransform({ type: 'overlapHide' })
.labelTransform({ type: 'contrastReverse' });
// 第二种方式
chart.labelTransform([{ type: 'overlapHide' }, { type: 'contrastReverse' }]);
({
type: 'interval',
labels: [
{
text: 'name', // 绑定的字段或者一个常量字符串
dy: -2, // @antv/g 支持的样式
fill: 'red', // @antv/g 支持的样式
selector: 'last', // 选择器
transform: [], // 标签转换
},
],
});
// 声明第一个 label
.label({
text: 'genre', // 指定绑定的字段
style: {
dy: -15, // 指定样式
},
})
// 声明第二个 label
.label({
text: 'sold', // 指定绑定的字段
style: {
fill: '#fff', // 指定样式
dy: 5,
},
});
- title - 图表标题
js
({
type: "interval",
title: {
title: "hello",
subtitle: "world",
},
});
// API
chart.interval().title({
title: "hello",
subtitle: "world",
});
- axis - 坐标轴:可以理解为是空间通道(x,y 和 position)对应比例尺的可视化。
js
// 第一种方式
chart
.interval()
.axis("x", { labelFormatter: "%0" })
.axis("y", { tickCount: 5 });
// 第二种方式
chart.interval().axis({
x: { labelFormatter: "%0" },
y: { tickCount: 5 },
});
({
type: "interval",
axis: { y: false }, // 隐藏 y 方向坐标轴
});
- legend - 图例:可以理解为是非空间通道(color,opacity,size,shape)对应比例尺的可视化。
js
// 第一种方式
chart.interval().legend("color", {}).legend("size", {});
// 第二种方式
chart.interval().legend({
color: {},
size: {},
});
({
type: "interval",
legend: { color: false }, // 隐藏 color 通道的图例
});
- tooltip - 提示信息:可以提供关于数据点的额外信息,帮助用户更好地理解和解释可视化,在可视化中 Tooltip 通常具有以下作用:
- 显示详细信息:Tooltip 可以显示有关数据点的详细信息,例如具体数值、百分比或其他相关属性。这有助于用户更深入地了解数据。
- 提高可读性:在复杂的可视化中,Tooltip 可以帮助用户更容易地识别和理解数据点。例如,在散点图中,当数据点密集时,Tooltip 可以显示特定点的详细信息,而无需将鼠标悬停在每个点上。
- 增强交互性:Tooltip 可以增强可视化的交互性。用户可以通过悬停或点击数据点来查看更多信息,这使得可视化更加动态和有趣。
- 突出显示关键信息:Tooltip 可以用来突出显示关键信息。例如,在时间序列图中,您可以使用 Tooltip 显示特定时间点的重要事件或突变。
js
({
type: "interval",
tooltip: {
title: "name", // 标题
items: ["genre"], // 数据项
},
});
// API
chart.interval().tooltip({
title: "name", // 标题
items: ["genre"], // 数据项
});
- scrollbar - 滚动条:可以用于过滤数据,可以和 x 或者 y 通道绑定的,滚动条默认都是关闭的。
js
// 第一种方式
chart.interval().scrollbar("x", {}).scrollbar("y", {});
// 第二种方式
chart.interval().scrollbar({
x: {},
y: {},
});
- slider - 拖拽轴:可以用于过滤数据,可以和 x 或者 y 通道绑定的,滑动条默认都是关闭的。
js
// 第一种方式
chart.interval().slider('x', {}).slider('y', {});
// 第二种方式
chart.interval().slider({
x: {},
y: {},
});
// 并且结合 view.interaction.tooltip 去配置提示信息的渲染和额外配置。
({
type: 'view',
interaction: {
tooltip: { series: true },
},
});
// API
chart.interaction('tooltip', { series: true });
tooltip: {
title: (d) => (d.sold > 150 ? 'high' : 'low'), // 设置 title
items: [
'genre', // 第一个 item
'sold', // 第二个 item
],
},
type Item = {
color?: string; // marker 的颜色
name?: string; // item 的名字
value?: string; // item 的值
};
// 当然对于 title 和 item 还提供了回调去获得最大的自定义能力。
({
tooltip: {
items: [
(d, index, data, column) => ({
color: d.sold > 150 ? 'red' : 'blue', // 指定 item 的颜色
name: index === 0 ? d.genre : `${d.genre} ${data[i].genre}`, // 指定 item 的名字
value: column.y.value[i], // 使用 y 通道的值
}),
],
},
});
- interaction - 交互: 提供了按需探索数据的能力。
js
// 第一种方式
chart.interaction('tooltip', {}).interaction('brushHighlight', {});
// 第二种方式
chart.interaction({
tooltip: {},
brushHighlight: {},
});
chart.interaction('elementHighlight', { link: true, background: true });
chart.line().interaction('elementHighlight', { link: false });
chart.area().interaction('elementHighlight', { background: false });
// 和下面的情况等价:
chart.interaction('elementHighlight', { link: false, background: false });
chart.line();
chart.area():
- theme - 主题:是图表中图形的一些默认样式。
包含的默认主题有:
- G2.Light
- G2.Dark
- G2.Classic
- G2.ClassicDark
- G2.Academy
js
({
type: "interval",
theme: { color: "red" }, // 设置默认颜色为红色
});
// API
chart.interval().theme({});
chart.theme({ type: "classicDark" }); // 使用暗色主题
// 定义主题
function CustomTheme() {
const light = G2.Light();
return { ...light, color: "red" };
}
// 注册主题
G2.register("theme.custom", CustomTheme);