feat: cleanup
8
packages/README.md
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[](./webpage-refactor/public/example-graph.png)
|
||||||
|
|
||||||
|
This repository contains the code for the website [utility-function-extractor.quantifieduncertainty.org/](https://utility-function-extractor.quantifieduncertainty.org/) and tools to analyze utility comparisons. For details, see the relevant folders.
|
||||||
|
|
||||||
|
- [Webpage repository](to do: add links)
|
||||||
|
- [Tools repository](to do: add link)
|
||||||
|
|
||||||
|
[](./webpage-refactor/public/example-table.png)
|
1
packages/webpage-legacy/README.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Deprecated; see webpage-refactor instead.
|
Before Width: | Height: | Size: 289 KiB After Width: | Height: | Size: 289 KiB |
Before Width: | Height: | Size: 294 KiB After Width: | Height: | Size: 294 KiB |
Before Width: | Height: | Size: 336 KiB After Width: | Height: | Size: 336 KiB |
Before Width: | Height: | Size: 282 KiB After Width: | Height: | Size: 282 KiB |
Before Width: | Height: | Size: 266 KiB After Width: | Height: | Size: 266 KiB |
Before Width: | Height: | Size: 294 KiB After Width: | Height: | Size: 294 KiB |
|
@ -354,7 +354,7 @@ export function CreateTable({ tableRows }) {
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<table className="w-full">
|
<table className="table-auto">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Id</th>
|
<th>Id</th>
|
337
packages/webpage-legacy/lib/pushToMongoManually.js
Normal file
|
@ -0,0 +1,337 @@
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
let data = [
|
||||||
|
{
|
||||||
|
source: "Thinking Fast and Slow",
|
||||||
|
|
||||||
|
target: "The Mathematical Theory of Communication",
|
||||||
|
|
||||||
|
distance: 99999.99999999999,
|
||||||
|
|
||||||
|
reasoning:
|
||||||
|
"TFS: Not original work. 1 million buyers, 0.3m readers, 0.03m did anything with it long-term. Debiasing doesn't work that much. But maybe some general sanity effects.\nMTC: foundational to half of good fields. Direct applications key to telecoms and internet, AI. Is very natural and probably invented anyway, but let's ignore replaceability. ",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "The Global Priorities Institute's Research Agenda",
|
||||||
|
|
||||||
|
target: "Superintelligence",
|
||||||
|
|
||||||
|
distance: 100,
|
||||||
|
|
||||||
|
reasoning:
|
||||||
|
"GPI: good stuff but v v hard questions read by ~200.\nSuperintelligence: Maybe 50,000 copies? associated interview tour transformed the field.",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "Thinking Fast and Slow",
|
||||||
|
|
||||||
|
target: "The Global Priorities Institute's Research Agenda",
|
||||||
|
|
||||||
|
distance: "100",
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "The Global Priorities Institute's Research Agenda",
|
||||||
|
|
||||||
|
target: "The Mathematical Theory of Communication",
|
||||||
|
|
||||||
|
distance: 1000,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "Superintelligence",
|
||||||
|
|
||||||
|
target: "The Mathematical Theory of Communication",
|
||||||
|
|
||||||
|
distance: 10,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "Categorizing Variants of Goodhart's Law",
|
||||||
|
|
||||||
|
target: "The Vulnerable World Hypothesis",
|
||||||
|
|
||||||
|
distance: 10,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "Shallow evaluations of longtermist organizations",
|
||||||
|
|
||||||
|
target: "The motivated reasoning critique of effective altruism",
|
||||||
|
|
||||||
|
distance: 10,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "Shallow evaluations of longtermist organizations",
|
||||||
|
|
||||||
|
target: "Categorizing Variants of Goodhart's Law",
|
||||||
|
|
||||||
|
distance: 100,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "The motivated reasoning critique of effective altruism",
|
||||||
|
|
||||||
|
target: "Categorizing Variants of Goodhart's Law",
|
||||||
|
|
||||||
|
distance: 10,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "Shallow evaluations of longtermist organizations",
|
||||||
|
|
||||||
|
target: "Thinking Fast and Slow",
|
||||||
|
|
||||||
|
distance: 10,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "Thinking Fast and Slow",
|
||||||
|
|
||||||
|
target: "The motivated reasoning critique of effective altruism",
|
||||||
|
|
||||||
|
distance: 1,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "The motivated reasoning critique of effective altruism",
|
||||||
|
|
||||||
|
target: "The Global Priorities Institute's Research Agenda",
|
||||||
|
|
||||||
|
distance: 1000,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "Categorizing Variants of Goodhart's Law",
|
||||||
|
|
||||||
|
target: "The Global Priorities Institute's Research Agenda",
|
||||||
|
|
||||||
|
distance: 100,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "The Vulnerable World Hypothesis",
|
||||||
|
|
||||||
|
target: "The Global Priorities Institute's Research Agenda",
|
||||||
|
|
||||||
|
distance: 10,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "Reversals in Psychology",
|
||||||
|
|
||||||
|
target: "A Model of Patient Spending and Movement Building",
|
||||||
|
|
||||||
|
distance: 10,
|
||||||
|
|
||||||
|
reasoning:
|
||||||
|
"RiP: Cleaning up 10,000 people's brains a bit.\nMPS: far more important topic",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "Database of orgs relevant to longtermist/x-risk work",
|
||||||
|
|
||||||
|
target:
|
||||||
|
"What are some low-information priors that you find practically useful for thinking about the world?",
|
||||||
|
|
||||||
|
distance: "5",
|
||||||
|
|
||||||
|
reasoning:
|
||||||
|
"\nDatabase just saves a bit of time, maybe 100 counterfactual applications",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "Reversals in Psychology",
|
||||||
|
|
||||||
|
target: "Database of orgs relevant to longtermist/x-risk work",
|
||||||
|
|
||||||
|
distance: 1,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "Database of orgs relevant to longtermist/x-risk work",
|
||||||
|
|
||||||
|
target: "A Model of Patient Spending and Movement Building",
|
||||||
|
|
||||||
|
distance: 10,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source:
|
||||||
|
"What are some low-information priors that you find practically useful for thinking about the world?",
|
||||||
|
|
||||||
|
target: "A Model of Patient Spending and Movement Building",
|
||||||
|
|
||||||
|
distance: 2,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "Center for Election Science EA Wiki stub",
|
||||||
|
|
||||||
|
target:
|
||||||
|
"Extinguishing or preventing coal seam fires is a potential cause area",
|
||||||
|
|
||||||
|
distance: 1000,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "A comment on setting up a charity",
|
||||||
|
|
||||||
|
target: "Center for Election Science EA Wiki stub",
|
||||||
|
|
||||||
|
distance: 10,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "A comment on setting up a charity",
|
||||||
|
|
||||||
|
target: "Reversals in Psychology",
|
||||||
|
|
||||||
|
distance: 200,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "Center for Election Science EA Wiki stub",
|
||||||
|
|
||||||
|
target: "Reversals in Psychology",
|
||||||
|
|
||||||
|
distance: 20,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "Reversals in Psychology",
|
||||||
|
|
||||||
|
target:
|
||||||
|
"Extinguishing or preventing coal seam fires is a potential cause area",
|
||||||
|
|
||||||
|
distance: "50",
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "Database of orgs relevant to longtermist/x-risk work",
|
||||||
|
|
||||||
|
target:
|
||||||
|
"Extinguishing or preventing coal seam fires is a potential cause area",
|
||||||
|
|
||||||
|
distance: "50",
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source:
|
||||||
|
"What are some low-information priors that you find practically useful for thinking about the world?",
|
||||||
|
|
||||||
|
target:
|
||||||
|
"Extinguishing or preventing coal seam fires is a potential cause area",
|
||||||
|
|
||||||
|
distance: "10",
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "A Model of Patient Spending and Movement Building",
|
||||||
|
|
||||||
|
target:
|
||||||
|
"Extinguishing or preventing coal seam fires is a potential cause area",
|
||||||
|
|
||||||
|
distance: 1,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "A comment on setting up a charity",
|
||||||
|
|
||||||
|
target: "Shallow evaluations of longtermist organizations",
|
||||||
|
|
||||||
|
distance: 1000,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "Center for Election Science EA Wiki stub",
|
||||||
|
|
||||||
|
target: "Shallow evaluations of longtermist organizations",
|
||||||
|
|
||||||
|
distance: 100,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "Reversals in Psychology",
|
||||||
|
|
||||||
|
target: "Shallow evaluations of longtermist organizations",
|
||||||
|
|
||||||
|
distance: 100,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
source: "Database of orgs relevant to longtermist/x-risk work",
|
||||||
|
|
||||||
|
target: "Shallow evaluations of longtermist organizations",
|
||||||
|
|
||||||
|
distance: 100,
|
||||||
|
|
||||||
|
reasoning: "",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
async function pushToMongoManually() {
|
||||||
|
let response = await axios.post(
|
||||||
|
"http://metaforecast-twitter-bot.herokuapp.com/utility-function-extractor",
|
||||||
|
{
|
||||||
|
data: data,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
console.log(response);
|
||||||
|
}
|
||||||
|
pushToMongoManually();
|
||||||
|
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
1702
packages/webpage-refactor/LICENSE.txt
Normal file
|
@ -4,13 +4,37 @@ This repository creates a react webpage that allows to extract a utility functio
|
||||||
|
|
||||||
It presents the users with a series of elements to compare, using merge-sort in the background to cleverly minimize the number of choices needed.
|
It presents the users with a series of elements to compare, using merge-sort in the background to cleverly minimize the number of choices needed.
|
||||||
|
|
||||||
Then, it cleverly aggregates them, by taking each element as a reference point in turn, and computing the possible distances from that reference point to all other points, and taking the geometric mean of these distances. This produces a number representing the value of each element, such that the ratios between elements represent the user's preferences: a utility function.
|
![](./public/example-prompt.png)
|
||||||
|
|
||||||
|
Then, it cleverly aggregates them, on the one hand by producing a graphical representation:
|
||||||
|
|
||||||
|
![](./public/example-graph.png)
|
||||||
|
|
||||||
|
and on the other hand doing some fast and clever mean aggregation [^1]:
|
||||||
|
|
||||||
|
![](./public/example-table.png)
|
||||||
|
|
||||||
Initially, users could only input numbers, e.g., "A is `3` times better than B". But now, users can also input distributions, using the [squiggle](https://www.squiggle-language.com/) syntax, e.g., "A is `1 to 10` times better than B", or "A is `mm(normal(1, 10), uniform(0,100))` better than B".
|
Initially, users could only input numbers, e.g., "A is `3` times better than B". But now, users can also input distributions, using the [squiggle](https://www.squiggle-language.com/) syntax, e.g., "A is `1 to 10` times better than B", or "A is `mm(normal(1, 10), uniform(0,100))` better than B".
|
||||||
|
|
||||||
##
|
**If you want to use the utility function extractor for a project, we are happy to add a page for your project, like `utility-function-extractor.quantifieduncertainty.org/your-project`**.
|
||||||
|
|
||||||
## Object structure
|
## Built with
|
||||||
|
|
||||||
|
- [Nextjs](https://nextjs.org/)
|
||||||
|
- [Netlify](https://github.com/netlify/netlify-plugin-nextjs/#readme)
|
||||||
|
- [React](https://reactjs.org/)
|
||||||
|
- [Squiggle](https://www.squiggle-language.com/)
|
||||||
|
- [Utility tools](to do: add links)
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Navigate to [utility-function-extractor.quantifieduncertainty.org/](https://utility-function-extractor.quantifieduncertainty.org/), and start comparing objects.
|
||||||
|
|
||||||
|
You can change the list of objects to be compared by clicking on "advanced options".
|
||||||
|
|
||||||
|
After comparing objects for a while, you will get a table and a graph with results. You can also use the [utility tools](to do: add link) package to process these results, for which you will need the json of comparisons, which can be found in "Advanced options" -> "Load comparisons"
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
The core structure is json array of objects. Only the "name" attribute is required. If there is a "url", it is displayed nicely.
|
The core structure is json array of objects. Only the "name" attribute is required. If there is a "url", it is displayed nicely.
|
||||||
|
|
||||||
|
@ -29,9 +53,35 @@ The core structure is json array of objects. Only the "name" attribute is requir
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Netlify
|
The core structure for links is as follows:
|
||||||
|
|
||||||
https://github.com/netlify/netlify-plugin-nextjs/#readme
|
```
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"source": "Peter Parker",
|
||||||
|
"target": "Spiderman",
|
||||||
|
"squiggleString": "1 to 100",
|
||||||
|
"distance": 26.639800977355474
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "Spiderman",
|
||||||
|
"target": "Doctor Octopus",
|
||||||
|
"squiggleString": "20 to 2000",
|
||||||
|
"distance": 6.76997149080232
|
||||||
|
},
|
||||||
|
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
A previous version of this webpage had a more complicated structure, but it has since been simplified.
|
||||||
|
|
||||||
|
## Contributions and help
|
||||||
|
|
||||||
|
We welcome PR requests.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Distributed under the MIT License. See LICENSE.txt for more information.
|
||||||
|
|
||||||
## To do
|
## To do
|
||||||
|
|
||||||
|
@ -40,12 +90,16 @@ https://github.com/netlify/netlify-plugin-nextjs/#readme
|
||||||
- [x] Push to github
|
- [x] Push to github
|
||||||
- [x] Push to netlify
|
- [x] Push to netlify
|
||||||
- [x] Don't allow further comparisons after completion
|
- [x] Don't allow further comparisons after completion
|
||||||
- [ ] Paths table
|
- [x] Paths table
|
||||||
- [ ] Add paths table
|
- [x] Add paths table
|
||||||
- [ ] warn that the paths table is approximate.
|
- [x] warn that the paths table is approximate.
|
||||||
- However, I really don't feel like re-adding this after having worked out the distribution rather than the mean aggregation
|
- However, I really don't feel like re-adding this after having worked out the distribution rather than the mean aggregation
|
||||||
- However, I think it does make it more user to other users.
|
- However, I think it does make it more user to other users.
|
||||||
- [ ] Add functionality like names, etc.
|
- [ ] Add functionality like names, etc.
|
||||||
- I also don't feel like doing this
|
- I also don't feel like doing this
|
||||||
- [ ] Look back at Amazon thing which has been running
|
- [ ] Look back at Amazon thing which has been running
|
||||||
- [ ] Change README.
|
- [x] Change README.
|
||||||
|
|
||||||
|
## Footnotes
|
||||||
|
|
||||||
|
[^1]: The program takes each element as a reference point in turn, and computing the possible distances from that reference point to all other points, and taking the geometric mean of these distances. This produces a number representing the value of each element, such that the ratios between elements represent the user's preferences: a utility function. However, this isn't perfect; the principled approach woud be to aggregate the distributions rather than their means. But this principled approach is much more slowly. For the principled approach, see the `utility-tools` repository.
|
||||||
|
|
|
@ -39,11 +39,12 @@ export function AdvancedOptions({
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="">
|
||||||
<br />
|
<br />
|
||||||
{/* Show advanced options*/}
|
{/* Show advanced options*/}
|
||||||
<button
|
<button
|
||||||
className="text-gray-500 text-sm"
|
key={"advancedOptionsButton-top"}
|
||||||
|
className="text-gray-500 text-sm "
|
||||||
onClick={() => changeShowAdvanceOptions(!showAdvancedOptions)}
|
onClick={() => changeShowAdvanceOptions(!showAdvancedOptions)}
|
||||||
>
|
>
|
||||||
Advanced options ▼
|
Advanced options ▼
|
||||||
|
@ -56,7 +57,7 @@ export function AdvancedOptions({
|
||||||
<button
|
<button
|
||||||
className={effectButtonStyle}
|
className={effectButtonStyle}
|
||||||
onClick={() => buttonToggles[i]()}
|
onClick={() => buttonToggles[i]()}
|
||||||
id={`advancedOptionsButton-${i}`}
|
key={`advancedOptionsButton-${i}`}
|
||||||
>
|
>
|
||||||
{buttonName}
|
{buttonName}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
|
import { Separator } from "../separator.js";
|
||||||
|
|
||||||
// import JSONInput from "react-json-editor-ajrm/index";
|
// import JSONInput from "react-json-editor-ajrm/index";
|
||||||
// import locale from "react-json-editor-ajrm/locale/en";
|
// import locale from "react-json-editor-ajrm/locale/en";
|
||||||
|
@ -75,6 +76,7 @@ export function ComparisonsChanger({
|
||||||
onSubmit={handleSubmitInner}
|
onSubmit={handleSubmitInner}
|
||||||
className={`inline ${show ? "" : "hidden"}`}
|
className={`inline ${show ? "" : "hidden"}`}
|
||||||
>
|
>
|
||||||
|
<Separator />
|
||||||
<h3 className="text-lg mt-8">Load comparisons</h3>
|
<h3 className="text-lg mt-8">Load comparisons</h3>
|
||||||
<p>These can be edited, which will override your current comparisons.</p>
|
<p>These can be edited, which will override your current comparisons.</p>
|
||||||
<br />
|
<br />
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
import { Separator } from "../separator.js";
|
||||||
|
|
||||||
export function DataSetChanger({ onChangeOfDataset, show, listOfElements }) {
|
export function DataSetChanger({ onChangeOfDataset, show, listOfElements }) {
|
||||||
/*let [value, setValue] = useState(`[
|
/*let [value, setValue] = useState(`[
|
||||||
|
@ -54,6 +55,7 @@ export function DataSetChanger({ onChangeOfDataset, show, listOfElements }) {
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className={`${show ? "" : "hidden"} `}>
|
<div className={`${show ? "" : "hidden"} `}>
|
||||||
|
<Separator />
|
||||||
<form onSubmit={handleSubmitInner} className="inline mt-0">
|
<form onSubmit={handleSubmitInner} className="inline mt-0">
|
||||||
<h3 className="text-lg mt-8 mb-4">Change dataset</h3>
|
<h3 className="text-lg mt-8 mb-4">Change dataset</h3>
|
||||||
<textarea
|
<textarea
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import React, { state } from "react";
|
import React, { state } from "react";
|
||||||
import { CopyBlock, googlecode } from "react-code-blocks";
|
import { CopyBlock, googlecode } from "react-code-blocks";
|
||||||
|
import { Separator } from "../separator.js";
|
||||||
// googlecode
|
// googlecode
|
||||||
|
|
||||||
export function ShowComparisons({ links, show }) {
|
export function ShowComparisons({ links, show }) {
|
||||||
return (
|
return (
|
||||||
<div className={`text-left ${show ? "" : "hidden"}`}>
|
<div className={`text-left ${show ? "" : "hidden"}`}>
|
||||||
|
<Separator />
|
||||||
<h3 className="text-lg mt-8">Comparisons</h3>
|
<h3 className="text-lg mt-8">Comparisons</h3>
|
||||||
<CopyBlock
|
<CopyBlock
|
||||||
text={JSON.stringify(links, null, 4)}
|
text={JSON.stringify(links, null, 4)}
|
||||||
|
|
|
@ -2,11 +2,13 @@ import React, { useEffect, useState, useRef } from "react";
|
||||||
import colormap from "colormap";
|
import colormap from "colormap";
|
||||||
import cytoscape from "cytoscape";
|
import cytoscape from "cytoscape";
|
||||||
import spread from "cytoscape-spread";
|
import spread from "cytoscape-spread";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
resolveToNumIfPossible,
|
resolveToNumIfPossible,
|
||||||
getSquiggleSparkline,
|
getSquiggleSparkline,
|
||||||
} from "../../lib/squiggle.js";
|
} from "../../lib/squiggle.js";
|
||||||
import { truncateValueForDisplay } from "../../lib/truncateNums.js";
|
import { truncateValueForDisplay } from "../../lib/truncateNums.js";
|
||||||
|
import { cutOffLongNames } from "../../lib/stringManipulations.js";
|
||||||
|
|
||||||
// import dagre from "cytoscape-dagre";
|
// import dagre from "cytoscape-dagre";
|
||||||
// import cola from "cytoscape-cola";
|
// import cola from "cytoscape-cola";
|
||||||
|
@ -38,32 +40,30 @@ const getEdgeLabel = async (squiggleString) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const getColors = (n) => {
|
const getColors = (n) => {
|
||||||
let colors = colormap({
|
let colors;
|
||||||
colormap: "viridis",
|
if (n >= 9) {
|
||||||
nshades: n,
|
colors = colormap({
|
||||||
format: "hex",
|
colormap: "viridis",
|
||||||
alpha: 1,
|
nshades: n,
|
||||||
});
|
format: "hex",
|
||||||
return colors;
|
alpha: 1,
|
||||||
};
|
});
|
||||||
|
|
||||||
const cutOffLongNames = (string) => {
|
|
||||||
let maxLength = 40;
|
|
||||||
let result;
|
|
||||||
if (string.length < maxLength) {
|
|
||||||
result = string;
|
|
||||||
} else {
|
} else {
|
||||||
result = string.slice(0, maxLength - 4);
|
colors = colormap({
|
||||||
result = result + "...";
|
colormap: "greys", // hot,
|
||||||
|
nshades: n,
|
||||||
|
format: "hex",
|
||||||
|
alpha: 1,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return result;
|
return colors;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function Graph({
|
export function Graph({
|
||||||
listOfElements,
|
listOfElements,
|
||||||
links,
|
links,
|
||||||
isListOrdered,
|
isListOrdered,
|
||||||
mergeSortOrder,
|
listAfterMergeSort,
|
||||||
}) {
|
}) {
|
||||||
const containerRef = useRef("hello-world");
|
const containerRef = useRef("hello-world");
|
||||||
const [visibility, setVisibility] = useState(""); /// useState("invisible");
|
const [visibility, setVisibility] = useState(""); /// useState("invisible");
|
||||||
|
@ -72,14 +72,14 @@ export function Graph({
|
||||||
listOfElements,
|
listOfElements,
|
||||||
links,
|
links,
|
||||||
isListOrdered,
|
isListOrdered,
|
||||||
mergeSortOrder,
|
listAfterMergeSort,
|
||||||
}) => {
|
}) => {
|
||||||
//setVisibility("invisible");
|
//setVisibility("invisible");
|
||||||
let layoutName = "circle"; //
|
let layoutName = "circle"; //
|
||||||
|
|
||||||
// cytoscape.use(circle); // spread, circle,
|
// cytoscape.use(circle); // spread, circle,
|
||||||
let listOfElementsForGraph = isListOrdered
|
let listOfElementsForGraph = isListOrdered
|
||||||
? mergeSortOrder
|
? listAfterMergeSort
|
||||||
: listOfElements;
|
: listOfElements;
|
||||||
|
|
||||||
let colors = new Array(listOfElements.length);
|
let colors = new Array(listOfElements.length);
|
||||||
|
@ -92,10 +92,11 @@ export function Graph({
|
||||||
data: {
|
data: {
|
||||||
id: cutOffLongNames(element.name),
|
id: cutOffLongNames(element.name),
|
||||||
color: colors[i] || "darkgreen",
|
color: colors[i] || "darkgreen",
|
||||||
labelColor:
|
labelColor: isListOrdered
|
||||||
isListOrdered && i >= listOfElementsForGraph.length - 2
|
? i >= listOfElementsForGraph.length - 2
|
||||||
? "black"
|
? "black"
|
||||||
: "white",
|
: "white"
|
||||||
|
: "white",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -195,22 +196,38 @@ export function Graph({
|
||||||
userPanningEnabled: false,
|
userPanningEnabled: false,
|
||||||
};
|
};
|
||||||
cytoscape(config);
|
cytoscape(config);
|
||||||
// setTimeout(() => setVisibility(""), 700);
|
//setTimeout(() => setVisibility(""), 700);
|
||||||
};
|
};
|
||||||
useEffect(async () => {
|
useEffect(async () => {
|
||||||
await callEffect({ listOfElements, links, isListOrdered, mergeSortOrder });
|
await callEffect({
|
||||||
|
listOfElements,
|
||||||
|
links,
|
||||||
|
isListOrdered,
|
||||||
|
listAfterMergeSort,
|
||||||
|
});
|
||||||
// console.log(JSON.stringify(config, null, 10));
|
// console.log(JSON.stringify(config, null, 10));
|
||||||
}, [listOfElements, links, isListOrdered]);
|
}, [listOfElements, links, isListOrdered, listAfterMergeSort]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="">
|
||||||
<div className={visibility}>
|
<div className={visibility + "grid grid-cols-1 place-items-center "}>
|
||||||
<div ref={containerRef} style={{ height: "900px", width: "1000px" }} />
|
<div
|
||||||
|
ref={containerRef}
|
||||||
|
style={{
|
||||||
|
height: "900px", // isListOrdered ? "900px" : "500px",
|
||||||
|
width: "900px", // isListOrdered ? "900px" : "500px",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
className={effectButtonStyle}
|
className={effectButtonStyle}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
callEffect({ listOfElements, links, isListOrdered, mergeSortOrder })
|
callEffect({
|
||||||
|
listOfElements,
|
||||||
|
links,
|
||||||
|
isListOrdered,
|
||||||
|
listAfterMergeSort,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{"Redraw graph"}
|
{"Redraw graph"}
|
||||||
|
|
|
@ -1,89 +0,0 @@
|
||||||
import { SimpleReactCytoscape } from "simple-react-cytoscape";
|
|
||||||
import { Core } from "cytoscape";
|
|
||||||
import { useCallback, useState } from "react";
|
|
||||||
|
|
||||||
/*
|
|
||||||
const elements = [
|
|
||||||
// list of graph elements to start with
|
|
||||||
{
|
|
||||||
// node a
|
|
||||||
data: { id: "a" },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// node b
|
|
||||||
data: { id: "b" },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// node c
|
|
||||||
data: { id: "c" },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// edge ab
|
|
||||||
data: { id: "ab", source: "a", target: "b" },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// edge ab
|
|
||||||
data: { id: "ac", source: "a", target: "c" },
|
|
||||||
},
|
|
||||||
];
|
|
||||||
*/
|
|
||||||
|
|
||||||
const style = [
|
|
||||||
// the stylesheet for the graph
|
|
||||||
{
|
|
||||||
selector: "node",
|
|
||||||
style: {
|
|
||||||
"background-color": "#666",
|
|
||||||
label: "data(id)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
selector: "edge",
|
|
||||||
style: {
|
|
||||||
width: 3,
|
|
||||||
"line-color": "#ccc",
|
|
||||||
"target-arrow-color": "#ccc",
|
|
||||||
"target-arrow-shape": "triangle",
|
|
||||||
"curve-style": "bezier",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export function Graph({ listOfElements, links }) {
|
|
||||||
const [myCy, setMyCy] = useState();
|
|
||||||
|
|
||||||
const cyCallback = useCallback(
|
|
||||||
(cy) => {
|
|
||||||
setMyCy(cy);
|
|
||||||
},
|
|
||||||
[listOfElements, links]
|
|
||||||
);
|
|
||||||
|
|
||||||
let nodeElements = listOfElements.map((element) => {
|
|
||||||
return { data: { id: element.name } };
|
|
||||||
});
|
|
||||||
let linkElements = links.map((link, i) => {
|
|
||||||
return {
|
|
||||||
data: {
|
|
||||||
id: `link-i`,
|
|
||||||
source: link.source,
|
|
||||||
target: link.target,
|
|
||||||
label: link.distance,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
let elements = [...nodeElements, ...linkElements];
|
|
||||||
let options = {
|
|
||||||
elements,
|
|
||||||
style,
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div className="App">
|
|
||||||
<p>"a"</p>
|
|
||||||
<SimpleReactCytoscape options={options} cyCallback={cyCallback} />
|
|
||||||
<h3>JSON representation</h3>
|
|
||||||
{/*<p>{myCy && JSON.stringify(myCy.json())}</p>*/}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
import React, { useEffect, useMemo, useState } from "react";
|
|
||||||
import cytoscape from "cytoscape";
|
|
||||||
|
|
||||||
export function Graph({ listOfElements, links, options, getCy }) {
|
|
||||||
const [cy, setCy] = useState();
|
|
||||||
const id = useRef("cytoscape-id");
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!cy) {
|
|
||||||
let container = null;
|
|
||||||
try {
|
|
||||||
container = document.getElementById(id) || undefined;
|
|
||||||
} catch (e) {
|
|
||||||
// Might be running Headless (the unit test are headless)
|
|
||||||
container = undefined;
|
|
||||||
}
|
|
||||||
const newCy = cytoscape({
|
|
||||||
...options,
|
|
||||||
container,
|
|
||||||
});
|
|
||||||
setCy(newCy);
|
|
||||||
// If a callback was supplied we can now return the value
|
|
||||||
if (getCy) {
|
|
||||||
getCy(newCy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [cy, getCy, id, options]);
|
|
||||||
|
|
||||||
return <div id={id} className="simple-react-cytoscape" />;
|
|
||||||
}
|
|
|
@ -5,6 +5,8 @@ import { Title } from "./title.js";
|
||||||
import { ProgressIndicator } from "./progressIndicator.js";
|
import { ProgressIndicator } from "./progressIndicator.js";
|
||||||
import { DisplayElementForComparison } from "./displayElementForComparison.js";
|
import { DisplayElementForComparison } from "./displayElementForComparison.js";
|
||||||
import { ComparisonActuator } from "./comparisonActuator.js";
|
import { ComparisonActuator } from "./comparisonActuator.js";
|
||||||
|
import { Separator } from "./separator.js";
|
||||||
|
import { ResultsTable } from "./resultsTable.js";
|
||||||
|
|
||||||
import { AdvancedOptions } from "./advancedOptions/advancedOptions.js";
|
import { AdvancedOptions } from "./advancedOptions/advancedOptions.js";
|
||||||
import { Graph } from "./graph/graph.js";
|
import { Graph } from "./graph/graph.js";
|
||||||
|
@ -26,7 +28,7 @@ export function Homepage({ listOfElementsInit }) {
|
||||||
|
|
||||||
// is list ordered?
|
// is list ordered?
|
||||||
const [isListOrdered, setIsListOrdered] = useState(false);
|
const [isListOrdered, setIsListOrdered] = useState(false);
|
||||||
const [mergeSortOrder, setMergeSortOrder] = useState([]);
|
const [listAfterMergeSort, setListAfterMergeSort] = useState([]);
|
||||||
|
|
||||||
// list of comparisons
|
// list of comparisons
|
||||||
const [links, setLinks] = useState([]);
|
const [links, setLinks] = useState([]);
|
||||||
|
@ -48,6 +50,7 @@ export function Homepage({ listOfElementsInit }) {
|
||||||
setPairCurrentlyBeingCompared([newListOfElements[0], newListOfElements[1]]);
|
setPairCurrentlyBeingCompared([newListOfElements[0], newListOfElements[1]]);
|
||||||
setNumStepsNow(0);
|
setNumStepsNow(0);
|
||||||
setIsListOrdered(false);
|
setIsListOrdered(false);
|
||||||
|
setListAfterMergeSort([]);
|
||||||
};
|
};
|
||||||
|
|
||||||
// process next step
|
// process next step
|
||||||
|
@ -62,9 +65,9 @@ export function Homepage({ listOfElementsInit }) {
|
||||||
setIsListOrdered(false);
|
setIsListOrdered(false);
|
||||||
setPairCurrentlyBeingCompared(newPairToCompare);
|
setPairCurrentlyBeingCompared(newPairToCompare);
|
||||||
} else {
|
} else {
|
||||||
setIsListOrdered(true);
|
setListAfterMergeSort(mergeSortOutput.orderedList);
|
||||||
setMergeSortOrder(mergeSortOutput.orderedList);
|
|
||||||
pushToMongo({ mergeSortOutput, links });
|
pushToMongo({ mergeSortOutput, links });
|
||||||
|
setIsListOrdered(true); // good if it's at the end.
|
||||||
// alert(JSON.stringify(mergeSortOutput, null, 4));
|
// alert(JSON.stringify(mergeSortOutput, null, 4));
|
||||||
// chooseNextPairToCompareRandomly({ listOfElements });
|
// chooseNextPairToCompareRandomly({ listOfElements });
|
||||||
// return 1;
|
// return 1;
|
||||||
|
@ -118,6 +121,7 @@ export function Homepage({ listOfElementsInit }) {
|
||||||
numStepsNow={numStepsNow}
|
numStepsNow={numStepsNow}
|
||||||
numElements={listOfElements.length}
|
numElements={listOfElements.length}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Comparisons section */}
|
{/* Comparisons section */}
|
||||||
<div className={"" /*isListOrdered ? "hidden" : ""*/}>
|
<div className={"" /*isListOrdered ? "hidden" : ""*/}>
|
||||||
<div className="flex justify-evenly mt-10">
|
<div className="flex justify-evenly mt-10">
|
||||||
|
@ -137,26 +141,32 @@ export function Homepage({ listOfElementsInit }) {
|
||||||
></DisplayElementForComparison>
|
></DisplayElementForComparison>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* <Graph />
|
|
||||||
|
|
||||||
|
{/* <Results table /> */}
|
||||||
|
<ResultsTable
|
||||||
|
isListOrdered={isListOrdered}
|
||||||
|
listAfterMergeSort={listAfterMergeSort}
|
||||||
|
links={links}
|
||||||
|
/>
|
||||||
|
|
||||||
*/}
|
{/* <Graph /> */}
|
||||||
|
<Separator />
|
||||||
<Graph
|
<Graph
|
||||||
listOfElements={listOfElements}
|
listOfElements={listOfElements}
|
||||||
links={links}
|
links={links}
|
||||||
isListOrdered={isListOrdered}
|
isListOrdered={isListOrdered}
|
||||||
mergeSortOrder={mergeSortOrder}
|
listAfterMergeSort={listAfterMergeSort}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Advanced options section */}
|
{/* Advanced options section */}
|
||||||
<div>
|
<Separator />
|
||||||
<AdvancedOptions
|
<AdvancedOptions
|
||||||
links={links}
|
links={links}
|
||||||
setLinks={setLinks}
|
setLinks={setLinks}
|
||||||
listOfElements={listOfElements}
|
listOfElements={listOfElements}
|
||||||
moveToNextStep={moveToNextStep}
|
moveToNextStep={moveToNextStep}
|
||||||
onChangeOfDataset={onChangeOfDataset}
|
onChangeOfDataset={onChangeOfDataset}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
166
packages/webpage-refactor/components/resultsTable.js
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
import { findDistances, aggregatePaths } from "utility-tools";
|
||||||
|
|
||||||
|
import { Separator } from "./separator.js";
|
||||||
|
|
||||||
|
import { truncateValueForDisplay } from "../lib/truncateNums.js";
|
||||||
|
import { cutOffLongNames } from "../lib/stringManipulations.js";
|
||||||
|
|
||||||
|
async function fullResultsTable({ listAfterMergeSort, links }) {
|
||||||
|
console.log("listAfterMergeSort", listAfterMergeSort);
|
||||||
|
console.log(links);
|
||||||
|
let pathsArray = await findDistances({
|
||||||
|
orderedList: listAfterMergeSort,
|
||||||
|
links: links,
|
||||||
|
});
|
||||||
|
// console.log(pathsArray);
|
||||||
|
let aggregatedPaths = await aggregatePaths({
|
||||||
|
pathsArray: pathsArray,
|
||||||
|
orderedList: listAfterMergeSort,
|
||||||
|
aggregationType: "mean",
|
||||||
|
// VERBOSE: false,
|
||||||
|
});
|
||||||
|
return aggregatedPaths;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sum = (arr) => arr.reduce((a, b) => a + b, 0);
|
||||||
|
|
||||||
|
function getStdev(arr) {
|
||||||
|
if (Array.isArray(arr) && arr.length > 0) {
|
||||||
|
const n = arr.length;
|
||||||
|
const mean = arr.reduce((a, b) => a + b) / n;
|
||||||
|
return Math.sqrt(
|
||||||
|
arr.map((x) => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const geomMean = (arr) => {
|
||||||
|
let n = arr.length;
|
||||||
|
let logavg = sum(arr.map((x) => Math.log(x))); // works for low numbers much better
|
||||||
|
let result = Math.exp(logavg / n);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCoefficientOfVariation = (arr) => {
|
||||||
|
let nonPositiveNumbers = arr.filter((x) => x <= 0);
|
||||||
|
if (nonPositiveNumbers.length == 0) {
|
||||||
|
let gm = geomMean(arr);
|
||||||
|
let stdev = getStdev(arr);
|
||||||
|
return stdev / gm;
|
||||||
|
} else {
|
||||||
|
return getStdev(arr) / avg(arr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function abridgeArrayAndDisplay(array) {
|
||||||
|
let newArray;
|
||||||
|
let formatForDisplay;
|
||||||
|
if (array.length > 10) {
|
||||||
|
newArray = array.slice(0, 9);
|
||||||
|
formatForDisplay = newArray.map((d) => truncateValueForDisplay(d));
|
||||||
|
formatForDisplay[9] = "...";
|
||||||
|
} else {
|
||||||
|
newArray = array;
|
||||||
|
formatForDisplay = newArray.map((d) => truncateValueForDisplay(d));
|
||||||
|
}
|
||||||
|
let result = JSON.stringify(formatForDisplay, null, 2).replaceAll(`"`, "");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRow(row, i) {
|
||||||
|
return (
|
||||||
|
<tr
|
||||||
|
className="border-b dark:bg-gray-800 dark:border-gray-700 odd:bg-white even:bg-gray-50 odd:dark:bg-gray-800 even:dark:bg-gray-700"
|
||||||
|
key={`row-display-${i}`}
|
||||||
|
>
|
||||||
|
<td className="px-6 py-4 pt-7">{i}</td>
|
||||||
|
<td className="px-6 py-4">{cutOffLongNames(row.name)}</td>
|
||||||
|
<td className="text-center px-6 py-4">
|
||||||
|
{abridgeArrayAndDisplay(row.arrayMeans)}
|
||||||
|
</td>
|
||||||
|
<td className="text-center px-6 py-4">
|
||||||
|
{truncateValueForDisplay(row.aggregatedMeans)}
|
||||||
|
</td>
|
||||||
|
<td className="text-center px-6 py-4">
|
||||||
|
{truncateValueForDisplay(getCoefficientOfVariation(row.arrayMeans))}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reactTableContents(tableContents) {
|
||||||
|
// alert(JSON.stringify(tableContents));
|
||||||
|
// return "Hello";
|
||||||
|
return tableContents.map((row, i) => getRow(row, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ResultsTable({ isListOrdered, listAfterMergeSort, links }) {
|
||||||
|
const [isTableComputed, setIsTableComputed] = useState(false);
|
||||||
|
const [tableContents, setTableContents] = useState([]);
|
||||||
|
|
||||||
|
useEffect(async () => {
|
||||||
|
// console.log(JSON.stringify(config, null, 10));
|
||||||
|
if (isListOrdered && listAfterMergeSort.length > 0) {
|
||||||
|
// both necessary because there is a small moment when list is ordered
|
||||||
|
// but listAfterMergeSort wasn't ready yet
|
||||||
|
let tableContentsResult = await fullResultsTable({
|
||||||
|
listAfterMergeSort,
|
||||||
|
links,
|
||||||
|
});
|
||||||
|
console.log(tableContentsResult);
|
||||||
|
// alert(JSON.stringify(tableContentsResult));
|
||||||
|
setTableContents(tableContentsResult);
|
||||||
|
setIsTableComputed(true);
|
||||||
|
}
|
||||||
|
}, [isListOrdered, listAfterMergeSort, links]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{!(isListOrdered && isTableComputed) ? (
|
||||||
|
""
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
<Separator />
|
||||||
|
<div className="relative overflow-x-auto shadow-md sm:rounded-lg mt-10">
|
||||||
|
<table className="w-full text-sm text-left text-gray-800 dark:text-gray-400">
|
||||||
|
<thead className=" text-xs text-gray-700 bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
|
||||||
|
<tr>
|
||||||
|
<th scope="col" className="px-6 py-3">
|
||||||
|
Position
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th scope="col" className="px-6 py-3">
|
||||||
|
Element
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th scope="col" className="text-center px-6 py-3">
|
||||||
|
Possible relative values
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th scope="col" className="text-center px-6 py-3">
|
||||||
|
Aggregated Means*
|
||||||
|
</th>
|
||||||
|
<th scope="col" className="text-center px-6 py-3">
|
||||||
|
Coefficient of variation
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>{reactTableContents(tableContents)}</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="grid w-full place-items-center text-center ">
|
||||||
|
<p className="mt-8 max-w-5xl">
|
||||||
|
*This is the geometric mean if all elements are either all positive or
|
||||||
|
all negative, and the arithmetic mean otherwise. For a principled
|
||||||
|
aggregation which is able to produce meaningfull 90% confidence
|
||||||
|
intervals, see the utility-tools package in npm or github
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
9
packages/webpage-refactor/components/separator.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export function Separator() {
|
||||||
|
return (
|
||||||
|
<div class="py-4">
|
||||||
|
<div class="w-full border-t border-4 border-gray-300 mt-10"></div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
11
packages/webpage-refactor/lib/stringManipulations.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
export const cutOffLongNames = (string) => {
|
||||||
|
let maxLength = 40;
|
||||||
|
let result;
|
||||||
|
if (string.length < maxLength) {
|
||||||
|
result = string;
|
||||||
|
} else {
|
||||||
|
result = string.slice(0, maxLength - 4);
|
||||||
|
result = result + "...";
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
|
@ -27,7 +27,7 @@
|
||||||
"react-markdown": "^6.0.2",
|
"react-markdown": "^6.0.2",
|
||||||
"remark-gfm": "^1.0.0",
|
"remark-gfm": "^1.0.0",
|
||||||
"simple-react-cytoscape": "^1.0.4",
|
"simple-react-cytoscape": "^1.0.4",
|
||||||
"utility-tools": "^0.2.2"
|
"utility-tools": "^0.2.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@netlify/plugin-nextjs": "^4.2.1",
|
"@netlify/plugin-nextjs": "^4.2.1",
|
||||||
|
|
BIN
packages/webpage-refactor/public/example-graph.png
Normal file
After Width: | Height: | Size: 182 KiB |
BIN
packages/webpage-refactor/public/example-graph2.png
Normal file
After Width: | Height: | Size: 243 KiB |
BIN
packages/webpage-refactor/public/example-prompt.png
Normal file
After Width: | Height: | Size: 58 KiB |
BIN
packages/webpage-refactor/public/example-table.png
Normal file
After Width: | Height: | Size: 145 KiB |
|
@ -4048,6 +4048,14 @@ utility-tools@^0.2.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
"@quri/squiggle-lang" "^0.2.11"
|
"@quri/squiggle-lang" "^0.2.11"
|
||||||
|
|
||||||
|
utility-tools@^0.2.5:
|
||||||
|
version "0.2.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/utility-tools/-/utility-tools-0.2.5.tgz#73ee06c88d74fc5a7bf87882caf93abed28600c2"
|
||||||
|
integrity sha512-sXT3RiOdjgO0DeYr5G3CPYrrXR2+8+d+GBGN6VELYXSFWfzBNUN1DA/alyYyuDaXRI+iBQequpuPy9rsHvsXGA==
|
||||||
|
dependencies:
|
||||||
|
"@quri/squiggle-lang" "^0.2.11"
|
||||||
|
utility-tools "^0.2.2"
|
||||||
|
|
||||||
vfile-message@^2.0.0:
|
vfile-message@^2.0.0:
|
||||||
version "2.0.4"
|
version "2.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a"
|
resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a"
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
## About
|
|
||||||
|
|
||||||
This repository creates a react webpage that allows to extract a utility function from possibly inconsistent binary comparisons. It presents the users with a series of elements to compare, using merge-sort in the background to cleverly minimize the number of choices needed. Then, it cleverly aggregates them, by taking each element as a reference point in turn, and computing the possible distances from that reference point to all other points, and taking the geometric mean of these distances. This produces a number representing the value of each element, such that the ratios between elements represent the user's preferences: a utility function!
|
|
||||||
|
|
||||||
Initially, users could only input numbers, e.g., "A is `3` times better than B". But now, users can also input distributions, using the [squiggle](https://www.squiggle-language.com/) syntax, e.g., "A is `1 to 10` times better than B", or "A is `mm(normal(1, 10), uniform(0,100))` better than B".
|
|
||||||
|
|
||||||
## Object structure
|
|
||||||
|
|
||||||
The core structure is json array of objects. Only the "name" attribute is required. If there is a "url", it is displayed nicely.
|
|
||||||
|
|
||||||
```
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"name": "Peter Parker",
|
|
||||||
"someOptionalKey": "...",
|
|
||||||
"anotherMoreOptionalKey": "...",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Spiderman",
|
|
||||||
"someOptionalKey": "...",
|
|
||||||
"anotherMoreOptionalKey": "..."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Netlify
|
|
||||||
|
|
||||||
https://github.com/netlify/netlify-plugin-nextjs/#readme
|
|
||||||
|
|
||||||
## To do
|
|
||||||
|
|
||||||
- [ ] Extract merge, findPath and aggregatePath functionality into different repos
|
|
||||||
- [ ] Add functionality like names, etc.
|
|