-
Notifications
You must be signed in to change notification settings - Fork 166
/
Copy pathsample.js
71 lines (64 loc) · 2.49 KB
/
sample.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import { calcNodeColor } from "../util/colorHelpers";
import {RESAMPLE} from "./types";
/**
* Currently this is changing the values behind the selected color-by.
*
* TODO: generalise to any trait
* TODO: Frequencies need updating?
* TODO: second tree
*/
export const sampleTraitFromUncertainty = ({trait, returnToOriginal=false}) => {
console.log(`sampleTraitFromUncertainty trait=${trait} returnToOriginal=${returnToOriginal}`);
return (dispatch, getState) => {
const { controls, tree } = getState();
tree.nodes.forEach((n) => {
if (n.node_attrs[trait] && n.node_attrs[trait].confidence) {
if (returnToOriginal) {
if (!n.node_attrs[trait].originalValue) {
console.error("Original state not saved...");
return;
}
n.node_attrs[trait].value = n.node_attrs[trait].originalValue;
} else {
if (!n.node_attrs[trait].originalValue) {
n.node_attrs[trait].originalValue = n.node_attrs[trait].value; // allows us to go back to original state
}
if (Array.isArray(n.node_attrs[trait].confidence)) {
n.node_attrs[trait].value = sampleUniformlyBetweenBounds(n.node_attrs[trait].confidence);
} else {
n.node_attrs[trait].value = sampleFromDiscreteDistribution(n.node_attrs[trait].confidence);
}
}
}
});
const colorBy = controls.colorBy;
const dispatchObj = {type: RESAMPLE};
if (trait === colorBy) {
/* if the current color-by is the trait we're resampling, then we need to update the node colors */
dispatchObj.nodeColors = calcNodeColor(tree, controls.colorScale);
dispatchObj.nodeColorsVersion = tree.nodeColorsVersion+1;
}
dispatch(dispatchObj);
};
};
function sampleFromDiscreteDistribution(confidenceObj) {
/* based on the algorithm behind R's `sample` function */
// to-do: if the probabilities don't sum to 1 the output will be biased towards the final value
const values = Object.keys(confidenceObj);
const probabilities = Object.values(confidenceObj);
const n = values.length;
const cumulativeProbs = new Array(n);
cumulativeProbs[0] = probabilities[0];
for (let i = 1; i<n; i++) {
cumulativeProbs[i] = probabilities[i] + cumulativeProbs[i-1];
}
const rU = Math.random();
let j;
for (j=0; j<(n-1); j++) {
if (rU <= cumulativeProbs[j]) break;
}
return values[j];
}
function sampleUniformlyBetweenBounds(bounds) {
return bounds[0] + (bounds[1]-bounds[0])*Math.random();
}