g6/packages/site/docs/api/Algorithm.zh.md
2023-02-02 10:31:36 +08:00

24 KiB
Raw Blame History

title order
图算法 Algorithm 15

图算法提供了一种最有效的分析关联数据的方法,它们描述了如何处理图以发现一些定性或者定量的结论。图算法基于图论,利用节点之间的关系来推断复杂系统的结构和变化。我们可以使用这些算法来发现隐藏的信息,验证业务假设,并对行为进行预测。

如果你对数据结构及算法感兴趣,可以通过 javascript-algorithms 来进一步学习。

G6 从 V3.5 版本开始加入了图算法,在以后版本更新中,我们会不断丰富内置的算法。

GADDI 图模式匹配

「v4.2.2」新特性

GADDI 图模式匹配算法是一种支持结构和语义的图模式匹配算法,给定一个模式,可通过在算法在原数据上查找结果和语义相同、相似的结构。DEMO

img

参数

名称 类型 是否必选 描述
graphData GraphData true 原图数据
pattern GraphData true 需要查找的模式图数据
k number false 匹配算法的参数,设置为 undefined 则自动设置
length number false 匹配算法的参数,设置为 undefined 则自动设置
nodeLabelProp number false 节点聚类信息的属性名,默认为 'cluster'
edgeLabelProp number false 边聚类信息的属性名,默认为 'cluster'

用法

import G6, { Algorithm } from '@antv/g6'
const graph = new G6.Graph({
  container: 'container',
  width: 500,
  height: 500
})

const graphData = {
  nodes: [
    { id: 'A', cluster: 'nc1' },
    { id: 'B', cluster: 'nc1' },
    { id: 'C', cluster: 'nc2' },
    { id: 'D', cluster: 'nc1' },
    { id: 'E', cluster: 'nc3' },
  ],
  edges: [
    { source: 'A', target: 'B', cluster: 'ec1' },
    { source: 'B', target: 'C', cluster: 'ec2' },
    { source: 'A', target: 'D', cluster: 'ec1' },
    { source: 'A', target: 'E', cluster: 'ec2' },
  ]
}

graph.data(data)
graph.render()

const { GADDI } = Algorithm;
const patternData = {
  nodes: [
    { id: 'pn1', cluster: 'nc1' },
    { id: 'pn2', cluster: 'nc1' },
    { id: 'pn3', cluster: 'nc3' },
  ],
  edges: [
    { source: 'pn1', target: 'pn2', cluster: 'ec1' },
    { source: 'pn1', target: 'pn3', cluster: 'ec2' },
  ]
}
const resultMatches = GADDI(graphData, patternData, true, undefined, undefined, 'cluster', 'cluster');

console.log(resultMatches);
  // output:
  // [{
  //   nodes: [
  //     { id: 'A', cluster: 'nc1' },
  //     { id: 'B', cluster: 'nc1' },
  //     { id: 'E', cluster: 'nc3' },],
  //   edges: [
  //     { source: 'A', target: 'B', cluster: 'ec1' },
  //     { source: 'A', target: 'E', cluster: 'ec2' }
  //   ]
  // }]

depthFirstSearch

深度优先搜索Depth First Search简称 DFS算法是一种用于遍历或搜索树或图的算法。沿着树的深度遍历树的节点尽可能深的搜索树的分支。当节点 v 的所在边都己被探寻过,搜索将回溯到发现节点 v 的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。

img

图片来源

参数

名称 类型 是否必选 描述
graphData GraphData true 图数据,满足 G6 数据格式。注意4.1 以前的版本该参数请传入图实例
startNodeId string true 开始访问的节点的 ID
callbacks IAlgorithmCallbacks false 遍历的回调函数

用法

import G6, { Algorithm } from '@antv/g6'
const graph = new G6.Graph({
  container: 'container',
  width: 500,
  height: 500
})

const data = {
  nodes: [
    {
      id: 'A'
    },
    {
      id: 'B'
    },
    {
      id: 'C'
    },
    {
      id: 'D'
    },
    {
      id: 'E'
    },
    {
      id: 'F'
    },
    {
      id: 'G'
    },
  ],
  edges: [
    {
      source: 'A',
      target: 'B'
    },
    {
      source: 'B',
      target: 'C'
    },
    {
      source: 'C',
      target: 'G'
    },
    {
      source: 'A',
      target: 'D'
    },
    {
      source: 'A',
      target: 'E'
    },
    {
      source: 'E',
      target: 'F'
    },
    {
      source: 'F',
      target: 'D'
    },
    {
      source: 'D',
      target: 'G'
    },
  ]
}

