@visactor/vgrammar-venn
Version:
Venn layout transform for VGrammar
67 lines (61 loc) • 2.47 kB
JavaScript
import { greedyLayout } from "./greedy-layout";
import { lossFunction } from "./loss";
import { constrainedMDSLayout } from "./constrained-mds-layout";
import { nelderMead } from "@visactor/vutils";
export function venn(areas, parameters) {
(parameters = parameters || {}).maxIterations = parameters.maxIterations || 500;
const initialLayout = parameters.initialLayout || bestInitialLayout, loss = parameters.lossFunction || lossFunction, circles = initialLayout(areas = addMissingAreas(areas), parameters), initial = [], setIds = [];
for (const setId in circles) circles.hasOwnProperty(setId) && (initial.push(circles[setId].x),
initial.push(circles[setId].y), setIds.push(setId));
const positions = nelderMead((function(values) {
const current = {};
for (let i = 0; i < setIds.length; ++i) {
const setId = setIds[i];
current[setId] = {
x: values[2 * i],
y: values[2 * i + 1],
radius: circles[setId].radius
};
}
return loss(current, areas);
}), initial, parameters).x;
for (let i = 0; i < setIds.length; ++i) {
const setId = setIds[i];
circles[setId].x = positions[2 * i], circles[setId].y = positions[2 * i + 1];
}
return circles;
}
function addMissingAreas(areas) {
areas = areas.slice();
const ids = [], pairs = {};
for (let i = 0; i < areas.length; ++i) {
const area = areas[i];
if (1 === area.sets.length) ids.push(area.sets[0]); else if (2 === area.sets.length) {
const a = area.sets[0], b = area.sets[1];
pairs[[ a, b ].toString()] = !0, pairs[[ b, a ].toString()] = !0;
}
}
ids.sort((function(a, b) {
return +(a > b);
}));
for (let i = 0; i < ids.length; ++i) {
const a = ids[i];
for (let j = i + 1; j < ids.length; ++j) {
const b = ids[j];
[ a, b ].toString() in pairs || areas.push({
sets: [ a, b ],
size: 0
});
}
}
return areas;
}
export function bestInitialLayout(areas, params) {
let initial = greedyLayout(areas, params);
const loss = params.lossFunction || lossFunction;
if (areas.length >= 8) {
const constrained = constrainedMDSLayout(areas, params);
loss(constrained, areas) + 1e-8 < loss(initial, areas) && (initial = constrained);
}
return initial;
}