From 64fbe05f3af31b6079f6d2858d8afdc1899dcb0f Mon Sep 17 00:00:00 2001 From: Sam Nolan Date: Sat, 30 Apr 2022 15:16:13 +0000 Subject: [PATCH] Basic stats table. Unformatted --- .../src/components/DistributionChart.tsx | 97 ++++++++++++++++--- .../src/components/FunctionChart.tsx | 1 + .../src/components/SquiggleChart.tsx | 34 +++++-- packages/squiggle-lang/src/js/index.ts | 1 + 4 files changed, 113 insertions(+), 20 deletions(-) diff --git a/packages/components/src/components/DistributionChart.tsx b/packages/components/src/components/DistributionChart.tsx index 6bef36c7..0350bcf8 100644 --- a/packages/components/src/components/DistributionChart.tsx +++ b/packages/components/src/components/DistributionChart.tsx @@ -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 = ({ distribution, width, height, + showSummary, }: DistributionChartProps) => { let shape = distribution.pointSet(); if (shape.tag === "Ok") { let widthProp = width ? width - 20 : undefined; - var result = ( - + return ( + <> + + {showSummary ? : <>} + ); } else { - var result = ( + return ( {distributionErrorToString(shape.value)} ); } - 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 = ({ + 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 + ): React.ReactNode => { + if (x.tag === "Ok") { + return ( + + {Intl.NumberFormat("en-US", { maximumSignificantDigits: 3 }).format( + x.value + )} + + ); + } else { + return ( + + {distributionErrorToString(x.value)} + + ); + } + }; + + return ( + + + {"Mean"} + {"5%"} + {"10%"} + {"Q1 (25%)"} + {"Median (50%)"} + {"Q3 (75%)"} + {"90%"} + {"95%"} + + + {unwrapResult(mean)} + {unwrapResult(p5)} + {unwrapResult(p10)} + {unwrapResult(Q1)} + {unwrapResult(median)} + {unwrapResult(Q3)} + {unwrapResult(p90)} + {unwrapResult(p95)} + +
+ ); }; diff --git a/packages/components/src/components/FunctionChart.tsx b/packages/components/src/components/FunctionChart.tsx index ea00aa9c..86678b27 100644 --- a/packages/components/src/components/FunctionChart.tsx +++ b/packages/components/src/components/FunctionChart.tsx @@ -61,6 +61,7 @@ export const FunctionChart: React.FC<{ distribution={mouseItem.value} width={400} height={140} + showSummary={false} /> ) : ( <> diff --git a/packages/components/src/components/SquiggleChart.tsx b/packages/components/src/components/SquiggleChart.tsx index 31cd9787..6fdc6486 100644 --- a/packages/components/src/components/SquiggleChart.tsx +++ b/packages/components/src/components/SquiggleChart.tsx @@ -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 = ({ expression, width, height, + showSummary, }: SquiggleItemProps) => { switch (expression.tag) { case "number": @@ -83,6 +86,7 @@ const SquiggleItem: React.FC = ({ distribution={expression.value} height={height} width={width} + showSummary={showSummary} /> ); @@ -105,7 +109,12 @@ const SquiggleItem: React.FC = ({ return ( {expression.value.map((r) => ( - + ))} ); @@ -115,17 +124,16 @@ const SquiggleItem: React.FC = ({ {Object.entries(expression.value).map(([key, r]) => ( <> {key} - + ))} ); - default: - return ( - - {"We don't currently have a working viewer for record types."} - - ); } }; @@ -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 = ({ bindings = defaultBindings, jsImports = defaultImports, width = NaN, + showSummary = false, }: SquiggleChartProps) => { let samplingInputs: samplingParams = { sampleCount: sampleCount, @@ -188,7 +199,12 @@ export const SquiggleChart: React.FC = ({ let expression = expressionResult.value; onChange(expression); internal = ( - + ); } else { internal = ( diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index ce4d9428..0b521079 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -11,6 +11,7 @@ export { makeSampleSetDist, errorValueToString, distributionErrorToString, + distributionError, } from "../rescript/TypescriptInterface.gen"; export type { samplingParams,