diff --git a/lib/displayAsMarkdown.js b/lib/displayAsMarkdown.js index a744346..b7a710d 100644 --- a/lib/displayAsMarkdown.js +++ b/lib/displayAsMarkdown.js @@ -17,7 +17,7 @@ if (!String.prototype.replaceAll) { } export function DisplayAsMarkdown({markdowntext}){ - console.log(markdowntext) + //console.log(markdowntext) markdowntext = markdowntext.replaceAll("\n", "\n\n") return(

{`${element.name}`}

- {otherpairs.map(pair =>

{`${pair.key}: ${pair.value}`}

)} + {otherpairs.map(pair =>

{`${pair.key}: ${pair.value}`}

)} ) } \ No newline at end of file diff --git a/lib/findPaths.js b/lib/findPaths.js index 933b4f9..e240d39 100644 --- a/lib/findPaths.js +++ b/lib/findPaths.js @@ -6,7 +6,7 @@ let avg = arr => arr.reduce((a,b) => (a+b)) / arr.length /* Main function */ -function findPathsInner({sourceElementId, targetElementId, pathSoFar, links, listOfElements, maxLengthOfPath}){ +function findPathsInner({sourceElementId, targetElementId, pathSoFar, links, nodes, maxLengthOfPath}){ let paths = [] if(maxLengthOfPath > 0){ @@ -16,65 +16,47 @@ function findPathsInner({sourceElementId, targetElementId, pathSoFar, links, lis ((link.source == targetElementId) && (link.target == sourceElementId)) ){ paths.push(pathSoFar.concat(link).flat()) - //console.log(`Final path found at recursion level: ${maxLengthOfPath}. Source: ${sourceElementId}, target=${targetElementId}`) - //console.log(link) } else if((link.source == sourceElementId)){ - let newPaths = findPathsInner({sourceElementId:link.target, targetElementId, pathSoFar: pathSoFar.concat(link).flat(), links, listOfElements, maxLengthOfPath: (maxLengthOfPath-1)}) + let newPaths = findPathsInner({sourceElementId:link.target, targetElementId, pathSoFar: pathSoFar.concat(link).flat(), links, nodes, maxLengthOfPath: (maxLengthOfPath-1)}) if(newPaths.length != 0){ - //console.log(`New link, at recursion level: ${maxLengthOfPath}. Source: ${sourceElementId}, target=${targetElementId}. PathSoFar: ${pathSoFar}`) - //console.log(link) - //console.log(newPaths) paths.push(...newPaths) } }else if((link.target == sourceElementId)){ - let newPaths = findPathsInner({sourceElementId:link.source, targetElementId, pathSoFar: pathSoFar.concat(link).flat(), links, listOfElements, maxLengthOfPath: (maxLengthOfPath-1)}) + let newPaths = findPathsInner({sourceElementId:link.source, targetElementId, pathSoFar: pathSoFar.concat(link).flat(), links, nodes, maxLengthOfPath: (maxLengthOfPath-1)}) if(newPaths.length != 0){ - //console.log(`New link, at recursion level: ${maxLengthOfPath}. Source: ${sourceElementId}, target=${targetElementId}. PathSoFar: ${pathSoFar}`) - //console.log(link) - //console.log(newPaths) paths.push(...newPaths) } } - } } - + return paths } -function findPaths({sourceElementId, targetElementId, links, listOfElements}){ - let positionSourceElement = listOfElements.map((element, i) => (element.id)).indexOf(sourceElementId) - let positionTargetElement = listOfElements.map((element, i) => (element.id)).indexOf(targetElementId) +function findPaths({sourceElementId, targetElementId, links, nodes}){ + let positionSourceElement = nodes.map((element, i) => (element.id)).indexOf(sourceElementId) + let positionTargetElement = nodes.map((element, i) => (element.id)).indexOf(targetElementId) let maxLengthOfPath = Math.abs(positionSourceElement - positionTargetElement) - console.log(maxLengthOfPath) - return findPathsInner({sourceElementId, targetElementId, pathSoFar: [], links, listOfElements, maxLengthOfPath}) + return findPathsInner({sourceElementId, targetElementId, pathSoFar: [], links, nodes, maxLengthOfPath}) } -function findDistance({sourceElementId, targetElementId, links, listOfElements}){ - let paths = findPaths({sourceElementId, targetElementId, links, listOfElements}) - // console.log(paths) +function findDistance({sourceElementId, targetElementId, nodes, links}){ + let paths = findPaths({sourceElementId, targetElementId, nodes, links}) let weights = [] for(let path of paths){ let currentSource = sourceElementId let weight = 1 - // console.log(path) for(let element of path){ - // console.log(element) - // console.log(element.source) - // console.log(element.target) let distance = 0 if(element.source == currentSource){ - // console.log("A") distance = element.distance currentSource = element.target }else if(element.target == currentSource){ - // console.log("B") distance = 1/Number(element.distance) currentSource = element.source } weight = weight*distance - // console.log(weight) } weights.push(weight) @@ -84,64 +66,53 @@ function findDistance({sourceElementId, targetElementId, links, listOfElements}) return weights.map(weight => Math.round(weight*100)/100) } -function findDistancesForAllElements({links, listOfElements}){ - let referenceElement = listOfElements.filter(x => x.isReferenceValue)[0] - console.log(referenceElement.id) - let distances = listOfElements.map(element =>{ - if(element.isReferenceValue){ - return [1] - }else{ - // console.log({sourceElementId: referenceElement.id, targetElementId: element.id, links, listOfElements}) - return findDistance({sourceElementId: Number(referenceElement.id), targetElementId: Number(element.id), links, listOfElements}) - } - }) +function findDistancesForAllElements({nodes, links}){ + let referenceElements = nodes.filter(x => x.isReferenceValue) + let midpoint = Math.round(nodes.length/2) + let referenceElement = referenceElements.length > 0 ? referenceElements[0] : nodes[midpoint] + + let distances = nodes.map(element => + element.isReferenceValue ? [1] : findDistance({sourceElementId: referenceElement.id, targetElementId: element.id, nodes, links}) + ) return distances } -export function CreateTableWithDistances({isListOrdered, quantitativeComparisons, listOfElements, referenceValueId}){ - if(!isListOrdered){ // listOfElements - console.log - console.log("List of Elements: ") - console.log(listOfElements) - return (
) +export function CreateTableWithDistances({isListOrdered, nodes, links}){ + if(!isListOrdered){ + return (
{""}
) } else { - console.log(`isListOrdered: ${isListOrdered}`) - console.log("List Of Elements:") - console.log(listOfElements) - let links = quantitativeComparisons.map(([element1, element2, distance]) => ({source: element1, target: element2, distance: distance})) - - let distances = findDistancesForAllElements({links, listOfElements}) + let distances = findDistancesForAllElements({nodes, links}) + let rows = nodes.map((element, i) => ({id: element.id, name: element.name, distances: distances[i]})) - let rows = listOfElements.map((element, i) => ({id: element.id, name: element.name, distances: distances[i]})) - - return(
- - - - - - - - - - - - - - {rows.map(row => - - - - - - - - - )} - -
Id   Element    Possible relative values    Average relative value
{row.id}   {row.name}   {JSON.stringify(row.distances, null, 2)}   {avg(row.distances).toFixed(2)}
-
-) + return( +
+ + + + + + + + + + + + + + {rows.map(row => + + + + + + + + + )} + +
Id   Element    Possible relative values    Average relative value
{row.id}   {row.name}   {JSON.stringify(row.distances, null, 2)}   {avg(row.distances).toFixed(2)}
+
+ ) } } @@ -152,16 +123,16 @@ export function CreateTableWithDistances({isListOrdered, quantitativeComparisons /* const directory = path.join(process.cwd(),"pages") let links = JSON.parse(fs.readFileSync(path.join(directory, 'distancesExample.json'), 'utf8')); -let listOfElements = JSON.parse(fs.readFileSync(path.join(directory, 'listOfPosts.json'), 'utf8')); +let nodes = JSON.parse(fs.readFileSync(path.join(directory, 'listOfPosts.json'), 'utf8')); -let paths = findPathsInner({sourceElementId:2, targetElementId:0, pathSoFar: [], links, listOfElements, maxLengthOfPath: 2}) +let paths = findPathsInner({sourceElementId:2, targetElementId:0, pathSoFar: [], links, nodes, maxLengthOfPath: 2}) console.log(JSON.stringify(paths, null, 2)) */ /* -let paths = findPaths({sourceElementId:2, targetElementId:0, links, listOfElements}) +let paths = findPaths({sourceElementId:2, targetElementId:0, links, nodes}) console.log(JSON.stringify(paths, null, 2)) */ /* -let distances = findDistance({sourceElementId:2, targetElementId:4, links, listOfElements}) +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 82ebe5f..01d8322 100644 --- a/lib/labeledgraph.js +++ b/lib/labeledgraph.js @@ -5,20 +5,8 @@ function getlength(number) { return number.toString().length; } -function drawGraphInner(list, quantitativeComparisons){ +function drawGraphInner({nodes, links}){ - // Build the graph object - let nodes = list.map((x,i) => ({id: i, name: x})) - let links = quantitativeComparisons.map(([element1, element2, distance]) => ({source: list.indexOf(element1), target: list.indexOf(element2), distance: distance})) - console.log("Links") - console.log(links) - - let data = ({ - nodes, - links: links - }) - console.log(data) - // Build the d3 graph let margin = {top: 0, right: 30, bottom: 20, left: 30}; let width = 900 - margin.left - margin.right; @@ -31,22 +19,21 @@ function drawGraphInner(list, quantitativeComparisons){ .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); - console.log(data) - // List of node names - var nodeNames = data.nodes.map(function(d){return d.name}) + // List of node ids + var nodeids = nodes.map(function(d){return d.id}) // A linear scale to position the nodes on the X axis var x = d3.scalePoint() .range([0, width]) - .domain(nodeNames) + .domain(nodeids) // Add the circle for the nodes svg .selectAll("mynodes") - .data(data.nodes) + .data(nodes) .enter() .append("circle") - .attr("cx", function(d){ return(x(d.name))}) + .attr("cx", function(d){ return(x(d.id))}) .attr("cy", height-30) .attr("r", 8) .style("fill", "#69b3a2") @@ -54,37 +41,24 @@ function drawGraphInner(list, quantitativeComparisons){ // And give them a label svg .selectAll("mylabels") - .data(data.nodes) + .data(nodes) .enter() .append("text") - .attr("x", function(d){ return(x(d.name))}) + .attr("x", function(d){ return(x(d.id))}) .attr("y", height-10) - .text(function(d){ return(d.name)}) + .text(function(d){ return(d.id)}) .style("text-anchor", "middle") - - - - // Add links between nodes. - // In the input data, links are provided between nodes -id-, not between node names. - // So one has to link ids and names - // Note Nuño: This is inefficient, and we could have built the data object to avoid this. However, every time I try to refactor this, the thing breaks. - var nodesById = {}; - data.nodes.forEach(function (n) { - nodesById[n.id] = n; - }); - - // Cool, now if I do nodesById["2"].name I've got the name of the node with id 2 - + // Add the links svg .selectAll('mylinks') - .data(data.links) + .data(links) .enter() .append('path') .attr('d', function (d) { - let start = x(nodesById[d.source].name) + let start = x(d.source) // X position of start node on the X axis - let end = x(nodesById[d.target].name) + let end = x(d.target) // X position of end node return ['M', start, @@ -105,20 +79,20 @@ function drawGraphInner(list, quantitativeComparisons){ // labels for links svg .selectAll('mylinks') - .data(data.links) + .data(links) .enter() .append("text") .attr("x", function(d){ - let start = x(nodesById[d.source].name) + let start = x(d.source) // X position of start node on the X axis - let end = x(nodesById[d.target].name) + 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(nodesById[d.source].name) + let start = x(d.source) // X position of start node on the X axis - let end = x(nodesById[d.target].name) + let end = x(d.target) // X position of end node return height-32-(Math.abs(start-end)/2)//height-30 }) @@ -130,10 +104,10 @@ function drawGraphInner(list, quantitativeComparisons){ } -export function DrawGraph({list, quantitativeComparisons, isListOrdered}) { +export function DrawGraph({isListOrdered, nodes, links}) { if(isListOrdered){ - drawGraphInner(list, quantitativeComparisons); + drawGraphInner({ nodes, links}); } return ( diff --git a/pages/index.js b/pages/index.js index 3482590..b5d965f 100644 --- a/pages/index.js +++ b/pages/index.js @@ -11,6 +11,7 @@ import {CreateTableWithDistances} from '../lib/findPaths' // Utilities let increasingList = (n) => Array.from(Array(n).keys()) +let buildLinks = quantitativeComparisons => quantitativeComparisons.map(([element1, element2, distance]) => ({source: element1, target: element2, distance: distance})) Array.prototype.containsArray = function(val) { var hash = {}; @@ -20,7 +21,7 @@ Array.prototype.containsArray = function(val) { return hash.hasOwnProperty(val); } -let checkIfListIsOrdered = (arr, binaryComparisons) => { // list of ids +let checkIfListIsOrdered = (arr, binaryComparisons) => { let l = arr.length let isOrdered = true for(let i=0; i { // list of ids } let simplifySliderValue = value => 10**value >= 3 ? Math.round(10**value) : Math.round(10*10**value)/10 + let displayFunctionSlider = (value) => { let result if(value >= 0){ @@ -45,13 +47,14 @@ let displayFunctionSlider = (value) => { let nicelyFormatLinks = (quantitativeComparisons , list) => quantitativeComparisons.map(([element1, element2, distance]) => ({source: list.indexOf(element1), target: list.indexOf(element2), distance: distance})) -// data +/* React components */ +// fs can only be used here. export async function getStaticProps() { //getServerSideProps // const { metaforecasts } = await getForecasts(); const directory = path.join(process.cwd(),"pages") let listOfPosts = JSON.parse(fs.readFileSync(path.join(directory, 'listOfPosts.json'), 'utf8')); - console.log(directory) + //console.log(directory) //console.log("metaforecasts", metaforecasts) return { props: { @@ -60,16 +63,17 @@ export async function getStaticProps() { }; } -// Main +// Main react component export default function Home({listOfPosts}) { // State - let list = increasingList(listOfPosts.length)//[1,2,3,4,5,6,7,8,9,10] // listOfPosts.map(element => element.id)// - let referenceValueId = 1//listOfPosts.filter(post => post.isReferenceValue || false)[0].id - const [toComparePair, setToComparePair] = useState([list[list.length-2], list[list.length-1]]) - const [binaryComparisons, setBinaryComparisons] = useState([]) + let list = increasingList(listOfPosts.length) // [0,1,2,3,4] + listOfPosts = listOfPosts.map((element, i) => ({...element, id: i})) + const [toComparePair, setToComparePair] = useState([list[list.length-2], list[list.length-1]]) const [sliderValue, setSliderValue] = useState(0) - const [quantitativeComparisons, setQuantitativeComparisons] = useState([]) + + const [binaryComparisons, setBinaryComparisons] = useState([]) + const [quantitativeComparisons, setQuantitativeComparisons] = useState([]) // More expressive, but more laborious to search through. For the ordering step, I only manipulate the binaryComparisons. const [isListOrdered, setIsListOrdered] = useState(false) const [orderedList, setOrderedList] = useState([]) @@ -82,9 +86,9 @@ export default function Home({listOfPosts}) { return element1Greater && !element2Greater } else{ setToComparePair([element1, element2]) - console.log(`No comparison found between ${element1} and ${element2}`) - console.log(`Comparisons:`) - console.log(JSON.stringify(newBinaryComparisons, null, 4)); + //console.log(`No comparison found between ${element1} and ${element2}`) + //console.log(`Comparisons:`) + //console.log(JSON.stringify(newBinaryComparisons, null, 4)); return "No comparison found" } } @@ -134,19 +138,19 @@ export default function Home({listOfPosts}) { } let nextStepSimple = (binaryComparisons, element1, element2) => { - console.log("Binary comparisons: ") - console.log(JSON.stringify(binaryComparisons, null, 4)); + //console.log("Binary comparisons: ") + //console.log(JSON.stringify(binaryComparisons, null, 4)); let newComparison = [element1, element2] // [element1, element2] let newBinaryComparisons = [...binaryComparisons, newComparison] - console.log("New binaryComparisons: ") - console.log(JSON.stringify(newBinaryComparisons, null, 4)); + //console.log("New binaryComparisons: ") + //console.log(JSON.stringify(newBinaryComparisons, null, 4)); setBinaryComparisons(newBinaryComparisons) let result = mergeSort(list, newBinaryComparisons) - console.log(result) + //console.log(result) if(result != "No comparison found; unable to proceed" && checkIfListIsOrdered(result, newBinaryComparisons)){ - console.log(result) + //console.log(result) setIsListOrdered(true) setOrderedList(result) } @@ -218,15 +222,14 @@ export default function Home({listOfPosts}) { + nodes={orderedList.map(i => listOfPosts[i])} + links={buildLinks(quantitativeComparisons)}>
listOfPosts[i])} - referenceValueId={referenceValueId} + nodes={orderedList.map(i => listOfPosts[i])} + links={buildLinks(quantitativeComparisons)} >
diff --git a/pages/listOfPosts.json b/pages/listOfPosts.json index edb2538..9862bd4 100644 --- a/pages/listOfPosts.json +++ b/pages/listOfPosts.json @@ -1,20 +1,17 @@ [ { - "id": 0, "name": "Relative Impact of the First 10 EA Forum Prize Winners", "url": "https://forum.effectivealtruism.org/posts/pqphZhx2nJocGCpwc/relative-impact-of-the-first-10-ea-forum-prize-winners", "author": "Nuño Sempere", "karma": 80 }, { - "id": 1, "name": "Introducing Metaforecast: A Forecast Aggregator and Search Tool", "url": "https://forum.effectivealtruism.org/posts/tEo5oXeSNcB3sYr8m/introducing-metaforecast-a-forecast-aggregator-and-search", "author": "Nuño Sempere", "karma": 115 }, { - "id": 2, "name": "Forecasting Prize Results", "url": "https://forum.effectivealtruism.org/posts/8QFWHzmur4roAcnCf/forecasting-prize-results", "author": "Nuño Sempere", @@ -22,14 +19,12 @@ "isReferenceValue": true }, { - "id": 3, "name": "A Funnel for Cause Candidates", "url": "https://forum.effectivealtruism.org/posts/iRA4Dd2bfX9nukSo3/a-funnel-for-cause-candidates", "author": "Nuño Sempere", "karma": 34 }, { - "id": 4, "name": "2020: Forecasting in Review", "url": "https://forum.effectivealtruism.org/posts/8shCj2eoQygQvtoZP/2020-forecasting-in-review", "author": "Nuño Sempere", diff --git a/pages/listOfPosts_full.json b/pages/listOfPosts_full.json index ef92b70..5f99abe 100644 --- a/pages/listOfPosts_full.json +++ b/pages/listOfPosts_full.json @@ -1,69 +1,59 @@ [ { - "id": "0", "name": "Relative Impact of the First 10 EA Forum Prize Winners", "url": "https://forum.effectivealtruism.org/posts/pqphZhx2nJocGCpwc/relative-impact-of-the-first-10-ea-forum-prize-winners", "author": "Nuño Sempere", "karma": 80 }, { - "id": "1", "name": "Introducing Metaforecast: A Forecast Aggregator and Search Tool", "url": "https://forum.effectivealtruism.org/posts/tEo5oXeSNcB3sYr8m/introducing-metaforecast-a-forecast-aggregator-and-search", "author": "Nuño Sempere", "karma": 115 }, { - "id": "2", "name": "Forecasting Prize Results", "url": "https://forum.effectivealtruism.org/posts/8QFWHzmur4roAcnCf/forecasting-prize-results", "author": "Nuño Sempere", "karma": 44 }, { - "id": "3", "name": "A Funnel for Cause Candidates", "url": "https://forum.effectivealtruism.org/posts/iRA4Dd2bfX9nukSo3/a-funnel-for-cause-candidates", "author": "Nuño Sempere", "karma": 34 }, { - "id": "4", "name": "2020: Forecasting in Review", "url": "https://forum.effectivealtruism.org/posts/8shCj2eoQygQvtoZP/2020-forecasting-in-review", "author": "Nuño Sempere", "karma": 35 }, { - "id": "5", "name": "Big List of Cause Candidates", "url": "https://forum.effectivealtruism.org/posts/SCqRu6shoa8ySvRAa/big-list-of-cause-candidates", "author": "Nuño Sempere", "karma": 182 }, { - "id": "6", "name": "An experiment to evaluate the value of one researcher's work", "url": "https://forum.effectivealtruism.org/posts/udGBF8YWshCKwRKTp/an-experiment-to-evaluate-the-value-of-one-researcher-s-work", "author": "Nuño Sempere", "karma": 55 }, { - "id": "7", "name": "Predicting the Value of Small Altruistic Projects: A Proof of Concept Experiment", "url": "https://forum.effectivealtruism.org/posts/qb56nicbnj9asSemx/predicting-the-value-of-small-altruistic-projects-a-proof-of", "author": "Nuño Sempere", "karma": 51 }, { - "id": "8", "name": "Incentive Problems With Current Forecasting Competitions", "url": "https://forum.effectivealtruism.org/posts/ztmBA8v6KvGChxw92/incentive-problems-with-current-forecasting-competitions", "author": "Nuño Sempere", "karma": 54 }, { - "id": "9", "name": "Shapley Values: Better Than Counterfactuals", "url": "https://forum.effectivealtruism.org/posts/XHZJ9i7QBtAJZ6byW/shapley-values-better-than-counterfactuals", "author": "Nuño Sempere",