graph.data(data)
graph.render()

const { depthFirstSearch } = Algorithm
depthFirstSearch(data, 'A', {
  enter: ({ current, previous }) => {
    // 开始遍历点的回调
  },
  leave: ({ current, previous }) => {
    // 遍历完节点的回调
  },
})

breadthFirstSearch

广度优先搜索算法Breadth First Search简称 BFS又译作宽度优先搜索或横向优先搜索是一种图搜索算法。简单的说BFS 是从根节点开始,沿着树的宽度遍历树的节点。如果所有节点均被访问,则算法中止。广度优先搜索的实现一般采用 open-closed 表。

img

图片来源

参数

名称 类型 是否必选 描述
graphData GraphData true 图数据,满足 G6 数据格式。注意4.1 以前的版本该参数请传入图实例
startNodeId string true 开始访问的节点的 ID
originalCallbacks IAlgorithmCallbacks false 遍历的回调函数

用法

import G6, { Algorithm } from '@antv/g6'
const graph = new G6.Graph({
  container: 'container',
  width: 500,
  height: 500
})

const data = {
  nodes: [
    {
      id: 'A'
    },
    {
      id: 'B'
    },
    {
      id: 'C'
    },
    {
      id: 'D'
    },
    {
      id: 'E'
    },
    {
      id: 'F'
    },
    {
      id: 'G'
    },
  ],
  edges: [
    {
      source: 'A',
      target: 'B'
    },
    {
      source: 'B',
      target: 'C'
    },
    {
      source: 'C',
      target: 'G'
    },
    {
      source: 'A',
      target: 'D'
    },
    {
      source: 'A',
      target: 'E'
    },
    {
      source: 'E',
      target: 'F'
    },
    {
      source: 'F',
      target: 'D'
    },
    {
      source: 'D',
      target: 'G'
    },
  ]
}

graph.data(data)
graph.render()

const { breadthFirstSearch } = Algorithm
breadthFirstSearch(data, 'A', {
  enter: ({ current, previous }) => {
    // 开始遍历点的回调
  },
  leave: ({ current, previous }) => {
    // 遍历完节点的回调
  },
})

labelPropagation

G6 4.0 起支持 标签传播算法,自动为数据聚类。优势:速度较 LOUVAIN 快。

参考资料:https://en.wikipedia.org/wiki/Label_propagation_algorithm

参数

名称 类型 是否必选 描述
data GraphData true 图数据
directed Boolean false 是否是有向图,默认为 false
weightPropertyName String false 边权重的属名称,默认为 `'weight',若数据中没有权重,则默认每条边权重为 1
maxIteration Number false 最大迭代次数,默认为 1000

返回值

返回聚合数据,并为输入的 data 中的每个节点数据加上 clusterId 字段。聚合数据 ClusterData 类型如下:

interface ClusterData {
  clusters: {
    // 聚类数组
    id: string; // 聚类 Id
    nodes: NodeConfig[]; // 该聚类包含的节点
  }[];
  clusterEdges: {
    // 聚类与聚类之间的边数组
    source: string; // 起点聚类 id
    target: string; // 终点聚类 id
    count: number; // 该边所包含的真实边个数
  }[];
}

返回值示例:

{
  clusters: [
    {id: 'cluster1', nodes: [ {id: 'node1', clusterId: 'cluster1'}, {id: 'node2', clusterId: 'cluster1'} ]},
    {id: 'cluster2', nodes: [ {id: 'node3', clusterId: 'cluster2'} ]},
  ],
  clusterEdges: [
    {source: 'cluster1', target: 'cluster2', count: 10},
    {source: 'cluster1', target: 'cluster1', count: 3},
  ]
}

用法

import G6, { Algorithm } from '@antv/g6';
const graph = new G6.Graph({
  container: 'container',
  width: 500,
  height: 500,
});

const data = {
  nodes: [
    { id: 'A' },
    { id: 'B' },
    { id: 'C' },
    { id: 'D' },
    { id: 'E' },
    { id: 'F' },
    { id: 'G' },
  ],
  edges: [
    { source: 'A', target: 'B' },
    { source: 'B', target: 'C' },
    { source: 'A', target: 'C' },
    { source: 'D', arget: 'A' },
    { source: 'D', target: 'E' },
    { source: 'E', target: 'F' },
  ],
};

graph.data(data);
graph.render();

const { labelPropagation } = Algorithm;

// result 中包含 clusters 与 clusterEdges 数组。data 中的每个节点数据将带有 clusterId 字段
let result = labelPropagation(data);

louvain

G6 4.0 起支持 LOUVAIN 自动聚类算法。优势:根据节点间的紧密程度计算,较之于 Label Propagation 更准确。

参考资料:https://en.wikipedia.org/wiki/Louvain_method

参数

名称 类型 是否必选 描述
data GraphData true 图数据
directed Boolean false 是否是有向图,默认为 false
weightPropertyName String false 边权重的属名称,默认为 `'weight',若数据中没有权重,则默认每条边权重为 1
threshold Number false 停止迭代的阈值,默认为 0.0001

