Merge remote-tracking branch 'origin/develop' into scoring-cleanup-three
This commit is contained in:
commit
e9968288fd
|
@ -5,18 +5,15 @@ import {
|
||||||
distributionError,
|
distributionError,
|
||||||
distributionErrorToString,
|
distributionErrorToString,
|
||||||
} from "@quri/squiggle-lang";
|
} from "@quri/squiggle-lang";
|
||||||
import { Vega, VisualizationSpec } from "react-vega";
|
import { Vega } from "react-vega";
|
||||||
import * as chartSpecification from "../vega-specs/spec-distributions.json";
|
|
||||||
import { ErrorAlert } from "./Alert";
|
import { ErrorAlert } from "./Alert";
|
||||||
import { useSize } from "react-use";
|
import { useSize } from "react-use";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
linearXScale,
|
buildVegaSpec,
|
||||||
logXScale,
|
DistributionChartSpecOptions,
|
||||||
linearYScale,
|
} from "../lib/distributionSpecBuilder";
|
||||||
expYScale,
|
|
||||||
} from "./DistributionVegaScales";
|
|
||||||
import { NumberShower } from "./NumberShower";
|
import { NumberShower } from "./NumberShower";
|
||||||
|
|
||||||
export type DistributionPlottingSettings = {
|
export type DistributionPlottingSettings = {
|
||||||
|
@ -24,27 +21,26 @@ export type DistributionPlottingSettings = {
|
||||||
showSummary: boolean;
|
showSummary: boolean;
|
||||||
/** Whether to show the user graph controls (scale etc) */
|
/** Whether to show the user graph controls (scale etc) */
|
||||||
showControls: boolean;
|
showControls: boolean;
|
||||||
/** Set the x scale to be logarithmic by deault */
|
} & DistributionChartSpecOptions;
|
||||||
logX: boolean;
|
|
||||||
/** Set the y scale to be exponential by deault */
|
|
||||||
expY: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type DistributionChartProps = {
|
export type DistributionChartProps = {
|
||||||
distribution: Distribution;
|
distribution: Distribution;
|
||||||
width?: number;
|
width?: number;
|
||||||
height: number;
|
height: number;
|
||||||
|
actions?: boolean;
|
||||||
} & DistributionPlottingSettings;
|
} & DistributionPlottingSettings;
|
||||||
|
|
||||||
export const DistributionChart: React.FC<DistributionChartProps> = ({
|
export const DistributionChart: React.FC<DistributionChartProps> = (props) => {
|
||||||
distribution,
|
const {
|
||||||
height,
|
distribution,
|
||||||
showSummary,
|
height,
|
||||||
width,
|
showSummary,
|
||||||
showControls,
|
width,
|
||||||
logX,
|
showControls,
|
||||||
expY,
|
logX,
|
||||||
}) => {
|
expY,
|
||||||
|
actions = false,
|
||||||
|
} = props;
|
||||||
const [isLogX, setLogX] = React.useState(logX);
|
const [isLogX, setLogX] = React.useState(logX);
|
||||||
const [isExpY, setExpY] = React.useState(expY);
|
const [isExpY, setExpY] = React.useState(expY);
|
||||||
|
|
||||||
|
@ -64,7 +60,7 @@ export const DistributionChart: React.FC<DistributionChartProps> = ({
|
||||||
const massBelow0 =
|
const massBelow0 =
|
||||||
shape.value.continuous.some((x) => x.x <= 0) ||
|
shape.value.continuous.some((x) => x.x <= 0) ||
|
||||||
shape.value.discrete.some((x) => x.x <= 0);
|
shape.value.discrete.some((x) => x.x <= 0);
|
||||||
const spec = buildVegaSpec(isLogX, isExpY);
|
const spec = buildVegaSpec(props);
|
||||||
|
|
||||||
let widthProp = width ? width : size.width;
|
let widthProp = width ? width : size.width;
|
||||||
if (widthProp < 20) {
|
if (widthProp < 20) {
|
||||||
|
@ -82,7 +78,7 @@ export const DistributionChart: React.FC<DistributionChartProps> = ({
|
||||||
data={{ con: shape.value.continuous, dis: shape.value.discrete }}
|
data={{ con: shape.value.continuous, dis: shape.value.discrete }}
|
||||||
width={widthProp - 10}
|
width={widthProp - 10}
|
||||||
height={height}
|
height={height}
|
||||||
actions={false}
|
actions={actions}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<ErrorAlert heading="Log Domain Error">
|
<ErrorAlert heading="Log Domain Error">
|
||||||
|
@ -116,16 +112,6 @@ export const DistributionChart: React.FC<DistributionChartProps> = ({
|
||||||
return sized;
|
return sized;
|
||||||
};
|
};
|
||||||
|
|
||||||
function buildVegaSpec(isLogX: boolean, isExpY: boolean): VisualizationSpec {
|
|
||||||
return {
|
|
||||||
...chartSpecification,
|
|
||||||
scales: [
|
|
||||||
isLogX ? logXScale : linearXScale,
|
|
||||||
isExpY ? expYScale : linearYScale,
|
|
||||||
],
|
|
||||||
} as VisualizationSpec;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface CheckBoxProps {
|
interface CheckBoxProps {
|
||||||
label: string;
|
label: string;
|
||||||
onChange: (x: boolean) => void;
|
onChange: (x: boolean) => void;
|
||||||
|
|
|
@ -44,6 +44,18 @@ export interface SquiggleChartProps {
|
||||||
logX?: boolean;
|
logX?: boolean;
|
||||||
/** Set the y scale to be exponential by deault */
|
/** Set the y scale to be exponential by deault */
|
||||||
expY?: boolean;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultOnChange = () => {};
|
const defaultOnChange = () => {};
|
||||||
|
@ -65,6 +77,12 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = React.memo(
|
||||||
diagramStart = 0,
|
diagramStart = 0,
|
||||||
diagramStop = 10,
|
diagramStop = 10,
|
||||||
diagramCount = 100,
|
diagramCount = 100,
|
||||||
|
tickFormat,
|
||||||
|
minX,
|
||||||
|
maxX,
|
||||||
|
color,
|
||||||
|
title,
|
||||||
|
distributionChartActions,
|
||||||
}) => {
|
}) => {
|
||||||
const result = useSquiggle({
|
const result = useSquiggle({
|
||||||
code,
|
code,
|
||||||
|
@ -83,6 +101,12 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = React.memo(
|
||||||
showSummary,
|
showSummary,
|
||||||
logX,
|
logX,
|
||||||
expY,
|
expY,
|
||||||
|
format: tickFormat,
|
||||||
|
minX,
|
||||||
|
maxX,
|
||||||
|
color,
|
||||||
|
title,
|
||||||
|
actions: distributionChartActions,
|
||||||
};
|
};
|
||||||
|
|
||||||
let chartSettings = {
|
let chartSettings = {
|
||||||
|
|
|
@ -18,7 +18,7 @@ import clsx from "clsx";
|
||||||
|
|
||||||
import { defaultBindings, environment } from "@quri/squiggle-lang";
|
import { defaultBindings, environment } from "@quri/squiggle-lang";
|
||||||
|
|
||||||
import { SquiggleChart } from "./SquiggleChart";
|
import { SquiggleChart, 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";
|
||||||
|
@ -27,28 +27,16 @@ import { Toggle } from "./ui/Toggle";
|
||||||
import { Checkbox } from "./ui/Checkbox";
|
import { Checkbox } from "./ui/Checkbox";
|
||||||
import { StyledTab } from "./ui/StyledTab";
|
import { StyledTab } from "./ui/StyledTab";
|
||||||
|
|
||||||
interface PlaygroundProps {
|
type PlaygroundProps = SquiggleChartProps & {
|
||||||
/** The initial squiggle string to put in the playground */
|
/** The initial squiggle string to put in the playground */
|
||||||
defaultCode?: string;
|
defaultCode?: string;
|
||||||
/** How many pixels high is the playground */
|
/** How many pixels high is the playground */
|
||||||
height?: number;
|
|
||||||
/** Whether to show the types of outputs in the playground */
|
|
||||||
showTypes?: boolean;
|
|
||||||
/** Whether to show the log scale controls in the playground */
|
|
||||||
showControls?: boolean;
|
|
||||||
/** Whether to show the summary table in the playground */
|
|
||||||
showSummary?: boolean;
|
|
||||||
/** Whether to log the x coordinate on distribution charts */
|
|
||||||
logX?: boolean;
|
|
||||||
/** Whether to exp the y coordinate on distribution charts */
|
|
||||||
expY?: boolean;
|
|
||||||
/** If code is set, component becomes controlled */
|
|
||||||
code?: string;
|
|
||||||
onCodeChange?(expr: string): void;
|
onCodeChange?(expr: string): void;
|
||||||
|
/* When settings change */
|
||||||
onSettingsChange?(settings: any): void;
|
onSettingsChange?(settings: any): void;
|
||||||
/** Should we show the editor? */
|
/** Should we show the editor? */
|
||||||
showEditor?: boolean;
|
showEditor?: boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
const schema = yup.object({}).shape({
|
const schema = yup.object({}).shape({
|
||||||
sampleCount: yup
|
sampleCount: yup
|
||||||
|
@ -82,6 +70,12 @@ const schema = yup.object({}).shape({
|
||||||
showEditor: yup.boolean().required(),
|
showEditor: yup.boolean().required(),
|
||||||
logX: yup.boolean().required(),
|
logX: yup.boolean().required(),
|
||||||
expY: yup.boolean().required(),
|
expY: yup.boolean().required(),
|
||||||
|
tickFormat: yup.string().default(".9~s"),
|
||||||
|
title: yup.string(),
|
||||||
|
color: yup.string().default("#739ECC").required(),
|
||||||
|
minX: yup.number(),
|
||||||
|
maxX: yup.number(),
|
||||||
|
distributionChartActions: yup.boolean(),
|
||||||
showSettingsPage: yup.boolean().default(false),
|
showSettingsPage: yup.boolean().default(false),
|
||||||
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),
|
||||||
|
@ -114,7 +108,7 @@ function InputItem<T>({
|
||||||
}: {
|
}: {
|
||||||
name: Path<T>;
|
name: Path<T>;
|
||||||
label: string;
|
label: string;
|
||||||
type: "number";
|
type: "number" | "text" | "color";
|
||||||
register: UseFormRegister<T>;
|
register: UseFormRegister<T>;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
|
@ -122,7 +116,7 @@ function InputItem<T>({
|
||||||
<div className="text-sm font-medium text-gray-600 mb-1">{label}</div>
|
<div className="text-sm font-medium text-gray-600 mb-1">{label}</div>
|
||||||
<input
|
<input
|
||||||
type={type}
|
type={type}
|
||||||
{...register(name)}
|
{...register(name, { valueAsNumber: type === "number" })}
|
||||||
className="form-input max-w-lg block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:max-w-xs sm:text-sm border-gray-300 rounded-md"
|
className="form-input max-w-lg block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:max-w-xs sm:text-sm border-gray-300 rounded-md"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
@ -202,6 +196,11 @@ const ViewSettings: React.FC<{ register: UseFormRegister<FormFields> }> = ({
|
||||||
name="expY"
|
name="expY"
|
||||||
label="Show y scale exponentially"
|
label="Show y scale exponentially"
|
||||||
/>
|
/>
|
||||||
|
<Checkbox
|
||||||
|
register={register}
|
||||||
|
name="distributionChartActions"
|
||||||
|
label="Show vega chart controls"
|
||||||
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
register={register}
|
register={register}
|
||||||
name="showControls"
|
name="showControls"
|
||||||
|
@ -212,6 +211,36 @@ const ViewSettings: React.FC<{ register: UseFormRegister<FormFields> }> = ({
|
||||||
name="showSummary"
|
name="showSummary"
|
||||||
label="Show summary statistics"
|
label="Show summary statistics"
|
||||||
/>
|
/>
|
||||||
|
<InputItem
|
||||||
|
name="minX"
|
||||||
|
type="number"
|
||||||
|
register={register}
|
||||||
|
label="The minimum of the charted distribution domain"
|
||||||
|
/>
|
||||||
|
<InputItem
|
||||||
|
name="maxX"
|
||||||
|
type="number"
|
||||||
|
register={register}
|
||||||
|
label="The maximum of the charted distribution domain"
|
||||||
|
/>
|
||||||
|
<InputItem
|
||||||
|
name="title"
|
||||||
|
type="text"
|
||||||
|
register={register}
|
||||||
|
label="The title shown on the distribution"
|
||||||
|
/>
|
||||||
|
<InputItem
|
||||||
|
name="tickFormat"
|
||||||
|
type="text"
|
||||||
|
register={register}
|
||||||
|
label="The format that the ticks are rendered"
|
||||||
|
/>
|
||||||
|
<InputItem
|
||||||
|
name="color"
|
||||||
|
type="color"
|
||||||
|
register={register}
|
||||||
|
label="The color of the charted distribution"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</HeadedSection>
|
</HeadedSection>
|
||||||
</div>
|
</div>
|
||||||
|
@ -385,6 +414,12 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
|
||||||
showSummary = false,
|
showSummary = false,
|
||||||
logX = false,
|
logX = false,
|
||||||
expY = false,
|
expY = false,
|
||||||
|
title,
|
||||||
|
minX,
|
||||||
|
maxX,
|
||||||
|
color = "#739ECC",
|
||||||
|
tickFormat = ".9~s",
|
||||||
|
distributionChartActions,
|
||||||
code: controlledCode,
|
code: controlledCode,
|
||||||
onCodeChange,
|
onCodeChange,
|
||||||
onSettingsChange,
|
onSettingsChange,
|
||||||
|
@ -408,6 +443,12 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
|
||||||
showControls,
|
showControls,
|
||||||
logX,
|
logX,
|
||||||
expY,
|
expY,
|
||||||
|
title,
|
||||||
|
minX,
|
||||||
|
maxX,
|
||||||
|
color,
|
||||||
|
tickFormat,
|
||||||
|
distributionChartActions,
|
||||||
showSummary,
|
showSummary,
|
||||||
showEditor,
|
showEditor,
|
||||||
leftSizePercent: 50,
|
leftSizePercent: 50,
|
||||||
|
@ -440,15 +481,7 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
|
||||||
<SquiggleChart
|
<SquiggleChart
|
||||||
code={renderedCode}
|
code={renderedCode}
|
||||||
environment={env}
|
environment={env}
|
||||||
diagramStart={Number(vars.diagramStart)}
|
{...vars}
|
||||||
diagramStop={Number(vars.diagramStop)}
|
|
||||||
diagramCount={Number(vars.diagramCount)}
|
|
||||||
height={vars.chartHeight}
|
|
||||||
showTypes={vars.showTypes}
|
|
||||||
showControls={vars.showControls}
|
|
||||||
showSummary={vars.showSummary}
|
|
||||||
logX={vars.logX}
|
|
||||||
expY={vars.expY}
|
|
||||||
bindings={defaultBindings}
|
bindings={defaultBindings}
|
||||||
jsImports={imports}
|
jsImports={imports}
|
||||||
/>
|
/>
|
||||||
|
@ -496,6 +529,7 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
|
||||||
|
|
||||||
const withoutEditor = <div className="mt-3">{tabs}</div>;
|
const withoutEditor = <div className="mt-3">{tabs}</div>;
|
||||||
|
|
||||||
|
console.log(vars);
|
||||||
return (
|
return (
|
||||||
<SquiggleContainer>
|
<SquiggleContainer>
|
||||||
<StyledTab.Group>
|
<StyledTab.Group>
|
||||||
|
|
256
packages/components/src/lib/distributionSpecBuilder.ts
Normal file
256
packages/components/src/lib/distributionSpecBuilder.ts
Normal file
|
@ -0,0 +1,256 @@
|
||||||
|
import { VisualizationSpec } from "react-vega";
|
||||||
|
import type { LogScale, LinearScale, PowScale } from "vega";
|
||||||
|
|
||||||
|
export type DistributionChartSpecOptions = {
|
||||||
|
/** Set the x scale to be logarithmic by deault */
|
||||||
|
logX: boolean;
|
||||||
|
/** Set the y scale to be exponential by deault */
|
||||||
|
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;
|
||||||
|
/** The title of the chart */
|
||||||
|
title?: string;
|
||||||
|
/** The formatting of the ticks */
|
||||||
|
format?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export let linearXScale: LinearScale = {
|
||||||
|
name: "xscale",
|
||||||
|
clamp: true,
|
||||||
|
type: "linear",
|
||||||
|
range: "width",
|
||||||
|
zero: false,
|
||||||
|
nice: false,
|
||||||
|
domain: {
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
data: "con",
|
||||||
|
field: "x",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: "dis",
|
||||||
|
field: "x",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
export let linearYScale: LinearScale = {
|
||||||
|
name: "yscale",
|
||||||
|
type: "linear",
|
||||||
|
range: "height",
|
||||||
|
zero: false,
|
||||||
|
domain: {
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
data: "con",
|
||||||
|
field: "y",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: "dis",
|
||||||
|
field: "y",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export let logXScale: LogScale = {
|
||||||
|
name: "xscale",
|
||||||
|
type: "log",
|
||||||
|
range: "width",
|
||||||
|
zero: false,
|
||||||
|
base: 10,
|
||||||
|
nice: false,
|
||||||
|
clamp: true,
|
||||||
|
domain: {
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
data: "con",
|
||||||
|
field: "x",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: "dis",
|
||||||
|
field: "x",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export let expYScale: PowScale = {
|
||||||
|
name: "yscale",
|
||||||
|
type: "pow",
|
||||||
|
exponent: 0.1,
|
||||||
|
range: "height",
|
||||||
|
zero: false,
|
||||||
|
nice: false,
|
||||||
|
domain: {
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
data: "con",
|
||||||
|
field: "y",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: "dis",
|
||||||
|
field: "y",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export function buildVegaSpec(
|
||||||
|
specOptions: DistributionChartSpecOptions
|
||||||
|
): VisualizationSpec {
|
||||||
|
let {
|
||||||
|
format = ".9~s",
|
||||||
|
color = "#739ECC",
|
||||||
|
title,
|
||||||
|
minX,
|
||||||
|
maxX,
|
||||||
|
logX,
|
||||||
|
expY,
|
||||||
|
} = specOptions;
|
||||||
|
|
||||||
|
let xScale = logX ? logXScale : linearXScale;
|
||||||
|
if (minX !== undefined && Number.isFinite(minX)) {
|
||||||
|
xScale = { ...xScale, domainMin: minX };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxX !== undefined && Number.isFinite(maxX)) {
|
||||||
|
xScale = { ...xScale, domainMax: maxX };
|
||||||
|
}
|
||||||
|
|
||||||
|
let spec: VisualizationSpec = {
|
||||||
|
$schema: "https://vega.github.io/schema/vega/v5.json",
|
||||||
|
description: "A basic area chart example",
|
||||||
|
width: 500,
|
||||||
|
height: 100,
|
||||||
|
padding: 5,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
name: "con",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dis",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
signals: [],
|
||||||
|
scales: [xScale, expY ? expYScale : linearYScale],
|
||||||
|
axes: [
|
||||||
|
{
|
||||||
|
orient: "bottom",
|
||||||
|
scale: "xscale",
|
||||||
|
labelColor: "#727d93",
|
||||||
|
tickColor: "#fff",
|
||||||
|
tickOpacity: 0.0,
|
||||||
|
domainColor: "#fff",
|
||||||
|
domainOpacity: 0.0,
|
||||||
|
format: format,
|
||||||
|
tickCount: 10,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
marks: [
|
||||||
|
{
|
||||||
|
type: "area",
|
||||||
|
from: {
|
||||||
|
data: "con",
|
||||||
|
},
|
||||||
|
encode: {
|
||||||
|
update: {
|
||||||
|
interpolate: { value: "linear" },
|
||||||
|
x: {
|
||||||
|
scale: "xscale",
|
||||||
|
field: "x",
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
scale: "yscale",
|
||||||
|
field: "y",
|
||||||
|
},
|
||||||
|
y2: {
|
||||||
|
scale: "yscale",
|
||||||
|
value: 0,
|
||||||
|
},
|
||||||
|
fill: {
|
||||||
|
value: color,
|
||||||
|
},
|
||||||
|
fillOpacity: {
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "rect",
|
||||||
|
from: {
|
||||||
|
data: "dis",
|
||||||
|
},
|
||||||
|
encode: {
|
||||||
|
enter: {
|
||||||
|
width: {
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
x: {
|
||||||
|
scale: "xscale",
|
||||||
|
field: "x",
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
scale: "yscale",
|
||||||
|
field: "y",
|
||||||
|
},
|
||||||
|
y2: {
|
||||||
|
scale: "yscale",
|
||||||
|
value: 0,
|
||||||
|
},
|
||||||
|
fill: {
|
||||||
|
value: "#2f65a7",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "symbol",
|
||||||
|
from: {
|
||||||
|
data: "dis",
|
||||||
|
},
|
||||||
|
encode: {
|
||||||
|
enter: {
|
||||||
|
shape: {
|
||||||
|
value: "circle",
|
||||||
|
},
|
||||||
|
size: [{ value: 100 }],
|
||||||
|
tooltip: {
|
||||||
|
signal: "datum.y",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
x: {
|
||||||
|
scale: "xscale",
|
||||||
|
field: "x",
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
scale: "yscale",
|
||||||
|
field: "y",
|
||||||
|
},
|
||||||
|
fill: {
|
||||||
|
value: "#1e4577",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
if (title) {
|
||||||
|
spec = {
|
||||||
|
...spec,
|
||||||
|
title: {
|
||||||
|
text: title,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return spec;
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ import { Canvas, Meta, Story, Props } from "@storybook/addon-docs";
|
||||||
|
|
||||||
<Meta title="Squiggle/SquiggleChart" component={SquiggleChart} />
|
<Meta title="Squiggle/SquiggleChart" component={SquiggleChart} />
|
||||||
|
|
||||||
export const Template = SquiggleChart;
|
export const Template = (props) => <SquiggleChart {...props} />;
|
||||||
/*
|
/*
|
||||||
We have to hardcode a width here, because otherwise some interaction with
|
We have to hardcode a width here, because otherwise some interaction with
|
||||||
Storybook creates an infinite loop with the internal width
|
Storybook creates an infinite loop with the internal width
|
||||||
|
|
|
@ -22,6 +22,13 @@ module FooImplementation = {
|
||||||
let makeFoo = (a: string, b: string, _environment): string => `I am ${a}-foo and I am ${b}-foo`
|
let makeFoo = (a: string, b: string, _environment): string => `I am ${a}-foo and I am ${b}-foo`
|
||||||
let makeBar = (a: float, b: float, _environment): string =>
|
let makeBar = (a: float, b: float, _environment): string =>
|
||||||
`I am ${a->Js.Float.toString}-bar and I am ${b->Js.Float.toString}-bar`
|
`I am ${a->Js.Float.toString}-bar and I am ${b->Js.Float.toString}-bar`
|
||||||
|
// You can also define functions that has their internal errors
|
||||||
|
let makeReturningError = (_a: float, _b: float, _environment): result<float, ErrorValue.t> =>
|
||||||
|
if false {
|
||||||
|
0.->Ok
|
||||||
|
} else {
|
||||||
|
ErrorValue.RETodo("test error")->Error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// There is a potential for type modules to define lift functions
|
// There is a potential for type modules to define lift functions
|
||||||
|
@ -38,6 +45,17 @@ module FooFFI = {
|
||||||
| [IEvNumber(a), IEvNumber(b)] => FooImplementation.makeBar(a, b, environment)->IEvString->Some
|
| [IEvNumber(a), IEvNumber(b)] => FooImplementation.makeBar(a, b, environment)->IEvString->Some
|
||||||
| _ => None
|
| _ => None
|
||||||
}
|
}
|
||||||
|
let makeReturningError: ExpressionT.optionFfiFnReturningResult = (
|
||||||
|
args: array<InternalExpressionValue.t>,
|
||||||
|
environment,
|
||||||
|
) =>
|
||||||
|
switch args {
|
||||||
|
| [IEvNumber(a), IEvNumber(b)] =>
|
||||||
|
FooImplementation.makeReturningError(a, b, environment)
|
||||||
|
->Belt.Result.map(v => v->InternalExpressionValue.IEvNumber)
|
||||||
|
->Some
|
||||||
|
| _ => None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let fooModule: Module.t =
|
let fooModule: Module.t =
|
||||||
|
@ -47,6 +65,7 @@ let fooModule: Module.t =
|
||||||
->Module.defineBool("fooBool", FooImplementation.fooBool)
|
->Module.defineBool("fooBool", FooImplementation.fooBool)
|
||||||
->Module.defineFunction("makeFoo", FooFFI.makeFoo)
|
->Module.defineFunction("makeFoo", FooFFI.makeFoo)
|
||||||
->Module.defineFunction("makeBar", FooFFI.makeBar)
|
->Module.defineFunction("makeBar", FooFFI.makeBar)
|
||||||
|
->Module.defineFunctionReturningResult("makeReturningError", FooFFI.makeReturningError)
|
||||||
|
|
||||||
let makeBindings = (prevBindings: Bindings.t): Bindings.t =>
|
let makeBindings = (prevBindings: Bindings.t): Bindings.t =>
|
||||||
prevBindings->Module.defineModule("Foo", fooModule)
|
prevBindings->Module.defineModule("Foo", fooModule)
|
|
@ -72,6 +72,10 @@ type ffiFn = (
|
||||||
) => result<internalExpressionValue, Reducer_ErrorValue.errorValue>
|
) => result<internalExpressionValue, Reducer_ErrorValue.errorValue>
|
||||||
|
|
||||||
type optionFfiFn = (array<internalExpressionValue>, environment) => option<internalExpressionValue>
|
type optionFfiFn = (array<internalExpressionValue>, environment) => option<internalExpressionValue>
|
||||||
|
type optionFfiFnReturningResult = (
|
||||||
|
array<internalExpressionValue>,
|
||||||
|
environment,
|
||||||
|
) => option<result<internalExpressionValue, Reducer_ErrorValue.errorValue>>
|
||||||
|
|
||||||
type expressionOrFFI =
|
type expressionOrFFI =
|
||||||
| NotFFI(expression)
|
| NotFFI(expression)
|
||||||
|
|
|
@ -126,6 +126,17 @@ let functionNotFoundErrorFFIFn = (functionName: string): ExpressionT.ffiFn => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let convertOptionToFfiFnReturningResult = (
|
||||||
|
myFunctionName: string,
|
||||||
|
myFunction: ExpressionT.optionFfiFnReturningResult,
|
||||||
|
): ExpressionT.ffiFn => {
|
||||||
|
(args: array<InternalExpressionValue.t>, environment) => {
|
||||||
|
myFunction(args, environment)->Belt.Option.getWithDefault(
|
||||||
|
functionNotFoundErrorFFIFn(myFunctionName)(args, environment),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let convertOptionToFfiFn = (
|
let convertOptionToFfiFn = (
|
||||||
myFunctionName: string,
|
myFunctionName: string,
|
||||||
myFunction: ExpressionT.optionFfiFn,
|
myFunction: ExpressionT.optionFfiFn,
|
||||||
|
@ -159,4 +170,15 @@ let defineFunction = (nameSpace: t, identifier: string, value: ExpressionT.optio
|
||||||
nameSpace->define(identifier, convertOptionToFfiFn(identifier, value)->eLambdaFFIValue)
|
nameSpace->define(identifier, convertOptionToFfiFn(identifier, value)->eLambdaFFIValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
let emptyStdLib: t = emptyModule->defineBool("stdlib", true)
|
let defineFunctionReturningResult = (
|
||||||
|
nameSpace: t,
|
||||||
|
identifier: string,
|
||||||
|
value: ExpressionT.optionFfiFnReturningResult,
|
||||||
|
): t => {
|
||||||
|
nameSpace->define(
|
||||||
|
identifier,
|
||||||
|
convertOptionToFfiFnReturningResult(identifier, value)->eLambdaFFIValue,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let emptyStdLib: t = emptyModule->defineBool("_standardLibrary", true)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user