Basic stats table. Unformatted

This commit is contained in:
Sam Nolan 2022-04-30 15:16:13 +00:00
parent 99b9bc6b1e
commit 64fbe05f3a
4 changed files with 113 additions and 20 deletions

View File

@ -1,8 +1,12 @@
import * as React from "react";
import _ from "lodash";
import type { Spec } from "vega";
import type { Distribution } from "@quri/squiggle-lang";
import { distributionErrorToString } from "@quri/squiggle-lang";
import {
Distribution,
result,
distributionError,
distributionErrorToString,
} from "@quri/squiggle-lang";
import { createClassFromSpec } from "react-vega";
import * as chartSpecification from "../vega-specs/spec-distributions.json";
import { ErrorBox } from "./ErrorBox";
@ -16,30 +20,101 @@ type DistributionChartProps = {
distribution: Distribution;
width: number;
height: number;
/** Whether to show a summary of means, stdev, percentiles etc */
showSummary: boolean;
};
export const DistributionChart: React.FC<DistributionChartProps> = ({
distribution,
width,
height,
showSummary,
}: DistributionChartProps) => {
let shape = distribution.pointSet();
if (shape.tag === "Ok") {
let widthProp = width ? width - 20 : undefined;
var result = (
return (
<>
<SquiggleVegaChart
data={{ con: shape.value.continuous, dis: shape.value.discrete }}
width={widthProp}
height={height}
actions={false}
/>
{showSummary ? <SummaryTable distribution={distribution} /> : <></>}
</>
);
} else {
var result = (
return (
<ErrorBox heading="Distribution Error">
{distributionErrorToString(shape.value)}
</ErrorBox>
);
}
return result;
};
type SummaryTableProps = {
distribution: Distribution;
};
const Table = styled.table``;
const Row = styled.tr``;
const Cell = styled.td``;
const TableHeader = styled.th``;
const SummaryTable: React.FC<SummaryTableProps> = ({
distribution,
}: SummaryTableProps) => {
let mean = distribution.mean();
let median = distribution.inv(0.5);
let p5 = distribution.inv(0.05);
let p10 = distribution.inv(0.1);
let Q1 = distribution.inv(0.25);
let Q3 = distribution.inv(0.75);
let p90 = distribution.inv(0.9);
let p95 = distribution.inv(0.95);
let unwrapResult = (
x: result<number, distributionError>
): React.ReactNode => {
if (x.tag === "Ok") {
return (
<span>
{Intl.NumberFormat("en-US", { maximumSignificantDigits: 3 }).format(
x.value
)}
</span>
);
} else {
return (
<ErrorBox heading="Distribution Error">
{distributionErrorToString(x.value)}
</ErrorBox>
);
}
};
return (
<Table>
<Row>
<TableHeader>{"Mean"}</TableHeader>
<TableHeader>{"5%"}</TableHeader>
<TableHeader>{"10%"}</TableHeader>
<TableHeader>{"Q1 (25%)"}</TableHeader>
<TableHeader>{"Median (50%)"}</TableHeader>
<TableHeader>{"Q3 (75%)"}</TableHeader>
<TableHeader>{"90%"}</TableHeader>
<TableHeader>{"95%"}</TableHeader>
</Row>
<Row>
<Cell>{unwrapResult(mean)}</Cell>
<Cell>{unwrapResult(p5)}</Cell>
<Cell>{unwrapResult(p10)}</Cell>
<Cell>{unwrapResult(Q1)}</Cell>
<Cell>{unwrapResult(median)}</Cell>
<Cell>{unwrapResult(Q3)}</Cell>
<Cell>{unwrapResult(p90)}</Cell>
<Cell>{unwrapResult(p95)}</Cell>
</Row>
</Table>
);
};

View File

@ -61,6 +61,7 @@ export const FunctionChart: React.FC<{
distribution={mouseItem.value}
width={400}
height={140}
showSummary={false}
/>
) : (
<></>

View File

@ -54,12 +54,15 @@ export interface SquiggleItemProps {
expression: squiggleExpression;
width: number;
height: number;
/** Whether to show a summary of statistics for distributions */
showSummary: boolean;
}
const SquiggleItem: React.FC<SquiggleItemProps> = ({
expression,
width,
height,
showSummary,
}: SquiggleItemProps) => {
switch (expression.tag) {
case "number":
@ -83,6 +86,7 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({
distribution={expression.value}
height={height}
width={width}
showSummary={showSummary}
/>
</VariableBox>
);
@ -105,7 +109,12 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({
return (
<VariableBox heading="Array">
{expression.value.map((r) => (
<SquiggleItem expression={r} width={width - 20} height={50} />
<SquiggleItem
expression={r}
width={width - 20}
height={50}
showSummary={showSummary}
/>
))}
</VariableBox>
);
@ -115,17 +124,16 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({
{Object.entries(expression.value).map(([key, r]) => (
<>
<RecordKeyHeader>{key}</RecordKeyHeader>
<SquiggleItem expression={r} width={width - 20} height={50} />
<SquiggleItem
expression={r}
width={width - 20}
height={50}
showSummary={showSummary}
/>
</>
))}
</VariableBox>
);
default:
return (
<ErrorBox heading="No Viewer">
{"We don't currently have a working viewer for record types."}
</ErrorBox>
);
}
};
@ -155,6 +163,8 @@ export interface SquiggleChartProps {
bindings?: bindings;
/** JS imported parameters */
jsImports?: jsImports;
/** Whether to show a summary of the distirbution */
showSummary?: boolean;
}
const ChartWrapper = styled.div`
@ -172,6 +182,7 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = ({
bindings = defaultBindings,
jsImports = defaultImports,
width = NaN,
showSummary = false,
}: SquiggleChartProps) => {
let samplingInputs: samplingParams = {
sampleCount: sampleCount,
@ -188,7 +199,12 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = ({
let expression = expressionResult.value;
onChange(expression);
internal = (
<SquiggleItem expression={expression} width={width} height={height} />
<SquiggleItem
expression={expression}
width={width}
height={height}
showSummary={showSummary}
/>
);
} else {
internal = (

View File

@ -11,6 +11,7 @@ export {
makeSampleSetDist,
errorValueToString,
distributionErrorToString,
distributionError,
} from "../rescript/TypescriptInterface.gen";
export type {
samplingParams,