Merge pull request #753 from quantified-uncertainty/graph-settings

Add logX and expY props
This commit is contained in:
Ozzie Gooen 2022-06-22 20:53:24 -07:00 committed by GitHub
commit 06d78048db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 119 additions and 39 deletions

View File

@ -19,25 +19,38 @@ import {
} from "./DistributionVegaScales"; } from "./DistributionVegaScales";
import { NumberShower } from "./NumberShower"; import { NumberShower } from "./NumberShower";
type DistributionChartProps = { export type DistributionPlottingSettings = {
distribution: Distribution;
width?: number;
height: number;
/** Whether to show a summary of means, stdev, percentiles etc */ /** Whether to show a summary of means, stdev, percentiles etc */
showSummary: boolean; showSummary: boolean;
/** Whether to show the user graph controls (scale etc) */ /** Whether to show the user graph controls (scale etc) */
showControls?: boolean; showControls: boolean;
/** Set the x scale to be logarithmic by deault */
logX: boolean;
/** Set the y scale to be exponential by deault */
expY: boolean;
}; };
export type DistributionChartProps = {
distribution: Distribution;
width?: number;
height: number;
} & DistributionPlottingSettings;
export const DistributionChart: React.FC<DistributionChartProps> = ({ export const DistributionChart: React.FC<DistributionChartProps> = ({
distribution, distribution,
height, height,
showSummary, showSummary,
width, width,
showControls = false, showControls,
logX,
expY,
}) => { }) => {
const [isLogX, setLogX] = React.useState(false); const [isLogX, setLogX] = React.useState(logX);
const [isExpY, setExpY] = React.useState(false); const [isExpY, setExpY] = React.useState(expY);
React.useEffect(() => setLogX(logX), [logX]);
React.useEffect(() => setExpY(expY), [expY]);
const shape = distribution.pointSet(); const shape = distribution.pointSet();
const [sized] = useSize((size) => { const [sized] = useSize((size) => {
if (shape.tag === "Error") { if (shape.tag === "Error") {
@ -63,6 +76,7 @@ export const DistributionChart: React.FC<DistributionChartProps> = ({
return ( return (
<div style={{ width: widthProp }}> <div style={{ width: widthProp }}>
{!(isLogX && massBelow0) ? (
<Vega <Vega
spec={spec} spec={spec}
data={{ con: shape.value.continuous, dis: shape.value.discrete }} data={{ con: shape.value.continuous, dis: shape.value.discrete }}
@ -70,6 +84,11 @@ export const DistributionChart: React.FC<DistributionChartProps> = ({
height={height} height={height}
actions={false} actions={false}
/> />
) : (
<ErrorAlert heading="Log Domain Error">
Cannot graph distribution with negative values on logarithmic scale.
</ErrorAlert>
)}
<div className="flex justify-center"> <div className="flex justify-center">
{showSummary && <SummaryTable distribution={distribution} />} {showSummary && <SummaryTable distribution={distribution} />}
</div> </div>
@ -126,7 +145,7 @@ export const CheckBox: React.FC<CheckBoxProps> = ({
<span title={tooltip}> <span title={tooltip}>
<input <input
type="checkbox" type="checkbox"
value={value + ""} checked={value}
onChange={() => onChange(!value)} onChange={() => onChange(!value)}
disabled={disabled} disabled={disabled}
className="form-checkbox" className="form-checkbox"

View File

@ -2,6 +2,7 @@ import * as React from "react";
import { lambdaValue, environment, runForeign } from "@quri/squiggle-lang"; import { lambdaValue, environment, runForeign } from "@quri/squiggle-lang";
import { FunctionChart1Dist } from "./FunctionChart1Dist"; import { FunctionChart1Dist } from "./FunctionChart1Dist";
import { FunctionChart1Number } from "./FunctionChart1Number"; import { FunctionChart1Number } from "./FunctionChart1Number";
import { DistributionPlottingSettings } from "./DistributionChart";
import { ErrorAlert, MessageAlert } from "./Alert"; import { ErrorAlert, MessageAlert } from "./Alert";
export type FunctionChartSettings = { export type FunctionChartSettings = {
@ -13,6 +14,7 @@ export type FunctionChartSettings = {
interface FunctionChartProps { interface FunctionChartProps {
fn: lambdaValue; fn: lambdaValue;
chartSettings: FunctionChartSettings; chartSettings: FunctionChartSettings;
distributionPlotSettings: DistributionPlottingSettings;
environment: environment; environment: environment;
height: number; height: number;
} }
@ -21,6 +23,7 @@ export const FunctionChart: React.FC<FunctionChartProps> = ({
fn, fn,
chartSettings, chartSettings,
environment, environment,
distributionPlotSettings,
height, height,
}) => { }) => {
if (fn.parameters.length > 1) { if (fn.parameters.length > 1) {
@ -53,6 +56,7 @@ export const FunctionChart: React.FC<FunctionChartProps> = ({
chartSettings={chartSettings} chartSettings={chartSettings}
environment={environment} environment={environment}
height={height} height={height}
distributionPlotSettings={distributionPlotSettings}
/> />
); );
case "number": case "number":

View File

@ -13,7 +13,10 @@ import {
} from "@quri/squiggle-lang"; } from "@quri/squiggle-lang";
import { createClassFromSpec } from "react-vega"; import { createClassFromSpec } from "react-vega";
import * as percentilesSpec from "../vega-specs/spec-percentiles.json"; import * as percentilesSpec from "../vega-specs/spec-percentiles.json";
import { DistributionChart } from "./DistributionChart"; import {
DistributionChart,
DistributionPlottingSettings,
} from "./DistributionChart";
import { NumberShower } from "./NumberShower"; import { NumberShower } from "./NumberShower";
import { ErrorAlert } from "./Alert"; import { ErrorAlert } from "./Alert";
@ -44,6 +47,7 @@ export type FunctionChartSettings = {
interface FunctionChart1DistProps { interface FunctionChart1DistProps {
fn: lambdaValue; fn: lambdaValue;
chartSettings: FunctionChartSettings; chartSettings: FunctionChartSettings;
distributionPlotSettings: DistributionPlottingSettings;
environment: environment; environment: environment;
height: number; height: number;
} }
@ -150,6 +154,7 @@ export const FunctionChart1Dist: React.FC<FunctionChart1DistProps> = ({
fn, fn,
chartSettings, chartSettings,
environment, environment,
distributionPlotSettings,
height, height,
}) => { }) => {
let [mouseOverlay, setMouseOverlay] = React.useState(0); let [mouseOverlay, setMouseOverlay] = React.useState(0);
@ -175,7 +180,7 @@ export const FunctionChart1Dist: React.FC<FunctionChart1DistProps> = ({
distribution={mouseItem.value.value} distribution={mouseItem.value.value}
width={400} width={400}
height={50} height={50}
showSummary={false} {...distributionPlotSettings}
/> />
) : null; ) : null;

View File

@ -37,6 +37,10 @@ export interface SquiggleChartProps {
showTypes?: boolean; showTypes?: boolean;
/** Whether to show graph controls (scale etc)*/ /** Whether to show graph controls (scale etc)*/
showControls?: boolean; showControls?: boolean;
/** Set the x scale to be logarithmic by deault */
logX?: boolean;
/** Set the y scale to be exponential by deault */
expY?: boolean;
} }
const defaultOnChange = () => {}; const defaultOnChange = () => {};
@ -53,6 +57,8 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = ({
width, width,
showTypes = false, showTypes = false,
showControls = false, showControls = false,
logX = false,
expY = false,
chartSettings = defaultChartSettings, chartSettings = defaultChartSettings,
}) => { }) => {
const { result } = useSquiggle({ const { result } = useSquiggle({
@ -67,14 +73,20 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = ({
return <SquiggleErrorAlert error={result.value} />; return <SquiggleErrorAlert error={result.value} />;
} }
let distributionPlotSettings = {
showControls,
showSummary,
logX,
expY,
};
return ( return (
<SquiggleItem <SquiggleItem
expression={result.value} expression={result.value}
width={width} width={width}
height={height} height={height}
showSummary={showSummary} distributionPlotSettings={distributionPlotSettings}
showTypes={showTypes} showTypes={showTypes}
showControls={showControls}
chartSettings={chartSettings} chartSettings={chartSettings}
environment={environment ?? defaultEnvironment} environment={environment ?? defaultEnvironment}
/> />

View File

@ -54,6 +54,10 @@ export interface SquiggleEditorProps {
showControls?: boolean; showControls?: boolean;
/** Whether to show a summary table */ /** Whether to show a summary table */
showSummary?: boolean; showSummary?: boolean;
/** Whether to log the x coordinate on distribution charts */
logX?: boolean;
/** Whether to exp the y coordinate on distribution charts */
expY?: boolean;
} }
export const SquiggleEditor: React.FC<SquiggleEditorProps> = ({ export const SquiggleEditor: React.FC<SquiggleEditorProps> = ({
@ -69,8 +73,14 @@ export const SquiggleEditor: React.FC<SquiggleEditorProps> = ({
showTypes = false, showTypes = false,
showControls = false, showControls = false,
showSummary = false, showSummary = false,
logX = false,
expY = false,
}: SquiggleEditorProps) => { }: SquiggleEditorProps) => {
const [code, setCode] = useState(initialSquiggleString); const [code, setCode] = useState(initialSquiggleString);
React.useEffect(
() => setCode(initialSquiggleString),
[initialSquiggleString]
);
const { result, observableRef } = useSquiggle({ const { result, observableRef } = useSquiggle({
code, code,
@ -86,6 +96,13 @@ export const SquiggleEditor: React.FC<SquiggleEditorProps> = ({
count: diagramCount, count: diagramCount,
}; };
const distributionPlotSettings = {
showControls,
showSummary,
logX,
expY,
};
return ( return (
<div ref={observableRef}> <div ref={observableRef}>
<SquiggleContainer> <SquiggleContainer>
@ -95,9 +112,8 @@ export const SquiggleEditor: React.FC<SquiggleEditorProps> = ({
expression={result.value} expression={result.value}
width={width} width={width}
height={200} height={200}
showSummary={showSummary} distributionPlotSettings={distributionPlotSettings}
showTypes={showTypes} showTypes={showTypes}
showControls={showControls}
chartSettings={chartSettings} chartSettings={chartSettings}
environment={environment ?? defaultEnvironment} environment={environment ?? defaultEnvironment}
/> />
@ -136,6 +152,10 @@ export const SquigglePartial: React.FC<SquigglePartialProps> = ({
jsImports = defaultImports, jsImports = defaultImports,
}: SquigglePartialProps) => { }: SquigglePartialProps) => {
const [code, setCode] = useState(initialSquiggleString); const [code, setCode] = useState(initialSquiggleString);
React.useEffect(
() => setCode(initialSquiggleString),
[initialSquiggleString]
);
const { result, observableRef } = useSquigglePartial({ const { result, observableRef } = useSquigglePartial({
code, code,

View File

@ -5,7 +5,10 @@ import {
declaration, declaration,
} from "@quri/squiggle-lang"; } from "@quri/squiggle-lang";
import { NumberShower } from "./NumberShower"; import { NumberShower } from "./NumberShower";
import { DistributionChart } from "./DistributionChart"; import {
DistributionChart,
DistributionPlottingSettings,
} from "./DistributionChart";
import { FunctionChart, FunctionChartSettings } from "./FunctionChart"; import { FunctionChart, FunctionChartSettings } from "./FunctionChart";
function getRange<a>(x: declaration<a>) { function getRange<a>(x: declaration<a>) {
@ -61,12 +64,9 @@ export interface SquiggleItemProps {
expression: squiggleExpression; expression: squiggleExpression;
width?: number; width?: number;
height: number; height: number;
/** Whether to show a summary of statistics for distributions */ distributionPlotSettings: DistributionPlottingSettings;
showSummary: boolean;
/** Whether to show type information */ /** Whether to show type information */
showTypes: boolean; showTypes: boolean;
/** Whether to show users graph controls (scale etc) */
showControls: boolean;
/** Settings for displaying functions */ /** Settings for displaying functions */
chartSettings: FunctionChartSettings; chartSettings: FunctionChartSettings;
/** Environment for further function executions */ /** Environment for further function executions */
@ -77,9 +77,8 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
expression, expression,
width, width,
height, height,
showSummary, distributionPlotSettings,
showTypes = false, showTypes = false,
showControls = false,
chartSettings, chartSettings,
environment, environment,
}) => { }) => {
@ -104,10 +103,9 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
) : null} ) : null}
<DistributionChart <DistributionChart
distribution={expression.value} distribution={expression.value}
{...distributionPlotSettings}
height={height} height={height}
width={width} width={width}
showSummary={showSummary}
showControls={showControls}
/> />
</VariableBox> </VariableBox>
); );
@ -155,11 +153,10 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
expression={r} expression={r}
width={width !== undefined ? width - 20 : width} width={width !== undefined ? width - 20 : width}
height={50} height={50}
distributionPlotSettings={distributionPlotSettings}
showTypes={showTypes} showTypes={showTypes}
showControls={showControls}
chartSettings={chartSettings} chartSettings={chartSettings}
environment={environment} environment={environment}
showSummary={showSummary}
/> />
</div> </div>
</div> </div>
@ -181,8 +178,7 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
width={width !== undefined ? width - 20 : width} width={width !== undefined ? width - 20 : width}
height={height / 3} height={height / 3}
showTypes={showTypes} showTypes={showTypes}
showSummary={showSummary} distributionPlotSettings={distributionPlotSettings}
showControls={showControls}
chartSettings={chartSettings} chartSettings={chartSettings}
environment={environment} environment={environment}
/> />
@ -220,6 +216,7 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
<FunctionChart <FunctionChart
fn={expression.value} fn={expression.value}
chartSettings={chartSettings} chartSettings={chartSettings}
distributionPlotSettings={distributionPlotSettings}
height={height} height={height}
environment={{ environment={{
sampleCount: environment.sampleCount / 10, sampleCount: environment.sampleCount / 10,
@ -234,6 +231,7 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
<FunctionChart <FunctionChart
fn={expression.value.fn} fn={expression.value.fn}
chartSettings={getChartSettings(expression.value)} chartSettings={getChartSettings(expression.value)}
distributionPlotSettings={distributionPlotSettings}
height={height} height={height}
environment={{ environment={{
sampleCount: environment.sampleCount / 10, sampleCount: environment.sampleCount / 10,

View File

@ -32,6 +32,10 @@ interface PlaygroundProps {
showControls?: boolean; showControls?: boolean;
/** Whether to show the summary table in the playground */ /** Whether to show the summary table in the playground */
showSummary?: boolean; showSummary?: boolean;
/** Whether to log the x coordinate on distribution charts */
logX?: boolean;
/** Whether to exp the y coordinate on distribution charts */
expY?: boolean;
/** If code is set, component becomes controlled */ /** If code is set, component becomes controlled */
code?: string; code?: string;
onCodeChange?(expr: string): void; onCodeChange?(expr: string): void;
@ -72,6 +76,8 @@ const schema = yup
showControls: yup.boolean(), showControls: yup.boolean(),
showSummary: yup.boolean(), showSummary: yup.boolean(),
showEditor: yup.boolean(), showEditor: yup.boolean(),
logX: yup.boolean(),
expY: yup.boolean(),
showSettingsPage: yup.boolean().default(false), showSettingsPage: yup.boolean().default(false),
diagramStart: yup diagramStart: yup
.number() .number()
@ -204,6 +210,8 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
showTypes = false, showTypes = false,
showControls = false, showControls = false,
showSummary = false, showSummary = false,
logX = false,
expY = false,
code: controlledCode, code: controlledCode,
onCodeChange, onCodeChange,
onSettingsChange, onSettingsChange,
@ -221,10 +229,12 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
sampleCount: 1000, sampleCount: 1000,
xyPointLength: 1000, xyPointLength: 1000,
chartHeight: 150, chartHeight: 150,
showTypes: showTypes, showTypes,
showControls: showControls, showControls,
showSummary: showSummary, logX,
showEditor: showEditor, expY,
showSummary,
showEditor,
leftSizePercent: 50, leftSizePercent: 50,
showSettingsPage: false, showSettingsPage: false,
diagramStart: 0, diagramStart: 0,
@ -320,6 +330,16 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
<div className="pt-8"> <div className="pt-8">
<HeadedSection title="Distribution Display Settings"> <HeadedSection title="Distribution Display Settings">
<div className="space-y-2"> <div className="space-y-2">
<Checkbox
register={register}
name="logX"
label="Show x scale logarithmically"
/>
<Checkbox
register={register}
name="expY"
label="Show y scale exponentially"
/>
<Checkbox <Checkbox
register={register} register={register}
name="showControls" name="showControls"
@ -410,6 +430,8 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
showTypes={vars.showTypes} showTypes={vars.showTypes}
showControls={vars.showControls} showControls={vars.showControls}
showSummary={vars.showSummary} showSummary={vars.showSummary}
logX={vars.logX}
expY={vars.expY}
bindings={defaultBindings} bindings={defaultBindings}
jsImports={imports} jsImports={imports}
/> />