返回值

返回聚合数据,并为输入的 data 中的每个节点数据加上 clusterId 字段。聚合数据 ClusterData 类型如下:

interface ClusterData {
  clusters: {
    // 聚类数组
    id: string; // 聚类 Id
    nodes: NodeConfig[]; // 该聚类包含的节点
    sumTot?: number; // 该聚类内部边总数
  }[];
  clusterEdges: {
    // 聚类与聚类之间的边数组
    source: string; // 起点聚类 id
    target: string; // 终点聚类 id
    count: number; // 该边所包含的真实边个数
  }[];
}

返回值示例:

{
  clusters: [
    {id: 'cluster1', sumTot: 8, nodes: [ {id: 'node1', clusterId: 'cluster1'}, {id: 'node2', clusterId: 'cluster1'} ]},
    {id: 'cluster2', sumTot: 15, nodes: [ {id: 'node3', clusterId: 'cluster2'} ]},
  ],
  clusterEdges: [
    {source: 'cluster1', target: 'cluster2', count: 10},
    {source: 'cluster1', target: 'cluster1', count: 3},
  ]
}

用法

import G6, { Algorithm } from '@antv/g6';
const graph = new G6.Graph({
  container: 'container',
  width: 500,
  height: 500,
});

const data = {
  nodes: [
    { id: 'A' },
    { id: 'B' },
    { id: 'C' },
    { id: 'D' },
    { id: 'E' },
    { id: 'F' },
    { id: 'G' },
  ],
  edges: [
    { source: 'A', target: 'B' },
    { source: 'B', target: 'C' },
    { source: 'A', target: 'C' },
    { source: 'D', arget: 'A' },
    { source: 'D', target: 'E' },
    { source: 'E', target: 'F' },
  ],
};

graph.data(data);
graph.render();

const { louvain } = Algorithm;

// result 中包含 clusters 与 clusterEdges 数组。data 中的每个节点数据将带有 clusterId 字段
let result = louvain(data);

detectDirectedCycle

在给定的有向图中,检查是否包括圈。如果给定的图中至少包括一个圈,则返回包括的第一个圈,否则返回 null。

参考资料:

参数

名称 类型 是否必选 描述
graphData GraphData true 图数据,满足 G6 数据格式。注意4.1 以前的版本该参数请传入图实例

返回值

返回检测到的圈,否则返回 null。

用法

import G6, { Algorithm } from '@antv/g6';
const graph = new G6.Graph({
  container: 'container',
  width: 500,
  height: 500,
});

const data = {
  nodes: [
    { id: 'A' },
    { id: 'B' },
    { id: 'C' },
    { id: 'D' },
    { id: 'E' },
    { id: 'F' },
    { id: 'G' },
  ],
  edges: [
    { source: 'A', target: 'B' },
    { source: 'B', target: 'C' },
    { source: 'A', target: 'C' },
    { source: 'D', arget: 'A' },
    { source: 'D', target: 'E' },
    { source: 'E', target: 'F' },
  ],
};

graph.data(data);
graph.render();

const { detectDirectedCycle } = Algorithm;

// 此时图中没有环result 为 null
let result = detectDirectedCycle(data);

// 当数据中加入 F->D 这条边后,图中有一个环
data.edges.push({
  source: 'F',
  target: 'D',
});

graph.changeData(data);

// 返回数据
/**
* {
    D: Node,
    F: Node,
    E: Node,
  }
*/
result = detectDirectedCycle(data);

detectAllCycles(graphData, directed, nodeIds, include)

