@graphty/layout
Version:
graph layout algorithms based on networkx
73 lines • 2.93 kB
JavaScript
import { getNodesFromGraph } from '../../utils/graph';
import { _processParams } from '../../utils/params';
import { rescaleLayout } from '../../utils/rescale';
/**
* Position nodes in layers of straight lines (multipartite layout).
*
* @param G - Graph or list of nodes
* @param subsetKey - Object mapping layers to node sets, or node attribute name
* @param align - The alignment of nodes: 'vertical' or 'horizontal'
* @param scale - Scale factor for positions
* @param center - Coordinate pair around which to center the layout
* @returns Positions dictionary keyed by node
*/
export function multipartiteLayout(G, subsetKey = 'subset', align = 'vertical', scale = 1, center = null) {
if (align !== 'vertical' && align !== 'horizontal') {
throw new Error("align must be either vertical or horizontal");
}
const processed = _processParams(G, center || [0, 0], 2);
const graph = processed.G;
center = processed.center;
const allNodes = getNodesFromGraph(graph);
if (allNodes.length === 0) {
return {};
}
// Convert subsetKey to a layer mapping if it's a string
let layers = {};
if (typeof subsetKey === 'string') {
// In JS we don't have access to node attributes directly
// This is a simplification - in a real implementation we would need
// to access node attributes from the graph
console.warn("Using string subsetKey requires node attributes, using default partitioning");
// Create a simple partitioning as fallback
layers = { 0: allNodes };
}
else {
// subsetKey is already a mapping of layers to nodes
// Convert single nodes to arrays
for (const [key, value] of Object.entries(subsetKey)) {
if (Array.isArray(value)) {
layers[key] = value;
}
else {
layers[key] = [value];
}
}
}
const layerCount = Object.keys(layers).length;
let pos = {};
// Process each layer
Object.entries(layers).forEach(([layer, nodes], layerIdx) => {
const layerNodes = Array.isArray(nodes) ? nodes : [nodes];
const layerSize = layerNodes.length;
layerNodes.forEach((node, nodeIdx) => {
// Place nodes in a grid: layerIdx determines x-coordinate (column)
// nodeIdx determines y-coordinate (row position within column)
const x = layerIdx - (layerCount - 1) / 2;
const y = nodeIdx - (layerSize - 1) / 2;
pos[node] = [x, y];
});
});
// Rescale positions
pos = rescaleLayout(pos, scale, center);
// Handle horizontal alignment
if (align === 'horizontal') {
for (const node in pos) {
const temp = pos[node][0];
pos[node][0] = pos[node][1];
pos[node][1] = temp;
}
}
return pos;
}
//# sourceMappingURL=multipartite.js.map