simplify settings objects (WIP)

This commit is contained in:
Vyacheslav Matyukhin 2022-07-29 02:52:32 +04:00
parent 4cdf9a6008
commit a3187b0a15
No known key found for this signature in database
GPG Key ID: 3D2A774C5489F96C
12 changed files with 211 additions and 285 deletions

View File

@ -16,27 +16,43 @@ import {
import { NumberShower } from "./NumberShower";
import { hasMassBelowZero } from "../lib/distributionUtils";
export type DistributionPlottingSettings = {
export type PlotSettings = {
/** Whether to show a summary of means, stdev, percentiles etc */
showSummary: boolean;
actions?: boolean;
/** Whether to show vega actions to the user, so they can copy the chart spec */
actions: boolean;
} & DistributionChartSpecOptions;
export const plotSettingsFromPartial = (
partial: Partial<PlotSettings>
): PlotSettings => {
return {
showSummary: false,
logX: false,
expY: false,
color: "#739ECC",
tickFormat: ".9~s",
title: "",
actions: false,
...partial,
};
};
export type DistributionChartProps = {
distribution: Distribution;
width?: number;
height: number;
} & DistributionPlottingSettings;
settings: PlotSettings;
};
export const DistributionChart: React.FC<DistributionChartProps> = (props) => {
const {
distribution,
height,
showSummary,
width,
logX,
actions = false,
settings: { showSummary, logX, actions },
} = props;
const shape = distribution.pointSet();
const [sized] = useSize((size) => {
if (shape.tag === "Error") {
@ -47,7 +63,7 @@ export const DistributionChart: React.FC<DistributionChartProps> = (props) => {
);
}
const spec = buildVegaSpec(props);
const spec = buildVegaSpec(props.settings);
let widthProp = width ? width : size.width;
if (widthProp < 20) {
@ -131,15 +147,15 @@ const SummaryTable: React.FC<SummaryTableProps> = ({ distribution }) => {
<table className="border border-collapse border-slate-400">
<thead className="bg-slate-50">
<tr>
<TableHeadCell>{"Mean"}</TableHeadCell>
{hasResult(stdev) && <TableHeadCell>{"Stdev"}</TableHeadCell>}
<TableHeadCell>{"5%"}</TableHeadCell>
<TableHeadCell>{"10%"}</TableHeadCell>
<TableHeadCell>{"25%"}</TableHeadCell>
<TableHeadCell>{"50%"}</TableHeadCell>
<TableHeadCell>{"75%"}</TableHeadCell>
<TableHeadCell>{"90%"}</TableHeadCell>
<TableHeadCell>{"95%"}</TableHeadCell>
<TableHeadCell>Mean</TableHeadCell>
{hasResult(stdev) && <TableHeadCell>Stdev</TableHeadCell>}
<TableHeadCell>5%</TableHeadCell>
<TableHeadCell>10%</TableHeadCell>
<TableHeadCell>25%</TableHeadCell>
<TableHeadCell>50%</TableHeadCell>
<TableHeadCell>75%</TableHeadCell>
<TableHeadCell>90%</TableHeadCell>
<TableHeadCell>95%</TableHeadCell>
</tr>
</thead>
<tbody>

View File

@ -7,28 +7,42 @@ import {
} from "@quri/squiggle-lang";
import { FunctionChart1Dist } from "./FunctionChart1Dist";
import { FunctionChart1Number } from "./FunctionChart1Number";
import { DistributionPlottingSettings } from "./DistributionChart";
import { PlotSettings } from "./DistributionChart";
import { ErrorAlert, MessageAlert } from "./Alert";
export type FunctionChartSettings = {
export type FunctionSettings = {
/** Where the function domain starts */
start: number;
/** Where the function domain ends */
stop: number;
/** The amount of stops sampled */
count: number;
};
interface FunctionChartProps {
fn: lambdaValue;
chartSettings: FunctionChartSettings;
distributionPlotSettings: DistributionPlottingSettings;
functionSettings: FunctionSettings;
plotSettings: PlotSettings;
environment: environment;
height: number;
}
export const functionSettingsFromPartial = (
partial: Partial<FunctionSettings>
): FunctionSettings => {
return {
start: 0,
stop: 10,
count: 20,
...partial,
};
};
export const FunctionChart: React.FC<FunctionChartProps> = ({
fn,
chartSettings,
functionSettings,
environment,
distributionPlotSettings,
plotSettings,
height,
}) => {
if (fn.parameters.length > 1) {
@ -38,8 +52,8 @@ export const FunctionChart: React.FC<FunctionChartProps> = ({
</MessageAlert>
);
}
const result1 = runForeign(fn, [chartSettings.start], environment);
const result2 = runForeign(fn, [chartSettings.stop], environment);
const result1 = runForeign(fn, [functionSettings.start], environment);
const result2 = runForeign(fn, [functionSettings.stop], environment);
const getValidResult = () => {
if (result1.tag === "Ok") {
return result1;
@ -64,17 +78,17 @@ export const FunctionChart: React.FC<FunctionChartProps> = ({
return (
<FunctionChart1Dist
fn={fn}
chartSettings={chartSettings}
chartSettings={functionSettings}
environment={environment}
height={height}
distributionPlotSettings={distributionPlotSettings}
distributionPlotSettings={plotSettings}
/>
);
case "number":
return (
<FunctionChart1Number
fn={fn}
chartSettings={chartSettings}
chartSettings={functionSettings}
environment={environment}
height={height}
/>

View File

@ -13,12 +13,10 @@ import {
} from "@quri/squiggle-lang";
import { createClassFromSpec } from "react-vega";
import * as percentilesSpec from "../vega-specs/spec-percentiles.json";
import {
DistributionChart,
DistributionPlottingSettings,
} from "./DistributionChart";
import { DistributionChart, PlotSettings } from "./DistributionChart";
import { NumberShower } from "./NumberShower";
import { ErrorAlert } from "./Alert";
import { FunctionSettings } from "./FunctionChart";
let SquigglePercentilesChart = createClassFromSpec({
spec: percentilesSpec as Spec,
@ -38,16 +36,11 @@ function unwrap<a, b>(x: result<a, b>): a {
throw Error("FAILURE TO UNWRAP");
}
}
export type FunctionChartSettings = {
start: number;
stop: number;
count: number;
};
interface FunctionChart1DistProps {
fn: lambdaValue;
chartSettings: FunctionChartSettings;
distributionPlotSettings: DistributionPlottingSettings;
chartSettings: FunctionSettings;
distributionPlotSettings: PlotSettings;
environment: environment;
height: number;
}
@ -182,7 +175,7 @@ export const FunctionChart1Dist: React.FC<FunctionChart1DistProps> = ({
distribution={mouseItem.value.value}
width={400}
height={50}
{...distributionPlotSettings}
settings={distributionPlotSettings}
/>
) : null;

View File

@ -10,6 +10,8 @@ import {
} from "@quri/squiggle-lang";
import { useSquiggle } from "../lib/hooks";
import { SquiggleViewer } from "./SquiggleViewer";
import { FunctionSettings, functionSettingsFromPartial } from "./FunctionChart";
import { PlotSettings, plotSettingsFromPartial } from "./DistributionChart";
export interface SquiggleChartProps {
/** The input string for squiggle */
@ -20,12 +22,8 @@ export interface SquiggleChartProps {
sampleCount?: number;
/** The amount of points returned to draw the distribution */
environment?: environment;
/** If the result is a function, where the function domain starts */
diagramStart?: number;
/** If the result is a function, where the function domain ends */
diagramStop?: number;
/** If the result is a function, the amount of stops sampled */
diagramCount?: number;
plotSettings?: PlotSettings;
functionSettings?: FunctionSettings;
/** When the squiggle code gets reevaluated */
onChange?(expr: squiggleExpression | undefined): void;
/** CSS width of the element */
@ -35,24 +33,6 @@ export interface SquiggleChartProps {
bindings?: bindings;
/** JS imported parameters */
jsImports?: jsImports;
/** Whether to show a summary of the distribution */
showSummary?: boolean;
/** Set the x scale to be logarithmic by deault */
logX?: boolean;
/** Set the y scale to be exponential by deault */
expY?: boolean;
/** How to format numbers on the x axis */
tickFormat?: string;
/** Title of the graphed distribution */
title?: string;
/** Color of the graphed distribution */
color?: string;
/** Specify the lower bound of the x scale */
minX?: number;
/** Specify the upper bound of the x scale */
maxX?: number;
/** Whether to show vega actions to the user, so they can copy the chart spec */
distributionChartActions?: boolean;
enableLocalSettings?: boolean;
}
@ -67,19 +47,9 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = React.memo(
height = 200,
bindings = defaultBindings,
jsImports = defaultImports,
showSummary = false,
width,
logX = false,
expY = false,
diagramStart = 0,
diagramStop = 10,
diagramCount = 100,
tickFormat,
minX,
maxX,
color,
title,
distributionChartActions,
functionSettings,
plotSettings,
enableLocalSettings = false,
}) => {
const result = useSquiggle({
@ -91,31 +61,13 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = React.memo(
executionId,
});
const distributionPlotSettings = {
showSummary,
logX,
expY,
format: tickFormat,
minX,
maxX,
color,
title,
actions: distributionChartActions,
};
const chartSettings = {
start: diagramStart,
stop: diagramStop,
count: diagramCount,
};
return (
<SquiggleViewer
result={result}
width={width}
height={height}
distributionPlotSettings={distributionPlotSettings}
chartSettings={chartSettings}
plotSettings={plotSettingsFromPartial(plotSettings || {})}
functionSettings={functionSettingsFromPartial(functionSettings || {})}
environment={environment ?? defaultEnvironment}
enableLocalSettings={enableLocalSettings}
/>

View File

@ -6,7 +6,7 @@ import React, {
useRef,
useCallback,
} from "react";
import { useForm, UseFormRegister, useWatch } from "react-hook-form";
import { useForm, UseFormRegister } from "react-hook-form";
import * as yup from "yup";
import { useMaybeControlledValue, useRunnerState } from "../lib/hooks";
import { yupResolver } from "@hookform/resolvers/yup";
@ -36,10 +36,8 @@ import { InputItem } from "./ui/InputItem";
import { Text } from "./ui/Text";
import { ViewSettings, viewSettingsSchema } from "./ViewSettings";
import { HeadedSection } from "./ui/HeadedSection";
import {
defaultColor,
defaultTickFormat,
} from "../lib/distributionSpecBuilder";
import { plotSettingsFromPartial } from "./DistributionChart";
import { functionSettingsFromPartial } from "./FunctionChart";
type PlaygroundProps = SquiggleChartProps & {
/** The initial squiggle string to put in the playground */
@ -52,8 +50,8 @@ type PlaygroundProps = SquiggleChartProps & {
};
const schema = yup
.object({})
.shape({
.object({
sampleSettings: yup.object({
sampleCount: yup
.number()
.required()
@ -70,6 +68,7 @@ const schema = yup
.default(1000)
.min(10)
.max(10000),
}),
})
.concat(viewSettingsSchema);
@ -81,7 +80,7 @@ const SamplingSettings: React.FC<{ register: UseFormRegister<FormFields> }> = ({
<div className="space-y-6 p-3 max-w-xl">
<div>
<InputItem
name="sampleCount"
name="sampleSettings.sampleCount"
type="number"
label="Sample Count"
register={register}
@ -95,7 +94,7 @@ const SamplingSettings: React.FC<{ register: UseFormRegister<FormFields> }> = ({
</div>
<div>
<InputItem
name="xyPointLength"
name="sampleSettings.xyPointLength"
type="number"
register={register}
label="Coordinate Count (For PointSet Shapes)"
@ -207,15 +206,8 @@ export const PlaygroundContext = React.createContext<PlaygroundContextShape>({
export const SquigglePlayground: FC<PlaygroundProps> = ({
defaultCode = "",
height = 500,
showSummary = false,
logX = false,
expY = false,
title,
minX,
maxX,
color = defaultColor,
tickFormat = defaultTickFormat,
distributionChartActions,
plotSettings: initialPlotSettings,
functionSettings: initialFunctionSettings,
code: controlledCode,
onCodeChange,
onSettingsChange,
@ -229,41 +221,40 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
const [imports, setImports] = useState({});
const { register, control } = useForm({
resolver: yupResolver(schema),
defaultValues: {
const defaultValues = {
chartHeight: 150,
showEditor,
sampleSettings: {
sampleCount: 1000,
xyPointLength: 1000,
chartHeight: 150,
logX,
expY,
title,
minX,
maxX,
color,
tickFormat,
distributionChartActions,
showSummary,
showEditor,
diagramStart: 0,
diagramStop: 10,
diagramCount: 20,
},
});
const vars = useWatch({
control,
});
plotSettings: plotSettingsFromPartial(initialPlotSettings || {}),
functionSettings: functionSettingsFromPartial(
initialFunctionSettings || {}
),
};
const { register, watch, getValues } = useForm<FormFields>({
resolver: yupResolver(schema),
defaultValues,
});
watch();
const [settings, setSettings] = useState(() => getValues());
useEffect(() => {
onSettingsChange?.(vars);
}, [vars, onSettingsChange]);
const subscription = watch(() => {
setSettings(getValues());
onSettingsChange?.(getValues());
});
return () => subscription.unsubscribe();
}, [onSettingsChange, getValues, watch]);
const env: environment = useMemo(
() => ({
sampleCount: Number(vars.sampleCount),
xyPointLength: Number(vars.xyPointLength),
sampleCount: Number(settings.sampleSettings.sampleCount),
xyPointLength: Number(settings.sampleSettings.xyPointLength),
}),
[vars.sampleCount, vars.xyPointLength]
[settings.sampleSettings.sampleCount, settings.sampleSettings.xyPointLength]
);
const {
@ -285,7 +276,8 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
code={renderedCode}
executionId={executionId}
environment={env}
{...vars}
plotSettings={settings.plotSettings}
functionSettings={settings.functionSettings}
bindings={defaultBindings}
jsImports={imports}
enableLocalSettings={true}
@ -293,7 +285,7 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
</div>
);
const firstTab = vars.showEditor ? (
const firstTab = settings.showEditor ? (
<div className="border border-slate-200">
<CodeEditor
value={code}
@ -363,8 +355,8 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
<div className="flex justify-between items-center">
<StyledTab.List>
<StyledTab
name={vars.showEditor ? "Code" : "Display"}
icon={vars.showEditor ? CodeIcon : EyeIcon}
name={settings.showEditor ? "Code" : "Display"}
icon={settings.showEditor ? CodeIcon : EyeIcon}
/>
<StyledTab name="Sampling Settings" icon={CogIcon} />
<StyledTab name="View Settings" icon={ChartSquareBarIcon} />
@ -378,7 +370,7 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
onAutorunModeChange={setAutorunMode}
/>
</div>
{vars.showEditor ? withEditor : withoutEditor}
{settings.showEditor ? withEditor : withoutEditor}
</div>
</StyledTab.Group>
</PlaygroundContext.Provider>

View File

@ -2,7 +2,7 @@ import React from "react";
import { squiggleExpression, declaration } from "@quri/squiggle-lang";
import { NumberShower } from "../NumberShower";
import { DistributionChart } from "../DistributionChart";
import { FunctionChart, FunctionChartSettings } from "../FunctionChart";
import { FunctionChart, FunctionSettings } from "../FunctionChart";
import clsx from "clsx";
import { VariableBox } from "./VariableBox";
import { ItemSettingsMenu } from "./ItemSettingsMenu";
@ -21,7 +21,7 @@ function getRange<a>(x: declaration<a>) {
}
}
function getChartSettings<a>(x: declaration<a>): FunctionChartSettings {
function getFunctionSettings<a>(x: declaration<a>): FunctionSettings {
const range = getRange(x);
const min = range.floats ? range.floats.min : 0;
const max = range.floats ? range.floats.max : 10;
@ -96,7 +96,7 @@ export const ExpressionViewer: React.FC<Props> = ({
return (
<DistributionChart
distribution={expression.value}
{...settings.distributionPlotSettings}
settings={settings.plotSettings}
height={settings.height}
width={width}
/>
@ -189,8 +189,8 @@ export const ExpressionViewer: React.FC<Props> = ({
)})`}</div>
<FunctionChart
fn={expression.value}
chartSettings={settings.chartSettings}
distributionPlotSettings={settings.distributionPlotSettings}
functionSettings={settings.functionSettings}
plotSettings={settings.plotSettings}
height={settings.height}
environment={{
sampleCount: settings.environment.sampleCount / 10,
@ -219,8 +219,8 @@ export const ExpressionViewer: React.FC<Props> = ({
{(settings) => (
<FunctionChart
fn={expression.value.fn}
chartSettings={getChartSettings(expression.value)}
distributionPlotSettings={settings.distributionPlotSettings}
functionSettings={getFunctionSettings(expression.value)}
plotSettings={settings.plotSettings}
height={settings.height}
environment={{
sampleCount: settings.environment.sampleCount / 10,

View File

@ -3,13 +3,13 @@ import React, { useContext, useRef, useState, useEffect } from "react";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import { Modal } from "../ui/Modal";
import { ViewSettings, viewSettingsSchema } from "../ViewSettings";
import {
ViewSettings,
ViewSettingsFormFields,
viewSettingsSchema,
} from "../ViewSettings";
import { Path, pathAsString } from "./utils";
import { ViewerContext } from "./ViewerContext";
import {
defaultColor,
defaultTickFormat,
} from "../../lib/distributionSpecBuilder";
import { PlaygroundContext } from "../SquigglePlayground";
type Props = {
@ -34,48 +34,25 @@ const ItemSettingsModal: React.FC<
const mergedSettings = getMergedSettings(path);
const { register, watch } = useForm({
const { register, watch } = useForm<ViewSettingsFormFields>({
resolver: yupResolver(viewSettingsSchema),
defaultValues: {
// this is a mess and should be fixed
showEditor: true, // doesn't matter
chartHeight: mergedSettings.height,
showSummary: mergedSettings.distributionPlotSettings.showSummary,
logX: mergedSettings.distributionPlotSettings.logX,
expY: mergedSettings.distributionPlotSettings.expY,
tickFormat:
mergedSettings.distributionPlotSettings.format || defaultTickFormat,
title: mergedSettings.distributionPlotSettings.title,
color: mergedSettings.distributionPlotSettings.color || defaultColor,
minX: mergedSettings.distributionPlotSettings.minX,
maxX: mergedSettings.distributionPlotSettings.maxX,
distributionChartActions: mergedSettings.distributionPlotSettings.actions,
diagramStart: mergedSettings.chartSettings.start,
diagramStop: mergedSettings.chartSettings.stop,
diagramCount: mergedSettings.chartSettings.count,
plotSettings: mergedSettings.plotSettings,
functionSettings: mergedSettings.functionSettings,
},
});
useEffect(() => {
const subscription = watch((vars) => {
const settings = getSettings(path); // get the latest version
setSettings(path, {
...settings,
distributionPlotSettings: {
showSummary: vars.showSummary,
logX: vars.logX,
expY: vars.expY,
format: vars.tickFormat,
title: vars.title,
color: vars.color,
minX: vars.minX,
maxX: vars.maxX,
actions: vars.distributionChartActions,
},
chartSettings: {
start: vars.diagramStart,
stop: vars.diagramStop,
count: vars.diagramCount,
},
// vars should be defined and react-hook-form is too conservative with its types so these `?.` are ok... hopefully.
// This might cause a bug in the future. I don't really understand why react-hook-form needs to return partials here.
plotSettings: vars?.plotSettings,
functionSettings: vars?.functionSettings,
});
onChange();
});
@ -141,13 +118,13 @@ export const ItemSettingsMenu: React.FC<Props> = (props) => {
className="h-5 w-5 cursor-pointer text-slate-400 hover:text-slate-500"
onClick={() => setIsOpen(!isOpen)}
/>
{settings.distributionPlotSettings || settings.chartSettings ? (
{settings.plotSettings || settings.functionSettings ? (
<button
onClick={() => {
setSettings(props.path, {
...settings,
distributionPlotSettings: undefined,
chartSettings: undefined,
plotSettings: undefined,
functionSettings: undefined,
});
props.onChange();
}}

View File

@ -1,5 +1,7 @@
import { defaultEnvironment } from "@quri/squiggle-lang";
import React from "react";
import { plotSettingsFromPartial } from "../DistributionChart";
import { functionSettingsFromPartial } from "../FunctionChart";
import { LocalItemSettings, MergedItemSettings, Path } from "./utils";
type ViewerContextShape = {
@ -17,16 +19,8 @@ export const ViewerContext = React.createContext<ViewerContextShape>({
getMergedSettings: () => ({
collapsed: false,
// copy-pasted from SquiggleChart
chartSettings: {
start: 0,
stop: 10,
count: 100,
},
distributionPlotSettings: {
showSummary: false,
logX: false,
expY: false,
},
plotSettings: plotSettingsFromPartial({}),
functionSettings: functionSettingsFromPartial({}),
environment: defaultEnvironment,
height: 150,
}),

View File

@ -1,7 +1,7 @@
import React, { useCallback, useRef } from "react";
import { environment } from "@quri/squiggle-lang";
import { DistributionPlottingSettings } from "../DistributionChart";
import { FunctionChartSettings } from "../FunctionChart";
import { PlotSettings } from "../DistributionChart";
import { FunctionSettings } from "../FunctionChart";
import { ExpressionViewer } from "./ExpressionViewer";
import { ViewerContext } from "./ViewerContext";
import {
@ -18,9 +18,8 @@ type Props = {
result: ReturnType<typeof useSquiggle>;
width?: number;
height: number;
distributionPlotSettings: DistributionPlottingSettings;
/** Settings for displaying functions */
chartSettings: FunctionChartSettings;
plotSettings: PlotSettings;
functionSettings: FunctionSettings;
/** Environment for further function executions */
environment: environment;
enableLocalSettings?: boolean;
@ -36,8 +35,8 @@ export const SquiggleViewer: React.FC<Props> = ({
result,
width,
height,
distributionPlotSettings,
chartSettings,
plotSettings,
functionSettings,
environment,
enableLocalSettings = false,
}) => {
@ -62,13 +61,13 @@ export const SquiggleViewer: React.FC<Props> = ({
(path: Path) => {
const localSettings = getSettings(path);
const result: MergedItemSettings = {
distributionPlotSettings: {
...distributionPlotSettings,
...(localSettings.distributionPlotSettings || {}),
plotSettings: {
...plotSettings,
...(localSettings.plotSettings || {}),
},
chartSettings: {
...chartSettings,
...(localSettings.chartSettings || {}),
functionSettings: {
...functionSettings,
...(localSettings.functionSettings || {}),
},
environment: {
...environment,
@ -78,7 +77,7 @@ export const SquiggleViewer: React.FC<Props> = ({
};
return result;
},
[distributionPlotSettings, chartSettings, environment, height, getSettings]
[plotSettings, functionSettings, environment, height, getSettings]
);
return (

View File

@ -1,18 +1,18 @@
import { DistributionPlottingSettings } from "../DistributionChart";
import { FunctionChartSettings } from "../FunctionChart";
import { PlotSettings } from "../DistributionChart";
import { FunctionSettings } from "../FunctionChart";
import { environment } from "@quri/squiggle-lang";
export type LocalItemSettings = {
collapsed: boolean;
distributionPlotSettings?: Partial<DistributionPlottingSettings>;
chartSettings?: Partial<FunctionChartSettings>;
plotSettings?: Partial<PlotSettings>;
functionSettings?: Partial<FunctionSettings>;
height?: number;
environment?: Partial<environment>;
};
export type MergedItemSettings = {
distributionPlotSettings: DistributionPlottingSettings;
chartSettings: FunctionChartSettings;
plotSettings: PlotSettings;
functionSettings: FunctionSettings;
height: number;
environment: environment;
};

View File

@ -5,36 +5,36 @@ import { InputItem } from "./ui/InputItem";
import { Checkbox } from "./ui/Checkbox";
import { HeadedSection } from "./ui/HeadedSection";
import { Text } from "./ui/Text";
import {
defaultColor,
defaultTickFormat,
} from "../lib/distributionSpecBuilder";
export const viewSettingsSchema = yup.object({}).shape({
chartHeight: yup.number().required().positive().integer().default(350),
showSummary: yup.boolean().required(),
showEditor: yup.boolean().required(),
plotSettings: yup.object({
showSummary: yup.boolean().required(),
logX: yup.boolean().required(),
expY: yup.boolean().required(),
tickFormat: yup.string().default(defaultTickFormat),
title: yup.string(),
color: yup.string().default(defaultColor).required(),
tickFormat: yup.string().required(),
title: yup.string().default(""),
color: yup.string().required(),
minX: yup.number(),
maxX: yup.number(),
distributionChartActions: yup.boolean(),
diagramStart: yup.number().required().positive().integer().default(0).min(0),
diagramStop: yup.number().required().positive().integer().default(10).min(0),
diagramCount: yup.number().required().positive().integer().default(20).min(2),
actions: yup.boolean().required(),
}),
functionSettings: yup.object({
start: yup.number().required().positive().integer().default(0).min(0),
stop: yup.number().required().positive().integer().default(10).min(0),
count: yup.number().required().positive().integer().default(20).min(2),
}),
});
type FormFields = yup.InferType<typeof viewSettingsSchema>;
export type ViewSettingsFormFields = yup.InferType<typeof viewSettingsSchema>;
// This component is used in two places: for global settings in SquigglePlayground, and for item-specific settings in modal dialogs.
export const ViewSettings: React.FC<{
withShowEditorSetting?: boolean;
withFunctionSettings?: boolean;
disableLogXSetting?: boolean;
register: UseFormRegister<FormFields>;
register: UseFormRegister<ViewSettingsFormFields>;
}> = ({
withShowEditorSetting = true,
withFunctionSettings = true,
@ -66,7 +66,7 @@ export const ViewSettings: React.FC<{
<div className="space-y-2">
<Checkbox
register={register}
name="logX"
name="plotSettings.logX"
label="Show x scale logarithmically"
disabled={disableLogXSetting}
tooltip={
@ -77,45 +77,45 @@ export const ViewSettings: React.FC<{
/>
<Checkbox
register={register}
name="expY"
name="plotSettings.expY"
label="Show y scale exponentially"
/>
<Checkbox
register={register}
name="distributionChartActions"
name="plotSettings.actions"
label="Show vega chart controls"
/>
<Checkbox
register={register}
name="showSummary"
name="plotSettings.showSummary"
label="Show summary statistics"
/>
<InputItem
name="minX"
name="plotSettings.minX"
type="number"
register={register}
label="Min X Value"
/>
<InputItem
name="maxX"
name="plotSettings.maxX"
type="number"
register={register}
label="Max X Value"
/>
<InputItem
name="title"
name="plotSettings.title"
type="text"
register={register}
label="Title"
/>
<InputItem
name="tickFormat"
name="plotSettings.tickFormat"
type="text"
register={register}
label="Tick Format"
/>
<InputItem
name="color"
name="plotSettings.color"
type="color"
register={register}
label="Color"
@ -137,19 +137,19 @@ export const ViewSettings: React.FC<{
<div className="space-y-4">
<InputItem
type="number"
name="diagramStart"
name="functionSettings.start"
register={register}
label="Min X Value"
/>
<InputItem
type="number"
name="diagramStop"
name="functionSettings.stop"
register={register}
label="Max X Value"
/>
<InputItem
type="number"
name="diagramCount"
name="functionSettings.count"
register={register}
label="Points between X min and X max to sample"
/>

View File

@ -2,20 +2,20 @@ import { VisualizationSpec } from "react-vega";
import type { LogScale, LinearScale, PowScale } from "vega";
export type DistributionChartSpecOptions = {
/** Set the x scale to be logarithmic by deault */
/** Set the x scale to be logarithmic by default */
logX: boolean;
/** Set the y scale to be exponential by deault */
/** Set the y scale to be exponential by default */
expY: boolean;
/** The minimum x coordinate shown on the chart */
minX?: number;
/** The maximum x coordinate shown on the chart */
maxX?: number;
/** The color of the chart */
color?: string;
color: string;
/** The title of the chart */
title?: string;
/** The formatting of the ticks */
format?: string;
title: string;
/** How to format numbers on the x axis */
tickFormat: string;
};
export let linearXScale: LinearScale = {
@ -100,21 +100,10 @@ export let expYScale: PowScale = {
},
};
export const defaultTickFormat = ".9~s";
export const defaultColor = "#739ECC";
export function buildVegaSpec(
specOptions: DistributionChartSpecOptions
): VisualizationSpec {
let {
format = defaultTickFormat,
color = defaultColor,
title,
minX,
maxX,
logX,
expY,
} = specOptions;
let { tickFormat, color, title, minX, maxX, logX, expY } = specOptions;
let xScale = logX ? logXScale : linearXScale;
if (minX !== undefined && Number.isFinite(minX)) {
@ -150,7 +139,7 @@ export function buildVegaSpec(
tickOpacity: 0.0,
domainColor: "#fff",
domainOpacity: 0.0,
format: format,
format: tickFormat,
tickCount: 10,
},
],