simplify settings objects (WIP)
This commit is contained in:
parent
4cdf9a6008
commit
a3187b0a15
|
@ -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>
|
||||
|
|
|
@ -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}
|
||||
/>
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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}
|
||||
/>
|
||||
|
|
|
@ -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,24 +50,25 @@ type PlaygroundProps = SquiggleChartProps & {
|
|||
};
|
||||
|
||||
const schema = yup
|
||||
.object({})
|
||||
.shape({
|
||||
sampleCount: yup
|
||||
.number()
|
||||
.required()
|
||||
.positive()
|
||||
.integer()
|
||||
.default(1000)
|
||||
.min(10)
|
||||
.max(1000000),
|
||||
xyPointLength: yup
|
||||
.number()
|
||||
.required()
|
||||
.positive()
|
||||
.integer()
|
||||
.default(1000)
|
||||
.min(10)
|
||||
.max(10000),
|
||||
.object({
|
||||
sampleSettings: yup.object({
|
||||
sampleCount: yup
|
||||
.number()
|
||||
.required()
|
||||
.positive()
|
||||
.integer()
|
||||
.default(1000)
|
||||
.min(10)
|
||||
.max(1000000),
|
||||
xyPointLength: yup
|
||||
.number()
|
||||
.required()
|
||||
.positive()
|
||||
.integer()
|
||||
.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>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
}}
|
||||
|
|
|
@ -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,
|
||||
}),
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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(),
|
||||
logX: yup.boolean().required(),
|
||||
expY: yup.boolean().required(),
|
||||
tickFormat: yup.string().default(defaultTickFormat),
|
||||
title: yup.string(),
|
||||
color: yup.string().default(defaultColor).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),
|
||||
plotSettings: yup.object({
|
||||
showSummary: yup.boolean().required(),
|
||||
logX: yup.boolean().required(),
|
||||
expY: yup.boolean().required(),
|
||||
tickFormat: yup.string().required(),
|
||||
title: yup.string().default(""),
|
||||
color: yup.string().required(),
|
||||
minX: yup.number(),
|
||||
maxX: yup.number(),
|
||||
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"
|
||||
/>
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
],
|
||||
|
|
Loading…
Reference in New Issue
Block a user