feat: Added GiveWell points of comparison

Taken from: https://docs.google.com/spreadsheets/d/11HsJLpq0Suf3SK_PmzzWpK1tr_BTd364j0l3xVvSCQw/edit#gid=1362437801
This commit is contained in:
NunoSempere 2021-09-22 21:45:18 +02:00
parent 134e526f74
commit 010a9b3b27
3 changed files with 136 additions and 104 deletions

View File

@ -16,7 +16,7 @@ const railStyle = {
position: 'absolute', position: 'absolute',
width: '100%', width: '100%',
height: 15, height: 15,
marginTop: 30, marginTop: 25,
borderRadius: 5, borderRadius: 5,
backgroundColor: 'lightgrey', backgroundColor: 'lightgrey',
} }
@ -77,12 +77,13 @@ function Track({ source, target, getTrackProps }) {
/* Body */ /* Body */
// Two functions, essentially identical. // Two functions, essentially identical.
export function SliderElement({ onChange, value, displayFunction }) { export function SliderElement({ onChange, value, displayFunction }) {
let toLogDomain = (arr) => [Math.log(arr[0])/Math.log(10), Math.log(arr[1])/Math.log(10)]
return ( return (
<Slider <Slider
rootStyle={sliderStyle /* inline styles for the outer div. Can also use className prop. */} rootStyle={sliderStyle /* inline styles for the outer div. Can also use className prop. */}
domain={[-3,3]} domain={toLogDomain([1/250,250])}
values={[value]} values={[value]}
step={0.0001}
onChange={onChange} onChange={onChange}
reversed={true} reversed={true}
> >

View File

@ -2,22 +2,22 @@ import Head from 'next/head'
import React, { useState } from "react"; import React, { useState } from "react";
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import {DrawGraph, removeOldSvg} from '../lib/labeledgraph'; import { DrawGraph, removeOldSvg } from '../lib/labeledgraph';
import { SliderElement, SubmitSliderButton } from "../lib/slider"; import { SliderElement, SubmitSliderButton } from "../lib/slider";
import {DisplayElement} from '../lib/displayElement' import { DisplayElement } from '../lib/displayElement'
import {DisplayAsMarkdown} from '../lib/displayAsMarkdown' import { DisplayAsMarkdown } from '../lib/displayAsMarkdown'
import {CreateTableWithDistances} from '../lib/findPaths' import { CreateTableWithDistances } from '../lib/findPaths'
import {TextAreaForJson} from "../lib/textAreaForJson" import { TextAreaForJson } from "../lib/textAreaForJson"
// Utilities // Utilities
let increasingList = (n) => Array.from(Array(n).keys()) let increasingList = (n) => Array.from(Array(n).keys())
let buildLinks = quantitativeComparisons => quantitativeComparisons.map(([element1, element2, distance]) => ({source: element1, target: element2, distance: distance})) let buildLinks = quantitativeComparisons => quantitativeComparisons.map(([element1, element2, distance]) => ({ source: element1, target: element2, distance: distance }))
Array.prototype.containsArray = function(val) { Array.prototype.containsArray = function (val) {
var hash = {}; var hash = {};
for(var i=0; i<this.length; i++) { for (var i = 0; i < this.length; i++) {
hash[this[i]] = i; hash[this[i]] = i;
} }
return hash.hasOwnProperty(val); return hash.hasOwnProperty(val);
} }
@ -25,20 +25,22 @@ Array.prototype.containsArray = function(val) {
let checkIfListIsOrdered = (arr, binaryComparisons) => { let checkIfListIsOrdered = (arr, binaryComparisons) => {
let l = arr.length let l = arr.length
let isOrdered = true let isOrdered = true
for(let i=0; i<l-1; i++){ for (let i = 0; i < l - 1; i++) {
isOrdered = isOrdered && binaryComparisons.containsArray([arr[i], arr[i+1]]) isOrdered = isOrdered && binaryComparisons.containsArray([arr[i], arr[i + 1]])
} }
return isOrdered return isOrdered
} }
let simplifySliderValue = value => 10**value >= 3 ? Math.round(10**value) : Math.round(10*10**value)/10 let transformSliderValueToActualValue = value => 10 ** value //>= 2 ? Math.round(10 ** value) : Math.round(10 * 10 ** value) / 10
let truncateValueForDisplay = value => value > 10 ? Math.round(value) : Math.round(value*10)/10
let transformSliderValueToPracticalValue = value => truncateValueForDisplay(transformSliderValueToActualValue(value))
let displayFunctionSlider = (value) => { let displayFunctionSlider = (value) => {
let result let result
if(value >= 0){ if (value >= 0) {
result = simplifySliderValue(value) result = transformSliderValueToPracticalValue(value)
}else{ } else {
let inverseresult = simplifySliderValue(-value) let inverseresult = transformSliderValueToPracticalValue(-value)
result = `1/${inverseresult}` result = `1/${inverseresult}`
} }
result = `The first option is ${result}x as valuable as the second one` result = `The first option is ${result}x as valuable as the second one`
@ -46,34 +48,34 @@ let displayFunctionSlider = (value) => {
}; };
let nicelyFormatLinks = (quantitativeComparisons , listOfElements) => quantitativeComparisons.map(([element1, element2, distance]) => ({source: listOfElements[element1].name, target: listOfElements[element2].name, distance: distance})) let nicelyFormatLinks = (quantitativeComparisons, listOfElements) => quantitativeComparisons.map(([element1, element2, distance]) => ({ source: listOfElements[element1].name, target: listOfElements[element2].name, distance: distance }))
/* React components */ /* React components */
// fs can only be used here. // fs can only be used here.
export async function getStaticProps() { export async function getStaticProps() {
//getServerSideProps //getServerSideProps
// const { metaforecasts } = await getForecasts(); // const { metaforecasts } = await getForecasts();
const directory = path.join(process.cwd(),"pages") const directory = path.join(process.cwd(), "pages")
let listOfPosts = JSON.parse(fs.readFileSync(path.join(directory, 'listOfPosts.json'), 'utf8')); let listOfMoralGoods = JSON.parse(fs.readFileSync(path.join(directory, 'listOfMoralGoods.json'), 'utf8'));
//console.log(directory) //console.log(directory)
//console.log("metaforecasts", metaforecasts) //console.log("metaforecasts", metaforecasts)
return { return {
props: { props: {
listOfElementsDefault: listOfPosts, listOfElementsDefault: listOfMoralGoods,
}, },
}; };
} }
// Main react component // Main react component
export default function Home({listOfElementsDefault}) { export default function Home({ listOfElementsDefault }) {
// State // State
let initialListOfElements = listOfElementsDefault.map((element, i) => ({...element, id: i})) let initialListOfElements = listOfElementsDefault.map((element, i) => ({ ...element, id: i }))
let initialPosList = increasingList(listOfElementsDefault.length) // [0,1,2,3,4] let initialPosList = increasingList(listOfElementsDefault.length) // [0,1,2,3,4]
//let listOfElements = listOfElementsDefault.map((element, i) => ({...element, id: i})) //let listOfElements = listOfElementsDefault.map((element, i) => ({...element, id: i}))
//let list = increasingList(listOfElementsDefault.length) // [0,1,2,3,4] //let list = increasingList(listOfElementsDefault.length) // [0,1,2,3,4]
//let initialComparePair = [list[list.length-2], list[list.length-1]] //let initialComparePair = [list[list.length-2], list[list.length-1]]
let initialComparePair = [initialPosList[initialPosList.length-2], initialPosList[initialPosList .length-1]] let initialComparePair = [initialPosList[initialPosList.length - 2], initialPosList[initialPosList.length - 1]]
let initialSliderValue = 0 let initialSliderValue = 0
let initialBinaryComparisons = [] let initialBinaryComparisons = []
let initialQuantitativeComparisons = [] let initialQuantitativeComparisons = []
@ -93,7 +95,7 @@ export default function Home({listOfElementsDefault}) {
const [binaryComparisons, setBinaryComparisons] = useState(initialBinaryComparisons) const [binaryComparisons, setBinaryComparisons] = useState(initialBinaryComparisons)
const [quantitativeComparisons, setQuantitativeComparisons] = useState(initialQuantitativeComparisons) // More expressive, but more laborious to search through. For the ordering step, I only manipulate the binaryComparisons. const [quantitativeComparisons, setQuantitativeComparisons] = useState(initialQuantitativeComparisons) // More expressive, but more laborious to search through. For the ordering step, I only manipulate the binaryComparisons.
const [isListOrdered, setIsListOrdered] = useState(initialIsListOdered) const [isListOrdered, setIsListOrdered] = useState(initialIsListOdered)
const [orderedList, setOrderedList] = useState(initialOrderedList) const [orderedList, setOrderedList] = useState(initialOrderedList)
let [showAdvancedOptions, changeShowAdvanceOptions] = useState(initialShowAdvancedOptions); let [showAdvancedOptions, changeShowAdvanceOptions] = useState(initialShowAdvancedOptions);
@ -101,7 +103,7 @@ export default function Home({listOfElementsDefault}) {
let [showChangeDataSet, changeshowChangeDataSet] = useState(initialShowChangeDataSet); let [showChangeDataSet, changeshowChangeDataSet] = useState(initialShowChangeDataSet);
let restart = (posList) => { let restart = (posList) => {
setToComparePair([posList[posList.length-2], posList[posList.length-1]]) setToComparePair([posList[posList.length - 2], posList[posList.length - 1]])
setSliderValue(initialSliderValue) setSliderValue(initialSliderValue)
setBinaryComparisons(initialBinaryComparisons) setBinaryComparisons(initialBinaryComparisons)
setQuantitativeComparisons(initialQuantitativeComparisons) setQuantitativeComparisons(initialQuantitativeComparisons)
@ -112,11 +114,11 @@ export default function Home({listOfElementsDefault}) {
let changeDataSet = (listOfElementsNew) => { let changeDataSet = (listOfElementsNew) => {
listOfElementsNew = listOfElementsNew =
listOfElementsNew.map((element, i) => ({...element, id: i})) listOfElementsNew.map((element, i) => ({ ...element, id: i }))
let newPosList = increasingList(listOfElementsNew.length) let newPosList = increasingList(listOfElementsNew.length)
setListOfElements(listOfElementsNew) setListOfElements(listOfElementsNew)
setPosList(increasingList(listOfElementsNew.length)) setPosList(increasingList(listOfElementsNew.length))
setToComparePair([newPosList[newPosList.length-2], newPosList[newPosList.length-1]]) setToComparePair([newPosList[newPosList.length - 2], newPosList[newPosList.length - 1]])
restart(newPosList) restart(newPosList)
} }
@ -124,9 +126,9 @@ export default function Home({listOfElementsDefault}) {
let compareTwoElements = (newBinaryComparisons, element1, element2) => { let compareTwoElements = (newBinaryComparisons, element1, element2) => {
let element1Greater = newBinaryComparisons.containsArray([element1, element2]) let element1Greater = newBinaryComparisons.containsArray([element1, element2])
let element2Greater = newBinaryComparisons.containsArray([element2, element1]) let element2Greater = newBinaryComparisons.containsArray([element2, element1])
if(element1Greater || element2Greater){ if (element1Greater || element2Greater) {
return element1Greater && !element2Greater return element1Greater && !element2Greater
} else{ } else {
setToComparePair([element1, element2]) setToComparePair([element1, element2])
//console.log(`No comparison found between ${element1} and ${element2}`) //console.log(`No comparison found between ${element1} and ${element2}`)
//console.log(`Comparisons:`) //console.log(`Comparisons:`)
@ -141,7 +143,7 @@ export default function Home({listOfElementsDefault}) {
while (left.length && right.length) { while (left.length && right.length) {
// insert the biggest element to the sortedArr // insert the biggest element to the sortedArr
let comparison = compareTwoElements(newBinaryComparisons, left[0], right[0]) let comparison = compareTwoElements(newBinaryComparisons, left[0], right[0])
if(comparison == "No comparison found"){ if (comparison == "No comparison found") {
return "No comparison found; unable to proceed" return "No comparison found; unable to proceed"
} }
else if (comparison) { // left[0] > right[0] else if (comparison) { // left[0] > right[0]
@ -155,9 +157,9 @@ export default function Home({listOfElementsDefault}) {
return [...sortedArr, ...left, ...right]; // if they don't have the same size, the remaining ones will be greater than the ones before return [...sortedArr, ...left, ...right]; // if they don't have the same size, the remaining ones will be greater than the ones before
} }
function mergeSort({array, comparisons}) { function mergeSort({ array, comparisons }) {
if(array == "No comparison found; unable to proceed"){ if (array == "No comparison found; unable to proceed") {
return "No comparison found; unable to proceed" return "No comparison found; unable to proceed"
} }
const half = array.length / 2; const half = array.length / 2;
@ -168,13 +170,13 @@ export default function Home({listOfElementsDefault}) {
const left = array.slice(0, half); // the first half of the array const left = array.slice(0, half); // the first half of the array
const right = array.slice(half, array.length) // Note that splice is destructive. const right = array.slice(half, array.length) // Note that splice is destructive.
let orderedFirstHalf = mergeSort({array:left, comparisons}) let orderedFirstHalf = mergeSort({ array: left, comparisons })
let orderedSecondHalf = mergeSort({array:right, comparisons}) let orderedSecondHalf = mergeSort({ array: right, comparisons })
if(orderedFirstHalf != "No comparison found; unable to proceed" && orderedSecondHalf != "No comparison found; unable to proceed"){ if (orderedFirstHalf != "No comparison found; unable to proceed" && orderedSecondHalf != "No comparison found; unable to proceed") {
let result = merge(comparisons, orderedFirstHalf, orderedSecondHalf); let result = merge(comparisons, orderedFirstHalf, orderedSecondHalf);
return result return result
}else{ } else {
return "No comparison found; unable to proceed" return "No comparison found; unable to proceed"
} }
} }
@ -189,9 +191,9 @@ export default function Home({listOfElementsDefault}) {
//console.log(JSON.stringify(newBinaryComparisons, null, 4)); //console.log(JSON.stringify(newBinaryComparisons, null, 4));
setBinaryComparisons(newBinaryComparisons) setBinaryComparisons(newBinaryComparisons)
let result = mergeSort({array: posList, comparisons: newBinaryComparisons}) let result = mergeSort({ array: posList, comparisons: newBinaryComparisons })
//console.log(result) //console.log(result)
if(result != "No comparison found; unable to proceed" && checkIfListIsOrdered(result, newBinaryComparisons)){ if (result != "No comparison found; unable to proceed" && checkIfListIsOrdered(result, newBinaryComparisons)) {
// console.log(`isListOrdered: ${isListOrdered}`) // console.log(`isListOrdered: ${isListOrdered}`)
console.log("poslist@nextStepSimple") console.log("poslist@nextStepSimple")
console.log(posList) console.log(posList)
@ -203,16 +205,16 @@ export default function Home({listOfElementsDefault}) {
} }
} }
let nextStepSlider = ({posList, binaryComparisons, sliderValue, element1, element2}) => { let nextStepSlider = ({ posList, binaryComparisons, sliderValue, element1, element2 }) => {
if(sliderValue < 0){ if (sliderValue < 0) {
sliderValue = -sliderValue; sliderValue = -sliderValue;
[element1,element2] = [element2,element1] [element1, element2] = [element2, element1]
} }
console.log(`posList@nextStepSlider:`) console.log(`posList@nextStepSlider:`)
console.log(posList) console.log(posList)
nextStepSimple(posList, binaryComparisons, element1, element2) nextStepSimple(posList, binaryComparisons, element1, element2)
let newQuantitativeComparison = [element1, element2, simplifySliderValue(sliderValue)] let newQuantitativeComparison = [element1, element2, transformSliderValueToPracticalValue(sliderValue)]
let newQuantitativeComparisons = [...quantitativeComparisons, newQuantitativeComparison] let newQuantitativeComparisons = [...quantitativeComparisons, newQuantitativeComparison]
setQuantitativeComparisons(newQuantitativeComparisons) setQuantitativeComparisons(newQuantitativeComparisons)
@ -231,37 +233,37 @@ export default function Home({listOfElementsDefault}) {
<main className="flex flex-col items-center w-full flex-1 px-20 text-center"> <main className="flex flex-col items-center w-full flex-1 px-20 text-center">
<h1 className="text-6xl font-bold"> <h1 className="text-6xl font-bold">
Utility Function Extractor Utility Function Extractor
</h1> </h1>
<div className = {`${isListOrdered ? "hidden" : ""}`}> <div className={`${isListOrdered ? "hidden" : ""}`}>
<div className="flex flex-wrap items-center max-w-4xl sm:w-full mt-10"> <div className="flex flex-wrap items-center max-w-4xl sm:w-full mt-10">
<div <div
className="flex m-auto border-gray-300 border-4 h-72 w-72 p-5" className="flex m-auto border-gray-300 border-4 h-72 w-72 p-5"
//onClick={() => nextStep(binaryComparisons, toComparePair[0], toComparePair[1])} //onClick={() => nextStep(binaryComparisons, toComparePair[0], toComparePair[1])}
> >
<div className="block m-auto text-center"> <div className="block m-auto text-center">
<DisplayElement element={listOfElements[toComparePair[0]]}> <DisplayElement element={listOfElements[toComparePair[0]]}>
</DisplayElement> </DisplayElement>
</div>
</div> </div>
<div </div>
className="flex m-auto border-gray-300 border-4 h-72 w-72 p-5" <div
//onClick={() => nextStep(binaryComparisons, toComparePair[1], toComparePair[0])} className="flex m-auto border-gray-300 border-4 h-72 w-72 p-5"
> //onClick={() => nextStep(binaryComparisons, toComparePair[1], toComparePair[0])}
<div className="block m-auto text-center"> >
<DisplayElement element={listOfElements[toComparePair[1]]}> <div className="block m-auto text-center">
</DisplayElement> <DisplayElement element={listOfElements[toComparePair[1]]}>
</div> </DisplayElement>
</div> </div>
</div>
</div> </div>
<div className={`flex row-start-3 row-end-3 col-start-1 col-end-4 md:col-start-3 md:col-end-3 md:row-start-1 md:row-end-1 lg:col-start-3 lg:col-end-3 lg:row-start-1 lg:row-end-1 items-center justify-center mb-4 mt-10 ${isListOrdered? "hidden" : ""}`}> <div className={`flex row-start-3 row-end-3 col-start-1 col-end-4 md:col-start-3 md:col-end-3 md:row-start-1 md:row-end-1 lg:col-start-3 lg:col-end-3 lg:row-start-1 lg:row-end-1 items-center justify-center mb-4 mt-10 ${isListOrdered ? "hidden" : ""}`}>
<SliderElement <SliderElement
className="flex items-center justify-center" className="flex items-center justify-center"
onChange={(event) => (setSliderValue(event[0]))} onChange={(event) => (setSliderValue(event[0]))}
value={sliderValue} value={sliderValue}
displayFunction={displayFunctionSlider} displayFunction={displayFunctionSlider}
/> />
</div> </div>
<SubmitSliderButton <SubmitSliderButton
posList={posList} posList={posList}
@ -279,14 +281,14 @@ export default function Home({listOfElementsDefault}) {
listOfElements={listOfElements} listOfElements={listOfElements}
links={buildLinks(quantitativeComparisons)}> links={buildLinks(quantitativeComparisons)}>
</DrawGraph> </DrawGraph>
<div className={`inline items-center text-center mt-10 ${isListOrdered? "": "hidden" }`}> <div className={`inline items-center text-center mt-10 ${isListOrdered ? "" : "hidden"}`}>
<CreateTableWithDistances <CreateTableWithDistances
isListOrdered={isListOrdered} isListOrdered={isListOrdered}
orderedList={orderedList} orderedList={orderedList}
listOfElements={listOfElements} listOfElements={listOfElements}
links={buildLinks(quantitativeComparisons)} links={buildLinks(quantitativeComparisons)}
> >
</CreateTableWithDistances> </CreateTableWithDistances>
</div> </div>
<div className="w-2/12 flex justify-center mt-10"> <div className="w-2/12 flex justify-center mt-10">
<button <button
@ -297,35 +299,35 @@ export default function Home({listOfElementsDefault}) {
</button> </button>
</div> </div>
<div className={`flex flex-wrap -mx-4 overflow-hidden ${showAdvancedOptions? "": "hidden"}`}> <div className={`flex flex-wrap -mx-4 overflow-hidden ${showAdvancedOptions ? "" : "hidden"}`}>
<div className="my-4 px-4 w-1/3 overflow-hidden"> <div className="my-4 px-4 w-1/3 overflow-hidden">
<button <button
className="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5" className="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5"
onClick={() => restart(posList)}> onClick={() => restart(posList)}>
Restart Restart
</button> </button>
</div> </div>
<div className="my-4 px-4 w-1/3 overflow-hidden"> <div className="my-4 px-4 w-1/3 overflow-hidden">
<button <button
className="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5" className="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5"
onClick={() => changeShowComparisons(!showComparisons)}> onClick={() => changeShowComparisons(!showComparisons)}>
Show comparisons Show comparisons
</button> </button>
</div> </div>
<div className="my-4 px-4 w-1/3 overflow-hidden"> <div className="my-4 px-4 w-1/3 overflow-hidden">
<button <button
className="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5" className="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5"
onClick={() => changeshowChangeDataSet(!showChangeDataSet)}> onClick={() => changeshowChangeDataSet(!showChangeDataSet)}>
Use your own data Use your own data
</button> </button>
</div> </div>
</div> </div>
<div className={`inline mt-5 ${showChangeDataSet ? "": "hidden" }`}> <div className={`inline mt-5 ${showChangeDataSet ? "" : "hidden"}`}>
<TextAreaForJson handleSubmit={changeDataSet}/> <TextAreaForJson handleSubmit={changeDataSet} />
</div> </div>
<div className={`inline mt-5 ${showComparisons? "": "hidden" }`}> <div className={`inline mt-5 ${showComparisons ? "" : "hidden"}`}>
{/* {/*
<DisplayAsMarkdown markdowntext={"## Ordered list\n\n" + JSON.stringify(orderedList.map(i => listOfElements[i]), null, 4)}></DisplayAsMarkdown> <DisplayAsMarkdown markdowntext={"## Ordered list\n\n" + JSON.stringify(orderedList.map(i => listOfElements[i]), null, 4)}></DisplayAsMarkdown>
*/} */}

View File

@ -0,0 +1,29 @@
[
{
"name": "Doubling consumption for one person for one year",
"note": "(at fairly low levels of wealth)",
"isReferenceValue": true
},
{
"name": "Averting the death of an individual under 5 from malaria"
},
{
"name": "Averting the death of an individual 5 or older from malaria"
},
{
"name": "Averting the death of a 6- to 59-month-old child",
"note": "(through Vitamin A Supplementation)"
},
{
"name": "Averting the death of an individual under 5 from vaccine-preventable diseases"
},
{
"name": "Averting the death of an individual 5-14 years old from vaccine-preventable diseases"
},
{
"name": "Averting the death of an individual 15-49 years old from vaccine-preventable diseases"
},
{
"name": "Averting the death of an individual 50-74 years old from vaccine-preventable diseases"
}
]