Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add a data transform for mapping node size #6347

Merged
merged 10 commits into from
Sep 19, 2024
Merged

Conversation

yvonneyx
Copy link
Contributor

  • 新增基于节点重要性动态调整节点大小的能力
  • 内置五种方式来衡量节点的重要性:度中心性、中介中心性、接近中心性、特征向量中心性、pagerank 中心性
  • 拿到节点重要性后通过用户自定义节点大小与插值函数来进行映射,内置了线性、对数、幂律和平方根
image
interface MapNodeSizeOptions extends BaseTransformOptions {
  /**
   * <zh/> 节点中心性的度量方法
   * - `'degree'`:度中心性,通过节点的度数(连接的边的数量)来衡量其重要性。度中心性高的节点通常具有较多的直接连接,在网络中可能扮演着重要的角色
   * - `'betweenness'`:介数中心性,通过节点在所有最短路径中出现的次数来衡量其重要性。介数中心性高的节点通常在网络中起到桥梁作用,控制着信息的流动
   * - `'closeness'`:接近中心性,通过节点到其他所有节点的最短路径长度总和的倒数来衡量其重要性。接近中心性高的节点通常能够更快地到达网络中的其他节点
   * - `'eigenvector'`:特征向量中心性,通过节点与其他中心节点的连接程度来衡量其重要性。特征向量中心性高的节点通常连接着其他重要节点
   * - `'pagerank'`:PageRank 中心性,通过节点被其他节点引用的次数来衡量其重要性,常用于有向图。PageRank 中心性高的节点通常在网络中具有较高的影响力,类似于网页排名算法
   * - 自定义中心性计算方法:`(graphData: GraphData) => CentralityResult`,其中 `graphData` 为图数据,`CentralityResult` 为节点 ID 到中心性值的映射
   *
   * <en/> The method of measuring the node centrality
   * - `'degree'`: Degree centrality, measures centrality by the degree (number of connected edges) of a node. Nodes with high degree centrality usually have more direct connections and may play important roles in the network
   * - `'betweenness'`: Betweenness centrality, measures centrality by the number of times a node appears in all shortest paths. Nodes with high betweenness centrality usually act as bridges in the network, controlling the flow of information
   * - `'closeness'`: Closeness centrality, measures centrality by the reciprocal of the average shortest path length from a node to all other nodes. Nodes with high closeness centrality usually can reach other nodes in the network more quickly
   * - `'eigenvector'`: Eigenvector centrality, measures centrality by the degree of connection between a node and other central nodes. Nodes with high eigenvector centrality usually connect to other important nodes
   * - `'pagerank'`: PageRank centrality, measures centrality by the number of times a node is referenced by other nodes, commonly used in directed graphs. Nodes with high PageRank centrality usually have high influence in the network, similar to the page ranking algorithm
   * - Custom centrality calculation method: `(graphData: GraphData) => Map<ID, number>`, where `graphData` is the graph data, and `Map<ID, number>` is the mapping from node ID to centrality value
   * @defaultValue `{ type: 'eigenvector' }`
   */
  centrality?:
    | { type: 'degree'; direction?: EdgeDirection }
    | { type: 'betweenness'; directed?: boolean; weightPropertyName?: string }
    | { type: 'closeness'; directed?: boolean; weightPropertyName?: string }
    | { type: 'eigenvector'; directed?: boolean }
    | { type: 'pagerank'; epsilon?: number; linkProb?: number }
    | ((graphData: GraphData) => Map<ID, number>);
  /**
   * <zh/> 节点最大尺寸
   *
   * <en/> The maximum size of the node
   * @defaultValue `80`
   */
  maxSize?: Size;
  /**
   * <zh/> 节点最小尺寸
   *
   * <en/> The minimum size of the node
   * @defaultValue `20`
   */
  minSize?: Size;
  /**
   * <zh/> 插值函数,用于将节点中心性映射到节点大小
   * - `'linear'`:线性插值函数,将一个值从一个范围线性映射到另一个范围,常用于处理中心性值的差异较小的情况
   * - `'log'`:对数插值函数,将一个值从一个范围对数映射到另一个范围,常用于处理中心性值的差异较大的情况
   * - `'pow'`:幂律插值函数,将一个值从一个范围幂律映射到另一个范围,常用于处理中心性值的差异较大的情况
   * - `'sqrt'`:平方根插值函数,将一个值从一个范围平方根映射到另一个范围,常用于处理中心性值的差异较大的情况
   * - 自定义插值函数:`(value: number, domain: [number, number], range: [number, number]) => number`,其中 `value` 为需要映射的值,`domain` 为输入值的范围,`range` 为输出值的范围
   *
   * <en/> Scale type
   * - `'linear'`: Linear scale, maps a value from one range to another range linearly, commonly used for cases where the difference in centrality values is small
   * - `'log'`: Logarithmic scale, maps a value from one range to another range logarithmically, commonly used for cases where the difference in centrality values is large
   * - `'pow'`: Power-law scale, maps a value from one range to another range using power law, commonly used for cases where the difference in centrality values is large
   * - `'sqrt'`: Square root scale, maps a value from one range to another range using square root, commonly used for cases where the difference in centrality values is large
   * - Custom scale: `(value: number, domain: [number, number], range: [number, number]) => number`,where `value` is the value to be mapped, `domain` is the input range, and `range` is the output range
   * @defaultValue `'log'`
   */
  scale?:
    | 'linear'
    | 'log'
    | 'pow'
    | 'sqrt'
    | ((value: number, domain: [number, number], range: [number, number]) => number);
}

