Minor refactors

This commit is contained in:
Ozzie Gooen 2022-05-15 15:21:00 -04:00
parent b015c20fa4
commit 91ccd333e0
2 changed files with 117 additions and 18 deletions

View File

@ -64,6 +64,81 @@ type percentiles = {
p99: number; p99: number;
}[]; }[];
type errors = _.Dictionary<
{
x: number;
value: string;
}[]
>;
type point = { x: number; value: result<Distribution, string> };
let getPercentiles = ({ chartSettings, fn, environment }) => {
let data1 = _rangeByCount(
chartSettings.start,
chartSettings.stop,
chartSettings.count
);
let valueData: point[] = data1.map((x) => {
let result = runForeign(fn, [x], environment);
if (result.tag === "Ok") {
if (result.value.tag == "distribution") {
return { x, value: { tag: "Ok", value: result.value.value } };
} else {
return {
x,
value: {
tag: "Error",
value:
"Cannot currently render functions that don't return distributions",
},
};
}
} else {
return {
x,
value: { tag: "Error", value: errorValueToString(result.value) },
};
}
});
let initialPartition: [
{ x: number; value: Distribution }[],
{ x: number; value: string }[]
] = [[], []];
let [functionImage, errors] = valueData.reduce((acc, current) => {
if (current.value.tag === "Ok") {
acc[0].push({ x: current.x, value: current.value.value });
} else {
acc[1].push({ x: current.x, value: current.value.value });
}
return acc;
}, initialPartition);
let groupedErrors: errors = _.groupBy(errors, (x) => x.value);
let percentiles: percentiles = functionImage.map(({ x, value }) => {
// We convert it to to a pointSet distribution first, so that in case its a sample set
// distribution, it doesn't internally convert it to a pointSet distribution for every
// single inv() call.
let toPointSet: Distribution = unwrap(value.toPointSet());
return {
x: x,
p1: unwrap(toPointSet.inv(0.01)),
p5: unwrap(toPointSet.inv(0.05)),
p10: unwrap(toPointSet.inv(0.12)),
p20: unwrap(toPointSet.inv(0.2)),
p30: unwrap(toPointSet.inv(0.3)),
p40: unwrap(toPointSet.inv(0.4)),
p50: unwrap(toPointSet.inv(0.5)),
p60: unwrap(toPointSet.inv(0.6)),
p70: unwrap(toPointSet.inv(0.7)),
p80: unwrap(toPointSet.inv(0.8)),
p90: unwrap(toPointSet.inv(0.9)),
p95: unwrap(toPointSet.inv(0.95)),
p99: unwrap(toPointSet.inv(0.99)),
};
});
return { percentiles, errors: groupedErrors };
};
export const FunctionChart: React.FC<FunctionChartProps> = ({ export const FunctionChart: React.FC<FunctionChartProps> = ({
fn, fn,
chartSettings, chartSettings,
@ -78,8 +153,14 @@ export const FunctionChart: React.FC<FunctionChartProps> = ({
} }
const signalListeners = { mousemove: handleHover, mouseout: handleOut }; const signalListeners = { mousemove: handleHover, mouseout: handleOut };
let mouseItem: result<squiggleExpression, errorValue> = !!mouseOverlay let mouseItem: result<squiggleExpression, errorValue> = !!mouseOverlay
? runForeign(fn, [mouseOverlay], { sampleCount: 10000, xyPointLength: 1000 }) ? runForeign(fn, [mouseOverlay], {
: { tag: "Error", value: { tag: "REExpectedType", value: "Expected float, got NaN" } }; sampleCount: 10000,
xyPointLength: 1000,
})
: {
tag: "Error",
value: { tag: "REExpectedType", value: "Expected float, got NaN" },
};
let showChart = let showChart =
mouseItem.tag === "Ok" && mouseItem.value.tag == "distribution" ? ( mouseItem.tag === "Ok" && mouseItem.value.tag == "distribution" ? (
<DistributionChart <DistributionChart
@ -91,15 +172,17 @@ export const FunctionChart: React.FC<FunctionChartProps> = ({
) : ( ) : (
<></> <></>
); );
let data1 = _rangeByCount(
chartSettings.start,
chartSettings.stop,
chartSettings.count
);
type point = { x: number; value: result<Distribution, string> };
let getPercentiles: () => percentiles = () => { let getPercentiles2: () => {
let valueData:any = data1.map((x) => { percentiles: percentiles;
errors: errors;
} = () => {
let data1 = _rangeByCount(
chartSettings.start,
chartSettings.stop,
chartSettings.count
);
let valueData: point[] = data1.map((x) => {
let result = runForeign(fn, [x], environment); let result = runForeign(fn, [x], environment);
if (result.tag === "Ok") { if (result.tag === "Ok") {
if (result.value.tag == "distribution") { if (result.value.tag == "distribution") {
@ -133,8 +216,11 @@ export const FunctionChart: React.FC<FunctionChartProps> = ({
} }
return acc; return acc;
}, initialPartition); }, initialPartition);
let groupedErrors: errors = _.groupBy(errors, (x) => x.value);
let percentiles:percentiles = functionImage.map(({ x, value }) => { let percentiles: percentiles = functionImage.map(({ x, value }) => {
// We convert it to to a pointSet distribution first, so that in case its a sample set
// distribution, it doesn't internally convert it to a pointSet distribution for every
// single inv() call.
let toPointSet: Distribution = unwrap(value.toPointSet()); let toPointSet: Distribution = unwrap(value.toPointSet());
return { return {
x: x, x: x,
@ -153,19 +239,31 @@ export const FunctionChart: React.FC<FunctionChartProps> = ({
p99: unwrap(toPointSet.inv(0.99)), p99: unwrap(toPointSet.inv(0.99)),
}; };
}); });
return percentiles; return { percentiles, errors: groupedErrors };
}; };
let _getPercentiles = React.useMemo(getPercentiles, [environment, fn]) let _getPercentiles = React.useMemo(getPercentiles2, [environment, fn]);
return ( return (
<> <>
<SquigglePercentilesChart <SquigglePercentilesChart
data={{ facet: _getPercentiles }} data={{ facet: _getPercentiles.percentiles }}
actions={false} actions={false}
signalListeners={signalListeners} signalListeners={signalListeners}
/> />
{showChart} {showChart}
{_.entries(_getPercentiles.errors).map(([errorName, errorPoints]) => (
<ErrorBox key={errorName} heading={errorName}>
Values:{" "}
{errorPoints
.map((r, i) => <NumberShower key={i} number={r.x} />)
.reduce((a, b) => (
<>
{a}, {b}
</>
))}
</ErrorBox>
))}
</> </>
); );
}; };

View File

@ -10,7 +10,6 @@ import {
jsImports, jsImports,
defaultImports, defaultImports,
defaultBindings, defaultBindings,
defaultEnvironment,
} from "@quri/squiggle-lang"; } from "@quri/squiggle-lang";
import { NumberShower } from "./NumberShower"; import { NumberShower } from "./NumberShower";
import { DistributionChart } from "./DistributionChart"; import { DistributionChart } from "./DistributionChart";
@ -194,7 +193,7 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({
<FunctionChart <FunctionChart
fn={expression.value} fn={expression.value}
chartSettings={chartSettings} chartSettings={chartSettings}
environment={{ sampleCount: environment.sampleCount / 10, xyPointLength: environment.sampleCount / 10 }} environment={{ sampleCount: environment.sampleCount / 10, xyPointLength: environment.xyPointLength / 10 }}
/> />
); );
} }
@ -233,6 +232,8 @@ const ChartWrapper = styled.div`
`; `;
let defaultChartSettings = { start: 0, stop: 10, count: 20 }; let defaultChartSettings = { start: 0, stop: 10, count: 20 };
let defaultEnvironment = { sampleCount: 10000, xyPointLength: 1000 };
export const SquiggleChart: React.FC<SquiggleChartProps> = ({ export const SquiggleChart: React.FC<SquiggleChartProps> = ({
squiggleString = "", squiggleString = "",
environment, environment,
@ -247,7 +248,7 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = ({
chartSettings = defaultChartSettings, chartSettings = defaultChartSettings,
}: SquiggleChartProps) => { }: SquiggleChartProps) => {
let expressionResult = run(squiggleString, bindings, environment, jsImports); let expressionResult = run(squiggleString, bindings, environment, jsImports);
let e = environment ? environment : { sampleCount: 100000, xyPointLength: 1000 }; let e = environment ? environment : defaultEnvironment;
let internal: JSX.Element; let internal: JSX.Element;
if (expressionResult.tag === "Ok") { if (expressionResult.tag === "Ok") {
let expression = expressionResult.value; let expression = expressionResult.value;