From 494779ce0ba0264946fb49ea4a6ade9249db9bb4 Mon Sep 17 00:00:00 2001 From: Joel Alan <31396322+lxfu1@users.noreply.github.com> Date: Fri, 15 Mar 2024 23:22:26 +0800 Subject: [PATCH] test: layout dendrogram (#5539) * test: layout dendrogram * fix: resolve conversation --- packages/g6/__tests__/demo/case/index.ts | 2 + .../demo/case/layout-dendrogram-basic.ts | 34 + .../demo/case/layout-dendrogram-tb.ts | 41 + .../snapshots/layouts/dendrogram/basic.svg | 1899 ++++++++++++++++ .../snapshots/layouts/dendrogram/tb.svg | 1951 +++++++++++++++++ .../__tests__/unit/layouts/dendrogram.spec.ts | 16 + .../net/dendrogram/demo/basicDendrogram.js | 158 -- .../net/dendrogram/demo/basicDendrogram.ts | 40 + .../demo/graphDataWithDendrogram.js | 177 -- .../examples/net/dendrogram/demo/meta.json | 10 +- .../net/dendrogram/demo/tbDendrogram.ts | 46 + 11 files changed, 4034 insertions(+), 340 deletions(-) create mode 100644 packages/g6/__tests__/demo/case/layout-dendrogram-basic.ts create mode 100644 packages/g6/__tests__/demo/case/layout-dendrogram-tb.ts create mode 100644 packages/g6/__tests__/snapshots/layouts/dendrogram/basic.svg create mode 100644 packages/g6/__tests__/snapshots/layouts/dendrogram/tb.svg create mode 100644 packages/g6/__tests__/unit/layouts/dendrogram.spec.ts delete mode 100644 packages/site/examples/net/dendrogram/demo/basicDendrogram.js create mode 100644 packages/site/examples/net/dendrogram/demo/basicDendrogram.ts delete mode 100644 packages/site/examples/net/dendrogram/demo/graphDataWithDendrogram.js create mode 100644 packages/site/examples/net/dendrogram/demo/tbDendrogram.ts diff --git a/packages/g6/__tests__/demo/case/index.ts b/packages/g6/__tests__/demo/case/index.ts index 8555bfd2dca..b36f67222a6 100644 --- a/packages/g6/__tests__/demo/case/index.ts +++ b/packages/g6/__tests__/demo/case/index.ts @@ -19,6 +19,8 @@ export * from './layout-combo-combined'; export * from './layout-concentric'; export * from './layout-dagre-flow'; export * from './layout-dagre-flow-combo'; +export * from './layout-dendrogram-basic'; +export * from './layout-dendrogram-tb'; export * from './layout-force'; export * from './layout-fruchterman-basic'; export * from './layout-fruchterman-cluster'; diff --git a/packages/g6/__tests__/demo/case/layout-dendrogram-basic.ts b/packages/g6/__tests__/demo/case/layout-dendrogram-basic.ts new file mode 100644 index 00000000000..b19a14df4fe --- /dev/null +++ b/packages/g6/__tests__/demo/case/layout-dendrogram-basic.ts @@ -0,0 +1,34 @@ +import { Graph, Utils } from '@/src'; +import data from '@@/dataset/algorithm-category.json'; +import type { STDTestCase } from '../types'; + +export const layoutDendrogramBasic: STDTestCase = async (context) => { + const graph = new Graph({ + ...context, + autoFit: 'view', + data: Utils.treeToGraphData(data), + node: { + style: { + labelText: (d) => d.id, + labelPlacement: (model) => (model.style!.children?.length ? 'left' : 'right'), + ports: [{ placement: 'right' }, { placement: 'left' }], + }, + }, + edge: { + style: { + type: 'cubic-horizontal', + }, + }, + layout: { + type: 'dendrogram', + direction: 'LR', + nodeSep: 36, + rankSep: 250, + }, + behaviors: ['drag-canvas', 'zoom-canvas', 'drag-node', 'collapse-expand-tree'], + }); + + await graph.render(); + + return graph; +}; diff --git a/packages/g6/__tests__/demo/case/layout-dendrogram-tb.ts b/packages/g6/__tests__/demo/case/layout-dendrogram-tb.ts new file mode 100644 index 00000000000..61dcd121972 --- /dev/null +++ b/packages/g6/__tests__/demo/case/layout-dendrogram-tb.ts @@ -0,0 +1,41 @@ +import { Graph, Utils } from '@/src'; +import data from '@@/dataset/algorithm-category.json'; +import type { STDTestCase } from '../types'; + +export const layoutDendrogramTb: STDTestCase = async (context) => { + const graph = new Graph({ + ...context, + autoFit: 'view', + data: Utils.treeToGraphData(data), + node: { + style: (model) => { + const hasChildren = !!model.style!.children?.length; + return { + labelMaxWidth: 200, + labelPlacement: hasChildren ? 'right' : 'bottom', + labelText: model.id, + labelTextAlign: 'start', + labelTextBaseline: hasChildren ? 'middle' : 'bottom', + transform: hasChildren ? '' : 'rotate(90)', + ports: [{ placement: 'bottom' }, { placement: 'top' }], + }; + }, + }, + edge: { + style: { + type: 'cubic-vertical', + }, + }, + layout: { + type: 'dendrogram', + direction: 'TB', + nodeSep: 40, + rankSep: 100, + }, + behaviors: ['drag-canvas', 'zoom-canvas', 'drag-node', 'collapse-expand-tree'], + }); + + await graph.render(); + + return graph; +}; diff --git a/packages/g6/__tests__/snapshots/layouts/dendrogram/basic.svg b/packages/g6/__tests__/snapshots/layouts/dendrogram/basic.svg new file mode 100644 index 00000000000..ff70f58d2fc --- /dev/null +++ b/packages/g6/__tests__/snapshots/layouts/dendrogram/basic.svg @@ -0,0 +1,1899 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Modeling Methods + + + + + + + + + + + + Classification + + + + + + + + + + + + Logistic regression + + + + + + + + + + + + Linear discriminant analysis + + + + + + + + + + + + Rules + + + + + + + + + + + + Decision trees + + + + + + + + + + + + Naive Bayes + + + + + + + + + + + + K nearest neighbor + + + + + + + + + + + + Probabilistic neural network + + + + + + + + + + + + Support vector machine + + + + + + + + + + + + Consensus + + + + + + + + + + + + Models diversity + + + + + + + + + + + + Different initializations + + + + + + + + + + + + Different parameter choices + + + + + + + + + + + + Different architectures + + + + + + + + + + + + Different modeling methods + + + + + + + + + + + + Different training sets + + + + + + + + + + + + Different feature sets + + + + + + + + + + + + Methods + + + + + + + + + + + + Classifier selection + + + + + + + + + + + + Classifier fusion + + + + + + + + + + + + Common + + + + + + + + + + + + Bagging + + + + + + + + + + + + Boosting + + + + + + + + + + + + AdaBoost + + + + + + + + + + + + Regression + + + + + + + + + + + + Multiple linear regression + + + + + + + + + + + + Partial least squares + + + + + + + + + + + + Multi-layer feed forward neural network + + + + + + + + + + + + General regression neural network + + + + + + + + + + + + Support vector regression + + + + + + + + \ No newline at end of file diff --git a/packages/g6/__tests__/snapshots/layouts/dendrogram/tb.svg b/packages/g6/__tests__/snapshots/layouts/dendrogram/tb.svg new file mode 100644 index 00000000000..2a0a5eaff96 --- /dev/null +++ b/packages/g6/__tests__/snapshots/layouts/dendrogram/tb.svg @@ -0,0 +1,1951 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Modeling Methods + + + + + + + + + + + + Classification + + + + + + + + + + + + Logistic regression + + + + + + + + + + + + Linear discriminant analysis + + + + + + + + + + + + Rules + + + + + + + + + + + + Decision trees + + + + + + + + + + + + Naive Bayes + + + + + + + + + + + + K nearest neighbor + + + + + + + + + + + + Probabilistic neural network + + + + + + + + + + + + Support vector machine + + + + + + + + + + + + Consensus + + + + + + + + + + + + Models diversity + + + + + + + + + + + + Different initializations + + + + + + + + + + + + Different parameter choices + + + + + + + + + + + + Different architectures + + + + + + + + + + + + Different modeling methods + + + + + + + + + + + + Different training sets + + + + + + + + + + + + Different feature sets + + + + + + + + + + + + Methods + + + + + + + + + + + + Classifier selection + + + + + + + + + + + + Classifier fusion + + + + + + + + + + + + Common + + + + + + + + + + + + Bagging + + + + + + + + + + + + Boosting + + + + + + + + + + + + AdaBoost + + + + + + + + + + + + Regression + + + + + + + + + + + + Multiple linear regression + + + + + + + + + + + + Partial least squares + + + + + + + + + + + + Multi-layer feed forward neural network + + + + + + + + + + + + General regression neural network + + + + + + + + + + + + Support vector regression + + + + + + + + \ No newline at end of file diff --git a/packages/g6/__tests__/unit/layouts/dendrogram.spec.ts b/packages/g6/__tests__/unit/layouts/dendrogram.spec.ts new file mode 100644 index 00000000000..6746c671595 --- /dev/null +++ b/packages/g6/__tests__/unit/layouts/dendrogram.spec.ts @@ -0,0 +1,16 @@ +import { layoutDendrogramBasic, layoutDendrogramTb } from '@@/demo/case'; +import { createDemoGraph } from '@@/utils'; + +describe('dendrogram', () => { + it('basic', async () => { + const graph = await createDemoGraph(layoutDendrogramBasic); + await expect(graph).toMatchSnapshot(__filename, 'basic'); + graph.destroy(); + }); + + it('tb', async () => { + const graph = await createDemoGraph(layoutDendrogramTb); + await expect(graph).toMatchSnapshot(__filename, 'tb'); + graph.destroy(); + }); +}); diff --git a/packages/site/examples/net/dendrogram/demo/basicDendrogram.js b/packages/site/examples/net/dendrogram/demo/basicDendrogram.js deleted file mode 100644 index 197dcf814dc..00000000000 --- a/packages/site/examples/net/dendrogram/demo/basicDendrogram.js +++ /dev/null @@ -1,158 +0,0 @@ -import { Graph, Extensions, extend } from '@antv/g6'; - -const ExtGraph = extend(Graph, { - edges: { - 'cubic-horizontal-edge': Extensions.CubicHorizontalEdge, - 'cubic-vertical-edge': Extensions.CubicVerticalEdge, - }, -}); -const layoutConfigs = { - LR: { - type: 'dendrogram', - direction: 'LR', // H / V / LR / RL / TB / BT - nodeSep: 36, - rankSep: 250, - }, - TB: { - type: 'dendrogram', - direction: 'TB', // H / V / LR / RL / TB / BT - nodeSep: 40, - rankSep: 100, - }, -}; - -const container = document.getElementById('container'); -const width = container.scrollWidth; -const height = container.scrollHeight || 500; - -fetch('https://gw.alipayobjects.com/os/antvdemo/assets/data/algorithm-category.json') - .then((res) => res.json()) - .then((data) => { - const graph = new ExtGraph({ - container, - width, - height, - transforms: [ - { - type: 'transform-v4-data', - activeLifecycle: ['read'], - }, - ], - modes: { - default: ['drag-canvas', 'zoom-canvas', 'drag-node', 'collapse-expand-tree'], - }, - node: (model) => { - const configRelatedToLayout = - model.data.layoutDirection === 'TB' - ? { - labelShape: { - text: model.id, - position: 'bottom', - offsetX: 0, - }, - anchorPoints: [ - [0.5, 0], - [0.5, 1], - ], - } - : { - labelShape: { - text: model.id, - position: model.data.childrenIds?.length ? 'left' : 'right', - offsetX: model.data.childrenIds?.length ? -10 : 10, - maxWidth: '300%', - }, - anchorPoints: [ - [0, 0.5], - [1, 0.5], - ], - }; - return { - id: model.id, - data: { - ...model.data, - labelBackgroundShape: {}, - ...configRelatedToLayout, - animates: { - update: [ - { - fields: ['x', 'y'], - duration: 500, - shapeId: 'group', - order: 0, - }, - ], - hide: [ - { - fields: ['opacity'], - duration: 200, - shapeId: 'keyShape', - }, - { - fields: ['opacity'], - duration: 200, - shapeId: 'labelShape', - }, - ], - show: [ - { - fields: ['opacity'], - duration: 1000, - shapeId: 'keyShape', - }, - { - fields: ['opacity'], - duration: 1000, - shapeId: 'labelShape', - }, - ], - }, - }, - }; - }, - edge: { - type: 'cubic-horizontal-edge', - }, - layout: layoutConfigs.LR, - autoFit: 'view', - data: { - type: 'treeData', - value: data, - }, - }); - - const btnContainer = document.createElement('div'); - btnContainer.style.position = 'absolute'; - container.appendChild(btnContainer); - const tip = document.createElement('span'); - tip.innerHTML = '👉 Change configs:'; - btnContainer.appendChild(tip); - - Object.keys(layoutConfigs).forEach((name, i) => { - const btn = document.createElement('a'); - btn.innerHTML = name; - btn.style.backgroundColor = 'rgba(255, 255, 255, 0.8)'; - btn.style.padding = '4px'; - btn.style.marginLeft = i > 0 ? '24px' : '8px'; - btnContainer.appendChild(btn); - btn.addEventListener('click', () => { - const updateEdges = graph.getAllEdgesData().map((edge) => ({ - id: edge.id, - data: { - type: name === 'LR' ? 'cubic-horizontal-edge' : 'cubic-vertical-edge', - }, - })); - const updateNodes = graph.getAllNodesData().map((node) => ({ - id: node.id, - data: { - layoutDirection: name, - }, - })); - graph.updateData('node', updateNodes); - graph.updateData('edge', updateEdges); - graph.layout(layoutConfigs[name]); - }); - }); - -window.graph = graph; - }); diff --git a/packages/site/examples/net/dendrogram/demo/basicDendrogram.ts b/packages/site/examples/net/dendrogram/demo/basicDendrogram.ts new file mode 100644 index 00000000000..1d68b2ecadb --- /dev/null +++ b/packages/site/examples/net/dendrogram/demo/basicDendrogram.ts @@ -0,0 +1,40 @@ +import { Graph, Utils } from '@antv/g6'; + +fetch('https://gw.alipayobjects.com/os/antvdemo/assets/data/algorithm-category.json') + .then((res) => res.json()) + .then((data) => { + const graph = new Graph({ + container: 'container', + autoFit: 'view', + data: Utils.treeToGraphData(data), + node: { + style: { + labelText: (d) => d.id, + labelPlacement: (model) => (model.style!.children?.length ? 'left' : 'right'), + ports: [ + { + placement: 'right', + }, + { + placement: 'left', + }, + ], + }, + }, + + edge: { + style: { + type: 'cubic-horizontal', + }, + }, + layout: { + type: 'dendrogram', + direction: 'LR', // H / V / LR / RL / TB / BT + nodeSep: 36, + rankSep: 250, + }, + behaviors: ['drag-canvas', 'zoom-canvas', 'drag-node', 'collapse-expand-tree'], + }); + + graph.render(); + }); diff --git a/packages/site/examples/net/dendrogram/demo/graphDataWithDendrogram.js b/packages/site/examples/net/dendrogram/demo/graphDataWithDendrogram.js deleted file mode 100644 index b0ad7ff11b0..00000000000 --- a/packages/site/examples/net/dendrogram/demo/graphDataWithDendrogram.js +++ /dev/null @@ -1,177 +0,0 @@ -import { Graph, Extensions, extend } from '@antv/g6'; - -const ExtGraph = extend(Graph, { - edges: { - 'cubic-horizontal-edge': Extensions.CubicHorizontalEdge, - 'cubic-vertical-edge': Extensions.CubicVerticalEdge, - }, - behaviors: { - 'activate-relations': Extensions.ActivateRelations, - }, -}); - -const layoutConfigs = { - LR: { - type: 'dendrogram', - direction: 'LR', // H / V / LR / RL / TB / BT - nodeSep: 40, - rankSep: 70, - }, - TB: { - type: 'dendrogram', - direction: 'TB', // H / V / LR / RL / TB / BT - nodeSep: 40, - rankSep: 40, - }, -}; - -const container = document.getElementById('container'); -const width = container.scrollWidth; -const height = container.scrollHeight || 500; - -fetch('https://gw.alipayobjects.com/os/antvdemo/assets/data/relations.json') - .then((res) => res.json()) - .then((data) => { - data.nodes.forEach((node, i) => (node.cluster = i % 3)); - const graph = new ExtGraph({ - container, - width, - height, - transforms: [ - { - type: 'transform-v4-data', - activeLifecycle: ['read'], - }, - ], - modes: { - default: ['drag-canvas', 'zoom-canvas', 'drag-node', 'collapse-expand-tree', 'activate-relations'], - }, - theme: { - type: 'spec', - specification: { - node: { - dataTypeField: 'cluster', - }, - }, - }, - node: (model) => { - return { - id: model.id, - data: { - ...model.data, - type: 'rect-node', - // lodLevels: [], - keyShape: { - width: 50, - height: 20, - }, - labelShape: { - text: model.id, - position: 'bottom', - maxWidth: '120%', - lod: Math.floor(Math.random() * 5 - 3), - fontSize: 8, - }, - labelBackgroundShape: {}, - anchorPoints: - model.data.layoutDirection === 'TB' - ? [ - [0.5, 0], - [0.5, 1], - ] - : [ - [0, 0.5], - [1, 0.5], - ], - animates: { - update: [ - { - fields: ['x', 'y'], - duration: 500, - shapeId: 'group', - order: 0, - }, - ], - hide: [ - { - fields: ['opacity'], - duration: 200, - shapeId: 'keyShape', - }, - { - fields: ['opacity'], - duration: 200, - shapeId: 'labelShape', - }, - ], - show: [ - { - fields: ['opacity'], - duration: 1000, - shapeId: 'keyShape', - }, - { - fields: ['opacity'], - duration: 1000, - shapeId: 'labelShape', - }, - ], - }, - }, - }; - }, - edge: { - type: 'cubic-horizontal-edge', - keyShape: { - opacity: 0.5, - endArrow: true, - }, - }, - layout: layoutConfigs.LR, - autoFit: 'view', - data: { - type: 'graphData', - value: data, - }, - edgeState: { - active: { - lineWidth: 3, - }, - }, - }); - - const btnContainer = document.createElement('div'); - btnContainer.style.position = 'absolute'; - container.appendChild(btnContainer); - const tip = document.createElement('span'); - tip.innerHTML = '👉 Change configs:'; - btnContainer.appendChild(tip); - - Object.keys(layoutConfigs).forEach((name, i) => { - const btn = document.createElement('a'); - btn.innerHTML = name; - btn.style.backgroundColor = 'rgba(255, 255, 255, 0.8)'; - btn.style.padding = '4px'; - btn.style.marginLeft = i > 0 ? '24px' : '8px'; - btnContainer.appendChild(btn); - btn.addEventListener('click', () => { - const updateEdges = graph.getAllEdgesData().map((edge) => ({ - id: edge.id, - data: { - type: name === 'LR' ? 'cubic-horizontal-edge' : 'cubic-vertical-edge', - }, - })); - const updateNodes = graph.getAllNodesData().map((node) => ({ - id: node.id, - data: { - layoutDirection: name, - }, - })); - graph.updateData('node', updateNodes); - graph.updateData('edge', updateEdges); - graph.layout(layoutConfigs[name]); - }); - }); - -window.graph = graph; - }); diff --git a/packages/site/examples/net/dendrogram/demo/meta.json b/packages/site/examples/net/dendrogram/demo/meta.json index c59df35c737..38938e3ca22 100644 --- a/packages/site/examples/net/dendrogram/demo/meta.json +++ b/packages/site/examples/net/dendrogram/demo/meta.json @@ -5,7 +5,7 @@ }, "demos": [ { - "filename": "basicDendrogram.js", + "filename": "basicDendrogram.ts", "title": { "zh": "生态树", "en": "Basic Dendrogram Layout" @@ -13,12 +13,12 @@ "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*P-qOSoDNuckAAAAAAAAAAAAADmJ7AQ/original" }, { - "filename": "graphDataWithDendrogram.js", + "filename": "tbDendrogram.ts", "title": { - "zh": "图数据使用生态树", - "en": "Basic Dendrogram Layout with Graph Data" + "zh": "至上而下的生态树", + "en": "Top to Bottom Dendrogram" }, - "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*Ti5tSZHz7vgAAAAAAAAAAAAADmJ7AQ/original" + "screenshot": "https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*nTKmRKkyUVUAAAAAAAAAAABkARQnAQ" } ] } diff --git a/packages/site/examples/net/dendrogram/demo/tbDendrogram.ts b/packages/site/examples/net/dendrogram/demo/tbDendrogram.ts new file mode 100644 index 00000000000..6e02641d4ca --- /dev/null +++ b/packages/site/examples/net/dendrogram/demo/tbDendrogram.ts @@ -0,0 +1,46 @@ +import { Graph, Utils } from '@antv/g6'; + +fetch('https://gw.alipayobjects.com/os/antvdemo/assets/data/algorithm-category.json') + .then((res) => res.json()) + .then((data) => { + const graph = new Graph({ + container: 'container', + autoFit: 'view', + data: Utils.treeToGraphData(data), + node: { + style: (model) => { + const hasChildren = !!model.style!.children?.length; + return { + labelText: model.id, + labelPlacement: hasChildren ? 'right' : 'bottom', + labelMaxWidth: 200, + labelTextAlign: 'start', + transform: hasChildren ? '' : 'rotate(90deg)', + ports: [ + { + placement: 'bottom', + }, + { + placement: 'top', + }, + ], + }; + }, + }, + + edge: { + style: { + type: 'cubic-vertical', + }, + }, + layout: { + type: 'dendrogram', + direction: 'TB', // H / V / LR / RL / TB / BT + nodeSep: 40, + rankSep: 100, + }, + behaviors: ['drag-canvas', 'zoom-canvas', 'drag-node', 'collapse-expand-tree'], + }); + + graph.render(); + });