From 5ece15365163fbee6bb6b53a39d2532a16abf8bf Mon Sep 17 00:00:00 2001 From: Pitchaya Boonsarngsuk <2285135b@student.gla.ac.uk> Date: Wed, 17 Jan 2018 09:55:43 +0000 Subject: [PATCH] Neighbor stop on little velocity changes --- .../js/src/neighbourSampling-papaparsing.js | 91 ++++++++++--------- src/hybridSimulation.js | 9 +- src/neighbourSamplingDistance.js | 74 +++++++++------ 3 files changed, 97 insertions(+), 77 deletions(-) diff --git a/examples/js/src/neighbourSampling-papaparsing.js b/examples/js/src/neighbourSampling-papaparsing.js index 64e7307..a133a39 100644 --- a/examples/js/src/neighbourSampling-papaparsing.js +++ b/examples/js/src/neighbourSampling-papaparsing.js @@ -166,51 +166,49 @@ function processData(data, error) { .nodes(nodes) .on("tick", ticked) .on("end", ended); - - - function ticked() { - // If rendering is selected, then draw at every iteration. - if (rendering === true) { - node // Each sub-circle in the SVG, update cx and cy - .attr("cx", function (d) { - return d.x; - }) - .attr("cy", function (d) { - return d.y; - }); - } - // Emit the distribution data to allow the drawing of the bar graph - if (springForce) { - intercom.emit("passedData", simulation.force(forceName).distributionData()); - } - } - - function ended() { - if (rendering !== true) { // Never drawn anything before? Now it's time. - node - .attr("cx", function (d) { - return d.x; - }) - .attr("cy", function (d) { - return d.y; - }); - } - - if (p1 !== 0) { - // Performance time measurement - p2 = performance.now(); - console.log("Execution time: " + (p2 - p1)); - // Do not calculate stress for data sets bigger than 100 000. - // if (nodes.length <= 100000) { - // console.log("Stress: ", simulation.force(forceName).stress()); - // } - // console.log(simulation.force(forceName).nodeNeighbours()); - p1 = 0; - p2 = 0; - } - } }; +function ticked() { + // If rendering is selected, then draw at every iteration. + if (rendering === true) { + node // Each sub-circle in the SVG, update cx and cy + .attr("cx", function (d) { + return d.x; + }) + .attr("cy", function (d) { + return d.y; + }); + } + // Emit the distribution data to allow the drawing of the bar graph + if (springForce) { + intercom.emit("passedData", simulation.force(forceName).distributionData()); + } +} + +function ended() { + if (rendering !== true) { // Never drawn anything before? Now it's time. + node + .attr("cx", function (d) { + return d.x; + }) + .attr("cy", function (d) { + return d.y; + }); + } + + if (p1 !== 0) { + // Performance time measurement + p2 = performance.now(); + console.log("Execution time: " + (p2 - p1)); + // Do not calculate stress for data sets bigger than 100 000. + // if (nodes.length <= 100000) { + // console.log("Stress: ", simulation.force(forceName).stress()); + // } + // console.log(simulation.force(forceName).nodeNeighbours()); + p1 = 0; + p2 = 0; + } +} function brushEnded() { var s = d3.event.selection, @@ -281,7 +279,10 @@ function startNeighbourSamplingSimulation() { // between nodes. .distance(function (s, t) { return distanceFunction(s, t, props, norm) * MULTIPLIER; - })); + }) + .stableVelocity(1.2 * MULTIPLIER) + .stableVeloHandler( function(){simulation.stop(); ended();} ) + ); // Restart the simulation. console.log(simulation.force(forceName).neighbourSize(), simulation.force(forceName).sampleSize()); simulation.alpha(1).restart(); @@ -310,7 +311,7 @@ function startHybridSimulation() { pivots: PIVOTS, numPivots: NUM_PIVOTS }; - .sampleSize(SAMPLE_SIZE); + console.log(configuration); hybridSimulation = d3.hybridSimulation(nodes, configuration); let sample = hybridSimulation.sample(); diff --git a/src/hybridSimulation.js b/src/hybridSimulation.js index c966834..961010f 100644 --- a/src/hybridSimulation.js +++ b/src/hybridSimulation.js @@ -34,13 +34,16 @@ export default function (nodes, config) { }) .on("end", ended); - sampleSimulation.force("forces", neighbourSamplingDistance() + sampleSimulation + .force("forces", neighbourSamplingDistance() .neighbourSize(neighbourSize) .sampleSize(sampleSize) .distanceRange(distanceRange) .distance(distanceFn) - ); - sampleSimulation.alpha(1).restart(); + .stableVelocity(60) + .stableVeloHandler(function(){sampleSimulation.stop(); ended();}) + ) + .alpha(1).restart(); function ended() { event.call("startFull"); diff --git a/src/neighbourSamplingDistance.js b/src/neighbourSamplingDistance.js index e5b468c..37eeae8 100644 --- a/src/neighbourSamplingDistance.js +++ b/src/neighbourSamplingDistance.js @@ -29,7 +29,9 @@ export default function () { //freeness = 0.85, //springForce = 0.7, //dampingFactor = 0.3, - velocity; + velocity, + stableVelocity = 0, + stableVeloHandler = null; /** * Calculates the forces at each iteration between the node and the @@ -39,21 +41,28 @@ export default function () { */ function force(alpha) { velocity = 0; - for (var i = 0, n = nodes.length; i < n; ++i) { + for (let i = 0, n = nodes.length; i < n; ++i) { // Randomize the samples for every node. samples[i] = randomizeSample(i); // Calculate the forces between node and its neighbours. - for (var [keyN, valueN] of neighbours[i]) { + for (let [keyN, valueN] of neighbours[i]) { setVelocity(i, keyN, valueN, alpha); } // Calculate the forces between node and its sample set. - for (var [keyS, valueS] of samples[i]) { + for (let [keyS, valueS] of samples[i]) { setVelocity(i, keyS, valueS, alpha); } // Check if there are a better neighbours in a sample array // for each node. findNewNeighbours(i); } + velocity /= nodes.length*alpha; + // Now total velocity change per node, alpha not considered + if(Math.abs(velocity)= nodes.length) { break; } - var rand = Math.floor((Math.random() * max)); + let rand = Math.floor((Math.random() * max)); // If the rand is already in random list or in exclude list // ignore it and get a new value. while (randElements.has(rand) || exclude.includes(rand)) { @@ -176,7 +185,7 @@ export default function () { */ function randomizeSample(index) { // Ignore the current neighbours of the node and itself. - var exclude = [index]; + let exclude = [index]; exclude = exclude.concat(Array.from(neighbours[index].keys())); return createRandomSample(index, exclude, nodes.length, sampleSize); } @@ -188,11 +197,11 @@ export default function () { * @param {number} index - index of current node. */ function findNewNeighbours(index) { - var sample = samples[index]; + let sample = samples[index]; if (neighbours[index].size > 0) { - for (var [key, value] of sample) { - var neighbMax = neighbours[index].entries().next().value; + for (let [key, value] of sample) { + let neighbMax = neighbours[index].entries().next().value; // Check if a value from sample could be a better neighbour // if so, replace it. @@ -212,9 +221,9 @@ export default function () { * @return {number} - stress of the layout. */ function getStress() { - var totalDiffSq = 0, totalHighDistSq = 0; - for (var i = 0, source, target, realDist, highDist; i < nodes.length; i++) { - for (var j = 0; j < nodes.length; j++) { + let totalDiffSq = 0, totalHighDistSq = 0; + for (let i = 0, source, target, realDist, highDist; i < nodes.length; i++) { + for (let j = 0; j < nodes.length; j++) { if (i !== j) { source = nodes[i], target = nodes[j]; realDist = Math.hypot(target.x - source.x, target.y - source.y); @@ -238,8 +247,8 @@ export default function () { function getDistributionData() { - var d = []; - for (var i = 0; i < nodes.length; i++) { + let d = []; + for (let i = 0; i < nodes.length; i++) { d.push({ "index": i, "size": neighbours[i].size }); } return { "maxSize": neighbourSize, "l": nodes.length, "distribution": d }; @@ -292,5 +301,12 @@ export default function () { return getDistributionData(); }; + force.stableVeloHandler = function (_) { + return arguments.length ? (stableVeloHandler = _, force) : stableVeloHandler; + }; + + force.stableVelocity = function (_) { + return arguments.length ? (stableVelocity = _, force) : stableVelocity; + }; return force; }