提供支持寻找图中所有环路的函数。对有向图来说返回所有简单环,简单环是指路径上的节点都只出现一次的闭合路径;对于无向图来说,返回一组完备的基本环

参考资料:

参数

名称 类型 是否必选 描述
graphData GraphData true 图数据,满足 G6 数据格式。注意4.1 以前的版本该参数请传入图实例
directed boolean false 是否考虑边的方向性,若不指定,则取图的 directed 属性
nodeIds string[] false 需包含或排除的节点 ID 的数组,若不指定,则返回图中所有的圈
include boolean false 若为 true, 则返回包含参数 nodeIds 中指定的节点的圈,否则,返回所有不包含 nodeIds 中指定的节点的圈。默认为 true

返回值

  • 返回值类型:[{[key: string]: Node}]
  • 返回一个数组表示检测到的所有符合条件的圈,每个环用一个 Object 表示,其中 key 为节点 idvalue 为该节点在环中指向的下一个节点。

用法

const { detectAllCycles } = Algorithm;

// 检测有向图中的所有简单环
const allCycles = detectAllCycles(data, true);

// 检测有向图中包含节点 B 的所有简单环
const allCycleIncludeB = detectAllCycles(data, true, ['B']);

// 检测无向图中所有不包含节点 B 的所有基本环
const allCycleExcludeB = detectAllCycles(data, false, ['B'], false);

findShortestPath(graphData, start, end, directed, weightPropertyName)

查找两点之间的最短路径。

参数

名称 类型 是否必选 描述
graphData GraphData true 图数据,满足 G6 数据格式。注意4.1 以前的版本该参数请传入图实例
start INode / string true G6 Node 实例或 ID路径起始点
end INode / string true G6 Node 实例或 ID路径终点
directed boolean false 是否考虑边的方向性,若不指定,则取图的 directed 属性
weightPropertyName string false 边的权重属性字段名,若不指定,则认为所有边权重相同

返回值

  • 返回值类型Object
 {
  length: number, // 最短路径长度
  path: string[],
  allPath: string[][] // start 到 end 的所有的最短路径
}
  • 返回的对象中length 属性代表最短路径的长度path 属性为构成一条最短路径的节点数组。

用法

const data = {
  nodes: [
    {
      id: 'A',
      label: 'A',
    },
    {
      id: 'B',
      label: 'B',
    },
    {
      id: 'C',
      label: 'C',
    },
    {
      id: 'D',
      label: 'D',
    },
    {
      id: 'E',
      label: 'E',
    },
    {
      id: 'F',
      label: 'F',
    },
    {
      id: 'G',
      label: 'G',
    },
    {
      id: 'H',
      label: 'H',
    },
  ],
  edges: [
    {
      source: 'A',
      target: 'B',
    },
    {
      source: 'B',
      target: 'C',
    },
    {
      source: 'C',
      target: 'G',
    },
    {
      source: 'A',
      target: 'D',
    },
    {
      source: 'A',
      target: 'E',
    },
    {
      source: 'E',
      target: 'F',
    },
    {
      source: 'F',
      target: 'D',
    },
    {
      source: 'D',
      target: 'E',
    },
  ],
};

const graph = new G6.Graph({
  container: 'container',
  width: 500,
  height: 500,
});
graph.data(data);
graph.render();

const { findShortestPath } = Algorithm;
// 不考虑边的方向性,查找节点 A 和 节点 C 之间的最短路径
const { length, path, allPath } = findShortestPath(data, 'A', 'C');
console.log(length, path);
// 期望输出2, ['A', 'B', 'C']

findAllPath(graphData, start, end, directed)

查找两点之间的所有路径。

参数

名称 类型 是否必选 描述
graphData GraphData true 图数据,满足 G6 数据格式。注意4.1 以前的版本该参数请传入图实例
start INode / string true G6 Node 实例或 ID路径起始点
end INode / string true G6 Node 实例或 ID路径终点
directed boolean false 是否考虑边的方向性,若不指定,则取图的 directed 属性

返回值

  • 返回值类型string[][]
  • 返回包含两个节点之间所有路径的数组,每条路径由节点 ID 数组表示

用法

