“两点一线构成图”,相信这是大家都对图的一个基本认知。在我们的业务开发中,往往也有大量场景需要对图进行可视化,如下图所示,不同的领域中,图均发挥着关键作用
如果你也需要对关系图进行可视化,不妨来试试 AntV 推出的图可视化工具 Graphin ~ 接下来让我们跟随这个在线教程 DEMO,来看看 Graphin 如何帮助我们完成一个图分析应用~
友情提示:本网站通过 dumi 生成,因此可以直接点击 demo 示例的右下角,展开源代码查看。
如果你是使用 React 的 Web 开发者,那么你大可将 Graphin 当作一个普通的 React 组件来使用。
本文采用 yarn 安装依赖,使用 npm 也可以。以下分别安装 Graphin 的核心组件
@antv/graphin和 分析组件@antv/graphin-components,以及 Graphin 官方提供的图标库@antv/graphin-icons
yarn add @antv/graphin@latest --saveyarn add @antv/graphin-components@latest --saveyarn add @antv/graphin-icons --save
完成一个图分析产品的第一步,就是将关系数据可视化出来。关系数据是非常典型的图结构,由节点 Node 和边 Edge 组成。Node 中只有 id 是必须参数,Edge 中只有 source 和 target 是必须参数,它分别代表边的开始节点和结束节点的 id
{
"nodes": [
{
"id": "node-0",
"x": 100,
"y": 100
},
{
"id": "node-1",
"x": 200,
"y": 200
},
{
"id": "node-2",
"x": 100,
"y": 300
}
],
"edges": [
{
"source": "node-0",
"target": "node-1"
}
]
}第一步我们完成了节点和边的渲染,但是它们的样式太过简单,如何将更多的信息呈现在节点和边上呢?这个时候可以利用视觉通道映射,除了常规的大小,形状,样式,Graphin 内置的节点和边 进行了规范。内置的节点 graphin-circle 由 5 部分图形组成,分别是 keyshape,label,icon,badges,halo,他们均放置在节点的style字段中,如下图node-0节点所示:
注意 ⚠️:这里为了演示效果,这里将全量配置文件展示出来,实际开发中,我们有
Utils.genDefaultNodeStyle工具函数,帮助我们根据主题样式快速生成配置文件。同时,每个节点也仅携带自己需要的部分样式(Graphin 在内部 与 每个节点的样式 做 deepMerge)
{
nodes: [
{
id: 'node-0',
x: 200,
y: 240,
style: {
// 节点的主要形状,即圆形容器,可以在这里设置节点的大小,border,填充色
keyshape: {
/** 容器的宽度 */
lineWidth: 3,
/** 节点的大小 */
size: 80,
/** 包围边颜色 */
stroke: parimaryColor,
/** 填充色 */
fill: Utils.hexToRgbaToHex(parimaryColor, 0.2),
/** 透明度 */
opacity: 1,
/** 鼠标样式 */
cursor: 'pointer',
},
// 是节点的标签,可以设置标签的值 和样式:放置方位,大小,字体颜色,偏移位置
label: {
/** label的名称 */
value: '节点-0',
/** 展示位置 'top' | 'bottom' | 'left' | 'right' | 'center'; */
position: 'top',
/** 文本填充色 */
fill: '#000',
/** 文本大小 */
fontSize: 16,
fontFamily: 'normal',
textAlign: 'center',
/** 文本在各自方向上的偏移量,主要为了便于调整文本位置 */
offset: 0,
},
// 是节点的中心 ICON 区域,icon 可以是图片,可以是文本,也可以是字体图标。
icon: {
/** 类型可以为字体图标,可以为网络图片,可以为纯文本 'font' | 'image' | 'text' */
type: 'font',
/** 根据类型,填写对应的值 */
value: icons.user,
/** 图标大小 */
size: 40,
/** 字体图标的填充色 */
fill: parimaryColor,
/** 字体Family */
fontFamily: 'graphin',
},
// 节点的徽标区域,是一个数组,可以分别在不同方位放置,其内容区域可以是文本,数字,也可以是图标。
badges: [
{
/** 放置的位置,ef:LT(left top)左上角 */
position: 'RT',
/** 类型可以为字体图标,可以为网络图片,可以为纯文本 */
type: 'text',
value: '10',
// type = image 时生效,表示图片的宽度和高度
size: [25, 25],
/** 徽标填充色 */
fill: Utils.hexToRgbaToHex(parimaryColor, 1),
/** 徽标描边色 */
stroke: '',
/** 徽标内文本的颜色 */
color: '#fff',
fontSize: 14,
fontFamily: '',
// badge 中文本距离四周的偏移量
padding: 0,
// badge 在 x 和 y 方向上的偏移量
offset: [0, 0],
},
{
/** 放置的位置,ef:LT(left top)左上角 */
position: 'LB',
/** 类型可以为字体图标,可以为网络图片,可以为纯文本 */
type: 'text',
value: 'Pin',
// type = image 时生效,表示图片的宽度和高度
size: [25, 25],
/** 徽标填充色 */
fill: Utils.hexToRgbaToHex(parimaryColor, 1),
/** 徽标描边色 */
stroke: '',
/** 徽标内文本的颜色 */
color: '#fff',
fontSize: 12,
fontFamily: '',
// badge 中文本距离四周的偏移量
padding: 0,
// badge 在 x 和 y 方向上的偏移量
offset: [0, 0],
},
],
// 节点的光环,在节点交互过程中(hover,selected,disabled,active)等,可以打开光环,默认是隐藏的,也可以自定义
halo: {
/** 光晕 */
fill: Utils.hexToRgbaToHex(parimaryColor, 0.2),
/** 透明度 */
opacity: 1,
/** 是否展示 */
visible: false,
/** 鼠标Hover上去样式 */
cursor: 'pointer',
},
// 节点的交互样式,默认 Graphin 已经内置了交互样式(即将 halo 图形显示出来),也可以自定义
status: {
hover: {
halo: {
visible: true,
},
},
selected: {
halo: {
visible: true,
},
keyshape: {
lineWidth: 10,
},
},
},
},
},
],
edges: [],
}
让我们继续我们的案例,现在 node-0 是一个用户,node-1 是一家企业,node-2 是另一家企业。通过上述 Graphin 内置的节点,重新整理,我们可以用节点的大小来代表企业的规模,节点的 icon 来展示不同的属性,颜色加以区分。
data.count映射为节点的大小data.type,映射为节点的 icon节点-0 是 节点-2 的背后实际控制人,可以映射为虚线边{
"nodes": [
{
"id": "node-0",
"x": 100,
"y": 100,
"data": {
"type": "user"
},
"style": {
"label": {
"value": "node-0"
},
"keyshape": {
"size": 30,
"stroke": "#FF6A00",
"fill": "#FF6A00",
"fillOpacity": 0.2,
"strokeOpacity": 1
},
"icon": {
"type": "font",
"value": "",
"size": 15,
"fill": "#FF6A00",
"fontFamily": "graphin"
}
}
},
{
"id": "node-1",
"x": 200,
"y": 200,
"data": {
"type": "company",
"count": 300
},
"style": {
"label": {
"value": "node-1"
},
"keyshape": {
"size": 60,
"stroke": "#46a7a6",
"fill": "#46a7a6",
"fillOpacity": 0.2,
"strokeOpacity": 1
},
"icon": {
"type": "font",
"value": "",
"size": 30,
"fill": "#46a7a6",
"fontFamily": "graphin"
}
}
},
{
"id": "node-2",
"x": 100,
"y": 300,
"data": {
"type": "company",
"count": 200
},
"style": {
"label": {
"value": "node-2"
},
"keyshape": {
"size": 40,
"stroke": "#46a7a6",
"fill": "#46a7a6",
"fillOpacity": 0.2,
"strokeOpacity": 1
},
"icon": {
"type": "font",
"value": "",
"size": 20,
"fill": "#46a7a6",
"fontFamily": "graphin"
}
}
}
],
"edges": [
{
"source": "node-0",
"target": "node-1"
},
{
"source": "node-0",
"target": "node-2",
"style": {
"keyshape": {
"lineDash": [
2,
2
],
"stroke": "#FF6A00"
},
"label": {
"value": "实际控制人",
"fill": "#FF6A00"
}
}
}
]
}在图可视化中,最富魅力的就是布局了。目前为止,我们接触到的第一个布局是preset,它的作用是将用户指定的 x,y 位置信息 渲染到画布上。想象下,上述的例子,真实场景下,数据是由服务端返回的。数据量未知,每个数据都不带布局信息,因此我们再也不能使用preset预设布局了。 那这个时候,合适的布局算法就显得尤为重要。 让我们用 Graphin 内置的工具函数Utils.mock 模拟一些数据,看看不同布局算法下,图可视化的展示效果
可以看出,同心圆算法布局下的节点,可以清晰看到中心节点,默认它是根据节点的度排序的。在一些团伙欺诈网络中,一眼就能看到中间的关键主犯。有向分层算法下的节点,根据边的流向依次分层排开,在一些有明显流向方向的网络中,比如资金流向网络,就可以清晰看出上下游关系。
但是在一些通用平台中,关系数据并不是一开始就做确定好用什么布局算法。这个时候,最方便的做法就是提供布局切换能力,让用户自主选择。当然基于 AI 的能力,我们根据数据打标,模型训练,可以预测出最佳布局,这部分能力正在建设中
数据也渲染了,也能正确布局了,这个时候,产品经理来找你,提出了一下诉求
最后,她再夸奖你一句,你这么棒,一定可以把这个图体验做好的~ 此刻的你,压抑住心中的冲动,真的是产品一张嘴,开发熬肝夜。
确实,好的交互,可以增强用户的分析体验,从这个角度出发,产品经理是对的。Graphin 也是从业务线打磨产出的技术产品,因此我们将交互解构出来,封装成组件,让用户按需引入。
import { Behaviors } from '@antv/graphin';const {TreeCollapse, // 树图的展开收起DragCanvas, // 拖拽画布ZoomCanvas, //缩放画布ClickSelect, // 点击选中节点BrushSelect, //圈选操作DragNode, // 拖拽节点ResizeCanvas, // 自动调整画布宽高LassoSelect, // 拉索操作DragCombo, // 拖拽ComboActivateRelations, // 关联高亮Hoverable, // Hover操作} = Behaviors;
随着业务的深入,用户的分析诉求越来越多,简单的画布和图元素操作已经不能满足用户的分析诉求了:
Graphin 根据《AntV 图可视分析解决方案》白皮书里的指导,总结整理了 26 款分析组件。
如果你耐着性子看到这里,那么我们可以一起聊聊业务。图可视分析在不同的业务领域应用,其实有一些点是共通的。比如,在知识图谱和金融风控中,分别有一个核心产品功能,前者是 知识推理,后者是风险探查,因为在这些场景下,主要利用的是下钻的数据分析方式,图数据的下钻,特殊点就在于这不仅是一个数据的动态过程,也是一个布局的动态过程。动态图的探索问题,是 Graphin 团队解决的第一个业务痛点问题,如今我们将这一问题抽象为数据驱动 + 渐进布局两个技术方案的组合,希望能对大家的业务产生一些帮助。
除了动态图布局,大图探索也是业务中常见的需求。采用 louvain 算法聚合 ,利用 Combo 能力或者节点聚合展示方式,再结合 MiniMap 小地图导航,鱼眼放大镜,可以初步满足大图的探索需求。这块DEMO 可以参考
以上便是我们的快速开始的全部内容:通过零碎的小 DEMO,我们基本上已经看到了 Graphin 的一个基本能力面貌:
如果你还感兴趣,可以继续阅读深入探索部分,将为大家介绍 Graphin 的扩展机制 和 组件的自定义机制,以及我们接下来重点要做的 GraphinStudio。