Add an optional simple summary table

This commit is contained in:
Sam Nolan 2022-05-09 19:21:54 +00:00
parent 19ebc322ad
commit aab6ac4940
3 changed files with 85 additions and 40 deletions

View File

@ -44,7 +44,7 @@ export const DistributionChart: React.FC<DistributionChartProps> = ({
shape.value.continuous.some((x) => x.x <= 0) || shape.value.continuous.some((x) => x.x <= 0) ||
shape.value.discrete.some((x) => x.x <= 0); shape.value.discrete.some((x) => x.x <= 0);
let spec = buildVegaSpec(isLogX, isExpY); let spec = buildVegaSpec(isLogX, isExpY);
let widthProp = width ? width - 20 : size.width - 10; let widthProp = width ? width : size.width;
// Check whether we should disable the checkbox // Check whether we should disable the checkbox
var logCheckbox = ( var logCheckbox = (
@ -65,11 +65,11 @@ export const DistributionChart: React.FC<DistributionChartProps> = ({
} }
var result = ( var result = (
<div> <ChartContainer width={widthProp + "px"}>
<Vega <Vega
spec={spec} spec={spec}
data={{ con: shape.value.continuous, dis: shape.value.discrete }} data={{ con: shape.value.continuous, dis: shape.value.discrete }}
width={widthProp} width={widthProp - 10}
height={height} height={height}
actions={false} actions={false}
/> />
@ -80,7 +80,7 @@ export const DistributionChart: React.FC<DistributionChartProps> = ({
<CheckBox label="Exp Y scale" value={isExpY} onChange={setExpY} /> <CheckBox label="Exp Y scale" value={isExpY} onChange={setExpY} />
</div> </div>
)} )}
</div> </ChartContainer>
); );
} else { } else {
var result = ( var result = (
@ -95,6 +95,12 @@ export const DistributionChart: React.FC<DistributionChartProps> = ({
return sized; return sized;
}; };
type ChartContainerProps = { width: string };
let ChartContainer = styled.div<ChartContainerProps>`
width: ${(props) => props.width};
`;
function buildVegaSpec(isLogX: boolean, isExpY: boolean): VisualizationSpec { function buildVegaSpec(isLogX: boolean, isExpY: boolean): VisualizationSpec {
return { return {
...chartSpecification, ...chartSpecification,
@ -141,10 +147,33 @@ type SummaryTableProps = {
distribution: Distribution; distribution: Distribution;
}; };
const Table = styled.table``; const Table = styled.table`
margin-left: auto;
margin-right: auto;
border-collapse: collapse;
text-align: center;
border-style: hidden;
`;
const TableHead = styled.thead`
border-bottom: 1px solid rgb(141 149 167);
`;
const TableHeadCell = styled.th`
border-right: 1px solid rgb(141 149 167);
border-left: 1px solid rgb(141 149 167);
padding: 0.3em;
`;
const TableBody = styled.tbody``;
const Row = styled.tr``; const Row = styled.tr``;
const Cell = styled.td``;
const TableHeader = styled.th``; const Cell = styled.td`
padding: 0.3em;
border-right: 1px solid rgb(141 149 167);
border-left: 1px solid rgb(141 149 167);
`;
const SummaryTable: React.FC<SummaryTableProps> = ({ const SummaryTable: React.FC<SummaryTableProps> = ({
distribution, distribution,
@ -179,26 +208,30 @@ const SummaryTable: React.FC<SummaryTableProps> = ({
return ( return (
<Table> <Table>
<Row> <TableHead>
<TableHeader>{"Mean"}</TableHeader> <Row>
<TableHeader>{"5%"}</TableHeader> <TableHeadCell>{"Mean"}</TableHeadCell>
<TableHeader>{"10%"}</TableHeader> <TableHeadCell>{"5%"}</TableHeadCell>
<TableHeader>{"Q1 (25%)"}</TableHeader> <TableHeadCell>{"10%"}</TableHeadCell>
<TableHeader>{"Median (50%)"}</TableHeader> <TableHeadCell>{"25%"}</TableHeadCell>
<TableHeader>{"Q3 (75%)"}</TableHeader> <TableHeadCell>{"50%"}</TableHeadCell>
<TableHeader>{"90%"}</TableHeader> <TableHeadCell>{"75%"}</TableHeadCell>
<TableHeader>{"95%"}</TableHeader> <TableHeadCell>{"90%"}</TableHeadCell>
</Row> <TableHeadCell>{"95%"}</TableHeadCell>
<Row> </Row>
<Cell>{unwrapResult(mean)}</Cell> </TableHead>
<Cell>{unwrapResult(p5)}</Cell> <TableBody>
<Cell>{unwrapResult(p10)}</Cell> <Row>
<Cell>{unwrapResult(Q1)}</Cell> <Cell>{unwrapResult(mean)}</Cell>
<Cell>{unwrapResult(median)}</Cell> <Cell>{unwrapResult(p5)}</Cell>
<Cell>{unwrapResult(Q3)}</Cell> <Cell>{unwrapResult(p10)}</Cell>
<Cell>{unwrapResult(p90)}</Cell> <Cell>{unwrapResult(Q1)}</Cell>
<Cell>{unwrapResult(p95)}</Cell> <Cell>{unwrapResult(median)}</Cell>
</Row> <Cell>{unwrapResult(Q3)}</Cell>
<Cell>{unwrapResult(p90)}</Cell>
<Cell>{unwrapResult(p95)}</Cell>
</Row>
</TableBody>
</Table> </Table>
); );
}; };

View File

@ -43,7 +43,9 @@ export interface SquiggleEditorProps {
/** Whether to show detail about types of the returns, default false */ /** Whether to show detail about types of the returns, default false */
showTypes?: boolean; showTypes?: boolean;
/** Whether to give users access to graph controls */ /** Whether to give users access to graph controls */
showControls: boolean; showControls?: boolean;
/** Whether to show a summary table */
showSummary?: boolean;
} }
const Input = styled.div` const Input = styled.div`
@ -67,6 +69,7 @@ export let SquiggleEditor: React.FC<SquiggleEditorProps> = ({
jsImports = defaultImports, jsImports = defaultImports,
showTypes = false, showTypes = false,
showControls = false, showControls = false,
showSummary = false,
}: SquiggleEditorProps) => { }: SquiggleEditorProps) => {
let [expression, setExpression] = React.useState(initialSquiggleString); let [expression, setExpression] = React.useState(initialSquiggleString);
return ( return (
@ -95,6 +98,7 @@ export let SquiggleEditor: React.FC<SquiggleEditorProps> = ({
jsImports={jsImports} jsImports={jsImports}
showTypes={showTypes} showTypes={showTypes}
showControls={showControls} showControls={showControls}
showSummary={showSummary}
/> />
</div> </div>
); );

View File

@ -40,18 +40,11 @@ function FieldFloat(Props: FieldFloatProps) {
); );
} }
interface Props { interface ShowBoxProps {
initialSquiggleString?: string;
height?: number;
showTypes?: boolean;
showControls?: boolean;
}
interface Props2 {
height: number; height: number;
} }
const ShowBox = styled.div<Props2>` const ShowBox = styled.div<ShowBoxProps>`
border: 1px solid #eee; border: 1px solid #eee;
border-radius: 2px; border-radius: 2px;
height: ${(props) => props.height}; height: ${(props) => props.height};
@ -76,12 +69,26 @@ const Row = styled.div`
`; `;
const Col = styled.div``; const Col = styled.div``;
let SquigglePlayground: FC<Props> = ({ interface PlaygroundProps {
/** The initial squiggle string to put in the playground */
initialSquiggleString?: string;
/** How many pixels high is the playground */
height?: number;
/** Whether to show the types of outputs in the playground */
showTypes?: boolean;
/** Whether to show the log scale controls in the playground */
showControls?: boolean;
/** Whether to show the summary table in the playground */
showSummary?: boolean;
}
let SquigglePlayground: FC<PlaygroundProps> = ({
initialSquiggleString = "", initialSquiggleString = "",
height = 300, height = 300,
showTypes = false, showTypes = false,
showControls = false, showControls = false,
}: Props) => { showSummary = false,
}: PlaygroundProps) => {
let [squiggleString, setSquiggleString] = useState(initialSquiggleString); let [squiggleString, setSquiggleString] = useState(initialSquiggleString);
let [sampleCount, setSampleCount] = useState(1000); let [sampleCount, setSampleCount] = useState(1000);
let [outputXYPoints, setOutputXYPoints] = useState(1000); let [outputXYPoints, setOutputXYPoints] = useState(1000);
@ -114,6 +121,7 @@ let SquigglePlayground: FC<Props> = ({
height={150} height={150}
showTypes={showTypes} showTypes={showTypes}
showControls={showControls} showControls={showControls}
showSummary={showSummary}
/> />
</Display> </Display>
</Col> </Col>
@ -122,7 +130,7 @@ let SquigglePlayground: FC<Props> = ({
); );
}; };
export default SquigglePlayground; export default SquigglePlayground;
export function renderSquigglePlaygroundToDom(props: Props) { export function renderSquigglePlaygroundToDom(props: PlaygroundProps) {
let parent = document.createElement("div"); let parent = document.createElement("div");
ReactDOM.render(<SquigglePlayground {...props} />, parent); ReactDOM.render(<SquigglePlayground {...props} />, parent);
return parent; return parent;