const data = {
  nodes: [
    {
      id: 'A',
      label: 'A',
    },
    {
      id: 'B',
      label: 'B',
    },
    {
      id: 'C',
      label: 'C',
    },
    {
      id: 'D',
      label: 'D',
    },
    {
      id: 'E',
      label: 'E',
    },
    {
      id: 'F',
      label: 'F',
    },
    {
      id: 'G',
      label: 'G',
    },
    {
      id: 'H',
      label: 'H',
    },
  ],
  edges: [
    {
      source: 'A',
      target: 'B',
    },
    {
      source: 'B',
      target: 'C',
    },
    {
      source: 'C',
      target: 'G',
    },
    {
      source: 'A',
      target: 'D',
    },
    {
      source: 'A',
      target: 'E',
    },
    {
      source: 'E',
      target: 'F',
    },
    {
      source: 'F',
      target: 'D',
    },
    {
      source: 'D',
      target: 'E',
    },
  ],
};

const graph = new G6.Graph({
  container: 'container',
  width: 500,
  height: 500,
});
graph.data(data);
graph.render();

const { findAllPath } = Algorithm;
const allPath = findAllPath(data, 'A', 'E');
console.log(allPath);
// 期望输出值:[['A', 'D', 'F', 'E'], ['A', 'D', 'E'], ['A', 'E']]

getConnectedComponents

返回图中的连通分量。若为无向图,连通分量指图中的极大连通子图,连通子图中任何两个顶点之间通过路径相互连接;若为有向图,则返回所有强连通分量,强连通分量指有向图中的极大强连通子图,强连通子图中任何两个节点之间都存在一条可达到彼此的有向路径。

参考资料:

名称 类型 是否必选 描述
graphData GraphData true 图数据,满足 G6 数据格式。注意4.1 以前的版本该参数请传入图实例
directed boolean false 是否考虑边的方向性,若不指定,则取图的 directed 属性

返回值

  • 返回值类型INode[][]
  • 返回一个数组表示检测到的所有连通分量,每个连通分量为节点数组。

用法

const data = {
  nodes: [
    {
      id: 'A',
    },
    {
      id: 'B',
    },
    {
      id: 'C',
    },
    {
      id: 'D',
    },
    {
      id: 'E',
    },
    {
      id: 'F',
    },
    {
      id: 'G',
    },
    {
      id: 'H',
    },
  ],
  edges: [
    {
      source: 'A',
      target: 'B',
    },
    {
      source: 'B',
      target: 'C',
    },
    {
      source: 'A',
      target: 'C',
    },
    {
      source: 'D',
      target: 'A',
    },
    {
      source: 'D',
      target: 'E',
    },
    {
      source: 'E',
      target: 'F',
    },
    {
      source: 'F',
      target: 'D',
    },
    {
      source: 'G',
      target: 'H',
    },
    {
      source: 'H',
      target: 'G',
    },
  ],
};
const graph = new G6.Graph({
  container: 'container',
  width: 500,
  height: 400,
});
graph.data(data);
graph.render();

// 图中的连通分量
const components = getConnectedComponents(data, false);
components.forEach((component) => {
  console.log(component.map((node) => node.get('id')));
});
// 期望输出结果:['A', 'B', 'C', 'D', 'E', 'F'], ['G', 'H']

// 有向图中的强连通分量
const components2 = getConnectedComponents(data, true);
components2.forEach((component) => {
  console.log(component.map((node) => node.get('id')));
});
// 期望输出结果:['A'], ['B'], ['C'], ['D', 'E', 'F'], ['G', 'H']

pageRank

PageRank 可以用来度量网络中节点的重要性最初用于标识网页的重要性对网页进行排序。PageRank 算法假设当前节点的重要性是由指向它的其他节点的重要性决定的,一个节点接收到的来自其他节点的入链 (inbound) 越多,则越重要,每个入链的权重由提供入链的节点的重要性决定。 因此 PageRank 除了考虑到入链数量还参考了入链“质量”。PageRank 通过迭代递归计算来更新每个节点的得分,直到得分稳定为止。

参考资料:

名称 类型 是否必选 描述
graphData GraphData true 图数据,满足 G6 数据格式。注意4.1 以前的版本该参数请传入图实例
epsilon number false 判断 PageRank 得分是否稳定的精度值,默认 0.000001
linkProb number false 阻尼系数dumping factor指任意时刻用户访问到某节点后继续访问该节点指向的节点的概率默认 0.85。

返回值

  • 返回值类型Object, {[key: string]: number}
  • 返回一个对象,表示节点 ID 对应的该节点的 PageRank 值。