@resetsix
Copy link

新增基于节点重要性动态调整节点大小的能力

也就是说,下个版本可以根据 label 内容的长度自动计算 node 的宽度了吗

@yvonneyx
Copy link
Contributor Author

新增基于节点重要性动态调整节点大小的能力

也就是说,下个版本可以根据 label 内容的长度自动计算 node 的宽度了吗

“根据 label 内容的长度自动计算 node 的宽度” 能力 G6 目前不考虑内置,实现起来也比较简单,可以参考:

const measureTextWidth = memoize(
  (text: string, font: any = {}): TextMetrics => {
    const { fontSize, fontFamily = 'sans-serif', fontWeight, fontStyle, fontVariant } = font;
    const ctx = getCanvasContext();
    // @see https://developer.mozilla.org/zh-CN/docs/Web/CSS/font
    ctx.font = [fontStyle, fontWeight, fontVariant, `${fontSize}px`, fontFamily].join(' ');
    return ctx.measureText(isString(text) ? text : '').width;
  },
  (text: string, font = {}) => [text, ...values(font)].join(''),
);

const graph = new G6.Graph({
    node: {
          style: { size: d => [measureTextWidth(d.label, {...}) , xxx] },
    }
})

@resetsix
Copy link

新增基于节点重要性动态调整节点大小的能力

也就是说,下个版本可以根据 label 内容的长度自动计算 node 的宽度了吗

“根据 label 内容的长度自动计算 node 的宽度” 能力 G6 目前不考虑内置,实现起来也比较简单,可以参考:

const measureTextWidth = memoize(
  (text: string, font: any = {}): TextMetrics => {
    const { fontSize, fontFamily = 'sans-serif', fontWeight, fontStyle, fontVariant } = font;
    const ctx = getCanvasContext();
    // @see https://developer.mozilla.org/zh-CN/docs/Web/CSS/font
    ctx.font = [fontStyle, fontWeight, fontVariant, `${fontSize}px`, fontFamily].join(' ');
    return ctx.measureText(isString(text) ? text : '').width;
  },
  (text: string, font = {}) => [text, ...values(font)].join(''),
);

const graph = new G6.Graph({
    node: {
          style: { size: d => [measureTextWidth(d.label, {...}) , xxx] },
    }
})

明白了,感谢。

@@ -87,11 +88,11 @@
"limit-size": [
{
"gzip": true,
"limit": "300 Kb",
"limit": "310 Kb",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个得关注下具体是哪部分增长了

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

多导出了 MapNodeSize 和 MapNodeSizeOptions

packages/g6/src/utils/scale.ts Outdated Show resolved Hide resolved
packages/g6/src/utils/transform.ts Show resolved Hide resolved
packages/g6/src/transforms/map-node-size.ts Outdated Show resolved Hide resolved
* <zh/> 节点最小尺寸
*
* <en/> The minimum size of the node
* @defaultValue `20`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

默认值好像不需要 ` 符号

* @param tolerance - <zh/> 收敛容差 | <en/> The convergence tolerance
* @returns <zh/> 主特征向量 | <en/> The principal eigenvector
*/
const powerIteration = (matrix: number[][], numNodes: number, maxIterations = 100, tolerance = 1e-6): number[] => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果引用了相关算法最好贴一下链接,方便后续维护

@yvonneyx yvonneyx merged commit dfa22d0 into v5 Sep 19, 2024
3 of 5 checks passed
@yvonneyx yvonneyx deleted the transform/map-node-size branch September 19, 2024 03:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants