“两点一线构成图”,相信这是大家都对图的一个基本认知。在我们的业务开发中,往往也有大量场景需要对图进行可视化,如下图所示,不同的领域中,图均发挥着关键作用
如果你也需要对关系图进行可视化,不妨来试试 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。