Merge pull request #504 from quantified-uncertainty/function-charts
Function charting
This commit is contained in:
commit
3cca106079
|
@ -1,18 +1,24 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import type { Spec } from "vega";
|
import type { Spec } from "vega";
|
||||||
import type { Distribution, errorValue, result } from "@quri/squiggle-lang";
|
import {
|
||||||
|
Distribution,
|
||||||
|
result,
|
||||||
|
lambdaValue,
|
||||||
|
environment,
|
||||||
|
runForeign,
|
||||||
|
errorValueToString,
|
||||||
|
} from "@quri/squiggle-lang";
|
||||||
import { createClassFromSpec } from "react-vega";
|
import { createClassFromSpec } from "react-vega";
|
||||||
import * as percentilesSpec from "../vega-specs/spec-percentiles.json";
|
import * as percentilesSpec from "../vega-specs/spec-percentiles.json";
|
||||||
import { DistributionChart } from "./DistributionChart";
|
import { DistributionChart } from "./DistributionChart";
|
||||||
|
import { NumberShower } from "./NumberShower";
|
||||||
import { ErrorBox } from "./ErrorBox";
|
import { ErrorBox } from "./ErrorBox";
|
||||||
|
|
||||||
let SquigglePercentilesChart = createClassFromSpec({
|
let SquigglePercentilesChart = createClassFromSpec({
|
||||||
spec: percentilesSpec as Spec,
|
spec: percentilesSpec as Spec,
|
||||||
});
|
});
|
||||||
|
|
||||||
type distPlusFn = (a: number) => result<Distribution, errorValue>;
|
|
||||||
|
|
||||||
const _rangeByCount = (start: number, stop: number, count: number) => {
|
const _rangeByCount = (start: number, stop: number, count: number) => {
|
||||||
const step = (stop - start) / (count - 1);
|
const step = (stop - start) / (count - 1);
|
||||||
const items = _.range(start, stop, step);
|
const items = _.range(start, stop, step);
|
||||||
|
@ -27,38 +33,36 @@ function unwrap<a, b>(x: result<a, b>): a {
|
||||||
throw Error("FAILURE TO UNWRAP");
|
throw Error("FAILURE TO UNWRAP");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export type FunctionChartSettings = {
|
||||||
|
start: number;
|
||||||
|
stop: number;
|
||||||
|
count: number;
|
||||||
|
};
|
||||||
|
|
||||||
function mapFilter<a, b>(xs: a[], f: (x: a) => b | undefined): b[] {
|
interface FunctionChartProps {
|
||||||
let initial: b[] = [];
|
fn: lambdaValue;
|
||||||
return xs.reduce((previous, current) => {
|
chartSettings: FunctionChartSettings;
|
||||||
let value: b | undefined = f(current);
|
environment: environment;
|
||||||
if (value !== undefined) {
|
|
||||||
return previous.concat([value]);
|
|
||||||
} else {
|
|
||||||
return previous;
|
|
||||||
}
|
|
||||||
}, initial);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FunctionChart: React.FC<{
|
export const FunctionChart: React.FC<FunctionChartProps> = ({
|
||||||
distPlusFn: distPlusFn;
|
fn,
|
||||||
diagramStart: number;
|
chartSettings,
|
||||||
diagramStop: number;
|
environment,
|
||||||
diagramCount: number;
|
}: FunctionChartProps) => {
|
||||||
}> = ({ distPlusFn, diagramStart, diagramStop, diagramCount }) => {
|
|
||||||
let [mouseOverlay, setMouseOverlay] = React.useState(0);
|
let [mouseOverlay, setMouseOverlay] = React.useState(0);
|
||||||
function handleHover(...args) {
|
function handleHover(_name: string, value: unknown) {
|
||||||
setMouseOverlay(args[1]);
|
setMouseOverlay(value as number);
|
||||||
}
|
}
|
||||||
function handleOut() {
|
function handleOut() {
|
||||||
setMouseOverlay(NaN);
|
setMouseOverlay(NaN);
|
||||||
}
|
}
|
||||||
const signalListeners = { mousemove: handleHover, mouseout: handleOut };
|
const signalListeners = { mousemove: handleHover, mouseout: handleOut };
|
||||||
let mouseItem = distPlusFn(mouseOverlay);
|
let mouseItem = runForeign(fn, [mouseOverlay], environment);
|
||||||
let showChart =
|
let showChart =
|
||||||
mouseItem.tag === "Ok" ? (
|
mouseItem.tag === "Ok" && mouseItem.value.tag == "distribution" ? (
|
||||||
<DistributionChart
|
<DistributionChart
|
||||||
distribution={mouseItem.value}
|
distribution={mouseItem.value.value}
|
||||||
width={400}
|
width={400}
|
||||||
height={140}
|
height={140}
|
||||||
showSummary={false}
|
showSummary={false}
|
||||||
|
@ -66,13 +70,49 @@ export const FunctionChart: React.FC<{
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
);
|
);
|
||||||
let data1 = _rangeByCount(diagramStart, diagramStop, diagramCount);
|
let data1 = _rangeByCount(
|
||||||
let valueData = mapFilter(data1, (x) => {
|
chartSettings.start,
|
||||||
let result = distPlusFn(x);
|
chartSettings.stop,
|
||||||
|
chartSettings.count
|
||||||
|
);
|
||||||
|
type point = { x: number; value: result<Distribution, string> };
|
||||||
|
let valueData: point[] = data1.map((x) => {
|
||||||
|
let result = runForeign(fn, [x], environment);
|
||||||
if (result.tag === "Ok") {
|
if (result.tag === "Ok") {
|
||||||
return { x: x, value: result.value };
|
if (result.value.tag == "distribution") {
|
||||||
|
return { x, value: { tag: "Ok", value: result.value.value } };
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
x,
|
||||||
|
value: {
|
||||||
|
tag: "Error",
|
||||||
|
value:
|
||||||
|
"Cannot currently render functions that don't return distributions",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
x,
|
||||||
|
value: { tag: "Error", value: errorValueToString(result.value) },
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}).map(({ x, value }) => {
|
});
|
||||||
|
|
||||||
|
let initialPartition: [
|
||||||
|
{ x: number; value: Distribution }[],
|
||||||
|
{ x: number; value: string }[]
|
||||||
|
] = [[], []];
|
||||||
|
let [functionImage, errors] = valueData.reduce((acc, current) => {
|
||||||
|
if (current.value.tag === "Ok") {
|
||||||
|
acc[0].push({ x: current.x, value: current.value.value });
|
||||||
|
} else {
|
||||||
|
acc[1].push({ x: current.x, value: current.value.value });
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, initialPartition);
|
||||||
|
|
||||||
|
let percentiles = functionImage.map(({ x, value }) => {
|
||||||
return {
|
return {
|
||||||
x: x,
|
x: x,
|
||||||
p1: unwrap(value.inv(0.01)),
|
p1: unwrap(value.inv(0.01)),
|
||||||
|
@ -91,24 +131,25 @@ export const FunctionChart: React.FC<{
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
let errorData = mapFilter(data1, (x) => {
|
let groupedErrors = _.groupBy(errors, (x) => x.value);
|
||||||
let result = distPlusFn(x);
|
|
||||||
if (result.tag === "Error") {
|
|
||||||
return { x: x, error: result.value };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
let error2 = _.groupBy(errorData, (x) => x.error);
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SquigglePercentilesChart
|
<SquigglePercentilesChart
|
||||||
data={{ facet: valueData }}
|
data={{ facet: percentiles }}
|
||||||
actions={false}
|
actions={false}
|
||||||
signalListeners={signalListeners}
|
signalListeners={signalListeners}
|
||||||
/>
|
/>
|
||||||
{showChart}
|
{showChart}
|
||||||
{_.keysIn(error2).map((k) => (
|
{_.entries(groupedErrors).map(([errorName, errorPoints]) => (
|
||||||
<ErrorBox heading={k}>
|
<ErrorBox heading={errorName}>
|
||||||
{`Values: [${error2[k].map((r) => r.x.toFixed(2)).join(",")}]`}
|
Values:{" "}
|
||||||
|
{errorPoints
|
||||||
|
.map((r) => <NumberShower number={r.x} />)
|
||||||
|
.reduce((a, b) => (
|
||||||
|
<>
|
||||||
|
{a}, {b}
|
||||||
|
</>
|
||||||
|
))}
|
||||||
</ErrorBox>
|
</ErrorBox>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -6,14 +6,16 @@ import {
|
||||||
errorValueToString,
|
errorValueToString,
|
||||||
squiggleExpression,
|
squiggleExpression,
|
||||||
bindings,
|
bindings,
|
||||||
samplingParams,
|
environment,
|
||||||
jsImports,
|
jsImports,
|
||||||
defaultImports,
|
defaultImports,
|
||||||
defaultBindings,
|
defaultBindings,
|
||||||
|
defaultEnvironment,
|
||||||
} from "@quri/squiggle-lang";
|
} from "@quri/squiggle-lang";
|
||||||
import { NumberShower } from "./NumberShower";
|
import { NumberShower } from "./NumberShower";
|
||||||
import { DistributionChart } from "./DistributionChart";
|
import { DistributionChart } from "./DistributionChart";
|
||||||
import { ErrorBox } from "./ErrorBox";
|
import { ErrorBox } from "./ErrorBox";
|
||||||
|
import { FunctionChart, FunctionChartSettings } from "./FunctionChart";
|
||||||
|
|
||||||
const variableBox = {
|
const variableBox = {
|
||||||
Component: styled.div`
|
Component: styled.div`
|
||||||
|
@ -36,7 +38,7 @@ const variableBox = {
|
||||||
interface VariableBoxProps {
|
interface VariableBoxProps {
|
||||||
heading: string;
|
heading: string;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
showTypes?: boolean;
|
showTypes: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const VariableBox: React.FC<VariableBoxProps> = ({
|
export const VariableBox: React.FC<VariableBoxProps> = ({
|
||||||
|
@ -68,9 +70,13 @@ export interface SquiggleItemProps {
|
||||||
/** Whether to show a summary of statistics for distributions */
|
/** Whether to show a summary of statistics for distributions */
|
||||||
showSummary: boolean;
|
showSummary: boolean;
|
||||||
/** Whether to show type information */
|
/** Whether to show type information */
|
||||||
showTypes?: boolean;
|
showTypes: boolean;
|
||||||
/** Whether to show users graph controls (scale etc) */
|
/** Whether to show users graph controls (scale etc) */
|
||||||
showControls?: boolean;
|
showControls: boolean;
|
||||||
|
/** Settings for displaying functions */
|
||||||
|
chartSettings: FunctionChartSettings;
|
||||||
|
/** Environment for further function executions */
|
||||||
|
environment: environment;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SquiggleItem: React.FC<SquiggleItemProps> = ({
|
const SquiggleItem: React.FC<SquiggleItemProps> = ({
|
||||||
|
@ -80,6 +86,8 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({
|
||||||
showSummary,
|
showSummary,
|
||||||
showTypes = false,
|
showTypes = false,
|
||||||
showControls = false,
|
showControls = false,
|
||||||
|
chartSettings,
|
||||||
|
environment,
|
||||||
}: SquiggleItemProps) => {
|
}: SquiggleItemProps) => {
|
||||||
switch (expression.tag) {
|
switch (expression.tag) {
|
||||||
case "number":
|
case "number":
|
||||||
|
@ -147,6 +155,8 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({
|
||||||
height={50}
|
height={50}
|
||||||
showTypes={showTypes}
|
showTypes={showTypes}
|
||||||
showControls={showControls}
|
showControls={showControls}
|
||||||
|
chartSettings={chartSettings}
|
||||||
|
environment={environment}
|
||||||
showSummary={showSummary}
|
showSummary={showSummary}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
@ -165,6 +175,8 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({
|
||||||
showTypes={showTypes}
|
showTypes={showTypes}
|
||||||
showSummary={showSummary}
|
showSummary={showSummary}
|
||||||
showControls={showControls}
|
showControls={showControls}
|
||||||
|
chartSettings={chartSettings}
|
||||||
|
environment={environment}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
))}
|
))}
|
||||||
|
@ -178,9 +190,11 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({
|
||||||
);
|
);
|
||||||
case "lambda":
|
case "lambda":
|
||||||
return (
|
return (
|
||||||
<ErrorBox heading="No Viewer">
|
<FunctionChart
|
||||||
There is no viewer currently available for function types.
|
fn={expression.value}
|
||||||
</ErrorBox>
|
chartSettings={chartSettings}
|
||||||
|
environment={environment}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -191,15 +205,9 @@ export interface SquiggleChartProps {
|
||||||
/** If the output requires monte carlo sampling, the amount of samples */
|
/** If the output requires monte carlo sampling, the amount of samples */
|
||||||
sampleCount?: number;
|
sampleCount?: number;
|
||||||
/** The amount of points returned to draw the distribution */
|
/** The amount of points returned to draw the distribution */
|
||||||
outputXYPoints?: number;
|
environment?: environment;
|
||||||
kernelWidth?: number;
|
/** If the result is a function, where the function starts, ends and the amount of stops */
|
||||||
pointDistLength?: number;
|
chartSettings?: FunctionChartSettings;
|
||||||
/** If the result is a function, where the function starts */
|
|
||||||
diagramStart?: number;
|
|
||||||
/** If the result is a function, where the function ends */
|
|
||||||
diagramStop?: number;
|
|
||||||
/** If the result is a function, how many points along the function it samples */
|
|
||||||
diagramCount?: number;
|
|
||||||
/** When the environment changes */
|
/** When the environment changes */
|
||||||
onChange?(expr: squiggleExpression): void;
|
onChange?(expr: squiggleExpression): void;
|
||||||
/** CSS width of the element */
|
/** CSS width of the element */
|
||||||
|
@ -223,10 +231,10 @@ const ChartWrapper = styled.div`
|
||||||
"Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
"Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
let defaultChartSettings = { start: 0, stop: 10, count: 100 };
|
||||||
export const SquiggleChart: React.FC<SquiggleChartProps> = ({
|
export const SquiggleChart: React.FC<SquiggleChartProps> = ({
|
||||||
squiggleString = "",
|
squiggleString = "",
|
||||||
sampleCount = 1000,
|
environment,
|
||||||
outputXYPoints = 1000,
|
|
||||||
onChange = () => {},
|
onChange = () => {},
|
||||||
height = 60,
|
height = 60,
|
||||||
bindings = defaultBindings,
|
bindings = defaultBindings,
|
||||||
|
@ -235,17 +243,10 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = ({
|
||||||
width,
|
width,
|
||||||
showTypes = false,
|
showTypes = false,
|
||||||
showControls = false,
|
showControls = false,
|
||||||
|
chartSettings = defaultChartSettings,
|
||||||
}: SquiggleChartProps) => {
|
}: SquiggleChartProps) => {
|
||||||
let samplingInputs: samplingParams = {
|
let expressionResult = run(squiggleString, bindings, environment, jsImports);
|
||||||
sampleCount: sampleCount,
|
let e = environment ? environment : defaultEnvironment;
|
||||||
xyPointLength: outputXYPoints,
|
|
||||||
};
|
|
||||||
let expressionResult = run(
|
|
||||||
squiggleString,
|
|
||||||
bindings,
|
|
||||||
samplingInputs,
|
|
||||||
jsImports
|
|
||||||
);
|
|
||||||
let internal: JSX.Element;
|
let internal: JSX.Element;
|
||||||
if (expressionResult.tag === "Ok") {
|
if (expressionResult.tag === "Ok") {
|
||||||
let expression = expressionResult.value;
|
let expression = expressionResult.value;
|
||||||
|
@ -258,6 +259,8 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = ({
|
||||||
showSummary={showSummary}
|
showSummary={showSummary}
|
||||||
showTypes={showTypes}
|
showTypes={showTypes}
|
||||||
showControls={showControls}
|
showControls={showControls}
|
||||||
|
chartSettings={chartSettings}
|
||||||
|
environment={e}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { CodeEditor } from "./CodeEditor";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import type {
|
import type {
|
||||||
squiggleExpression,
|
squiggleExpression,
|
||||||
samplingParams,
|
environment,
|
||||||
bindings,
|
bindings,
|
||||||
jsImports,
|
jsImports,
|
||||||
} from "@quri/squiggle-lang";
|
} from "@quri/squiggle-lang";
|
||||||
|
@ -21,11 +21,7 @@ export interface SquiggleEditorProps {
|
||||||
/** The input string for squiggle */
|
/** The input string for squiggle */
|
||||||
initialSquiggleString?: string;
|
initialSquiggleString?: string;
|
||||||
/** If the output requires monte carlo sampling, the amount of samples */
|
/** If the output requires monte carlo sampling, the amount of samples */
|
||||||
sampleCount?: number;
|
environment?: environment;
|
||||||
/** The amount of points returned to draw the distribution */
|
|
||||||
outputXYPoints?: number;
|
|
||||||
kernelWidth?: number;
|
|
||||||
pointDistLength?: number;
|
|
||||||
/** If the result is a function, where the function starts */
|
/** If the result is a function, where the function starts */
|
||||||
diagramStart?: number;
|
diagramStart?: number;
|
||||||
/** If the result is a function, where the function ends */
|
/** If the result is a function, where the function ends */
|
||||||
|
@ -57,13 +53,10 @@ const Input = styled.div`
|
||||||
export let SquiggleEditor: React.FC<SquiggleEditorProps> = ({
|
export let SquiggleEditor: React.FC<SquiggleEditorProps> = ({
|
||||||
initialSquiggleString = "",
|
initialSquiggleString = "",
|
||||||
width,
|
width,
|
||||||
sampleCount,
|
environment,
|
||||||
outputXYPoints,
|
diagramStart = 0,
|
||||||
kernelWidth,
|
diagramStop = 10,
|
||||||
pointDistLength,
|
diagramCount = 100,
|
||||||
diagramStart,
|
|
||||||
diagramStop,
|
|
||||||
diagramCount,
|
|
||||||
onChange,
|
onChange,
|
||||||
bindings = defaultBindings,
|
bindings = defaultBindings,
|
||||||
jsImports = defaultImports,
|
jsImports = defaultImports,
|
||||||
|
@ -72,6 +65,11 @@ export let SquiggleEditor: React.FC<SquiggleEditorProps> = ({
|
||||||
showSummary = false,
|
showSummary = false,
|
||||||
}: SquiggleEditorProps) => {
|
}: SquiggleEditorProps) => {
|
||||||
let [expression, setExpression] = React.useState(initialSquiggleString);
|
let [expression, setExpression] = React.useState(initialSquiggleString);
|
||||||
|
let chartSettings = {
|
||||||
|
start: diagramStart,
|
||||||
|
stop: diagramStop,
|
||||||
|
count: diagramCount,
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Input>
|
<Input>
|
||||||
|
@ -85,14 +83,9 @@ export let SquiggleEditor: React.FC<SquiggleEditorProps> = ({
|
||||||
</Input>
|
</Input>
|
||||||
<SquiggleChart
|
<SquiggleChart
|
||||||
width={width}
|
width={width}
|
||||||
|
environment={environment}
|
||||||
squiggleString={expression}
|
squiggleString={expression}
|
||||||
sampleCount={sampleCount}
|
chartSettings={chartSettings}
|
||||||
outputXYPoints={outputXYPoints}
|
|
||||||
kernelWidth={kernelWidth}
|
|
||||||
pointDistLength={pointDistLength}
|
|
||||||
diagramStart={diagramStart}
|
|
||||||
diagramStop={diagramStop}
|
|
||||||
diagramCount={diagramCount}
|
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
bindings={bindings}
|
bindings={bindings}
|
||||||
jsImports={jsImports}
|
jsImports={jsImports}
|
||||||
|
@ -140,11 +133,7 @@ export interface SquigglePartialProps {
|
||||||
/** The input string for squiggle */
|
/** The input string for squiggle */
|
||||||
initialSquiggleString?: string;
|
initialSquiggleString?: string;
|
||||||
/** If the output requires monte carlo sampling, the amount of samples */
|
/** If the output requires monte carlo sampling, the amount of samples */
|
||||||
sampleCount?: number;
|
environment?: environment;
|
||||||
/** The amount of points returned to draw the distribution */
|
|
||||||
outputXYPoints?: number;
|
|
||||||
kernelWidth?: number;
|
|
||||||
pointDistLength?: number;
|
|
||||||
/** If the result is a function, where the function starts */
|
/** If the result is a function, where the function starts */
|
||||||
diagramStart?: number;
|
diagramStart?: number;
|
||||||
/** If the result is a function, where the function ends */
|
/** If the result is a function, where the function ends */
|
||||||
|
@ -165,14 +154,9 @@ export let SquigglePartial: React.FC<SquigglePartialProps> = ({
|
||||||
initialSquiggleString = "",
|
initialSquiggleString = "",
|
||||||
onChange,
|
onChange,
|
||||||
bindings = defaultBindings,
|
bindings = defaultBindings,
|
||||||
sampleCount = 1000,
|
environment,
|
||||||
outputXYPoints = 1000,
|
|
||||||
jsImports = defaultImports,
|
jsImports = defaultImports,
|
||||||
}: SquigglePartialProps) => {
|
}: SquigglePartialProps) => {
|
||||||
let samplingInputs: samplingParams = {
|
|
||||||
sampleCount: sampleCount,
|
|
||||||
xyPointLength: outputXYPoints,
|
|
||||||
};
|
|
||||||
let [expression, setExpression] = React.useState(initialSquiggleString);
|
let [expression, setExpression] = React.useState(initialSquiggleString);
|
||||||
let [error, setError] = React.useState<string | null>(null);
|
let [error, setError] = React.useState<string | null>(null);
|
||||||
|
|
||||||
|
@ -180,7 +164,7 @@ export let SquigglePartial: React.FC<SquigglePartialProps> = ({
|
||||||
let squiggleResult = runPartial(
|
let squiggleResult = runPartial(
|
||||||
expression,
|
expression,
|
||||||
bindings,
|
bindings,
|
||||||
samplingInputs,
|
environment,
|
||||||
jsImports
|
jsImports
|
||||||
);
|
);
|
||||||
if (squiggleResult.tag == "Ok") {
|
if (squiggleResult.tag == "Ok") {
|
||||||
|
|
|
@ -4,6 +4,11 @@ import ReactDOM from "react-dom";
|
||||||
import { SquiggleChart } from "./SquiggleChart";
|
import { SquiggleChart } from "./SquiggleChart";
|
||||||
import CodeEditor from "./CodeEditor";
|
import CodeEditor from "./CodeEditor";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
import {
|
||||||
|
defaultBindings,
|
||||||
|
environment,
|
||||||
|
defaultImports,
|
||||||
|
} from "@quri/squiggle-lang";
|
||||||
|
|
||||||
interface FieldFloatProps {
|
interface FieldFloatProps {
|
||||||
label: string;
|
label: string;
|
||||||
|
@ -96,6 +101,15 @@ let SquigglePlayground: FC<PlaygroundProps> = ({
|
||||||
let [diagramStart, setDiagramStart] = useState(0);
|
let [diagramStart, setDiagramStart] = useState(0);
|
||||||
let [diagramStop, setDiagramStop] = useState(10);
|
let [diagramStop, setDiagramStop] = useState(10);
|
||||||
let [diagramCount, setDiagramCount] = useState(20);
|
let [diagramCount, setDiagramCount] = useState(20);
|
||||||
|
let chartSettings = {
|
||||||
|
start: diagramStart,
|
||||||
|
stop: diagramStop,
|
||||||
|
count: diagramCount,
|
||||||
|
};
|
||||||
|
let env: environment = {
|
||||||
|
sampleCount: sampleCount,
|
||||||
|
xyPointLength: outputXYPoints,
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<ShowBox height={height}>
|
<ShowBox height={height}>
|
||||||
<Row>
|
<Row>
|
||||||
|
@ -112,15 +126,13 @@ let SquigglePlayground: FC<PlaygroundProps> = ({
|
||||||
<Display maxHeight={height - 3}>
|
<Display maxHeight={height - 3}>
|
||||||
<SquiggleChart
|
<SquiggleChart
|
||||||
squiggleString={squiggleString}
|
squiggleString={squiggleString}
|
||||||
sampleCount={sampleCount}
|
environment={env}
|
||||||
outputXYPoints={outputXYPoints}
|
chartSettings={chartSettings}
|
||||||
diagramStart={diagramStart}
|
|
||||||
diagramStop={diagramStop}
|
|
||||||
diagramCount={diagramCount}
|
|
||||||
pointDistLength={pointDistLength}
|
|
||||||
height={150}
|
height={150}
|
||||||
showTypes={showTypes}
|
showTypes={showTypes}
|
||||||
showControls={showControls}
|
showControls={showControls}
|
||||||
|
bindings={defaultBindings}
|
||||||
|
jsImports={defaultImports}
|
||||||
showSummary={showSummary}
|
showSummary={showSummary}
|
||||||
/>
|
/>
|
||||||
</Display>
|
</Display>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import * as _ from "lodash";
|
import * as _ from "lodash";
|
||||||
import {
|
import {
|
||||||
samplingParams,
|
|
||||||
environment,
|
environment,
|
||||||
defaultEnvironment,
|
defaultEnvironment,
|
||||||
evaluatePartialUsingExternalBindings,
|
evaluatePartialUsingExternalBindings,
|
||||||
|
@ -8,6 +7,7 @@ import {
|
||||||
externalBindings,
|
externalBindings,
|
||||||
expressionValue,
|
expressionValue,
|
||||||
errorValue,
|
errorValue,
|
||||||
|
foreignFunctionInterface,
|
||||||
} from "../rescript/TypescriptInterface.gen";
|
} from "../rescript/TypescriptInterface.gen";
|
||||||
export {
|
export {
|
||||||
makeSampleSetDist,
|
makeSampleSetDist,
|
||||||
|
@ -15,25 +15,31 @@ export {
|
||||||
distributionErrorToString,
|
distributionErrorToString,
|
||||||
distributionError,
|
distributionError,
|
||||||
} from "../rescript/TypescriptInterface.gen";
|
} from "../rescript/TypescriptInterface.gen";
|
||||||
export type {
|
export type { errorValue, externalBindings as bindings, jsImports };
|
||||||
samplingParams,
|
|
||||||
errorValue,
|
|
||||||
externalBindings as bindings,
|
|
||||||
jsImports,
|
|
||||||
};
|
|
||||||
import {
|
import {
|
||||||
jsValueToBinding,
|
jsValueToBinding,
|
||||||
|
jsValueToExpressionValue,
|
||||||
jsValue,
|
jsValue,
|
||||||
rescriptExport,
|
rescriptExport,
|
||||||
squiggleExpression,
|
squiggleExpression,
|
||||||
convertRawToTypescript,
|
convertRawToTypescript,
|
||||||
|
lambdaValue,
|
||||||
} from "./rescript_interop";
|
} from "./rescript_interop";
|
||||||
import { result, resultMap, tag, tagged } from "./types";
|
import { result, resultMap, tag, tagged } from "./types";
|
||||||
import { Distribution, shape } from "./distribution";
|
import { Distribution, shape } from "./distribution";
|
||||||
|
|
||||||
export { Distribution, squiggleExpression, result, resultMap, shape };
|
export {
|
||||||
|
Distribution,
|
||||||
|
squiggleExpression,
|
||||||
|
result,
|
||||||
|
resultMap,
|
||||||
|
shape,
|
||||||
|
lambdaValue,
|
||||||
|
environment,
|
||||||
|
defaultEnvironment,
|
||||||
|
};
|
||||||
|
|
||||||
export let defaultSamplingInputs: samplingParams = {
|
export let defaultSamplingInputs: environment = {
|
||||||
sampleCount: 10000,
|
sampleCount: 10000,
|
||||||
xyPointLength: 10000,
|
xyPointLength: 10000,
|
||||||
};
|
};
|
||||||
|
@ -72,6 +78,20 @@ export function runPartial(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function runForeign(
|
||||||
|
fn: lambdaValue,
|
||||||
|
args: jsValue[],
|
||||||
|
environment?: environment
|
||||||
|
): result<squiggleExpression, errorValue> {
|
||||||
|
let e = environment ? environment : defaultEnvironment;
|
||||||
|
let res: result<expressionValue, errorValue> = foreignFunctionInterface(
|
||||||
|
fn,
|
||||||
|
args.map(jsValueToExpressionValue),
|
||||||
|
e
|
||||||
|
);
|
||||||
|
return resultMap(res, (x) => createTsExport(x, e));
|
||||||
|
}
|
||||||
|
|
||||||
function mergeImportsWithBindings(
|
function mergeImportsWithBindings(
|
||||||
bindings: externalBindings,
|
bindings: externalBindings,
|
||||||
imports: jsImports
|
imports: jsImports
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import * as _ from "lodash";
|
import * as _ from "lodash";
|
||||||
import {
|
import {
|
||||||
|
expressionValue,
|
||||||
mixedShape,
|
mixedShape,
|
||||||
sampleSetDist,
|
sampleSetDist,
|
||||||
genericDist,
|
genericDist,
|
||||||
|
@ -87,6 +88,8 @@ export type squiggleExpression =
|
||||||
| tagged<"number", number>
|
| tagged<"number", number>
|
||||||
| tagged<"record", { [key: string]: squiggleExpression }>;
|
| tagged<"record", { [key: string]: squiggleExpression }>;
|
||||||
|
|
||||||
|
export { lambdaValue };
|
||||||
|
|
||||||
export function convertRawToTypescript(
|
export function convertRawToTypescript(
|
||||||
result: rescriptExport,
|
result: rescriptExport,
|
||||||
environment: environment
|
environment: environment
|
||||||
|
@ -168,3 +171,21 @@ export function jsValueToBinding(value: jsValue): rescriptExport {
|
||||||
return { TAG: 7, _0: _.mapValues(value, jsValueToBinding) };
|
return { TAG: 7, _0: _.mapValues(value, jsValueToBinding) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function jsValueToExpressionValue(value: jsValue): expressionValue {
|
||||||
|
if (typeof value === "boolean") {
|
||||||
|
return { tag: "EvBool", value: value as boolean };
|
||||||
|
} else if (typeof value === "string") {
|
||||||
|
return { tag: "EvString", value: value as string };
|
||||||
|
} else if (typeof value === "number") {
|
||||||
|
return { tag: "EvNumber", value: value as number };
|
||||||
|
} else if (Array.isArray(value)) {
|
||||||
|
return { tag: "EvArray", value: value.map(jsValueToExpressionValue) };
|
||||||
|
} else {
|
||||||
|
// Record
|
||||||
|
return {
|
||||||
|
tag: "EvRecord",
|
||||||
|
value: _.mapValues(value, jsValueToExpressionValue),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -84,3 +84,6 @@ type environment = ReducerInterface_ExpressionValue.environment
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let defaultEnvironment = ReducerInterface_ExpressionValue.defaultEnvironment
|
let defaultEnvironment = ReducerInterface_ExpressionValue.defaultEnvironment
|
||||||
|
|
||||||
|
@genType
|
||||||
|
let foreignFunctionInterface = Reducer.foreignFunctionInterface
|
||||||
|
|
Loading…
Reference in New Issue
Block a user