diff --git a/examples/js/example-papaparsing.js b/examples/js/example-papaparsing.js
index 319d2aa..e7a89d6 100644
--- a/examples/js/example-papaparsing.js
+++ b/examples/js/example-papaparsing.js
@@ -1,409 +1,409 @@
-// Get the width and heigh of the SVG element.
-var width = +document.getElementById('svg').clientWidth,
- height = +document.getElementById('svg').clientHeight;
-
-var svg = d3.select("svg")
- .call(d3.zoom().scaleExtent([0.0001, 1000000]).on("zoom", function () {
- svg.attr("transform", d3.event.transform);
- }))
- .append("g");
-
-var div = d3.select("body").append("div")
- .attr("class", "tooltip")
- .style("opacity", 0);
-
-var brush = d3.brush()
- .extent([[-9999999, -9999999], [9999999, 9999999]])
- .on("end", brushEnded);
-
-svg.append("g")
- .attr("class", "brush")
- .call(brush);
-
-//var intercom = Intercom.getInstance();
-
-//intercom.on("select", unSelectNodes);
-
-var nodes, // as in Data points
- node, // as in SVG object that have all small circles on screen
- props,
- norm,
- p1 = 0,
- p2 = 0,
- size,
- distanceFunction,
- simulation,
- velocities = [],
- rendering = true, // Rendering during the execution.
- forceName = "forces",
- springForce = false,
- tooltipWidth = 0,
- fileName = "",
- selectedData,
- clickedIndex = -1,
- paused = false,
- alreadyRanIterations,
- tweakedVerOfLink,
- manualStop = false;
-
-// Default parameters
-var MULTIPLIER = 50,
- PERPLEXITY = 30,
- LEARNING_RATE = 10,
- NEIGHBOUR_SIZE = 10,
- SAMPLE_SIZE = 10,
- PIVOTS = false,
- NUM_PIVOTS = 3,
- ITERATIONS = 300,
- FULL_ITERATIONS = 20,
- NODE_SIZE = 10,
- COLOR_ATTRIBUTE = "",
- FULL_NEIGHBOUR_SIZE = 10,
- FULL_SAMPLE_SIZE = 10,
- INTERP_ENDING_ITS = 20;
-
-// Create a color scheme for a range of numbers.
-var color = d3.scaleOrdinal(d3.schemeCategory10);
-
-$(document).ready(function() {
- distanceFunction = calculateDistance;
- d3.select('#startSimulation').on('click', startHybridSimulation);
- $("#HLParameters").show();
-});
-
-/**
- * Parse the data from the provided csv file using Papa Parse library
- * @param {file} evt - csv file.
- */
-function parseFile(evt) {
- // Clear the previous nodes
- d3.selectAll(".nodes").remove();
- springForce = false;
-
- fileName = evt.target.files[0].name;
- Papa.parse(evt.target.files[0], {
- header: true,
- dynamicTyping: true,
- skipEmptyLines: true,
- complete: function (results) {
- processData(results.data, results.error);
- }
- });
-}
-
-/**
- * Process the data and pass it into D3 force simulation.
- * @param {array} data
- * @param {object} error
- */
-function processData(data, error) {
- if (error) throw error.message;
-
- nodes = data;
- size = nodes.length;
- simulation = d3.forceSimulation();
-
- // Calculate normalization parameters for distance fns
- norm = calculateNormalization(nodes);
- props = Object.keys(nodes[0]); // Properties to consider by distance fn
-
- COLOR_ATTRIBUTE = props[props.length-1];
-
- var opts = document.getElementById('color_attr').options;
-
- props.forEach(function (d) {
- opts.add(new Option(d, d, (d === COLOR_ATTRIBUTE) ? true : false));
- });
- opts.selectedIndex = props.length-1;
- //props.pop(); //Hide Iris index / last column from the distance function
-
-
- //Put the nodes at (0,0)
- nodes.forEach(function (d) {
- d.x = 0;
- d.y = 0;
- });
-
- addNodesToDOM(nodes);
-
- // Pass the nodes to the D3 force simulation.
- simulation
- .nodes(nodes)
- .stop();
-
- ticked();
-};
-
-function addNodesToDOM(data) {
- node = svg.append("g")
- .attr("class", "nodes")
- .selectAll("circle")
- .data(data)
- .enter().append("circle")
- .attr("r", NODE_SIZE)
- .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
- // Color code the data points by a property (for Poker Hands,
- // it is a CLASS property).
- .attr("fill", function (d) {
- return color(d[COLOR_ATTRIBUTE]);
- })
- .on("mouseover", function (d) {
- div.transition()
- .duration(200)
- .style("opacity", .9);
- div.html(formatTooltip(d))
- .style("left", (d3.event.pageX) + "px")
- .style("top", (d3.event.pageY - (15 * props.length)) + "px")
- .style("width", (6 * tooltipWidth) + "px")
- .style("height", (14 * props.length) + "px");
- highlightOnHover(d[COLOR_ATTRIBUTE]);
- })
- .on("mouseout", function (d) {
- div.transition()
- .duration(500)
- .style("opacity", 0);
- node.attr("opacity", 1);
- })
- .on("click", function (d) {
- console.log("click", clickedIndex);
- if (clickedIndex !== d.index) {
- if (springForce) {
- highlightNeighbours(Array.from(simulation.force(forceName).nodeNeighbours(d.index).keys()));
- clickedIndex = d.index;
- }
- } else {
- node.attr("r", NODE_SIZE).attr("stroke-width", 0);
- clickedIndex = -1;
- }
- });
- if (selectedData)
- unSelectNodes(selectedData);
-}
-
-function ticked() {
- alreadyRanIterations++;
- // 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*MULTIPLIER;
- })
- .attr("cy", function (d) {
- return d.y*MULTIPLIER;
- });
- }
- // Legacy: Emit the distribution data to allow the drawing of the bar graph
- //if (springForce) {
- // intercom.emit("passedData", simulation.force(forceName).distributionData());
- //}
- if(manualStop && alreadyRanIterations == ITERATIONS) {
- ended();
- }
-}
-
-function ended() {
- simulation.stop();
- simulation.force(forceName, null);
- if (rendering !== true) { // Never drawn anything before? Now it's time.
- node
- .attr("cx", function (d) {
- return d.x*MULTIPLIER;
- })
- .attr("cy", function (d) {
- return d.y*MULTIPLIER;
- });
- }
-
- if (p1 !== 0) {
- // Performance time measurement
- p2 = performance.now();
- console.log("Execution time: " + (p2 - p1));
- p1 = 0;
- p2 = 0;
- }
-}
-
-function brushEnded() {
- var s = d3.event.selection,
- results = [];
-
- if (s) {
-
- var x0 = s[0][0] - width / 2,
- y0 = s[0][1] - height / 2,
- x1 = s[1][0] - width / 2,
- y1 = s[1][1] - height / 2;
-
- if (nodes) {
- var sel = node.filter(function (d) {
- if (d.x > x0 && d.x < x1 && d.y > y0 && d.y < y1) {
- return true;
- }
- return false;
- }).data();
-
- results = sel.map(function (a) { return a.index; });
- }
-
- //intercom.emit("select", { name: fileName, indices: results });
-
- d3.select(".brush").call(brush.move, null);
- }
-}
-
-
-/**
- * Format the tooltip for the data
- * @param {*} node
- */
-function formatTooltip(node) {
- var textString = "",
- temp = "";
-
- tooltipWidth = 0;
- props.forEach(function (element) {
- temp = element + ": " + node[element] + "
";
- textString += temp;
- if (temp.length > tooltipWidth) {
- tooltipWidth = temp.length;
- }
- });
- return textString;
-}
-
-/**
- * Halt the execution.
- */
-function stopSimulation() {
- simulation.stop();
- if (typeof hybridSimulation !== 'undefined') {
- hybridSimulation.stop();
- }
-}
-
-/**
- * Calculate the average values of the array.
- * @param {array} array
- * @return {number} the mean of the array.
- */
-function getAverage(array) {
- console.log("getAverage", array);
- var total = 0;
- for (var i = 0; i < array.length; i++) {
- total += array[i];
- }
- return total / array.length;
-}
-
-/**
- * Deselect the nodes to match the selection from other window.
- * @param {*} data
- */
-function unSelectNodes(data) {
- selectedData = data;
- if (fileName === data.name && nodes) {
- node
- .classed("notSelected", function (d) {
- if (data.indices.indexOf(d.index) < 0) {
- return true;
- }
- return false;
- });
- }
-}
-
-
-/**
- * Highlight the neighbours for neighbour and sampling algorithm
- * @param {*} indices
- */
-function highlightNeighbours(indices) {
- node
- .attr("r", function (d) {
- if (indices.indexOf(d.index) >= 0) {
- return NODE_SIZE * 2;
- }
- return NODE_SIZE;
- })
- .attr("stroke-width", function (d) {
- if (indices.indexOf(d.index) >= 0) {
- return NODE_SIZE * 0.2 + "px";
- }
- return "0px";
- })
- .attr("stroke", "white");
-}
-
-
-/**
- * Highlight all the nodes with the same class on hover
- * @param {*} highlighValue
- */
-function highlightOnHover(highlighValue) {
- node.attr("opacity", function (d) {
- return (highlighValue === d[COLOR_ATTRIBUTE]) ? 1 : 0.3;
- });
-}
-
-/**
- * Color the nodes according to given attribute.
- */
-function colorToAttribute() {
- node.attr("fill", function (d) {
- return color(d[COLOR_ATTRIBUTE])
- });
-}
-
-
-/**
- * Update the distance range.
-
-function updateDistanceRange() {
- if (springForce) {
- simulation.force(forceName).distanceRange(SELECTED_DISTANCE);
- }
-}
-
-
-/**
- * Implemented pause/resume functionality
- */
-function pauseUnPause() {
- if (simulation) {
- if (paused) {
- simulation.force(forceName);
- simulation.restart();
- d3.select("#pauseButton").text("Pause");
- paused = false;
- } else {
- simulation.stop();
- d3.select("#pauseButton").text("Resume");
- paused = true;
- }
- }
-}
-
-
-/**
- * Average distances for each node.
- * @param {*} dataNodes
- * @param {*} properties
- * @param {*} normalization
-
-function calculateAverageDistance(dataNodes, properties, normalization) {
- var sum = 0,
- n = nodes.length;
-
- for (var i = 0; i < n; i++) {
- var sumNode = 0;
- for (var j = 0; j < n; j++) {
- if (i !== j) {
- sumNode += distanceFunction(nodes[i], nodes[j], properties, normalization);
- // console.log(sumNode);
- }
- }
- sum += sumNode / (n - 1);
- }
-
- return sum / n;
-}*/
+// Get the width and heigh of the SVG element.
+var width = +document.getElementById('svg').clientWidth,
+ height = +document.getElementById('svg').clientHeight;
+
+var svg = d3.select("svg")
+ .call(d3.zoom().scaleExtent([0.0001, 1000000]).on("zoom", function () {
+ svg.attr("transform", d3.event.transform);
+ }))
+ .append("g");
+
+var div = d3.select("body").append("div")
+ .attr("class", "tooltip")
+ .style("opacity", 0);
+
+var brush = d3.brush()
+ .extent([[-9999999, -9999999], [9999999, 9999999]])
+ .on("end", brushEnded);
+
+svg.append("g")
+ .attr("class", "brush")
+ .call(brush);
+
+//var intercom = Intercom.getInstance();
+
+//intercom.on("select", unSelectNodes);
+
+var nodes, // as in Data points
+ node, // as in SVG object that have all small circles on screen
+ props,
+ norm,
+ p1 = 0,
+ p2 = 0,
+ size,
+ distanceFunction,
+ simulation,
+ velocities = [],
+ rendering = true, // Rendering during the execution.
+ forceName = "forces",
+ springForce = false,
+ tooltipWidth = 0,
+ fileName = "",
+ selectedData,
+ clickedIndex = -1,
+ paused = false,
+ alreadyRanIterations,
+ tweakedVerOfLink,
+ manualStop = false;
+
+// Default parameters
+var MULTIPLIER = 50,
+ PERPLEXITY = 30,
+ LEARNING_RATE = 10,
+ NEIGHBOUR_SIZE = 10,
+ SAMPLE_SIZE = 10,
+ PIVOTS = false,
+ NUM_PIVOTS = 3,
+ ITERATIONS = 300,
+ FULL_ITERATIONS = 20,
+ NODE_SIZE = 10,
+ COLOR_ATTRIBUTE = "",
+ FULL_NEIGHBOUR_SIZE = 10,
+ FULL_SAMPLE_SIZE = 10,
+ INTERP_ENDING_ITS = 20;
+
+// Create a color scheme for a range of numbers.
+var color = d3.scaleOrdinal(d3.schemeCategory10);
+
+$(document).ready(function() {
+ distanceFunction = calculateDistance;
+ d3.select('#startSimulation').on('click', startHybridSimulation);
+ $("#HLParameters").show();
+});
+
+/**
+ * Parse the data from the provided csv file using Papa Parse library
+ * @param {file} evt - csv file.
+ */
+function parseFile(evt) {
+ // Clear the previous nodes
+ d3.selectAll(".nodes").remove();
+ springForce = false;
+
+ fileName = evt.target.files[0].name;
+ Papa.parse(evt.target.files[0], {
+ header: true,
+ dynamicTyping: true,
+ skipEmptyLines: true,
+ complete: function (results) {
+ processData(results.data, results.error);
+ }
+ });
+}
+
+/**
+ * Process the data and pass it into D3 force simulation.
+ * @param {array} data
+ * @param {object} error
+ */
+function processData(data, error) {
+ if (error) throw error.message;
+
+ nodes = data;
+ size = nodes.length;
+ simulation = d3.forceSimulation();
+
+ // Calculate normalization parameters for distance fns
+ norm = calculateNormalization(nodes);
+ props = Object.keys(nodes[0]); // Properties to consider by distance fn
+
+ COLOR_ATTRIBUTE = props[props.length-1];
+
+ var opts = document.getElementById('color_attr').options;
+
+ props.forEach(function (d) {
+ opts.add(new Option(d, d, (d === COLOR_ATTRIBUTE) ? true : false));
+ });
+ opts.selectedIndex = props.length-1;
+ //props.pop(); //Hide Iris index / last column from the distance function
+
+
+ //Put the nodes at (0,0)
+ nodes.forEach(function (d) {
+ d.x = 0;
+ d.y = 0;
+ });
+
+ addNodesToDOM(nodes);
+
+ // Pass the nodes to the D3 force simulation.
+ simulation
+ .nodes(nodes)
+ .stop();
+
+ ticked();
+};
+
+function addNodesToDOM(data) {
+ node = svg.append("g")
+ .attr("class", "nodes")
+ .selectAll("circle")
+ .data(data)
+ .enter().append("circle")
+ .attr("r", NODE_SIZE)
+ .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
+ // Color code the data points by a property (for Poker Hands,
+ // it is a CLASS property).
+ .attr("fill", function (d) {
+ return color(d[COLOR_ATTRIBUTE]);
+ })
+ .on("mouseover", function (d) {
+ div.transition()
+ .duration(200)
+ .style("opacity", .9);
+ div.html(formatTooltip(d))
+ .style("left", (d3.event.pageX) + "px")
+ .style("top", (d3.event.pageY - (15 * props.length)) + "px")
+ .style("width", (6 * tooltipWidth) + "px")
+ .style("height", (14 * props.length) + "px");
+ highlightOnHover(d[COLOR_ATTRIBUTE]);
+ })
+ .on("mouseout", function (d) {
+ div.transition()
+ .duration(500)
+ .style("opacity", 0);
+ node.attr("opacity", 1);
+ })
+ .on("click", function (d) {
+ console.log("click", clickedIndex);
+ if (clickedIndex !== d.index) {
+ if (springForce) {
+ highlightNeighbours(Array.from(simulation.force(forceName).nodeNeighbours(d.index).keys()));
+ clickedIndex = d.index;
+ }
+ } else {
+ node.attr("r", NODE_SIZE).attr("stroke-width", 0);
+ clickedIndex = -1;
+ }
+ });
+ if (selectedData)
+ unSelectNodes(selectedData);
+}
+
+function ticked() {
+ alreadyRanIterations++;
+ // 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*MULTIPLIER;
+ })
+ .attr("cy", function (d) {
+ return d.y*MULTIPLIER;
+ });
+ }
+ // Legacy: Emit the distribution data to allow the drawing of the bar graph
+ //if (springForce) {
+ // intercom.emit("passedData", simulation.force(forceName).distributionData());
+ //}
+ if(manualStop && alreadyRanIterations == ITERATIONS) {
+ ended();
+ }
+}
+
+function ended() {
+ simulation.stop();
+ simulation.force(forceName, null);
+ if (rendering !== true) { // Never drawn anything before? Now it's time.
+ node
+ .attr("cx", function (d) {
+ return d.x*MULTIPLIER;
+ })
+ .attr("cy", function (d) {
+ return d.y*MULTIPLIER;
+ });
+ }
+
+ if (p1 !== 0) {
+ // Performance time measurement
+ p2 = performance.now();
+ console.log("Execution time: " + (p2 - p1));
+ p1 = 0;
+ p2 = 0;
+ }
+}
+
+function brushEnded() {
+ var s = d3.event.selection,
+ results = [];
+
+ if (s) {
+
+ var x0 = s[0][0] - width / 2,
+ y0 = s[0][1] - height / 2,
+ x1 = s[1][0] - width / 2,
+ y1 = s[1][1] - height / 2;
+
+ if (nodes) {
+ var sel = node.filter(function (d) {
+ if (d.x > x0 && d.x < x1 && d.y > y0 && d.y < y1) {
+ return true;
+ }
+ return false;
+ }).data();
+
+ results = sel.map(function (a) { return a.index; });
+ }
+
+ //intercom.emit("select", { name: fileName, indices: results });
+
+ d3.select(".brush").call(brush.move, null);
+ }
+}
+
+
+/**
+ * Format the tooltip for the data
+ * @param {*} node
+ */
+function formatTooltip(node) {
+ var textString = "",
+ temp = "";
+
+ tooltipWidth = 0;
+ props.forEach(function (element) {
+ temp = element + ": " + node[element] + "
";
+ textString += temp;
+ if (temp.length > tooltipWidth) {
+ tooltipWidth = temp.length;
+ }
+ });
+ return textString;
+}
+
+/**
+ * Halt the execution.
+ */
+function stopSimulation() {
+ simulation.stop();
+ if (typeof hybridSimulation !== 'undefined') {
+ hybridSimulation.stop();
+ }
+}
+
+/**
+ * Calculate the average values of the array.
+ * @param {array} array
+ * @return {number} the mean of the array.
+ */
+function getAverage(array) {
+ console.log("getAverage", array);
+ var total = 0;
+ for (var i = 0; i < array.length; i++) {
+ total += array[i];
+ }
+ return total / array.length;
+}
+
+/**
+ * Deselect the nodes to match the selection from other window.
+ * @param {*} data
+ */
+function unSelectNodes(data) {
+ selectedData = data;
+ if (fileName === data.name && nodes) {
+ node
+ .classed("notSelected", function (d) {
+ if (data.indices.indexOf(d.index) < 0) {
+ return true;
+ }
+ return false;
+ });
+ }
+}
+
+
+/**
+ * Highlight the neighbours for neighbour and sampling algorithm
+ * @param {*} indices
+ */
+function highlightNeighbours(indices) {
+ node
+ .attr("r", function (d) {
+ if (indices.indexOf(d.index) >= 0) {
+ return NODE_SIZE * 2;
+ }
+ return NODE_SIZE;
+ })
+ .attr("stroke-width", function (d) {
+ if (indices.indexOf(d.index) >= 0) {
+ return NODE_SIZE * 0.2 + "px";
+ }
+ return "0px";
+ })
+ .attr("stroke", "white");
+}
+
+
+/**
+ * Highlight all the nodes with the same class on hover
+ * @param {*} highlighValue
+ */
+function highlightOnHover(highlighValue) {
+ node.attr("opacity", function (d) {
+ return (highlighValue === d[COLOR_ATTRIBUTE]) ? 1 : 0.3;
+ });
+}
+
+/**
+ * Color the nodes according to given attribute.
+ */
+function colorToAttribute() {
+ node.attr("fill", function (d) {
+ return color(d[COLOR_ATTRIBUTE])
+ });
+}
+
+
+/**
+ * Update the distance range.
+
+function updateDistanceRange() {
+ if (springForce) {
+ simulation.force(forceName).distanceRange(SELECTED_DISTANCE);
+ }
+}
+
+
+/**
+ * Implemented pause/resume functionality
+ */
+function pauseUnPause() {
+ if (simulation) {
+ if (paused) {
+ simulation.force(forceName);
+ simulation.restart();
+ d3.select("#pauseButton").text("Pause");
+ paused = false;
+ } else {
+ simulation.stop();
+ d3.select("#pauseButton").text("Resume");
+ paused = true;
+ }
+ }
+}
+
+
+/**
+ * Average distances for each node.
+ * @param {*} dataNodes
+ * @param {*} properties
+ * @param {*} normalization
+
+function calculateAverageDistance(dataNodes, properties, normalization) {
+ var sum = 0,
+ n = nodes.length;
+
+ for (var i = 0; i < n; i++) {
+ var sumNode = 0;
+ for (var j = 0; j < n; j++) {
+ if (i !== j) {
+ sumNode += distanceFunction(nodes[i], nodes[j], properties, normalization);
+ // console.log(sumNode);
+ }
+ }
+ sum += sumNode / (n - 1);
+ }
+
+ return sum / n;
+}*/