UNPKG

@formant/ava

Version:

A framework for automated visual analytics.

179 lines (178 loc) 7.67 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getAllStructFeats = exports.clusterNodes = exports.getAllFieldsInfo = exports.getLinkFields = exports.getNodeFields = void 0; var tslib_1 = require("tslib"); // TODO @chenluli: move @antv/algorithm from devDep to dep after this file is complete // eslint-disable-next-line import/no-extraneous-dependencies var AlgorithmSync = tslib_1.__importStar(require("@antv/algorithm")); var field_1 = require("../field"); var GraphAlgorithms = tslib_1.__assign({}, AlgorithmSync); function generateColDataFromArray(arr, columnNames) { var fields = []; for (var i = 0; i < arr.length; i += 1) { var datum = arr[i]; for (var j = 0; j < columnNames.length; j += 1) { var column = columnNames[j]; if (fields[j]) { fields[j].push(datum[column]); } else { fields[j] = [datum[column]]; } } } return fields; } function getNodeFields(nodes) { var _a = tslib_1.__read(nodes, 1), node0 = _a[0]; var nodeFieldNames = node0 ? Object.keys(node0) : []; var nodeFields = generateColDataFromArray(nodes, nodeFieldNames); return { nodeFields: nodeFields, nodeFieldNames: nodeFieldNames }; } exports.getNodeFields = getNodeFields; function getLinkFields(links) { var _a = tslib_1.__read(links, 1), link0 = _a[0]; var linkFieldNames = link0 ? Object.keys(link0) : []; var linkFields = generateColDataFromArray(links, linkFieldNames); return { linkFields: linkFields, linkFieldNames: linkFieldNames }; } exports.getLinkFields = getLinkFields; // Analyze fields function getFieldInfo(dataField, fieldName) { var fieldInfo = (0, field_1.analyzeField)(dataField); return tslib_1.__assign(tslib_1.__assign({}, fieldInfo), { name: fieldName }); } function getAllFieldsInfo(dataFields, fieldNames) { var fields = []; for (var i = 0; i < dataFields.length; i += 1) { var dataField = dataFields[i]; fields.push(getFieldInfo(dataField, fieldNames[i])); } return fields; } exports.getAllFieldsInfo = getAllFieldsInfo; /* eslint-disable no-param-reassign */ /** * find node clusters and assign the cluster field to each node * @param nodes * @param links */ function clusterNodes(nodes, nodeFieldsInfo, links) { var MAX_CLUSTER_NUM = 10; var fieldForCluster; for (var i = 0; i < nodeFieldsInfo.length; i += 1) { var field = nodeFieldsInfo[i]; if (field.levelOfMeasurements.indexOf('Nominal') > -1 || (field.levelOfMeasurements.indexOf('Ordinal') > -1 && field.missing === 0 && field.distinct > 1 && field.distinct <= MAX_CLUSTER_NUM)) { fieldForCluster = field; break; } } if (fieldForCluster) { for (var nodeIdx = 0; nodeIdx < nodes.length; nodeIdx += 1) { nodes[nodeIdx].cluster = nodes[nodeIdx][fieldForCluster.name]; } } else { var clusters = GraphAlgorithms.louvain({ nodes: nodes, edges: links }).clusters; var values = []; for (var i = 0; i < clusters.length; i += 1) { var cluster = clusters[i]; var nodes_1 = cluster.nodes, id = cluster.id; for (var nodeIdx = 0; nodeIdx < nodes_1.length; nodeIdx += 1) { nodes_1[nodeIdx].cluster = id; } values.push(id); } fieldForCluster = tslib_1.__assign(tslib_1.__assign({}, (0, field_1.analyzeField)(values)), { name: 'cluster' }); } return fieldForCluster; } exports.clusterNodes = clusterNodes; /* eslint-disable no-param-reassign */ /** * Calculate statistical and structural features for graph * @param nodes * @param links */ function getAllStructFeats(nodes, links) { var nodeStructFeats = []; var linkStructFeats = []; // TODO: whether the graph is directed need to be passed in var isDirected = false; var degrees = GraphAlgorithms.getDegree({ nodes: nodes, edges: links }); var pageRanks = GraphAlgorithms.pageRank({ nodes: nodes, edges: links }); var cycles = GraphAlgorithms.detectAllCycles({ nodes: nodes, edges: links }, false); var directedCycles = GraphAlgorithms.detectAllDirectedCycle({ nodes: nodes, edges: links }); var components = GraphAlgorithms.connectedComponent({ nodes: nodes, edges: links }, false); var strongConnectedComponents = GraphAlgorithms.connectedComponent({ nodes: nodes, edges: links }, true); var cycleCountMap = {}; for (var i = 0; i < cycles.length; i += 1) { var nodeIds = Object.keys(cycles[i]); for (var j = 0; j < nodeIds.length; j += 1) { var nodeId = nodeIds[j]; if (cycleCountMap[nodeId]) { cycleCountMap[nodeId] += 1; } else { cycleCountMap[nodeId] = 1; } } } var numberOfNodeInCycle = Object.values(cycleCountMap).filter(function (count) { return count; }).length; var cycleParticipate = numberOfNodeInCycle / nodes.length; for (var index = 0; index < nodes.length; index += 1) { var node = nodes[index]; var nodeFeat = { degree: degrees[node.id].degree, inDegree: degrees[node.id].inDegree, outDegree: degrees[node.id].outDegree, pageRank: pageRanks[node.id], cycleCount: cycleCountMap[node.id] || 0, }; nodeStructFeats.push(nodeFeat); nodes[index] = tslib_1.__assign(tslib_1.__assign({}, node), nodeFeat); } for (var index = 0; index < links.length; index += 1) { var link = links[index]; var linkFeat = {}; linkStructFeats.push(linkFeat); links[index] = tslib_1.__assign(tslib_1.__assign({}, link), linkFeat); } var nodeFeatNames = Object.keys(nodeStructFeats[0]); var linkFeatNames = Object.keys(linkStructFeats[0]); var nodeFeats = getAllFieldsInfo(generateColDataFromArray(nodeStructFeats, nodeFeatNames), nodeFeatNames); var linkFeats = getAllFieldsInfo(generateColDataFromArray(linkStructFeats, linkFeatNames), linkFeatNames); // Calculate the structural features and statistics of all nodes and links var nodeDegrees = nodes.map(function (node) { return Number(node.degree); }); var avgDegree = nodeDegrees.reduce(function (x, y) { return x + y; }) / nodeDegrees.length; var degreeDev = nodeDegrees.map(function (x) { return x - avgDegree; }); var degreeStd = Math.sqrt(degreeDev.map(function (x) { return Math.pow(x, 2); }).reduce(function (x, y) { return x + y; }) / (nodeDegrees.length - 1)); var graphInfo = { isDirected: isDirected, nodeCount: nodes.length, linkCount: links.length, isConnected: components && components.length === 1, isDAG: isDirected && directedCycles.length === 0, maxDegree: Math.max.apply(Math, tslib_1.__spreadArray([], tslib_1.__read(nodeDegrees), false)), avgDegree: avgDegree, degreeStd: degreeStd, cycleParticipate: cycleParticipate, cycleCount: cycles.length, directedCycleCount: directedCycles.length, // triangleCount: triangleMatches.length, componentCount: components.length, components: components, strongConnectedComponents: strongConnectedComponents, strongConnectedComponentCount: strongConnectedComponents.length, }; return { nodeFeats: nodeFeats, linkFeats: linkFeats, graphInfo: graphInfo, }; } exports.getAllStructFeats = getAllStructFeats;