diff --git a/lib/findPaths.js b/lib/findPaths.js
index 058c56a..cf33036 100644
--- a/lib/findPaths.js
+++ b/lib/findPaths.js
@@ -1,285 +1,328 @@
/* Imports*/
-import React from 'react';
-import { numToAlphabeticalString, formatLargeOrSmall, avg } from "../lib/utils.js"
+import React from "react";
+import {
+ numToAlphabeticalString,
+ formatLargeOrSmall,
+ avg,
+ geomMean,
+} from "../lib/utils.js";
/* Functions */
const pathPlusLink = (pathSoFar, link) => {
- return [...pathSoFar, link]
- // previously: pathSoFar.concat(link).flat()
- // Note that concat is not destructive
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat
-}
+ return [...pathSoFar, link];
+ // previously: pathSoFar.concat(link).flat()
+ // Note that concat is not destructive
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat
+};
async function findPathsWithoutPrunning({
- sourceElementId, targetElementId,
- maxLengthOfPath, pathSoFar,
- links, nodes
+ sourceElementId,
+ targetElementId,
+ maxLengthOfPath,
+ pathSoFar,
+ links,
+ nodes,
}) {
- // This is an un-used function which might make findPaths more understandable
- // It uses the same recursive functionality
- // but has no path prunning
- let paths = []
+ // This is an un-used function which might make findPaths more understandable
+ // It uses the same recursive functionality
+ // but has no path prunning
+ let paths = [];
- /* Path traversing */
- if (maxLengthOfPath > 0) {
- for (let link of links) { // vs let link of linksNow in findPaths
- if (
- ((link.source == sourceElementId) && (link.target == targetElementId)) ||
- ((link.source == targetElementId) && (link.target == sourceElementId))
- ) { // direct Path
- let newPath = pathPlusLink(pathSoFar, link)
- paths.push(newPath)
- } else if ((link.source == sourceElementId)) {
- let newPaths = await findPaths({
- pathSoFar: pathPlusLink(pathSoFar, link),
- maxLengthOfPath: (maxLengthOfPath - 1),
- sourceElementId: link.target,
- targetElementId,
- links: links, // vs let link of linksInner in findPaths
- nodes
- })
- if (newPaths.length != 0) {
- paths.push(...newPaths)
- }
- } else if ((link.target == sourceElementId)) {
- let newPaths = await findPaths({
- pathSoFar: pathPlusLink(pathSoFar, link),
- maxLengthOfPath: (maxLengthOfPath - 1),
- sourceElementId: link.source,
- targetElementId,
- links: links, // vs let link of linksInner in findPaths
- nodes
- })
- if (newPaths.length != 0) {
- paths.push(...newPaths)
- }
- }
+ /* Path traversing */
+ if (maxLengthOfPath > 0) {
+ for (let link of links) {
+ // vs let link of linksNow in findPaths
+ if (
+ (link.source == sourceElementId && link.target == targetElementId) ||
+ (link.source == targetElementId && link.target == sourceElementId)
+ ) {
+ // direct Path
+ let newPath = pathPlusLink(pathSoFar, link);
+ paths.push(newPath);
+ } else if (link.source == sourceElementId) {
+ let newPaths = await findPaths({
+ pathSoFar: pathPlusLink(pathSoFar, link),
+ maxLengthOfPath: maxLengthOfPath - 1,
+ sourceElementId: link.target,
+ targetElementId,
+ links: links, // vs let link of linksInner in findPaths
+ nodes,
+ });
+ if (newPaths.length != 0) {
+ paths.push(...newPaths);
}
+ } else if (link.target == sourceElementId) {
+ let newPaths = await findPaths({
+ pathSoFar: pathPlusLink(pathSoFar, link),
+ maxLengthOfPath: maxLengthOfPath - 1,
+ sourceElementId: link.source,
+ targetElementId,
+ links: links, // vs let link of linksInner in findPaths
+ nodes,
+ });
+ if (newPaths.length != 0) {
+ paths.push(...newPaths);
+ }
+ }
}
+ }
- return paths
+ return paths;
}
async function findPaths({
- sourceElementId, sourceElementPosition,
- targetElementId, targetElementPosition,
- maxLengthOfPath, pathSoFar,
- links, nodes
+ sourceElementId,
+ sourceElementPosition,
+ targetElementId,
+ targetElementPosition,
+ maxLengthOfPath,
+ pathSoFar,
+ links,
+ nodes,
}) {
- // This is the key path finding function
- // It finds the path from one element to another, recursively
- // It used to be very computationally expensive until I added
- // the path prunning step: Instead of traversing all links,
- // traverse only those which are between the origin and target links
- // this requires us to have a notion of "between"
+ // This is the key path finding function
+ // It finds the path from one element to another, recursively
+ // It used to be very computationally expensive until I added
+ // the path prunning step: Instead of traversing all links,
+ // traverse only those which are between the origin and target links
+ // this requires us to have a notion of "between"
- let paths = []
+ let paths = [];
- /* Path prunning*/
- let minPos = Math.min(sourceElementPosition, targetElementPosition)
- let maxPos = Math.max(sourceElementPosition, targetElementPosition)
- let linksInner = links.filter(link =>
- (minPos <= link.sourceElementPosition && link.sourceElementPosition <= maxPos) &&
- (minPos <= link.targetElementPosition && link.targetElementPosition <= maxPos)
- )
- let linksNow = linksInner.filter(link => (link.source == sourceElementId || link.target == sourceElementId))
+ /* Path prunning*/
+ let minPos = Math.min(sourceElementPosition, targetElementPosition);
+ let maxPos = Math.max(sourceElementPosition, targetElementPosition);
+ let linksInner = links.filter(
+ (link) =>
+ minPos <= link.sourceElementPosition &&
+ link.sourceElementPosition <= maxPos &&
+ minPos <= link.targetElementPosition &&
+ link.targetElementPosition <= maxPos
+ );
+ let linksNow = linksInner.filter(
+ (link) => link.source == sourceElementId || link.target == sourceElementId
+ );
- /* Path traversing */
- if (maxLengthOfPath > 0) {
- for (let link of linksNow) {
- if (
- ((link.source == sourceElementId) && (link.target == targetElementId)) ||
- ((link.source == targetElementId) && (link.target == sourceElementId))
- ) { // direct Path
- let newPath = pathPlusLink(pathSoFar, link)
- paths.push(newPath)
- } else if ((link.source == sourceElementId)) {
- let newPaths = await findPaths({
- pathSoFar: pathPlusLink(pathSoFar, link),
- maxLengthOfPath: (maxLengthOfPath - 1),
- sourceElementPosition: link.sourceElementPosition,
- sourceElementId: link.target,
- targetElementId, targetElementPosition,
- links: linksInner,
- nodes
- })
- if (newPaths.length != 0) {
- paths.push(...newPaths)
- }
- } else if ((link.target == sourceElementId)) {
- let newPaths = await findPaths({
- pathSoFar: pathPlusLink(pathSoFar, link),
- maxLengthOfPath: (maxLengthOfPath - 1),
- sourceElementPosition: link.sourceElementPosition,
- sourceElementId: link.source,
- targetElementPosition,
- targetElementId,
- links: linksInner,
- nodes
- })
- if (newPaths.length != 0) {
- paths.push(...newPaths)
- }
- }
+ /* Path traversing */
+ if (maxLengthOfPath > 0) {
+ for (let link of linksNow) {
+ if (
+ (link.source == sourceElementId && link.target == targetElementId) ||
+ (link.source == targetElementId && link.target == sourceElementId)
+ ) {
+ // direct Path
+ let newPath = pathPlusLink(pathSoFar, link);
+ paths.push(newPath);
+ } else if (link.source == sourceElementId) {
+ let newPaths = await findPaths({
+ pathSoFar: pathPlusLink(pathSoFar, link),
+ maxLengthOfPath: maxLengthOfPath - 1,
+ sourceElementPosition: link.sourceElementPosition,
+ sourceElementId: link.target,
+ targetElementId,
+ targetElementPosition,
+ links: linksInner,
+ nodes,
+ });
+ if (newPaths.length != 0) {
+ paths.push(...newPaths);
}
+ } else if (link.target == sourceElementId) {
+ let newPaths = await findPaths({
+ pathSoFar: pathPlusLink(pathSoFar, link),
+ maxLengthOfPath: maxLengthOfPath - 1,
+ sourceElementPosition: link.sourceElementPosition,
+ sourceElementId: link.source,
+ targetElementPosition,
+ targetElementId,
+ links: linksInner,
+ nodes,
+ });
+ if (newPaths.length != 0) {
+ paths.push(...newPaths);
+ }
+ }
}
+ }
- return paths
+ return paths;
}
async function findDistance({
- sourceElementId, sourceElementPosition,
- targetElementId, targetElementPosition,
- nodes, links
+ sourceElementId,
+ sourceElementPosition,
+ targetElementId,
+ targetElementPosition,
+ nodes,
+ links,
}) {
- // This function gets all possible paths using findPaths
- // then orders them correctly in the for loop
- // (by flipping the distance to 1/distance when necessary)
- // and then gets the array of weights for the different paths.
- console.log(`findDistance@findPaths.js from ${sourceElementPosition} to ${targetElementPosition}`)
+ // This function gets all possible paths using findPaths
+ // then orders them correctly in the for loop
+ // (by flipping the distance to 1/distance when necessary)
+ // and then gets the array of weights for the different paths.
+ console.log(
+ `findDistance@findPaths.js from ${sourceElementPosition} to ${targetElementPosition}`
+ );
- let maxLengthOfPath = Math.abs(sourceElementPosition - targetElementPosition)
- let paths = await findPaths({
- sourceElementId, sourceElementPosition,
- targetElementId, targetElementPosition,
- links, nodes,
- maxLengthOfPath, pathSoFar: []
- });
+ let maxLengthOfPath = Math.abs(sourceElementPosition - targetElementPosition);
+ let paths = await findPaths({
+ sourceElementId,
+ sourceElementPosition,
+ targetElementId,
+ targetElementPosition,
+ links,
+ nodes,
+ maxLengthOfPath,
+ pathSoFar: [],
+ });
- let weights = []
- for (let path of paths) {
- let currentSource = sourceElementId
- let weight = 1
- for (let element of path) {
- let distance = 0
- if (element.source == currentSource) {
- distance = element.distance
- currentSource = element.target
- } else if (element.target == currentSource) {
- distance = 1 / Number(element.distance)
- currentSource = element.source
- }
- weight = weight * distance
-
- }
- weights.push(weight)
+ let weights = [];
+ for (let path of paths) {
+ let currentSource = sourceElementId;
+ let weight = 1;
+ for (let element of path) {
+ let distance = 0;
+ if (element.source == currentSource) {
+ distance = element.distance;
+ currentSource = element.target;
+ } else if (element.target == currentSource) {
+ distance = 1 / Number(element.distance);
+ currentSource = element.source;
+ }
+ weight = weight * distance;
}
- return weights
+ weights.push(weight);
+ }
+ return weights;
}
async function findDistancesForAllElements({ nodes, links }) {
- // Simple wrapper function around findDistance
- // Needs to find the reference point first
- console.log("findDistancesForAllElements@findPaths.js")
- /* Get or build reference element */
- let referenceElements = nodes.filter(x => x.isReferenceValue)
- let midpoint = Math.round(nodes.length / 2)
- let referenceElement = referenceElements.length > 0 ? referenceElements[0] : nodes[midpoint]
- console.log(`referenceElement.position: ${referenceElement.position}`)
+ // Simple wrapper function around findDistance
+ // Needs to find the reference point first
+ console.log("findDistancesForAllElements@findPaths.js");
+ /* Get or build reference element */
+ let referenceElements = nodes.filter((x) => x.isReferenceValue);
+ let midpoint = Math.round(nodes.length / 2);
+ let referenceElement =
+ referenceElements.length > 0 ? referenceElements[0] : nodes[midpoint];
+ console.log(`referenceElement.position: ${referenceElement.position}`);
- /* Get distances. */
- let distances = nodes.map(node => {
- if (node.isReferenceValue || (node.id == referenceElement.id)) {
- return [1]
- } else {
- console.log("node")
- console.log(node)
- let distance = findDistance({
- sourceElementId: referenceElement.id,
- sourceElementPosition: referenceElement.position,
- targetElementId: node.id,
- targetElementPosition: node.position,
- nodes: nodes,
- links: links,
- })
- return distance
- }
- })
- distances = await Promise.all(distances)
- return distances
+ /* Get distances. */
+ let distances = nodes.map((node) => {
+ if (node.isReferenceValue || node.id == referenceElement.id) {
+ return [1];
+ } else {
+ console.log("node");
+ console.log(node);
+ let distance = findDistance({
+ sourceElementId: referenceElement.id,
+ sourceElementPosition: referenceElement.position,
+ targetElementId: node.id,
+ targetElementPosition: node.position,
+ nodes: nodes,
+ links: links,
+ });
+ return distance;
+ }
+ });
+ distances = await Promise.all(distances);
+ return distances;
}
-export async function buildRows({ isListOrdered, orderedList, listOfElements, links, rows, setTableRows }) {
- console.log("buildRows@findPaths.js")
- // This function is used in pages/comparisonView.js to create the rows that will be displayed.
- // it is in there because it needs to be deployed after isListOrdered becomes true,
- // and using an useEffect inside CreateTable was too messy.
- if (isListOrdered && !(orderedList.length < listOfElements.length) && rows.length == 0) {
- let nodes = []
- let positionDictionary = ({})
- orderedList.forEach((id, pos) => {
- nodes.push({ ...listOfElements[id], position: pos })
- positionDictionary[id] = pos
- })
- links = links.map(link => ({
- ...link,
- sourceElementPosition: positionDictionary[link.source],
- targetElementPosition: positionDictionary[link.target]
- }))
+export async function buildRows({
+ isListOrdered,
+ orderedList,
+ listOfElements,
+ links,
+ rows,
+ setTableRows,
+}) {
+ console.log("buildRows@findPaths.js");
+ // This function is used in pages/comparisonView.js to create the rows that will be displayed.
+ // it is in there because it needs to be deployed after isListOrdered becomes true,
+ // and using an useEffect inside CreateTable was too messy.
+ if (
+ isListOrdered &&
+ !(orderedList.length < listOfElements.length) &&
+ rows.length == 0
+ ) {
+ let nodes = [];
+ let positionDictionary = {};
+ orderedList.forEach((id, pos) => {
+ nodes.push({ ...listOfElements[id], position: pos });
+ positionDictionary[id] = pos;
+ });
+ links = links.map((link) => ({
+ ...link,
+ sourceElementPosition: positionDictionary[link.source],
+ targetElementPosition: positionDictionary[link.target],
+ }));
- let distances = await findDistancesForAllElements({ nodes, links })
- rows = nodes.map((element, i) => ({
- id: numToAlphabeticalString(element.position),
- position: element.position,
- name: element.name,
- distances: distances[i]
- }))
- console.log(rows)
- setTableRows(rows)
- }
+ let distances = await findDistancesForAllElements({ nodes, links });
+ rows = nodes.map((element, i) => ({
+ id: numToAlphabeticalString(element.position),
+ position: element.position,
+ name: element.name,
+ distances: distances[i],
+ }));
+ console.log(rows);
+ setTableRows(rows);
+ }
}
export function CreateTable({ tableRows }) {
- /* This function receives a list of rows, and displays them nicely. */
- function abridgeArrayAndDisplay(array) {
- let newArray
- let formatForDisplay
- if (array.length > 10) {
- newArray = array.slice(0, 9)
- formatForDisplay = newArray.map(d => formatLargeOrSmall(d))
- formatForDisplay[9] = "..."
- } else {
- newArray = array
- formatForDisplay = newArray.map(d => formatLargeOrSmall(d))
- }
- let result = JSON.stringify(formatForDisplay, null, 2).replaceAll(`"`, "")
- return result
+ /* This function receives a list of rows, and displays them nicely. */
+ function abridgeArrayAndDisplay(array) {
+ let newArray;
+ let formatForDisplay;
+ if (array.length > 10) {
+ newArray = array.slice(0, 9);
+ formatForDisplay = newArray.map((d) => formatLargeOrSmall(d));
+ formatForDisplay[9] = "...";
+ } else {
+ newArray = array;
+ formatForDisplay = newArray.map((d) => formatLargeOrSmall(d));
}
- return (
-
-
-
-
- Id |
- |
- Position |
- |
- Element |
- |
- Possible relative values |
- |
- Average relative value |
-
-
-
- {tableRows.map(row =>
- {row.id} |
- |
- {row.position} |
- |
- {row.name} |
- |
- {abridgeArrayAndDisplay(row.distances)} |
- |
- {formatLargeOrSmall(avg(row.distances))} |
-
- )}
-
-
-
- )
-
+ let result = JSON.stringify(formatForDisplay, null, 2).replaceAll(`"`, "");
+ return result;
+ }
+ return (
+
+
+
+
+ Id |
+ |
+ Position |
+ |
+ Element |
+ |
+ Possible relative values |
+ |
+ Average relative value |
+
+
+
+ {tableRows.map((row) => (
+
+ {row.id} |
+ |
+ {row.position} |
+ |
+ {row.name} |
+ |
+ {abridgeArrayAndDisplay(row.distances)} |
+ |
+
+ {formatLargeOrSmall(geomMean(row.distances))}
+ |
+
+ ))}
+
+
+
+ );
}
/* Testing */
@@ -300,4 +343,5 @@ console.log(JSON.stringify(paths, null, 2))
/*
let distances = findDistance({sourceElementId:2, targetElementId:4, links, nodes})
console.log(distances)
-*/
\ No newline at end of file
+*/
+
diff --git a/lib/labeledGraph.js b/lib/labeledGraph.js
index ec42813..4d12988 100644
--- a/lib/labeledGraph.js
+++ b/lib/labeledGraph.js
@@ -1,145 +1,171 @@
import React, { useState, useEffect } from "react";
-import * as d3 from 'd3';
-import { toLocale, truncateValueForDisplay, numToAlphabeticalString, formatLargeOrSmall } from "./utils.js"
+import * as d3 from "d3";
+import {
+ toLocale,
+ truncateValueForDisplay,
+ numToAlphabeticalString,
+ formatLargeOrSmall,
+} from "./utils.js";
let getlength = (number) => number.toString().length;
export function removeOldSvg() {
- d3.select("#graph").select("svg").remove();
+ d3.select("#graph").select("svg").remove();
}
function drawGraphInner({ nodes, links }) {
+ // List of node ids for convenience
+ var nodeids = nodes.map((node) => node.id);
+ var positionById = {};
+ nodeids.forEach((nodeid, i) => (positionById[nodeid] = i));
+ console.log("NodeIds/positionById");
+ console.log(nodeids);
+ console.log(positionById);
- // List of node ids for convenience
- var nodeids = nodes.map(node => node.id)
- var positionById = {}
- nodeids.forEach((nodeid, i) => positionById[nodeid] = i)
- console.log("NodeIds/positionById")
- console.log(nodeids)
- console.log(positionById)
+ // Calculate the dimensions
+ // let margin = { top: 0, right: 30, bottom: 20, left: 30 };
+ // let width = 900 - margin.left - margin.right;
- // Calculate the dimensions
- // let margin = { top: 0, right: 30, bottom: 20, left: 30 };
- // let width = 900 - margin.left - margin.right;
-
- let initialWindowWidth = window.innerWidth
- let margin = { top: 0, right: 10, bottom: 30, left: 10 };
- let width = initialWindowWidth*0.7 - margin.left - margin.right;
-
- var x = d3.scalePoint()
- .range([0, width])
- .domain(nodeids)
+ let initialWindowWidth = window.innerWidth;
+ let margin = { top: 0, right: 10, bottom: 30, left: 10 };
+ let width = initialWindowWidth * 0.8 - margin.left - margin.right;
- let heights = links.map(link => {
- let start = x(positionById[link.source])
- let end = x(positionById[link.target])
- return Math.abs(start - end) / 2 + 70 // Magic constant.
+ var x = d3.scalePoint().range([0, width]).domain(nodeids);
+
+ let heights = links.map((link) => {
+ let start = x(positionById[link.source]);
+ let end = x(positionById[link.target]);
+ return Math.abs(start - end) / 2 + 70; // Magic constant.
+ });
+ console.log(heights);
+ let maxheight = Math.max(...heights);
+ let height = maxheight - margin.top - margin.bottom;
+ console.log(`height: ${height}`);
+
+ // Build the d3 graph
+
+ removeOldSvg();
+ var svg = d3
+ .select("#graph")
+ .append("svg")
+ .attr("width", width + margin.left + margin.right)
+ .attr("height", height + margin.top + margin.bottom)
+ .append("g")
+ .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
+
+ // A linear scale to position the nodes on the X axis
+
+ // Add the circle for the nodes
+ svg
+ .selectAll("mynodes")
+ .data(nodes)
+ .enter()
+ .append("circle")
+ .attr("cx", function (d) {
+ return x(d.id);
})
- console.log(heights)
- let maxheight = Math.max(...heights)
- let height = maxheight - margin.top - margin.bottom;
- console.log(`height: ${height}`)
+ .attr("cy", height - 30)
+ .attr("r", 8)
+ .style("fill", "#69b3a2");
- // Build the d3 graph
+ // And give them a label
+ svg
+ .selectAll("mylabels")
+ .data(nodes)
+ .enter()
+ .append("text")
+ .attr("x", function (d) {
+ return x(d.id);
+ })
+ .attr("y", height - 10)
+ .text(function (d) {
+ return numToAlphabeticalString(d.position);
+ })
+ .style("text-anchor", "middle");
- removeOldSvg()
- var svg = d3.select("#graph")
- .append("svg")
- .attr("width", width + margin.left + margin.right)
- .attr("height", height + margin.top + margin.bottom)
- .append("g")
- .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
+ // Add the links
+ svg
+ .selectAll("mylinks")
+ .data(links)
+ .enter()
+ .append("path")
+ .attr("d", function (d) {
+ let start = x(d.source);
+ // X position of start node on the X axis
+ let end = x(d.target);
+ // X position of end node
+ return (
+ [
+ "M",
+ start,
+ height - 30,
+ // the arc starts at the coordinate x=start, y=height-30 (where the starting node is)
+ "A",
+ // This means we're gonna build an elliptical arc
+ (start - end) / 2,
+ ",",
+ // Next 2 lines are the coordinates of the inflexion point. Height of this point is proportional with start - end distance
+ (start - end) / 2,
+ 0,
+ 0,
+ ",",
+ start < end ? 1 : 0,
+ end,
+ ",",
+ height - 30,
+ ]
+ // We always want the arc on top. So if end is before start, putting 0 here turn the arc upside down.
+ .join(" ")
+ );
+ })
+ .style("fill", "none")
+ .attr("stroke", "black");
- // A linear scale to position the nodes on the X axis
-
-
- // Add the circle for the nodes
- svg
- .selectAll("mynodes")
- .data(nodes)
- .enter()
- .append("circle")
- .attr("cx", function (d) { return (x(d.id)) })
- .attr("cy", height - 30)
- .attr("r", 8)
- .style("fill", "#69b3a2")
-
- // And give them a label
- svg
- .selectAll("mylabels")
- .data(nodes)
- .enter()
- .append("text")
- .attr("x", function (d) { return (x(d.id)) })
- .attr("y", height - 10)
- .text(function (d) { return numToAlphabeticalString(d.position) })
- .style("text-anchor", "middle")
-
- // Add the links
- svg
- .selectAll('mylinks')
- .data(links)
- .enter()
- .append('path')
- .attr('d', function (d) {
- let start = x(d.source)
- // X position of start node on the X axis
- let end = x(d.target)
- // X position of end node
- return ['M',
- start,
- height - 30,
- // the arc starts at the coordinate x=start, y=height-30 (where the starting node is)
- 'A',
- // This means we're gonna build an elliptical arc
- (start - end) / 2, ',',
- // Next 2 lines are the coordinates of the inflexion point. Height of this point is proportional with start - end distance
- (start - end) / 2, 0, 0, ',',
- start < end ? 1 : 0, end, ',', height - 30]
- // We always want the arc on top. So if end is before start, putting 0 here turn the arc upside down.
- .join(' ');
- })
- .style("fill", "none")
- .attr("stroke", "black")
-
- // labels for links
- svg
- .selectAll('mylinks')
- .data(links)
- .enter()
- .append("text")
- .attr("x", function (d) {
- let start = x(d.source)
- // X position of start node on the X axis
- let end = x(d.target)
- // X position of end node
- return start + (end - start) / 2 //-4*getlength(d.distance)
- })
- .attr("y", function (d) {
- let start = x(d.source)
- // X position of start node on the X axis
- let end = x(d.target)
- // X position of end node
- return height - 32 - (Math.abs(start - end) / 2)//height-30
- })
- .text(function (d) {
- return formatLargeOrSmall(Number(d.distance))
- // return (truncateValueForDisplay(Number(d.distance)))
- //return(Number(d.distance).toPrecision(2).toString())
- })
- .style("text-anchor", "middle")
+ // labels for links
+ svg
+ .selectAll("mylinks")
+ .data(links)
+ .enter()
+ .append("text")
+ .attr("x", function (d) {
+ let start = x(d.source);
+ // X position of start node on the X axis
+ let end = x(d.target);
+ // X position of end node
+ return start + (end - start) / 2; //-4*getlength(d.distance)
+ })
+ .attr("y", function (d) {
+ let start = x(d.source);
+ // X position of start node on the X axis
+ let end = x(d.target);
+ // X position of end node
+ return height - 32 - Math.abs(start - end) / 2; //height-30
+ })
+ .text(function (d) {
+ return formatLargeOrSmall(Number(d.distance));
+ // return (truncateValueForDisplay(Number(d.distance)))
+ //return(Number(d.distance).toPrecision(2).toString())
+ })
+ .style("text-anchor", "middle");
}
-export function DrawGraph({ isListOrdered, orderedList, listOfElements, links }) {
- if (isListOrdered) {
- let nodes = orderedList.map((id, pos) => ({ ...listOfElements[id], position: pos }))
- drawGraphInner({ nodes, links });
- }
- return (
-
- );
+export function DrawGraph({
+ isListOrdered,
+ orderedList,
+ listOfElements,
+ links,
+}) {
+ if (isListOrdered) {
+ let nodes = orderedList.map((id, pos) => ({
+ ...listOfElements[id],
+ position: pos,
+ }));
+ drawGraphInner({ nodes, links });
+ }
+ return (
+
+ );
+}
-}
\ No newline at end of file
diff --git a/lib/utils.js b/lib/utils.js
index 8a9957b..b2647bb 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -1,78 +1,94 @@
-import crypto from "crypto"
+import crypto from "crypto";
-export const hashString = (string) => crypto.createHash('md5').update(string).digest('hex');
-const id = x => x
-export const transformSliderValueToActualValue = id
-export const transformSliderValueToPracticalValue = id
+export const hashString = (string) =>
+ crypto.createHash("md5").update(string).digest("hex");
+const id = (x) => x;
+export const transformSliderValueToActualValue = id;
+export const transformSliderValueToPracticalValue = id;
-export const _transformSliderValueToActualValue = value => 10 ** value //>= 2 ? Math.round(10 ** value) : Math.round(10 * 10 ** value) / 10
-export const toLocale = x => Number(x).toLocaleString()
-export const truncateValueForDisplay = value => {
- if (value > 10) {
- return Number(Math.round(value).toPrecision(2))
- } else if (value > 1) {
- return Math.round(value * 10) / 10
- } else if (value < 1) {
-
- }
-}
-export const _transformSliderValueToPracticalValue = value => truncateValueForDisplay(transformSliderValueToActualValue(value))
+export const _transformSliderValueToActualValue = (value) => 10 ** value; //>= 2 ? Math.round(10 ** value) : Math.round(10 * 10 ** value) / 10
+export const toLocale = (x) => Number(x).toLocaleString();
+export const truncateValueForDisplay = (value) => {
+ if (value > 10) {
+ return Number(Math.round(value).toPrecision(2));
+ } else if (value > 1) {
+ return Math.round(value * 10) / 10;
+ } else if (value < 1) {
+ }
+};
+export const _transformSliderValueToPracticalValue = (value) =>
+ truncateValueForDisplay(transformSliderValueToActualValue(value));
export function sleep(ms) {
- return new Promise(resolve => setTimeout(resolve, ms));
+ return new Promise((resolve) => setTimeout(resolve, ms));
}
export function numToAlphabeticalString(num) {
- // https://stackoverflow.com/questions/45787459/convert-number-to-alphabet-string-javascript/45787487
- num = num + 1
- var s = '', t;
- while (num > 0) {
- t = (num - 1) % 26;
- s = String.fromCharCode(65 + t) + s;
- num = (num - t) / 26 | 0;
- }
- return `#${s}` || undefined;
+ // https://stackoverflow.com/questions/45787459/convert-number-to-alphabet-string-javascript/45787487
+ num = num + 1;
+ var s = "",
+ t;
+ while (num > 0) {
+ t = (num - 1) % 26;
+ s = String.fromCharCode(65 + t) + s;
+ num = ((num - t) / 26) | 0;
+ }
+ return `#${s}` || undefined;
}
export function formatLargeOrSmall(num) {
- if (num > 1) {
- return toLocale(truncateValueForDisplay(num))
- } else if (num > 0) {
- return num.toFixed(-Math.floor(Math.log(num) / Math.log(10)) + 1);
- } else if (num < -1) {
- return num.toFixed(-Math.floor(Math.log(-num) / Math.log(10)) + 1);
- } else {
- return toLocale(num)//return "~0"
-
- }
+ if (num > 1) {
+ return toLocale(truncateValueForDisplay(num));
+ } else if (num > 0) {
+ return num.toFixed(-Math.floor(Math.log(num) / Math.log(10)) + 1);
+ } else if (num < -1) {
+ return num.toFixed(-Math.floor(Math.log(-num) / Math.log(10)) + 1);
+ } else {
+ return toLocale(num); //return "~0"
+ }
}
-const firstFewMaxMergeSortSequence = [0, 0, 1, 3, 5, 8, 11, 14, 17, 21, 25, 29, 33, 37, 41, 45, 49, 54, 59, 64, 69, 74, 79, 84, 89, 94, 99, 104, 109, 114, 119, 124, 129, 135, 141, 147, 153, 159, 165, 171, 177, 183, 189, 195, 201, 207, 213, 219, 225, 231, 237, 243, 249, 255, 261, 267, 273, 279, 285]
+const firstFewMaxMergeSortSequence = [
+ 0, 0, 1, 3, 5, 8, 11, 14, 17, 21, 25, 29, 33, 37, 41, 45, 49, 54, 59, 64, 69,
+ 74, 79, 84, 89, 94, 99, 104, 109, 114, 119, 124, 129, 135, 141, 147, 153, 159,
+ 165, 171, 177, 183, 189, 195, 201, 207, 213, 219, 225, 231, 237, 243, 249,
+ 255, 261, 267, 273, 279, 285,
+];
export function maxMergeSortSteps(n) {
- if (n < firstFewMaxMergeSortSequence.length) {
- return firstFewMaxMergeSortSequence[n]
- } else {
- return maxMergeSortSteps(Math.floor(n / 2)) + maxMergeSortSteps(Math.ceil(n / 2)) + n - 1
- }
+ if (n < firstFewMaxMergeSortSequence.length) {
+ return firstFewMaxMergeSortSequence[n];
+ } else {
+ return (
+ maxMergeSortSteps(Math.floor(n / 2)) +
+ maxMergeSortSteps(Math.ceil(n / 2)) +
+ n -
+ 1
+ );
+ }
}
export function expectedNumMergeSortSteps(n) {
- // https://cs.stackexchange.com/questions/82862/expected-number-of-comparisons-in-a-merge-step
- // n-2 for each step, so (n-2) + (n-2)/2 + (n-2)/4 + ...
- // ~ 2*(n-2) -1 = 2*n - 3
- if (n == 0) {
- return 0
- } else if (n == 1) {
- return 0
- } else if (n == 2) {
- return 1
- } else if (n == 3) {
- return 2
- } else {
- return Math.ceil((n ** 2) / (n + 2)) + expectedNumMergeSortSteps(Math.ceil(n / 2))
- }
+ // https://cs.stackexchange.com/questions/82862/expected-number-of-comparisons-in-a-merge-step
+ // n-2 for each step, so (n-2) + (n-2)/2 + (n-2)/4 + ...
+ // ~ 2*(n-2) -1 = 2*n - 3
+ if (n == 0) {
+ return 0;
+ } else if (n == 1) {
+ return 0;
+ } else if (n == 2) {
+ return 1;
+ } else if (n == 3) {
+ return 2;
+ } else {
+ return (
+ Math.ceil(n ** 2 / (n + 2)) + expectedNumMergeSortSteps(Math.ceil(n / 2))
+ );
+ }
}
-export const avg = arr => arr.reduce((a, b) => (a + b), 0) / arr.length
+export const avg = (arr) => arr.reduce((a, b) => a + b, 0) / arr.length;
-export const increasingList = (n) => Array.from(Array(n).keys())
+export const geomMean = (arr) =>
+ arr.reduce((a, b) => a * b, 1) ^ (1 / arr.length);
+
+export const increasingList = (n) => Array.from(Array(n).keys());