parent
							
								
									1ea3c975d5
								
							
						
					
					
						commit
						56c34de18a
					
				| 
						 | 
					@ -49,10 +49,10 @@ export function makePlot(record: SqRecord): Plot | void {
 | 
				
			||||||
export const DistributionChart: React.FC<DistributionChartProps> = (props) => {
 | 
					export const DistributionChart: React.FC<DistributionChartProps> = (props) => {
 | 
				
			||||||
  const {
 | 
					  const {
 | 
				
			||||||
    plot,
 | 
					    plot,
 | 
				
			||||||
    environment,
 | 
					 | 
				
			||||||
    height,
 | 
					    height,
 | 
				
			||||||
    showSummary,
 | 
					    showSummary,
 | 
				
			||||||
    width,
 | 
					    width,
 | 
				
			||||||
 | 
					    environment,
 | 
				
			||||||
    logX,
 | 
					    logX,
 | 
				
			||||||
    actions = false,
 | 
					    actions = false,
 | 
				
			||||||
  } = props;
 | 
					  } = props;
 | 
				
			||||||
| 
						 | 
					@ -89,8 +89,12 @@ export const DistributionChart: React.FC<DistributionChartProps> = (props) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const spec = buildVegaSpec({
 | 
					    const spec = buildVegaSpec({
 | 
				
			||||||
      ...props,
 | 
					      ...props,
 | 
				
			||||||
      minX: props.minX ?? Math.min(...domain.map((x) => x.x)),
 | 
					      minX: Number.isFinite(props.minX)
 | 
				
			||||||
      maxX: props.minX ?? Math.max(...domain.map((x) => x.x)),
 | 
					        ? props.minX
 | 
				
			||||||
 | 
					        : Math.min(...domain.map((x) => x.x)),
 | 
				
			||||||
 | 
					      maxX: Number.isFinite(props.maxX)
 | 
				
			||||||
 | 
					        ? props.maxX
 | 
				
			||||||
 | 
					        : Math.max(...domain.map((x) => x.x)),
 | 
				
			||||||
      maxY: Math.max(...domain.map((x) => x.y)),
 | 
					      maxY: Math.max(...domain.map((x) => x.y)),
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,161 +1,22 @@
 | 
				
			||||||
import * as React from "react";
 | 
					import * as React from "react";
 | 
				
			||||||
import { SqValue, environment, SqProject } from "@quri/squiggle-lang";
 | 
					import { useSquiggle, SquiggleArgs } from "../lib/hooks/useSquiggle";
 | 
				
			||||||
import { useSquiggle } from "../lib/hooks";
 | 
					import {
 | 
				
			||||||
import { SquiggleViewer } from "./SquiggleViewer";
 | 
					  SquiggleViewer,
 | 
				
			||||||
import { JsImports } from "../lib/jsImports";
 | 
					  FlattenedViewSettings,
 | 
				
			||||||
 | 
					  createViewSettings,
 | 
				
			||||||
 | 
					} from "./SquiggleViewer";
 | 
				
			||||||
import { getValueToRender } from "../lib/utility";
 | 
					import { getValueToRender } from "../lib/utility";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type SquiggleChartProps = {
 | 
					export type SquiggleChartProps = SquiggleArgs & FlattenedViewSettings;
 | 
				
			||||||
  /** The input string for squiggle */
 | 
					 | 
				
			||||||
  code: string;
 | 
					 | 
				
			||||||
  /** Allows to re-run the code if code hasn't changed */
 | 
					 | 
				
			||||||
  executionId?: number;
 | 
					 | 
				
			||||||
  /** If the output requires monte carlo sampling, the amount of samples */
 | 
					 | 
				
			||||||
  sampleCount?: number;
 | 
					 | 
				
			||||||
  /** 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;
 | 
					 | 
				
			||||||
  /** When the squiggle code gets reevaluated */
 | 
					 | 
				
			||||||
  onChange?(expr: SqValue | undefined, sourceName: string): void;
 | 
					 | 
				
			||||||
  /** CSS width of the element */
 | 
					 | 
				
			||||||
  width?: number;
 | 
					 | 
				
			||||||
  height?: number;
 | 
					 | 
				
			||||||
  /** 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 the x-axis should be dates or numbers */
 | 
					 | 
				
			||||||
  xAxisType?: "number" | "dateTime";
 | 
					 | 
				
			||||||
  /** Whether to show vega actions to the user, so they can copy the chart spec */
 | 
					 | 
				
			||||||
  distributionChartActions?: boolean;
 | 
					 | 
				
			||||||
  enableLocalSettings?: boolean;
 | 
					 | 
				
			||||||
} & (StandaloneExecutionProps | ProjectExecutionProps);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Props needed for a standalone execution
 | 
					 | 
				
			||||||
type StandaloneExecutionProps = {
 | 
					 | 
				
			||||||
  project?: undefined;
 | 
					 | 
				
			||||||
  continues?: undefined;
 | 
					 | 
				
			||||||
  /** The amount of points returned to draw the distribution, not needed if using a project */
 | 
					 | 
				
			||||||
  environment?: environment;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Props needed when executing inside a project.
 | 
					 | 
				
			||||||
type ProjectExecutionProps = {
 | 
					 | 
				
			||||||
  environment?: undefined;
 | 
					 | 
				
			||||||
  /** The project that this execution is part of */
 | 
					 | 
				
			||||||
  project: SqProject;
 | 
					 | 
				
			||||||
  /** What other squiggle sources from the project to continue. Default [] */
 | 
					 | 
				
			||||||
  continues?: string[];
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
const defaultOnChange = () => {};
 | 
					 | 
				
			||||||
const defaultImports: JsImports = {};
 | 
					 | 
				
			||||||
const defaultContinues: string[] = [];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const splitSquiggleChartSettings = (props: SquiggleChartProps) => {
 | 
					 | 
				
			||||||
  const {
 | 
					 | 
				
			||||||
    showSummary = false,
 | 
					 | 
				
			||||||
    logX = false,
 | 
					 | 
				
			||||||
    expY = false,
 | 
					 | 
				
			||||||
    diagramStart = 0,
 | 
					 | 
				
			||||||
    diagramStop = 10,
 | 
					 | 
				
			||||||
    diagramCount = 20,
 | 
					 | 
				
			||||||
    tickFormat,
 | 
					 | 
				
			||||||
    minX,
 | 
					 | 
				
			||||||
    maxX,
 | 
					 | 
				
			||||||
    color,
 | 
					 | 
				
			||||||
    title,
 | 
					 | 
				
			||||||
    xAxisType = "number",
 | 
					 | 
				
			||||||
    distributionChartActions,
 | 
					 | 
				
			||||||
  } = props;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const distributionPlotSettings = {
 | 
					 | 
				
			||||||
    showSummary,
 | 
					 | 
				
			||||||
    logX,
 | 
					 | 
				
			||||||
    expY,
 | 
					 | 
				
			||||||
    format: tickFormat,
 | 
					 | 
				
			||||||
    minX,
 | 
					 | 
				
			||||||
    maxX,
 | 
					 | 
				
			||||||
    color,
 | 
					 | 
				
			||||||
    title,
 | 
					 | 
				
			||||||
    xAxisType,
 | 
					 | 
				
			||||||
    actions: distributionChartActions,
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const chartSettings = {
 | 
					 | 
				
			||||||
    start: diagramStart,
 | 
					 | 
				
			||||||
    stop: diagramStop,
 | 
					 | 
				
			||||||
    count: diagramCount,
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return { distributionPlotSettings, chartSettings };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const SquiggleChart: React.FC<SquiggleChartProps> = React.memo(
 | 
					export const SquiggleChart: React.FC<SquiggleChartProps> = React.memo(
 | 
				
			||||||
  (props) => {
 | 
					  (props) => {
 | 
				
			||||||
    const { distributionPlotSettings, chartSettings } =
 | 
					    const resultAndBindings = useSquiggle(props);
 | 
				
			||||||
      splitSquiggleChartSettings(props);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const {
 | 
					 | 
				
			||||||
      code,
 | 
					 | 
				
			||||||
      jsImports = defaultImports,
 | 
					 | 
				
			||||||
      onChange = defaultOnChange, // defaultOnChange must be constant, don't move its definition here
 | 
					 | 
				
			||||||
      executionId = 0,
 | 
					 | 
				
			||||||
      width,
 | 
					 | 
				
			||||||
      height = 200,
 | 
					 | 
				
			||||||
      enableLocalSettings = false,
 | 
					 | 
				
			||||||
      continues = defaultContinues,
 | 
					 | 
				
			||||||
    } = props;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const p = React.useMemo(() => {
 | 
					 | 
				
			||||||
      if (props.project) {
 | 
					 | 
				
			||||||
        return props.project;
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        const p = SqProject.create();
 | 
					 | 
				
			||||||
        if (props.environment) {
 | 
					 | 
				
			||||||
          p.setEnvironment(props.environment);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return p;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }, [props.project, props.environment]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const resultAndBindings = useSquiggle({
 | 
					 | 
				
			||||||
      continues,
 | 
					 | 
				
			||||||
      project: p,
 | 
					 | 
				
			||||||
      code,
 | 
					 | 
				
			||||||
      jsImports,
 | 
					 | 
				
			||||||
      onChange,
 | 
					 | 
				
			||||||
      executionId,
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const valueToRender = getValueToRender(resultAndBindings);
 | 
					    const valueToRender = getValueToRender(resultAndBindings);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <SquiggleViewer
 | 
					      <SquiggleViewer {...createViewSettings(props)} result={valueToRender} />
 | 
				
			||||||
        result={valueToRender}
 | 
					 | 
				
			||||||
        width={width}
 | 
					 | 
				
			||||||
        height={height}
 | 
					 | 
				
			||||||
        distributionPlotSettings={distributionPlotSettings}
 | 
					 | 
				
			||||||
        chartSettings={chartSettings}
 | 
					 | 
				
			||||||
        environment={p.getEnvironment()}
 | 
					 | 
				
			||||||
        enableLocalSettings={enableLocalSettings}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,14 +1,14 @@
 | 
				
			||||||
import React from "react";
 | 
					import React from "react";
 | 
				
			||||||
import { CodeEditor } from "./CodeEditor";
 | 
					import { CodeEditor } from "./CodeEditor";
 | 
				
			||||||
import { SquiggleContainer } from "./SquiggleContainer";
 | 
					import { SquiggleContainer } from "./SquiggleContainer";
 | 
				
			||||||
 | 
					import { useMaybeControlledValue } from "../lib/hooks";
 | 
				
			||||||
 | 
					import { useSquiggle, SquiggleArgs } from "../lib/hooks/useSquiggle";
 | 
				
			||||||
 | 
					import { SqLocation } from "@quri/squiggle-lang";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  splitSquiggleChartSettings,
 | 
					  SquiggleViewer,
 | 
				
			||||||
  SquiggleChartProps,
 | 
					  createViewSettings,
 | 
				
			||||||
} from "./SquiggleChart";
 | 
					  FlattenedViewSettings,
 | 
				
			||||||
import { useMaybeControlledValue, useSquiggle } from "../lib/hooks";
 | 
					} from "./SquiggleViewer";
 | 
				
			||||||
import { JsImports } from "../lib/jsImports";
 | 
					 | 
				
			||||||
import { defaultEnvironment, SqLocation, SqProject } from "@quri/squiggle-lang";
 | 
					 | 
				
			||||||
import { SquiggleViewer } from "./SquiggleViewer";
 | 
					 | 
				
			||||||
import { getErrorLocations, getValueToRender } from "../lib/utility";
 | 
					import { getErrorLocations, getValueToRender } from "../lib/utility";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const WrappedCodeEditor: React.FC<{
 | 
					const WrappedCodeEditor: React.FC<{
 | 
				
			||||||
| 
						 | 
					@ -28,13 +28,11 @@ const WrappedCodeEditor: React.FC<{
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type SquiggleEditorProps = SquiggleChartProps & {
 | 
					export type SquiggleEditorProps = SquiggleArgs &
 | 
				
			||||||
  defaultCode?: string;
 | 
					  FlattenedViewSettings & {
 | 
				
			||||||
  onCodeChange?: (code: string) => void;
 | 
					    defaultCode?: string;
 | 
				
			||||||
};
 | 
					    onCodeChange?: (code: string) => void;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
const defaultOnChange = () => {};
 | 
					 | 
				
			||||||
const defaultImports: JsImports = {};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const SquiggleEditor: React.FC<SquiggleEditorProps> = (props) => {
 | 
					export const SquiggleEditor: React.FC<SquiggleEditorProps> = (props) => {
 | 
				
			||||||
  const [code, setCode] = useMaybeControlledValue({
 | 
					  const [code, setCode] = useMaybeControlledValue({
 | 
				
			||||||
| 
						 | 
					@ -43,34 +41,7 @@ export const SquiggleEditor: React.FC<SquiggleEditorProps> = (props) => {
 | 
				
			||||||
    onChange: props.onCodeChange,
 | 
					    onChange: props.onCodeChange,
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const { distributionPlotSettings, chartSettings } =
 | 
					  const resultAndBindings = useSquiggle({ ...props, code });
 | 
				
			||||||
    splitSquiggleChartSettings(props);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const {
 | 
					 | 
				
			||||||
    environment,
 | 
					 | 
				
			||||||
    jsImports = defaultImports,
 | 
					 | 
				
			||||||
    onChange = defaultOnChange, // defaultOnChange must be constant, don't move its definition here
 | 
					 | 
				
			||||||
    executionId = 0,
 | 
					 | 
				
			||||||
    width,
 | 
					 | 
				
			||||||
    height = 200,
 | 
					 | 
				
			||||||
    enableLocalSettings = false,
 | 
					 | 
				
			||||||
  } = props;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const project = React.useMemo(() => {
 | 
					 | 
				
			||||||
    const p = SqProject.create();
 | 
					 | 
				
			||||||
    if (environment) {
 | 
					 | 
				
			||||||
      p.setEnvironment(environment);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return p;
 | 
					 | 
				
			||||||
  }, [environment]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const resultAndBindings = useSquiggle({
 | 
					 | 
				
			||||||
    code,
 | 
					 | 
				
			||||||
    project,
 | 
					 | 
				
			||||||
    jsImports,
 | 
					 | 
				
			||||||
    onChange,
 | 
					 | 
				
			||||||
    executionId,
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const valueToRender = getValueToRender(resultAndBindings);
 | 
					  const valueToRender = getValueToRender(resultAndBindings);
 | 
				
			||||||
  const errorLocations = getErrorLocations(resultAndBindings.result);
 | 
					  const errorLocations = getErrorLocations(resultAndBindings.result);
 | 
				
			||||||
| 
						 | 
					@ -82,15 +53,7 @@ export const SquiggleEditor: React.FC<SquiggleEditorProps> = (props) => {
 | 
				
			||||||
        setCode={setCode}
 | 
					        setCode={setCode}
 | 
				
			||||||
        errorLocations={errorLocations}
 | 
					        errorLocations={errorLocations}
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
      <SquiggleViewer
 | 
					      <SquiggleViewer result={valueToRender} {...createViewSettings(props)} />
 | 
				
			||||||
        result={valueToRender}
 | 
					 | 
				
			||||||
        width={width}
 | 
					 | 
				
			||||||
        height={height}
 | 
					 | 
				
			||||||
        distributionPlotSettings={distributionPlotSettings}
 | 
					 | 
				
			||||||
        chartSettings={chartSettings}
 | 
					 | 
				
			||||||
        environment={environment ?? defaultEnvironment}
 | 
					 | 
				
			||||||
        enableLocalSettings={enableLocalSettings}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </SquiggleContainer>
 | 
					    </SquiggleContainer>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,6 +13,7 @@ import {
 | 
				
			||||||
  useRunnerState,
 | 
					  useRunnerState,
 | 
				
			||||||
  useSquiggle,
 | 
					  useSquiggle,
 | 
				
			||||||
} from "../lib/hooks";
 | 
					} from "../lib/hooks";
 | 
				
			||||||
 | 
					import { SquiggleArgs } from "../lib/hooks/useSquiggle";
 | 
				
			||||||
import { yupResolver } from "@hookform/resolvers/yup";
 | 
					import { yupResolver } from "@hookform/resolvers/yup";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  ChartSquareBarIcon,
 | 
					  ChartSquareBarIcon,
 | 
				
			||||||
| 
						 | 
					@ -28,9 +29,8 @@ import {
 | 
				
			||||||
} from "@heroicons/react/solid";
 | 
					} from "@heroicons/react/solid";
 | 
				
			||||||
import clsx from "clsx";
 | 
					import clsx from "clsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { environment, SqProject } from "@quri/squiggle-lang";
 | 
					import { environment } from "@quri/squiggle-lang";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { SquiggleChartProps } from "./SquiggleChart";
 | 
					 | 
				
			||||||
import { CodeEditor } from "./CodeEditor";
 | 
					import { CodeEditor } from "./CodeEditor";
 | 
				
			||||||
import { JsonEditor } from "./JsonEditor";
 | 
					import { JsonEditor } from "./JsonEditor";
 | 
				
			||||||
import { ErrorAlert, SuccessAlert } from "./Alert";
 | 
					import { ErrorAlert, SuccessAlert } from "./Alert";
 | 
				
			||||||
| 
						 | 
					@ -41,23 +41,27 @@ import { InputItem } from "./ui/InputItem";
 | 
				
			||||||
import { Text } from "./ui/Text";
 | 
					import { Text } from "./ui/Text";
 | 
				
			||||||
import { ViewSettings, viewSettingsSchema } from "./ViewSettings";
 | 
					import { ViewSettings, viewSettingsSchema } from "./ViewSettings";
 | 
				
			||||||
import { HeadedSection } from "./ui/HeadedSection";
 | 
					import { HeadedSection } from "./ui/HeadedSection";
 | 
				
			||||||
import { defaultTickFormat } from "../lib/distributionSpecBuilder";
 | 
					 | 
				
			||||||
import { Button } from "./ui/Button";
 | 
					import { Button } from "./ui/Button";
 | 
				
			||||||
import { JsImports } from "../lib/jsImports";
 | 
					import { JsImports } from "../lib/jsImports";
 | 
				
			||||||
import { getErrorLocations, getValueToRender } from "../lib/utility";
 | 
					import { getErrorLocations, getValueToRender } from "../lib/utility";
 | 
				
			||||||
import { SquiggleViewer } from "./SquiggleViewer";
 | 
					import {
 | 
				
			||||||
 | 
					  SquiggleViewer,
 | 
				
			||||||
 | 
					  FlattenedViewSettings,
 | 
				
			||||||
 | 
					  createViewSettings,
 | 
				
			||||||
 | 
					} from "./SquiggleViewer";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type PlaygroundProps = SquiggleChartProps & {
 | 
					type PlaygroundProps = SquiggleArgs &
 | 
				
			||||||
  /** The initial squiggle string to put in the playground */
 | 
					  FlattenedViewSettings & {
 | 
				
			||||||
  defaultCode?: string;
 | 
					    /** The initial squiggle string to put in the playground */
 | 
				
			||||||
  onCodeChange?(expr: string): void;
 | 
					    defaultCode?: string;
 | 
				
			||||||
  /* When settings change */
 | 
					    onCodeChange?(expr: string): void;
 | 
				
			||||||
  onSettingsChange?(settings: any): void;
 | 
					    /* When settings change */
 | 
				
			||||||
  /** Should we show the editor? */
 | 
					    onSettingsChange?(settings: any): void;
 | 
				
			||||||
  showEditor?: boolean;
 | 
					    /** Should we show the editor? */
 | 
				
			||||||
  /** Useful for playground on squiggle website, where we update the anchor link based on current code and settings */
 | 
					    showEditor?: boolean;
 | 
				
			||||||
  showShareButton?: boolean;
 | 
					    /** Useful for playground on squiggle website, where we update the anchor link based on current code and settings */
 | 
				
			||||||
};
 | 
					    showShareButton?: boolean;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const schema = yup
 | 
					const schema = yup
 | 
				
			||||||
  .object({})
 | 
					  .object({})
 | 
				
			||||||
| 
						 | 
					@ -78,6 +82,7 @@ const schema = yup
 | 
				
			||||||
      .default(1000)
 | 
					      .default(1000)
 | 
				
			||||||
      .min(10)
 | 
					      .min(10)
 | 
				
			||||||
      .max(10000),
 | 
					      .max(10000),
 | 
				
			||||||
 | 
					    showEditor: yup.boolean().required().default(true),
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
  .concat(viewSettingsSchema);
 | 
					  .concat(viewSettingsSchema);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -235,23 +240,14 @@ export const PlaygroundContext = React.createContext<PlaygroundContextShape>({
 | 
				
			||||||
  getLeftPanelElement: () => undefined,
 | 
					  getLeftPanelElement: () => undefined,
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const SquigglePlayground: FC<PlaygroundProps> = ({
 | 
					export const SquigglePlayground: FC<PlaygroundProps> = (props) => {
 | 
				
			||||||
  defaultCode = "",
 | 
					  const {
 | 
				
			||||||
  height = 500,
 | 
					    defaultCode = "",
 | 
				
			||||||
  showSummary = true,
 | 
					    code: controlledCode,
 | 
				
			||||||
  logX = false,
 | 
					    onCodeChange,
 | 
				
			||||||
  expY = false,
 | 
					    onSettingsChange,
 | 
				
			||||||
  title,
 | 
					    showShareButton = false,
 | 
				
			||||||
  minX,
 | 
					  } = props;
 | 
				
			||||||
  maxX,
 | 
					 | 
				
			||||||
  tickFormat = defaultTickFormat,
 | 
					 | 
				
			||||||
  distributionChartActions,
 | 
					 | 
				
			||||||
  code: controlledCode,
 | 
					 | 
				
			||||||
  onCodeChange,
 | 
					 | 
				
			||||||
  onSettingsChange,
 | 
					 | 
				
			||||||
  showEditor = true,
 | 
					 | 
				
			||||||
  showShareButton = false,
 | 
					 | 
				
			||||||
}) => {
 | 
					 | 
				
			||||||
  const [code, setCode] = useMaybeControlledValue({
 | 
					  const [code, setCode] = useMaybeControlledValue({
 | 
				
			||||||
    value: controlledCode,
 | 
					    value: controlledCode,
 | 
				
			||||||
    defaultValue: defaultCode,
 | 
					    defaultValue: defaultCode,
 | 
				
			||||||
| 
						 | 
					@ -260,29 +256,19 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [imports, setImports] = useState<JsImports>({});
 | 
					  const [imports, setImports] = useState<JsImports>({});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let defaultValues: FormFields = {
 | 
				
			||||||
 | 
					    ...schema.getDefault(),
 | 
				
			||||||
 | 
					    ...props,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const { register, control } = useForm({
 | 
					  const { register, control } = useForm({
 | 
				
			||||||
    resolver: yupResolver(schema),
 | 
					    resolver: yupResolver(schema),
 | 
				
			||||||
    defaultValues: {
 | 
					    defaultValues: defaultValues,
 | 
				
			||||||
      sampleCount: 1000,
 | 
					 | 
				
			||||||
      xyPointLength: 1000,
 | 
					 | 
				
			||||||
      chartHeight: 150,
 | 
					 | 
				
			||||||
      logX,
 | 
					 | 
				
			||||||
      expY,
 | 
					 | 
				
			||||||
      title,
 | 
					 | 
				
			||||||
      minX,
 | 
					 | 
				
			||||||
      maxX,
 | 
					 | 
				
			||||||
      tickFormat,
 | 
					 | 
				
			||||||
      distributionChartActions,
 | 
					 | 
				
			||||||
      showSummary,
 | 
					 | 
				
			||||||
      showEditor,
 | 
					 | 
				
			||||||
      diagramStart: 0,
 | 
					 | 
				
			||||||
      diagramStop: 10,
 | 
					 | 
				
			||||||
      diagramCount: 20,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  const vars = useWatch({
 | 
					  const rawVars = useWatch({
 | 
				
			||||||
    control,
 | 
					    control,
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					  let vars = useMemo(() => ({ ...schema.getDefault(), ...rawVars }), [rawVars]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    onSettingsChange?.(vars);
 | 
					    onSettingsChange?.(vars);
 | 
				
			||||||
| 
						 | 
					@ -305,20 +291,12 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
 | 
				
			||||||
    executionId,
 | 
					    executionId,
 | 
				
			||||||
  } = useRunnerState(code);
 | 
					  } = useRunnerState(code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const project = React.useMemo(() => {
 | 
					  let args: SquiggleArgs = props;
 | 
				
			||||||
    const p = SqProject.create();
 | 
					  args = { ...args, code, jsImports: imports, executionId };
 | 
				
			||||||
    if (environment) {
 | 
					  if (!args.project) {
 | 
				
			||||||
      p.setEnvironment(environment);
 | 
					    args = { ...args, environment };
 | 
				
			||||||
    }
 | 
					  }
 | 
				
			||||||
    return p;
 | 
					  const resultAndBindings = useSquiggle(args);
 | 
				
			||||||
  }, [environment]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const resultAndBindings = useSquiggle({
 | 
					 | 
				
			||||||
    code,
 | 
					 | 
				
			||||||
    project,
 | 
					 | 
				
			||||||
    jsImports: imports,
 | 
					 | 
				
			||||||
    executionId,
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const valueToRender = getValueToRender(resultAndBindings);
 | 
					  const valueToRender = getValueToRender(resultAndBindings);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -328,27 +306,7 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
 | 
				
			||||||
        {isRunning ? (
 | 
					        {isRunning ? (
 | 
				
			||||||
          <div className="absolute inset-0 bg-white opacity-0 animate-semi-appear" />
 | 
					          <div className="absolute inset-0 bg-white opacity-0 animate-semi-appear" />
 | 
				
			||||||
        ) : null}
 | 
					        ) : null}
 | 
				
			||||||
        <SquiggleViewer
 | 
					        <SquiggleViewer {...createViewSettings(vars)} result={valueToRender} />
 | 
				
			||||||
          result={valueToRender}
 | 
					 | 
				
			||||||
          environment={environment}
 | 
					 | 
				
			||||||
          height={vars.chartHeight || 150}
 | 
					 | 
				
			||||||
          distributionPlotSettings={{
 | 
					 | 
				
			||||||
            showSummary: vars.showSummary ?? false,
 | 
					 | 
				
			||||||
            logX: vars.logX ?? false,
 | 
					 | 
				
			||||||
            expY: vars.expY ?? false,
 | 
					 | 
				
			||||||
            format: vars.tickFormat,
 | 
					 | 
				
			||||||
            minX: vars.minX,
 | 
					 | 
				
			||||||
            maxX: vars.maxX,
 | 
					 | 
				
			||||||
            title: vars.title,
 | 
					 | 
				
			||||||
            actions: vars.distributionChartActions,
 | 
					 | 
				
			||||||
          }}
 | 
					 | 
				
			||||||
          chartSettings={{
 | 
					 | 
				
			||||||
            start: vars.diagramStart ?? 0,
 | 
					 | 
				
			||||||
            stop: vars.diagramStop ?? 10,
 | 
					 | 
				
			||||||
            count: vars.diagramCount ?? 20,
 | 
					 | 
				
			||||||
          }}
 | 
					 | 
				
			||||||
          enableLocalSettings={true}
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -363,7 +321,7 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
 | 
				
			||||||
        onSubmit={run}
 | 
					        onSubmit={run}
 | 
				
			||||||
        oneLine={false}
 | 
					        oneLine={false}
 | 
				
			||||||
        showGutter={true}
 | 
					        showGutter={true}
 | 
				
			||||||
        height={height - 1}
 | 
					        height={(props.chartHeight ?? 200) - 1}
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  ) : (
 | 
					  ) : (
 | 
				
			||||||
| 
						 | 
					@ -402,7 +360,7 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
 | 
				
			||||||
    <div className="flex mt-2">
 | 
					    <div className="flex mt-2">
 | 
				
			||||||
      <div
 | 
					      <div
 | 
				
			||||||
        className="w-1/2 relative"
 | 
					        className="w-1/2 relative"
 | 
				
			||||||
        style={{ minHeight: height }}
 | 
					        style={{ minHeight: props.chartHeight }}
 | 
				
			||||||
        ref={leftPanelRef}
 | 
					        ref={leftPanelRef}
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        {tabs}
 | 
					        {tabs}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -105,9 +105,9 @@ export const ExpressionViewer: React.FC<Props> = ({ value, width }) => {
 | 
				
			||||||
            return (
 | 
					            return (
 | 
				
			||||||
              <DistributionChart
 | 
					              <DistributionChart
 | 
				
			||||||
                plot={defaultPlot(value.value)}
 | 
					                plot={defaultPlot(value.value)}
 | 
				
			||||||
                environment={settings.environment}
 | 
					 | 
				
			||||||
                {...settings.distributionPlotSettings}
 | 
					                {...settings.distributionPlotSettings}
 | 
				
			||||||
                height={settings.height}
 | 
					                height={settings.chartHeight}
 | 
				
			||||||
 | 
					                environment={settings.environment}
 | 
				
			||||||
                width={width}
 | 
					                width={width}
 | 
				
			||||||
              />
 | 
					              />
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
| 
						 | 
					@ -178,7 +178,7 @@ export const ExpressionViewer: React.FC<Props> = ({ value, width }) => {
 | 
				
			||||||
                fn={value.value}
 | 
					                fn={value.value}
 | 
				
			||||||
                chartSettings={settings.chartSettings}
 | 
					                chartSettings={settings.chartSettings}
 | 
				
			||||||
                distributionPlotSettings={settings.distributionPlotSettings}
 | 
					                distributionPlotSettings={settings.distributionPlotSettings}
 | 
				
			||||||
                height={settings.height}
 | 
					                height={settings.chartHeight}
 | 
				
			||||||
                environment={{
 | 
					                environment={{
 | 
				
			||||||
                  sampleCount: settings.environment.sampleCount / 10,
 | 
					                  sampleCount: settings.environment.sampleCount / 10,
 | 
				
			||||||
                  xyPointLength: settings.environment.xyPointLength / 10,
 | 
					                  xyPointLength: settings.environment.xyPointLength / 10,
 | 
				
			||||||
| 
						 | 
					@ -203,7 +203,7 @@ export const ExpressionViewer: React.FC<Props> = ({ value, width }) => {
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
          }}
 | 
					          }}
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          {(settings) => (
 | 
					          {(_) => (
 | 
				
			||||||
            <div>NOT IMPLEMENTED IN 0.4 YET</div>
 | 
					            <div>NOT IMPLEMENTED IN 0.4 YET</div>
 | 
				
			||||||
            // <FunctionChart
 | 
					            // <FunctionChart
 | 
				
			||||||
            //   fn={expression.value.fn}
 | 
					            //   fn={expression.value.fn}
 | 
				
			||||||
| 
						 | 
					@ -252,7 +252,7 @@ export const ExpressionViewer: React.FC<Props> = ({ value, width }) => {
 | 
				
			||||||
                  plot={plot}
 | 
					                  plot={plot}
 | 
				
			||||||
                  environment={settings.environment}
 | 
					                  environment={settings.environment}
 | 
				
			||||||
                  {...settings.distributionPlotSettings}
 | 
					                  {...settings.distributionPlotSettings}
 | 
				
			||||||
                  height={settings.height}
 | 
					                  height={settings.chartHeight}
 | 
				
			||||||
                  width={width}
 | 
					                  width={width}
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
              );
 | 
					              );
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,9 +3,13 @@ import React, { useContext, useRef, useState, useEffect } from "react";
 | 
				
			||||||
import { useForm } from "react-hook-form";
 | 
					import { useForm } from "react-hook-form";
 | 
				
			||||||
import { yupResolver } from "@hookform/resolvers/yup";
 | 
					import { yupResolver } from "@hookform/resolvers/yup";
 | 
				
			||||||
import { Modal } from "../ui/Modal";
 | 
					import { Modal } from "../ui/Modal";
 | 
				
			||||||
import { ViewSettings, viewSettingsSchema } from "../ViewSettings";
 | 
					import {
 | 
				
			||||||
 | 
					  ViewSettings,
 | 
				
			||||||
 | 
					  viewSettingsSchema,
 | 
				
			||||||
 | 
					  mergedToViewSettings,
 | 
				
			||||||
 | 
					  viewSettingsToLocal,
 | 
				
			||||||
 | 
					} from "../ViewSettings";
 | 
				
			||||||
import { ViewerContext } from "./ViewerContext";
 | 
					import { ViewerContext } from "./ViewerContext";
 | 
				
			||||||
import { defaultTickFormat } from "../../lib/distributionSpecBuilder";
 | 
					 | 
				
			||||||
import { PlaygroundContext } from "../SquigglePlayground";
 | 
					import { PlaygroundContext } from "../SquigglePlayground";
 | 
				
			||||||
import { SqValue } from "@quri/squiggle-lang";
 | 
					import { SqValue } from "@quri/squiggle-lang";
 | 
				
			||||||
import { locationAsString } from "./utils";
 | 
					import { locationAsString } from "./utils";
 | 
				
			||||||
| 
						 | 
					@ -34,44 +38,14 @@ const ItemSettingsModal: React.FC<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const { register, watch } = useForm({
 | 
					  const { register, watch } = useForm({
 | 
				
			||||||
    resolver: yupResolver(viewSettingsSchema),
 | 
					    resolver: yupResolver(viewSettingsSchema),
 | 
				
			||||||
    defaultValues: {
 | 
					    defaultValues: mergedToViewSettings(mergedSettings),
 | 
				
			||||||
      // 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,
 | 
					 | 
				
			||||||
      minX: mergedSettings.distributionPlotSettings.minX,
 | 
					 | 
				
			||||||
      maxX: mergedSettings.distributionPlotSettings.maxX,
 | 
					 | 
				
			||||||
      distributionChartActions: mergedSettings.distributionPlotSettings.actions,
 | 
					 | 
				
			||||||
      diagramStart: mergedSettings.chartSettings.start,
 | 
					 | 
				
			||||||
      diagramStop: mergedSettings.chartSettings.stop,
 | 
					 | 
				
			||||||
      diagramCount: mergedSettings.chartSettings.count,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    const subscription = watch((vars) => {
 | 
					    const subscription = watch((vars) => {
 | 
				
			||||||
      const settings = getSettings(value.location); // get the latest version
 | 
					      const settings = getSettings(value.location); // get the latest version
 | 
				
			||||||
      setSettings(value.location, {
 | 
					      setSettings(value.location, {
 | 
				
			||||||
        ...settings,
 | 
					        ...settings,
 | 
				
			||||||
        distributionPlotSettings: {
 | 
					        ...viewSettingsToLocal(vars),
 | 
				
			||||||
          showSummary: vars.showSummary,
 | 
					 | 
				
			||||||
          logX: vars.logX,
 | 
					 | 
				
			||||||
          expY: vars.expY,
 | 
					 | 
				
			||||||
          format: vars.tickFormat,
 | 
					 | 
				
			||||||
          title: vars.title,
 | 
					 | 
				
			||||||
          minX: vars.minX,
 | 
					 | 
				
			||||||
          maxX: vars.maxX,
 | 
					 | 
				
			||||||
          actions: vars.distributionChartActions,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        chartSettings: {
 | 
					 | 
				
			||||||
          start: vars.diagramStart,
 | 
					 | 
				
			||||||
          stop: vars.diagramStop,
 | 
					 | 
				
			||||||
          count: vars.diagramCount,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
      onChange();
 | 
					      onChange();
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
| 
						 | 
					@ -102,7 +76,6 @@ const ItemSettingsModal: React.FC<
 | 
				
			||||||
      <Modal.Body>
 | 
					      <Modal.Body>
 | 
				
			||||||
        <ViewSettings
 | 
					        <ViewSettings
 | 
				
			||||||
          register={register}
 | 
					          register={register}
 | 
				
			||||||
          withShowEditorSetting={false}
 | 
					 | 
				
			||||||
          withFunctionSettings={withFunctionSettings}
 | 
					          withFunctionSettings={withFunctionSettings}
 | 
				
			||||||
          disableLogXSetting={disableLogX}
 | 
					          disableLogXSetting={disableLogX}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
import { defaultEnvironment, SqValueLocation } from "@quri/squiggle-lang";
 | 
					import { defaultEnvironment, SqValueLocation } from "@quri/squiggle-lang";
 | 
				
			||||||
import React from "react";
 | 
					import React from "react";
 | 
				
			||||||
import { LocalItemSettings, MergedItemSettings } from "./utils";
 | 
					import { LocalItemSettings, MergedItemSettings } from "./utils";
 | 
				
			||||||
 | 
					import { viewSettingsSchema, viewSettingsToMerged } from "../ViewSettings";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ViewerContextShape = {
 | 
					type ViewerContextShape = {
 | 
				
			||||||
  // Note that we don't store settings themselves in the context (that would cause rerenders of the entire tree on each settings update).
 | 
					  // Note that we don't store settings themselves in the context (that would cause rerenders of the entire tree on each settings update).
 | 
				
			||||||
| 
						 | 
					@ -16,19 +17,8 @@ export const ViewerContext = React.createContext<ViewerContextShape>({
 | 
				
			||||||
  getSettings: () => ({ collapsed: false }),
 | 
					  getSettings: () => ({ collapsed: false }),
 | 
				
			||||||
  getMergedSettings: () => ({
 | 
					  getMergedSettings: () => ({
 | 
				
			||||||
    collapsed: false,
 | 
					    collapsed: false,
 | 
				
			||||||
    // copy-pasted from SquiggleChart
 | 
					 | 
				
			||||||
    chartSettings: {
 | 
					 | 
				
			||||||
      start: 0,
 | 
					 | 
				
			||||||
      stop: 10,
 | 
					 | 
				
			||||||
      count: 100,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    distributionPlotSettings: {
 | 
					 | 
				
			||||||
      showSummary: false,
 | 
					 | 
				
			||||||
      logX: false,
 | 
					 | 
				
			||||||
      expY: false,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    environment: defaultEnvironment,
 | 
					    environment: defaultEnvironment,
 | 
				
			||||||
    height: 150,
 | 
					    ...viewSettingsToMerged(viewSettingsSchema.getDefault()),
 | 
				
			||||||
  }),
 | 
					  }),
 | 
				
			||||||
  setSettings() {},
 | 
					  setSettings() {},
 | 
				
			||||||
  enableLocalSettings: false,
 | 
					  enableLocalSettings: false,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,5 @@
 | 
				
			||||||
import React, { useCallback, useRef } from "react";
 | 
					import React, { useCallback, useRef } from "react";
 | 
				
			||||||
import { environment, SqValueLocation } from "@quri/squiggle-lang";
 | 
					import { SqValueLocation } from "@quri/squiggle-lang";
 | 
				
			||||||
import { DistributionPlottingSettings } from "../DistributionChart";
 | 
					 | 
				
			||||||
import { FunctionChartSettings } from "../FunctionChart";
 | 
					 | 
				
			||||||
import { ExpressionViewer } from "./ExpressionViewer";
 | 
					import { ExpressionViewer } from "./ExpressionViewer";
 | 
				
			||||||
import { ViewerContext } from "./ViewerContext";
 | 
					import { ViewerContext } from "./ViewerContext";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
| 
						 | 
					@ -10,20 +8,40 @@ import {
 | 
				
			||||||
  MergedItemSettings,
 | 
					  MergedItemSettings,
 | 
				
			||||||
} from "./utils";
 | 
					} from "./utils";
 | 
				
			||||||
import { useSquiggle } from "../../lib/hooks";
 | 
					import { useSquiggle } from "../../lib/hooks";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  EditableViewSettings,
 | 
				
			||||||
 | 
					  viewSettingsSchema,
 | 
				
			||||||
 | 
					  viewSettingsToMerged,
 | 
				
			||||||
 | 
					} from "../ViewSettings";
 | 
				
			||||||
import { SquiggleErrorAlert } from "../SquiggleErrorAlert";
 | 
					import { SquiggleErrorAlert } from "../SquiggleErrorAlert";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Flattened view settings, gets turned into props for SquiggleChart and SquiggleEditor
 | 
				
			||||||
 | 
					export type FlattenedViewSettings = Partial<
 | 
				
			||||||
 | 
					  EditableViewSettings & {
 | 
				
			||||||
 | 
					    width?: number;
 | 
				
			||||||
 | 
					    enableLocalSettings?: boolean;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ViewSettings = {
 | 
				
			||||||
 | 
					  width?: number;
 | 
				
			||||||
 | 
					  enableLocalSettings?: boolean;
 | 
				
			||||||
 | 
					} & Omit<MergedItemSettings, "environment">;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const createViewSettings = (
 | 
				
			||||||
 | 
					  props: FlattenedViewSettings
 | 
				
			||||||
 | 
					): ViewSettings => {
 | 
				
			||||||
 | 
					  const propsWithDefaults = { ...viewSettingsSchema.getDefault(), ...props };
 | 
				
			||||||
 | 
					  let merged = viewSettingsToMerged(propsWithDefaults);
 | 
				
			||||||
 | 
					  const { width, enableLocalSettings } = propsWithDefaults;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return { ...merged, width, enableLocalSettings };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
  /** The output of squiggle's run */
 | 
					  /** The output of squiggle's run */
 | 
				
			||||||
  result: ReturnType<typeof useSquiggle>["result"];
 | 
					  result: ReturnType<typeof useSquiggle>["result"];
 | 
				
			||||||
  width?: number;
 | 
					} & ViewSettings;
 | 
				
			||||||
  height: number;
 | 
					 | 
				
			||||||
  distributionPlotSettings: DistributionPlottingSettings;
 | 
					 | 
				
			||||||
  /** Settings for displaying functions */
 | 
					 | 
				
			||||||
  chartSettings: FunctionChartSettings;
 | 
					 | 
				
			||||||
  /** Environment for further function executions */
 | 
					 | 
				
			||||||
  environment: environment;
 | 
					 | 
				
			||||||
  enableLocalSettings?: boolean;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Settings = {
 | 
					type Settings = {
 | 
				
			||||||
  [k: string]: LocalItemSettings;
 | 
					  [k: string]: LocalItemSettings;
 | 
				
			||||||
| 
						 | 
					@ -34,10 +52,9 @@ const defaultSettings: LocalItemSettings = { collapsed: false };
 | 
				
			||||||
export const SquiggleViewer: React.FC<Props> = ({
 | 
					export const SquiggleViewer: React.FC<Props> = ({
 | 
				
			||||||
  result,
 | 
					  result,
 | 
				
			||||||
  width,
 | 
					  width,
 | 
				
			||||||
  height,
 | 
					  chartHeight,
 | 
				
			||||||
  distributionPlotSettings,
 | 
					  distributionPlotSettings,
 | 
				
			||||||
  chartSettings,
 | 
					  chartSettings,
 | 
				
			||||||
  environment,
 | 
					 | 
				
			||||||
  enableLocalSettings = false,
 | 
					  enableLocalSettings = false,
 | 
				
			||||||
}) => {
 | 
					}) => {
 | 
				
			||||||
  // can't store settings in the state because we don't want to rerender the entire tree on every change
 | 
					  // can't store settings in the state because we don't want to rerender the entire tree on every change
 | 
				
			||||||
| 
						 | 
					@ -59,6 +76,7 @@ export const SquiggleViewer: React.FC<Props> = ({
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const getMergedSettings = useCallback(
 | 
					  const getMergedSettings = useCallback(
 | 
				
			||||||
    (location: SqValueLocation) => {
 | 
					    (location: SqValueLocation) => {
 | 
				
			||||||
 | 
					      const env = location.project.getEnvironment();
 | 
				
			||||||
      const localSettings = getSettings(location);
 | 
					      const localSettings = getSettings(location);
 | 
				
			||||||
      const result: MergedItemSettings = {
 | 
					      const result: MergedItemSettings = {
 | 
				
			||||||
        distributionPlotSettings: {
 | 
					        distributionPlotSettings: {
 | 
				
			||||||
| 
						 | 
					@ -70,14 +88,14 @@ export const SquiggleViewer: React.FC<Props> = ({
 | 
				
			||||||
          ...(localSettings.chartSettings || {}),
 | 
					          ...(localSettings.chartSettings || {}),
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        environment: {
 | 
					        environment: {
 | 
				
			||||||
          ...environment,
 | 
					          ...env,
 | 
				
			||||||
          ...(localSettings.environment || {}),
 | 
					          ...localSettings.environment,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        height: localSettings.height || height,
 | 
					        chartHeight: localSettings.chartHeight || chartHeight,
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
      return result;
 | 
					      return result;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    [distributionPlotSettings, chartSettings, environment, height, getSettings]
 | 
					    [distributionPlotSettings, chartSettings, chartHeight, getSettings]
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,19 +1,19 @@
 | 
				
			||||||
import { DistributionPlottingSettings } from "../DistributionChart";
 | 
					import { DistributionPlottingSettings } from "../DistributionChart";
 | 
				
			||||||
import { FunctionChartSettings } from "../FunctionChart";
 | 
					import { FunctionChartSettings } from "../FunctionChart";
 | 
				
			||||||
import { environment, SqValueLocation } from "@quri/squiggle-lang";
 | 
					import { SqValueLocation, environment } from "@quri/squiggle-lang";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type LocalItemSettings = {
 | 
					export type LocalItemSettings = {
 | 
				
			||||||
  collapsed: boolean;
 | 
					  collapsed: boolean;
 | 
				
			||||||
  distributionPlotSettings?: Partial<DistributionPlottingSettings>;
 | 
					  distributionPlotSettings?: Partial<DistributionPlottingSettings>;
 | 
				
			||||||
  chartSettings?: Partial<FunctionChartSettings>;
 | 
					  chartSettings?: Partial<FunctionChartSettings>;
 | 
				
			||||||
  height?: number;
 | 
					  chartHeight?: number;
 | 
				
			||||||
  environment?: Partial<environment>;
 | 
					  environment?: environment;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type MergedItemSettings = {
 | 
					export type MergedItemSettings = {
 | 
				
			||||||
  distributionPlotSettings: DistributionPlottingSettings;
 | 
					  distributionPlotSettings: DistributionPlottingSettings;
 | 
				
			||||||
  chartSettings: FunctionChartSettings;
 | 
					  chartSettings: FunctionChartSettings;
 | 
				
			||||||
  height: number;
 | 
					  chartHeight: number;
 | 
				
			||||||
  environment: environment;
 | 
					  environment: environment;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,49 +5,137 @@ import { InputItem } from "./ui/InputItem";
 | 
				
			||||||
import { Checkbox } from "./ui/Checkbox";
 | 
					import { Checkbox } from "./ui/Checkbox";
 | 
				
			||||||
import { HeadedSection } from "./ui/HeadedSection";
 | 
					import { HeadedSection } from "./ui/HeadedSection";
 | 
				
			||||||
import { Text } from "./ui/Text";
 | 
					import { Text } from "./ui/Text";
 | 
				
			||||||
 | 
					import { MergedItemSettings, LocalItemSettings } from "./SquiggleViewer/utils";
 | 
				
			||||||
import { defaultTickFormat } from "../lib/distributionSpecBuilder";
 | 
					import { defaultTickFormat } from "../lib/distributionSpecBuilder";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const viewSettingsSchema = yup.object({}).shape({
 | 
					export const viewSettingsSchema = yup.object({}).shape({
 | 
				
			||||||
  chartHeight: yup.number().required().positive().integer().default(350),
 | 
					  chartHeight: yup.number().required().positive().integer().default(350),
 | 
				
			||||||
  showSummary: yup.boolean().required(),
 | 
					  showSummary: yup.boolean().required().default(false),
 | 
				
			||||||
  showEditor: yup.boolean().required(),
 | 
					  logX: yup.boolean().required().default(false),
 | 
				
			||||||
  logX: yup.boolean().required(),
 | 
					  expY: yup.boolean().required().default(false),
 | 
				
			||||||
  expY: yup.boolean().required(),
 | 
					  tickFormat: yup.string().required().default(defaultTickFormat),
 | 
				
			||||||
  tickFormat: yup.string().default(defaultTickFormat),
 | 
					 | 
				
			||||||
  title: yup.string(),
 | 
					  title: yup.string(),
 | 
				
			||||||
  minX: yup.number(),
 | 
					  minX: yup.number(),
 | 
				
			||||||
  maxX: yup.number(),
 | 
					  maxX: yup.number(),
 | 
				
			||||||
 | 
					  xAxisType: yup
 | 
				
			||||||
 | 
					    .mixed<"number" | "dateTime">()
 | 
				
			||||||
 | 
					    .oneOf(["number", "dateTime"])
 | 
				
			||||||
 | 
					    .default("number"),
 | 
				
			||||||
  distributionChartActions: yup.boolean(),
 | 
					  distributionChartActions: yup.boolean(),
 | 
				
			||||||
  diagramStart: yup.number().required().positive().integer().default(0).min(0),
 | 
					  diagramStart: yup.number().required().positive().integer().default(0).min(0),
 | 
				
			||||||
  diagramStop: yup.number().required().positive().integer().default(10).min(0),
 | 
					  diagramStop: yup.number().required().positive().integer().default(10).min(0),
 | 
				
			||||||
  diagramCount: yup.number().required().positive().integer().default(20).min(2),
 | 
					  diagramCount: yup.number().required().positive().integer().default(20).min(2),
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type FormFields = yup.InferType<typeof viewSettingsSchema>;
 | 
					export type EditableViewSettings = yup.InferType<typeof viewSettingsSchema>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const viewSettingsToMerged = (
 | 
				
			||||||
 | 
					  settings: EditableViewSettings
 | 
				
			||||||
 | 
					): Omit<MergedItemSettings, "environment"> => {
 | 
				
			||||||
 | 
					  const {
 | 
				
			||||||
 | 
					    showSummary,
 | 
				
			||||||
 | 
					    logX,
 | 
				
			||||||
 | 
					    expY,
 | 
				
			||||||
 | 
					    diagramStart,
 | 
				
			||||||
 | 
					    diagramStop,
 | 
				
			||||||
 | 
					    diagramCount,
 | 
				
			||||||
 | 
					    tickFormat,
 | 
				
			||||||
 | 
					    minX,
 | 
				
			||||||
 | 
					    maxX,
 | 
				
			||||||
 | 
					    title,
 | 
				
			||||||
 | 
					    xAxisType,
 | 
				
			||||||
 | 
					    distributionChartActions,
 | 
				
			||||||
 | 
					    chartHeight,
 | 
				
			||||||
 | 
					  } = settings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const distributionPlotSettings = {
 | 
				
			||||||
 | 
					    showSummary,
 | 
				
			||||||
 | 
					    logX,
 | 
				
			||||||
 | 
					    expY,
 | 
				
			||||||
 | 
					    format: tickFormat,
 | 
				
			||||||
 | 
					    minX,
 | 
				
			||||||
 | 
					    maxX,
 | 
				
			||||||
 | 
					    title,
 | 
				
			||||||
 | 
					    xAxisType,
 | 
				
			||||||
 | 
					    actions: distributionChartActions,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const chartSettings = {
 | 
				
			||||||
 | 
					    start: diagramStart,
 | 
				
			||||||
 | 
					    stop: diagramStop,
 | 
				
			||||||
 | 
					    count: diagramCount,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return { distributionPlotSettings, chartSettings, chartHeight };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const viewSettingsToLocal = (
 | 
				
			||||||
 | 
					  settings: Partial<EditableViewSettings>
 | 
				
			||||||
 | 
					): Omit<LocalItemSettings, "collapsed" | "environment"> => {
 | 
				
			||||||
 | 
					  const {
 | 
				
			||||||
 | 
					    showSummary,
 | 
				
			||||||
 | 
					    logX,
 | 
				
			||||||
 | 
					    expY,
 | 
				
			||||||
 | 
					    diagramStart,
 | 
				
			||||||
 | 
					    diagramStop,
 | 
				
			||||||
 | 
					    diagramCount,
 | 
				
			||||||
 | 
					    tickFormat,
 | 
				
			||||||
 | 
					    minX,
 | 
				
			||||||
 | 
					    maxX,
 | 
				
			||||||
 | 
					    title,
 | 
				
			||||||
 | 
					    xAxisType,
 | 
				
			||||||
 | 
					    distributionChartActions,
 | 
				
			||||||
 | 
					    chartHeight,
 | 
				
			||||||
 | 
					  } = settings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const distributionPlotSettings = {
 | 
				
			||||||
 | 
					    showSummary,
 | 
				
			||||||
 | 
					    logX,
 | 
				
			||||||
 | 
					    expY,
 | 
				
			||||||
 | 
					    format: tickFormat,
 | 
				
			||||||
 | 
					    minX,
 | 
				
			||||||
 | 
					    maxX,
 | 
				
			||||||
 | 
					    title,
 | 
				
			||||||
 | 
					    xAxisType,
 | 
				
			||||||
 | 
					    actions: distributionChartActions,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const chartSettings = {
 | 
				
			||||||
 | 
					    start: diagramStart,
 | 
				
			||||||
 | 
					    stop: diagramStop,
 | 
				
			||||||
 | 
					    count: diagramCount,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return { distributionPlotSettings, chartSettings, chartHeight };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const mergedToViewSettings = (
 | 
				
			||||||
 | 
					  mergedSettings: MergedItemSettings
 | 
				
			||||||
 | 
					): EditableViewSettings => ({
 | 
				
			||||||
 | 
					  chartHeight: mergedSettings.chartHeight,
 | 
				
			||||||
 | 
					  showSummary: mergedSettings.distributionPlotSettings.showSummary,
 | 
				
			||||||
 | 
					  logX: mergedSettings.distributionPlotSettings.logX,
 | 
				
			||||||
 | 
					  expY: mergedSettings.distributionPlotSettings.expY,
 | 
				
			||||||
 | 
					  tickFormat: mergedSettings.distributionPlotSettings.format,
 | 
				
			||||||
 | 
					  title: mergedSettings.distributionPlotSettings.title,
 | 
				
			||||||
 | 
					  minX: mergedSettings.distributionPlotSettings.minX,
 | 
				
			||||||
 | 
					  maxX: mergedSettings.distributionPlotSettings.maxX,
 | 
				
			||||||
 | 
					  distributionChartActions: mergedSettings.distributionPlotSettings.actions,
 | 
				
			||||||
 | 
					  xAxisType: mergedSettings.distributionPlotSettings.xAxisType,
 | 
				
			||||||
 | 
					  diagramStart: mergedSettings.chartSettings.start,
 | 
				
			||||||
 | 
					  diagramStop: mergedSettings.chartSettings.stop,
 | 
				
			||||||
 | 
					  diagramCount: mergedSettings.chartSettings.count,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 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<{
 | 
					export const ViewSettings: React.FC<{
 | 
				
			||||||
  withShowEditorSetting?: boolean;
 | 
					 | 
				
			||||||
  withFunctionSettings?: boolean;
 | 
					  withFunctionSettings?: boolean;
 | 
				
			||||||
  disableLogXSetting?: boolean;
 | 
					  disableLogXSetting?: boolean;
 | 
				
			||||||
  register: UseFormRegister<FormFields>;
 | 
					  register: UseFormRegister<EditableViewSettings>;
 | 
				
			||||||
}> = ({
 | 
					}> = ({ withFunctionSettings = true, disableLogXSetting, register }) => {
 | 
				
			||||||
  withShowEditorSetting = true,
 | 
					 | 
				
			||||||
  withFunctionSettings = true,
 | 
					 | 
				
			||||||
  disableLogXSetting,
 | 
					 | 
				
			||||||
  register,
 | 
					 | 
				
			||||||
}) => {
 | 
					 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div className="space-y-6 p-3 divide-y divide-gray-200 max-w-xl">
 | 
					    <div className="space-y-6 p-3 divide-y divide-gray-200 max-w-xl">
 | 
				
			||||||
      <HeadedSection title="General Display Settings">
 | 
					      <HeadedSection title="General Display Settings">
 | 
				
			||||||
        <div className="space-y-4">
 | 
					        <div className="space-y-4">
 | 
				
			||||||
          {withShowEditorSetting ? (
 | 
					 | 
				
			||||||
            <Checkbox
 | 
					 | 
				
			||||||
              name="showEditor"
 | 
					 | 
				
			||||||
              register={register}
 | 
					 | 
				
			||||||
              label="Show code editor on left"
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
          ) : null}
 | 
					 | 
				
			||||||
          <InputItem
 | 
					          <InputItem
 | 
				
			||||||
            name="chartHeight"
 | 
					            name="chartHeight"
 | 
				
			||||||
            type="number"
 | 
					            type="number"
 | 
				
			||||||
| 
						 | 
					@ -57,97 +145,115 @@ export const ViewSettings: React.FC<{
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </HeadedSection>
 | 
					      </HeadedSection>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <div className="pt-8">
 | 
					      <DistributionViewSettings
 | 
				
			||||||
        <HeadedSection title="Distribution Display Settings">
 | 
					        disableLogXSetting={disableLogXSetting}
 | 
				
			||||||
          <div className="space-y-2">
 | 
					        register={register}
 | 
				
			||||||
            <Checkbox
 | 
					      />
 | 
				
			||||||
              register={register}
 | 
					 | 
				
			||||||
              name="logX"
 | 
					 | 
				
			||||||
              label="Show x scale logarithmically"
 | 
					 | 
				
			||||||
              disabled={disableLogXSetting}
 | 
					 | 
				
			||||||
              tooltip={
 | 
					 | 
				
			||||||
                disableLogXSetting
 | 
					 | 
				
			||||||
                  ? "Your distribution has mass lower than or equal to 0. Log only works on strictly positive values."
 | 
					 | 
				
			||||||
                  : undefined
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
            <Checkbox
 | 
					 | 
				
			||||||
              register={register}
 | 
					 | 
				
			||||||
              name="expY"
 | 
					 | 
				
			||||||
              label="Show y scale exponentially"
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
            <Checkbox
 | 
					 | 
				
			||||||
              register={register}
 | 
					 | 
				
			||||||
              name="distributionChartActions"
 | 
					 | 
				
			||||||
              label="Show vega chart controls"
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
            <Checkbox
 | 
					 | 
				
			||||||
              register={register}
 | 
					 | 
				
			||||||
              name="showSummary"
 | 
					 | 
				
			||||||
              label="Show summary statistics"
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
            <InputItem
 | 
					 | 
				
			||||||
              name="minX"
 | 
					 | 
				
			||||||
              type="number"
 | 
					 | 
				
			||||||
              register={register}
 | 
					 | 
				
			||||||
              label="Min X Value"
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
            <InputItem
 | 
					 | 
				
			||||||
              name="maxX"
 | 
					 | 
				
			||||||
              type="number"
 | 
					 | 
				
			||||||
              register={register}
 | 
					 | 
				
			||||||
              label="Max X Value"
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
            <InputItem
 | 
					 | 
				
			||||||
              name="title"
 | 
					 | 
				
			||||||
              type="text"
 | 
					 | 
				
			||||||
              register={register}
 | 
					 | 
				
			||||||
              label="Title"
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
            <InputItem
 | 
					 | 
				
			||||||
              name="tickFormat"
 | 
					 | 
				
			||||||
              type="text"
 | 
					 | 
				
			||||||
              register={register}
 | 
					 | 
				
			||||||
              label="Tick Format"
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </HeadedSection>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      {withFunctionSettings ? (
 | 
					      {withFunctionSettings ? (
 | 
				
			||||||
        <div className="pt-8">
 | 
					        <FunctionViewSettings register={register} />
 | 
				
			||||||
          <HeadedSection title="Function Display Settings">
 | 
					 | 
				
			||||||
            <div className="space-y-6">
 | 
					 | 
				
			||||||
              <Text>
 | 
					 | 
				
			||||||
                When displaying functions of single variables that return
 | 
					 | 
				
			||||||
                numbers or distributions, we need to use defaults for the
 | 
					 | 
				
			||||||
                x-axis. We need to select a minimum and maximum value of x to
 | 
					 | 
				
			||||||
                sample, and a number n of the number of points to sample.
 | 
					 | 
				
			||||||
              </Text>
 | 
					 | 
				
			||||||
              <div className="space-y-4">
 | 
					 | 
				
			||||||
                <InputItem
 | 
					 | 
				
			||||||
                  type="number"
 | 
					 | 
				
			||||||
                  name="diagramStart"
 | 
					 | 
				
			||||||
                  register={register}
 | 
					 | 
				
			||||||
                  label="Min X Value"
 | 
					 | 
				
			||||||
                />
 | 
					 | 
				
			||||||
                <InputItem
 | 
					 | 
				
			||||||
                  type="number"
 | 
					 | 
				
			||||||
                  name="diagramStop"
 | 
					 | 
				
			||||||
                  register={register}
 | 
					 | 
				
			||||||
                  label="Max X Value"
 | 
					 | 
				
			||||||
                />
 | 
					 | 
				
			||||||
                <InputItem
 | 
					 | 
				
			||||||
                  type="number"
 | 
					 | 
				
			||||||
                  name="diagramCount"
 | 
					 | 
				
			||||||
                  register={register}
 | 
					 | 
				
			||||||
                  label="Points between X min and X max to sample"
 | 
					 | 
				
			||||||
                />
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
          </HeadedSection>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      ) : null}
 | 
					      ) : null}
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const DistributionViewSettings: React.FC<{
 | 
				
			||||||
 | 
					  disableLogXSetting?: boolean;
 | 
				
			||||||
 | 
					  register: UseFormRegister<EditableViewSettings>;
 | 
				
			||||||
 | 
					}> = ({ disableLogXSetting, register }) => {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className="pt-8">
 | 
				
			||||||
 | 
					      <HeadedSection title="Distribution Display Settings">
 | 
				
			||||||
 | 
					        <div className="space-y-2">
 | 
				
			||||||
 | 
					          <Checkbox
 | 
				
			||||||
 | 
					            register={register}
 | 
				
			||||||
 | 
					            name="logX"
 | 
				
			||||||
 | 
					            label="Show x scale logarithmically"
 | 
				
			||||||
 | 
					            disabled={disableLogXSetting}
 | 
				
			||||||
 | 
					            tooltip={
 | 
				
			||||||
 | 
					              disableLogXSetting
 | 
				
			||||||
 | 
					                ? "Your distribution has mass lower than or equal to 0. Log only works on strictly positive values."
 | 
				
			||||||
 | 
					                : undefined
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          <Checkbox
 | 
				
			||||||
 | 
					            register={register}
 | 
				
			||||||
 | 
					            name="expY"
 | 
				
			||||||
 | 
					            label="Show y scale exponentially"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          <Checkbox
 | 
				
			||||||
 | 
					            register={register}
 | 
				
			||||||
 | 
					            name="distributionChartActions"
 | 
				
			||||||
 | 
					            label="Show vega chart controls"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          <Checkbox
 | 
				
			||||||
 | 
					            register={register}
 | 
				
			||||||
 | 
					            name="showSummary"
 | 
				
			||||||
 | 
					            label="Show summary statistics"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          <InputItem
 | 
				
			||||||
 | 
					            name="minX"
 | 
				
			||||||
 | 
					            type="number"
 | 
				
			||||||
 | 
					            register={register}
 | 
				
			||||||
 | 
					            label="Min X Value"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          <InputItem
 | 
				
			||||||
 | 
					            name="maxX"
 | 
				
			||||||
 | 
					            type="number"
 | 
				
			||||||
 | 
					            register={register}
 | 
				
			||||||
 | 
					            label="Max X Value"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          <InputItem
 | 
				
			||||||
 | 
					            name="title"
 | 
				
			||||||
 | 
					            type="text"
 | 
				
			||||||
 | 
					            register={register}
 | 
				
			||||||
 | 
					            label="Title"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          <InputItem
 | 
				
			||||||
 | 
					            name="tickFormat"
 | 
				
			||||||
 | 
					            type="text"
 | 
				
			||||||
 | 
					            register={register}
 | 
				
			||||||
 | 
					            label="Tick Format"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </HeadedSection>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const FunctionViewSettings: React.FC<{
 | 
				
			||||||
 | 
					  register: UseFormRegister<EditableViewSettings>;
 | 
				
			||||||
 | 
					}> = ({ register }) => (
 | 
				
			||||||
 | 
					  <div className="pt-8">
 | 
				
			||||||
 | 
					    <HeadedSection title="Function Display Settings">
 | 
				
			||||||
 | 
					      <div className="space-y-6">
 | 
				
			||||||
 | 
					        <Text>
 | 
				
			||||||
 | 
					          When displaying functions of single variables that return numbers or
 | 
				
			||||||
 | 
					          distributions, we need to use defaults for the x-axis. We need to
 | 
				
			||||||
 | 
					          select a minimum and maximum value of x to sample, and a number n of
 | 
				
			||||||
 | 
					          the number of points to sample.
 | 
				
			||||||
 | 
					        </Text>
 | 
				
			||||||
 | 
					        <div className="space-y-4">
 | 
				
			||||||
 | 
					          <InputItem
 | 
				
			||||||
 | 
					            type="number"
 | 
				
			||||||
 | 
					            name="diagramStart"
 | 
				
			||||||
 | 
					            register={register}
 | 
				
			||||||
 | 
					            label="Min X Value"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          <InputItem
 | 
				
			||||||
 | 
					            type="number"
 | 
				
			||||||
 | 
					            name="diagramStop"
 | 
				
			||||||
 | 
					            register={register}
 | 
				
			||||||
 | 
					            label="Max X Value"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          <InputItem
 | 
				
			||||||
 | 
					            type="number"
 | 
				
			||||||
 | 
					            name="diagramCount"
 | 
				
			||||||
 | 
					            register={register}
 | 
				
			||||||
 | 
					            label="Points between X min and X max to sample"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </HeadedSection>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,9 +13,9 @@ export type DistributionChartSpecOptions = {
 | 
				
			||||||
  /** The title of the chart */
 | 
					  /** The title of the chart */
 | 
				
			||||||
  title?: string;
 | 
					  title?: string;
 | 
				
			||||||
  /** The formatting of the ticks */
 | 
					  /** The formatting of the ticks */
 | 
				
			||||||
  format?: string;
 | 
					  format: string;
 | 
				
			||||||
  /** Whether the x-axis should be dates or numbers */
 | 
					  /** Whether the x-axis should be dates or numbers */
 | 
				
			||||||
  xAxisType?: "number" | "dateTime";
 | 
					  xAxisType: "number" | "dateTime";
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** X Scales */
 | 
					/** X Scales */
 | 
				
			||||||
| 
						 | 
					@ -70,15 +70,7 @@ const width = 500;
 | 
				
			||||||
export function buildVegaSpec(
 | 
					export function buildVegaSpec(
 | 
				
			||||||
  specOptions: DistributionChartSpecOptions & { maxY: number }
 | 
					  specOptions: DistributionChartSpecOptions & { maxY: number }
 | 
				
			||||||
): VisualizationSpec {
 | 
					): VisualizationSpec {
 | 
				
			||||||
  const {
 | 
					  const { title, minX, maxX, logX, expY, xAxisType, maxY } = specOptions;
 | 
				
			||||||
    title,
 | 
					 | 
				
			||||||
    minX,
 | 
					 | 
				
			||||||
    maxX,
 | 
					 | 
				
			||||||
    logX,
 | 
					 | 
				
			||||||
    expY,
 | 
					 | 
				
			||||||
    xAxisType = "number",
 | 
					 | 
				
			||||||
    maxY,
 | 
					 | 
				
			||||||
  } = specOptions;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const dateTime = xAxisType === "dateTime";
 | 
					  const dateTime = xAxisType === "dateTime";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  result,
 | 
					  result,
 | 
				
			||||||
  SqError,
 | 
					  SqError,
 | 
				
			||||||
 | 
					  environment,
 | 
				
			||||||
  SqProject,
 | 
					  SqProject,
 | 
				
			||||||
  SqRecord,
 | 
					  SqRecord,
 | 
				
			||||||
  SqValue,
 | 
					  SqValue,
 | 
				
			||||||
| 
						 | 
					@ -9,13 +10,31 @@ import { useEffect, useMemo } from "react";
 | 
				
			||||||
import { JsImports, jsImportsToSquiggleCode } from "../jsImports";
 | 
					import { JsImports, jsImportsToSquiggleCode } from "../jsImports";
 | 
				
			||||||
import * as uuid from "uuid";
 | 
					import * as uuid from "uuid";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type SquiggleArgs = {
 | 
					export type SquiggleArgs = {
 | 
				
			||||||
  code: string;
 | 
					  code: string;
 | 
				
			||||||
  executionId?: number;
 | 
					  executionId?: number;
 | 
				
			||||||
  jsImports?: JsImports;
 | 
					  jsImports?: JsImports;
 | 
				
			||||||
 | 
					  onChange?: (
 | 
				
			||||||
 | 
					    expr: result<SqValue, SqError> | undefined,
 | 
				
			||||||
 | 
					    sourceName: string
 | 
				
			||||||
 | 
					  ) => void;
 | 
				
			||||||
 | 
					} & (StandaloneExecutionProps | ProjectExecutionProps);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Props needed for a standalone execution
 | 
				
			||||||
 | 
					type StandaloneExecutionProps = {
 | 
				
			||||||
 | 
					  project?: undefined;
 | 
				
			||||||
 | 
					  continues?: undefined;
 | 
				
			||||||
 | 
					  /** The amount of points returned to draw the distribution, not needed if using a project */
 | 
				
			||||||
 | 
					  environment?: environment;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Props needed when executing inside a project.
 | 
				
			||||||
 | 
					type ProjectExecutionProps = {
 | 
				
			||||||
 | 
					  environment?: undefined;
 | 
				
			||||||
 | 
					  /** The project that this execution is part of */
 | 
				
			||||||
  project: SqProject;
 | 
					  project: SqProject;
 | 
				
			||||||
 | 
					  /** What other squiggle sources from the project to continue. Default [] */
 | 
				
			||||||
  continues?: string[];
 | 
					  continues?: string[];
 | 
				
			||||||
  onChange?: (expr: SqValue | undefined, sourceName: string) => void;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type ResultAndBindings = {
 | 
					export type ResultAndBindings = {
 | 
				
			||||||
| 
						 | 
					@ -29,12 +48,24 @@ const defaultContinues = [];
 | 
				
			||||||
export const useSquiggle = (args: SquiggleArgs): ResultAndBindings => {
 | 
					export const useSquiggle = (args: SquiggleArgs): ResultAndBindings => {
 | 
				
			||||||
  const sourceName = useMemo(() => uuid.v4(), []);
 | 
					  const sourceName = useMemo(() => uuid.v4(), []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const env = args.project.getEnvironment();
 | 
					  const p = useMemo(() => {
 | 
				
			||||||
 | 
					    if (args.project) {
 | 
				
			||||||
 | 
					      return args.project;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      const p = SqProject.create();
 | 
				
			||||||
 | 
					      if (args.environment) {
 | 
				
			||||||
 | 
					        p.setEnvironment(args.environment);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return p;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }, [args.project, args.environment]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const env = p.getEnvironment();
 | 
				
			||||||
  const continues = args.continues || defaultContinues;
 | 
					  const continues = args.continues || defaultContinues;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const result = useMemo(
 | 
					  const result = useMemo(
 | 
				
			||||||
    () => {
 | 
					    () => {
 | 
				
			||||||
      const project = args.project;
 | 
					      const project = p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      project.setSource(sourceName, args.code);
 | 
					      project.setSource(sourceName, args.code);
 | 
				
			||||||
      let fullContinues = continues;
 | 
					      let fullContinues = continues;
 | 
				
			||||||
| 
						 | 
					@ -61,25 +92,23 @@ export const useSquiggle = (args: SquiggleArgs): ResultAndBindings => {
 | 
				
			||||||
      continues,
 | 
					      continues,
 | 
				
			||||||
      args.project,
 | 
					      args.project,
 | 
				
			||||||
      env,
 | 
					      env,
 | 
				
			||||||
 | 
					      p,
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const { onChange } = args;
 | 
					  const { onChange } = args;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    onChange?.(
 | 
					    onChange?.(result.result, sourceName);
 | 
				
			||||||
      result.result.tag === "Ok" ? result.result.value : undefined,
 | 
					 | 
				
			||||||
      sourceName
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }, [result, onChange, sourceName]);
 | 
					  }, [result, onChange, sourceName]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    return () => {
 | 
					    return () => {
 | 
				
			||||||
      args.project.removeSource(sourceName);
 | 
					      p.removeSource(sourceName);
 | 
				
			||||||
      if (args.project.getSource(importSourceName(sourceName)))
 | 
					      if (p.getSource(importSourceName(sourceName)))
 | 
				
			||||||
        args.project.removeSource(importSourceName(sourceName));
 | 
					        p.removeSource(importSourceName(sourceName));
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  }, [args.project, sourceName]);
 | 
					  }, [p, sourceName]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return result;
 | 
					  return result;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -250,5 +250,3 @@ to allow large and small numbers being printed cleanly.
 | 
				
			||||||
    {Template.bind({})}
 | 
					    {Template.bind({})}
 | 
				
			||||||
  </Story>
 | 
					  </Story>
 | 
				
			||||||
</Canvas>
 | 
					</Canvas>
 | 
				
			||||||
 | 
					 | 
				
			||||||
<Props of={SquiggleChart} />
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								packages/components/test/viewProps.test.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								packages/components/test/viewProps.test.tsx
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					import { render } from "@testing-library/react";
 | 
				
			||||||
 | 
					import React from "react";
 | 
				
			||||||
 | 
					import "@testing-library/jest-dom";
 | 
				
			||||||
 | 
					import { SquiggleChart } from "../src/index";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test("showSummary prop shows table", async () => {
 | 
				
			||||||
 | 
					  const { container } = render(
 | 
				
			||||||
 | 
					    <SquiggleChart code={"normal(5, 1)"} showSummary={true} />
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					  expect(container).toHaveTextContent("Mean");
 | 
				
			||||||
 | 
					  expect(container).toHaveTextContent("5");
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user