Merged with develop
This commit is contained in:
commit
b2c4f4f959
|
@ -3,18 +3,21 @@
|
||||||
"version": "0.2.20",
|
"version": "0.2.20",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@hookform/resolvers": "^2.8.10",
|
||||||
"@quri/squiggle-lang": "^0.2.8",
|
"@quri/squiggle-lang": "^0.2.8",
|
||||||
"@react-hook/size": "^2.1.2",
|
"@react-hook/size": "^2.1.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"react": "^18.1.0",
|
"react": "^18.1.0",
|
||||||
"react-ace": "^10.1.0",
|
"react-ace": "^10.1.0",
|
||||||
"react-dom": "^18.1.0",
|
"react-dom": "^18.1.0",
|
||||||
|
"react-hook-form": "^7.31.2",
|
||||||
"react-use": "^17.4.0",
|
"react-use": "^17.4.0",
|
||||||
"react-vega": "^7.5.1",
|
"react-vega": "^7.5.1",
|
||||||
"styled-components": "^5.3.5",
|
"styled-components": "^5.3.5",
|
||||||
"vega": "^5.22.1",
|
"vega": "^5.22.1",
|
||||||
"vega-embed": "^6.20.6",
|
"vega-embed": "^6.20.6",
|
||||||
"vega-lite": "^5.2.0"
|
"vega-lite": "^5.2.0",
|
||||||
|
"yup": "^0.32.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/plugin-proposal-private-property-in-object": "^7.17.12",
|
"@babel/plugin-proposal-private-property-in-object": "^7.17.12",
|
||||||
|
|
|
@ -1,40 +1,9 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import _ from "lodash";
|
import { lambdaValue, environment, runForeign } from "@quri/squiggle-lang";
|
||||||
import type { Spec } from "vega";
|
import { FunctionChart1Dist } from "./FunctionChart1Dist";
|
||||||
import {
|
import { FunctionChart1Number } from "./FunctionChart1Number";
|
||||||
Distribution,
|
|
||||||
result,
|
|
||||||
lambdaValue,
|
|
||||||
environment,
|
|
||||||
runForeign,
|
|
||||||
squiggleExpression,
|
|
||||||
errorValue,
|
|
||||||
errorValueToString,
|
|
||||||
} from "@quri/squiggle-lang";
|
|
||||||
import { createClassFromSpec } from "react-vega";
|
|
||||||
import * as percentilesSpec from "../vega-specs/spec-percentiles.json";
|
|
||||||
import { DistributionChart } from "./DistributionChart";
|
|
||||||
import { NumberShower } from "./NumberShower";
|
|
||||||
import { ErrorBox } from "./ErrorBox";
|
import { ErrorBox } from "./ErrorBox";
|
||||||
|
|
||||||
let SquigglePercentilesChart = createClassFromSpec({
|
|
||||||
spec: percentilesSpec as Spec,
|
|
||||||
});
|
|
||||||
|
|
||||||
const _rangeByCount = (start: number, stop: number, count: number) => {
|
|
||||||
const step = (stop - start) / (count - 1);
|
|
||||||
const items = _.range(start, stop, step);
|
|
||||||
const result = items.concat([stop]);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
function unwrap<a, b>(x: result<a, b>): a {
|
|
||||||
if (x.tag === "Ok") {
|
|
||||||
return x.value;
|
|
||||||
} else {
|
|
||||||
throw Error("FAILURE TO UNWRAP");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export type FunctionChartSettings = {
|
export type FunctionChartSettings = {
|
||||||
start: number;
|
start: number;
|
||||||
stop: number;
|
stop: number;
|
||||||
|
@ -45,167 +14,61 @@ interface FunctionChartProps {
|
||||||
fn: lambdaValue;
|
fn: lambdaValue;
|
||||||
chartSettings: FunctionChartSettings;
|
chartSettings: FunctionChartSettings;
|
||||||
environment: environment;
|
environment: environment;
|
||||||
|
height: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
type percentiles = {
|
|
||||||
x: number;
|
|
||||||
p1: number;
|
|
||||||
p5: number;
|
|
||||||
p10: number;
|
|
||||||
p20: number;
|
|
||||||
p30: number;
|
|
||||||
p40: number;
|
|
||||||
p50: number;
|
|
||||||
p60: number;
|
|
||||||
p70: number;
|
|
||||||
p80: number;
|
|
||||||
p90: number;
|
|
||||||
p95: number;
|
|
||||||
p99: number;
|
|
||||||
}[];
|
|
||||||
|
|
||||||
type errors = _.Dictionary<
|
|
||||||
{
|
|
||||||
x: number;
|
|
||||||
value: string;
|
|
||||||
}[]
|
|
||||||
>;
|
|
||||||
|
|
||||||
type point = { x: number; value: result<Distribution, string> };
|
|
||||||
|
|
||||||
let getPercentiles = ({ chartSettings, fn, environment }) => {
|
|
||||||
let chartPointsToRender = _rangeByCount(
|
|
||||||
chartSettings.start,
|
|
||||||
chartSettings.stop,
|
|
||||||
chartSettings.count
|
|
||||||
);
|
|
||||||
|
|
||||||
let chartPointsData: point[] = chartPointsToRender.map((x) => {
|
|
||||||
let result = runForeign(fn, [x], environment);
|
|
||||||
if (result.tag === "Ok") {
|
|
||||||
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) },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let initialPartition: [
|
|
||||||
{ x: number; value: Distribution }[],
|
|
||||||
{ x: number; value: string }[]
|
|
||||||
] = [[], []];
|
|
||||||
|
|
||||||
let [functionImage, errors] = chartPointsData.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 groupedErrors: errors = _.groupBy(errors, (x) => x.value);
|
|
||||||
|
|
||||||
let percentiles: percentiles = functionImage.map(({ x, value }) => {
|
|
||||||
// We convert it to to a pointSet distribution first, so that in case its a sample set
|
|
||||||
// distribution, it doesn't internally convert it to a pointSet distribution for every
|
|
||||||
// single inv() call.
|
|
||||||
let toPointSet: Distribution = unwrap(value.toPointSet());
|
|
||||||
return {
|
|
||||||
x: x,
|
|
||||||
p1: unwrap(toPointSet.inv(0.01)),
|
|
||||||
p5: unwrap(toPointSet.inv(0.05)),
|
|
||||||
p10: unwrap(toPointSet.inv(0.1)),
|
|
||||||
p20: unwrap(toPointSet.inv(0.2)),
|
|
||||||
p30: unwrap(toPointSet.inv(0.3)),
|
|
||||||
p40: unwrap(toPointSet.inv(0.4)),
|
|
||||||
p50: unwrap(toPointSet.inv(0.5)),
|
|
||||||
p60: unwrap(toPointSet.inv(0.6)),
|
|
||||||
p70: unwrap(toPointSet.inv(0.7)),
|
|
||||||
p80: unwrap(toPointSet.inv(0.8)),
|
|
||||||
p90: unwrap(toPointSet.inv(0.9)),
|
|
||||||
p95: unwrap(toPointSet.inv(0.95)),
|
|
||||||
p99: unwrap(toPointSet.inv(0.99)),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return { percentiles, errors: groupedErrors };
|
|
||||||
};
|
|
||||||
|
|
||||||
export const FunctionChart: React.FC<FunctionChartProps> = ({
|
export const FunctionChart: React.FC<FunctionChartProps> = ({
|
||||||
fn,
|
fn,
|
||||||
chartSettings,
|
chartSettings,
|
||||||
environment,
|
environment,
|
||||||
|
height,
|
||||||
}: FunctionChartProps) => {
|
}: FunctionChartProps) => {
|
||||||
let [mouseOverlay, setMouseOverlay] = React.useState(0);
|
let result1 = runForeign(fn, [chartSettings.start], environment);
|
||||||
function handleHover(_name: string, value: unknown) {
|
let result2 = runForeign(fn, [chartSettings.stop], environment);
|
||||||
setMouseOverlay(value as number);
|
let getValidResult = () => {
|
||||||
|
if (result1.tag === "Ok") {
|
||||||
|
return result1;
|
||||||
|
} else if (result2.tag === "Ok") {
|
||||||
|
return result2;
|
||||||
|
} else {
|
||||||
|
return result1;
|
||||||
}
|
}
|
||||||
function handleOut() {
|
|
||||||
setMouseOverlay(NaN);
|
|
||||||
}
|
|
||||||
const signalListeners = { mousemove: handleHover, mouseout: handleOut };
|
|
||||||
let mouseItem: result<squiggleExpression, errorValue> = !!mouseOverlay
|
|
||||||
? runForeign(fn, [mouseOverlay], environment)
|
|
||||||
: {
|
|
||||||
tag: "Error",
|
|
||||||
value: {
|
|
||||||
tag: "REExpectedType",
|
|
||||||
value: "Hover x-coordinate returned NaN. Expected a number.",
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
let showChart =
|
let validResult = getValidResult();
|
||||||
mouseItem.tag === "Ok" && mouseItem.value.tag == "distribution" ? (
|
let resultType = validResult.tag === "Ok" ? validResult.value.tag : "Error";
|
||||||
<DistributionChart
|
|
||||||
distribution={mouseItem.value.value}
|
|
||||||
width={400}
|
|
||||||
height={140}
|
|
||||||
showSummary={false}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
);
|
|
||||||
|
|
||||||
let getPercentilesMemoized = React.useMemo(
|
|
||||||
() => getPercentiles({ chartSettings, fn, environment }),
|
|
||||||
[environment, fn]
|
|
||||||
);
|
|
||||||
|
|
||||||
|
let component = () => {
|
||||||
|
switch (resultType) {
|
||||||
|
case "distribution":
|
||||||
return (
|
return (
|
||||||
<>
|
<FunctionChart1Dist
|
||||||
<SquigglePercentilesChart
|
fn={fn}
|
||||||
data={{ facet: getPercentilesMemoized.percentiles }}
|
chartSettings={chartSettings}
|
||||||
actions={false}
|
environment={environment}
|
||||||
signalListeners={signalListeners}
|
height={height}
|
||||||
/>
|
/>
|
||||||
{showChart}
|
|
||||||
{_.entries(getPercentilesMemoized.errors).map(
|
|
||||||
([errorName, errorPoints]) => (
|
|
||||||
<ErrorBox key={errorName} heading={errorName}>
|
|
||||||
Values:{" "}
|
|
||||||
{errorPoints
|
|
||||||
.map((r, i) => <NumberShower key={i} number={r.x} />)
|
|
||||||
.reduce((a, b) => (
|
|
||||||
<>
|
|
||||||
{a}, {b}
|
|
||||||
</>
|
|
||||||
))}
|
|
||||||
</ErrorBox>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
|
case "number":
|
||||||
|
return (
|
||||||
|
<FunctionChart1Number
|
||||||
|
fn={fn}
|
||||||
|
chartSettings={chartSettings}
|
||||||
|
environment={environment}
|
||||||
|
height={height}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
case "Error":
|
||||||
|
return (
|
||||||
|
<ErrorBox heading="Error">The function failed to be run</ErrorBox>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return (
|
||||||
|
<ErrorBox heading="No Viewer">
|
||||||
|
There is no function visualization for this type of function
|
||||||
|
</ErrorBox>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return component();
|
||||||
};
|
};
|
||||||
|
|
214
packages/components/src/components/FunctionChart1Dist.tsx
Normal file
214
packages/components/src/components/FunctionChart1Dist.tsx
Normal file
|
@ -0,0 +1,214 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import _ from "lodash";
|
||||||
|
import type { Spec } from "vega";
|
||||||
|
import {
|
||||||
|
Distribution,
|
||||||
|
result,
|
||||||
|
lambdaValue,
|
||||||
|
environment,
|
||||||
|
runForeign,
|
||||||
|
squiggleExpression,
|
||||||
|
errorValue,
|
||||||
|
errorValueToString,
|
||||||
|
} from "@quri/squiggle-lang";
|
||||||
|
import { createClassFromSpec } from "react-vega";
|
||||||
|
import * as percentilesSpec from "../vega-specs/spec-percentiles.json";
|
||||||
|
import { DistributionChart } from "./DistributionChart";
|
||||||
|
import { NumberShower } from "./NumberShower";
|
||||||
|
import { ErrorBox } from "./ErrorBox";
|
||||||
|
|
||||||
|
let SquigglePercentilesChart = createClassFromSpec({
|
||||||
|
spec: percentilesSpec as Spec,
|
||||||
|
});
|
||||||
|
|
||||||
|
const _rangeByCount = (start: number, stop: number, count: number) => {
|
||||||
|
const step = (stop - start) / (count - 1);
|
||||||
|
const items = _.range(start, stop, step);
|
||||||
|
const result = items.concat([stop]);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
function unwrap<a, b>(x: result<a, b>): a {
|
||||||
|
if (x.tag === "Ok") {
|
||||||
|
return x.value;
|
||||||
|
} else {
|
||||||
|
throw Error("FAILURE TO UNWRAP");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export type FunctionChartSettings = {
|
||||||
|
start: number;
|
||||||
|
stop: number;
|
||||||
|
count: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface FunctionChart1DistProps {
|
||||||
|
fn: lambdaValue;
|
||||||
|
chartSettings: FunctionChartSettings;
|
||||||
|
environment: environment;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
type percentiles = {
|
||||||
|
x: number;
|
||||||
|
p1: number;
|
||||||
|
p5: number;
|
||||||
|
p10: number;
|
||||||
|
p20: number;
|
||||||
|
p30: number;
|
||||||
|
p40: number;
|
||||||
|
p50: number;
|
||||||
|
p60: number;
|
||||||
|
p70: number;
|
||||||
|
p80: number;
|
||||||
|
p90: number;
|
||||||
|
p95: number;
|
||||||
|
p99: number;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
type errors = _.Dictionary<
|
||||||
|
{
|
||||||
|
x: number;
|
||||||
|
value: string;
|
||||||
|
}[]
|
||||||
|
>;
|
||||||
|
|
||||||
|
type point = { x: number; value: result<Distribution, string> };
|
||||||
|
|
||||||
|
let getPercentiles = ({ chartSettings, fn, environment }) => {
|
||||||
|
let chartPointsToRender = _rangeByCount(
|
||||||
|
chartSettings.start,
|
||||||
|
chartSettings.stop,
|
||||||
|
chartSettings.count
|
||||||
|
);
|
||||||
|
|
||||||
|
let chartPointsData: point[] = chartPointsToRender.map((x) => {
|
||||||
|
let result = runForeign(fn, [x], environment);
|
||||||
|
if (result.tag === "Ok") {
|
||||||
|
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) },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let initialPartition: [
|
||||||
|
{ x: number; value: Distribution }[],
|
||||||
|
{ x: number; value: string }[]
|
||||||
|
] = [[], []];
|
||||||
|
|
||||||
|
let [functionImage, errors] = chartPointsData.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 groupedErrors: errors = _.groupBy(errors, (x) => x.value);
|
||||||
|
|
||||||
|
let percentiles: percentiles = functionImage.map(({ x, value }) => {
|
||||||
|
// We convert it to to a pointSet distribution first, so that in case its a sample set
|
||||||
|
// distribution, it doesn't internally convert it to a pointSet distribution for every
|
||||||
|
// single inv() call.
|
||||||
|
let toPointSet: Distribution = unwrap(value.toPointSet());
|
||||||
|
return {
|
||||||
|
x: x,
|
||||||
|
p1: unwrap(toPointSet.inv(0.01)),
|
||||||
|
p5: unwrap(toPointSet.inv(0.05)),
|
||||||
|
p10: unwrap(toPointSet.inv(0.1)),
|
||||||
|
p20: unwrap(toPointSet.inv(0.2)),
|
||||||
|
p30: unwrap(toPointSet.inv(0.3)),
|
||||||
|
p40: unwrap(toPointSet.inv(0.4)),
|
||||||
|
p50: unwrap(toPointSet.inv(0.5)),
|
||||||
|
p60: unwrap(toPointSet.inv(0.6)),
|
||||||
|
p70: unwrap(toPointSet.inv(0.7)),
|
||||||
|
p80: unwrap(toPointSet.inv(0.8)),
|
||||||
|
p90: unwrap(toPointSet.inv(0.9)),
|
||||||
|
p95: unwrap(toPointSet.inv(0.95)),
|
||||||
|
p99: unwrap(toPointSet.inv(0.99)),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return { percentiles, errors: groupedErrors };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FunctionChart1Dist: React.FC<FunctionChart1DistProps> = ({
|
||||||
|
fn,
|
||||||
|
chartSettings,
|
||||||
|
environment,
|
||||||
|
height,
|
||||||
|
}: FunctionChart1DistProps) => {
|
||||||
|
let [mouseOverlay, setMouseOverlay] = React.useState(0);
|
||||||
|
function handleHover(_name: string, value: unknown) {
|
||||||
|
setMouseOverlay(value as number);
|
||||||
|
}
|
||||||
|
function handleOut() {
|
||||||
|
setMouseOverlay(NaN);
|
||||||
|
}
|
||||||
|
const signalListeners = { mousemove: handleHover, mouseout: handleOut };
|
||||||
|
let mouseItem: result<squiggleExpression, errorValue> = !!mouseOverlay
|
||||||
|
? runForeign(fn, [mouseOverlay], environment)
|
||||||
|
: {
|
||||||
|
tag: "Error",
|
||||||
|
value: {
|
||||||
|
tag: "REExpectedType",
|
||||||
|
value: "Hover x-coordinate returned NaN. Expected a number.",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let showChart =
|
||||||
|
mouseItem.tag === "Ok" && mouseItem.value.tag == "distribution" ? (
|
||||||
|
<DistributionChart
|
||||||
|
distribution={mouseItem.value.value}
|
||||||
|
width={400}
|
||||||
|
height={50}
|
||||||
|
showSummary={false}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
);
|
||||||
|
|
||||||
|
let getPercentilesMemoized = React.useMemo(
|
||||||
|
() => getPercentiles({ chartSettings, fn, environment }),
|
||||||
|
[environment, fn]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<SquigglePercentilesChart
|
||||||
|
data={{ facet: getPercentilesMemoized.percentiles }}
|
||||||
|
height={height}
|
||||||
|
actions={false}
|
||||||
|
signalListeners={signalListeners}
|
||||||
|
/>
|
||||||
|
{showChart}
|
||||||
|
{_.entries(getPercentilesMemoized.errors).map(
|
||||||
|
([errorName, errorPoints]) => (
|
||||||
|
<ErrorBox key={errorName} heading={errorName}>
|
||||||
|
Values:{" "}
|
||||||
|
{errorPoints
|
||||||
|
.map((r, i) => <NumberShower key={i} number={r.x} />)
|
||||||
|
.reduce((a, b) => (
|
||||||
|
<>
|
||||||
|
{a}, {b}
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</ErrorBox>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
119
packages/components/src/components/FunctionChart1Number.tsx
Normal file
119
packages/components/src/components/FunctionChart1Number.tsx
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import _ from "lodash";
|
||||||
|
import type { Spec } from "vega";
|
||||||
|
import {
|
||||||
|
result,
|
||||||
|
lambdaValue,
|
||||||
|
environment,
|
||||||
|
runForeign,
|
||||||
|
errorValueToString,
|
||||||
|
} from "@quri/squiggle-lang";
|
||||||
|
import { createClassFromSpec } from "react-vega";
|
||||||
|
import * as lineChartSpec from "../vega-specs/spec-line-chart.json";
|
||||||
|
import { ErrorBox } from "./ErrorBox";
|
||||||
|
|
||||||
|
let SquiggleLineChart = createClassFromSpec({
|
||||||
|
spec: lineChartSpec as Spec,
|
||||||
|
});
|
||||||
|
|
||||||
|
const _rangeByCount = (start: number, stop: number, count: number) => {
|
||||||
|
const step = (stop - start) / (count - 1);
|
||||||
|
const items = _.range(start, stop, step);
|
||||||
|
const result = items.concat([stop]);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type FunctionChartSettings = {
|
||||||
|
start: number;
|
||||||
|
stop: number;
|
||||||
|
count: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface FunctionChart1NumberProps {
|
||||||
|
fn: lambdaValue;
|
||||||
|
chartSettings: FunctionChartSettings;
|
||||||
|
environment: environment;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
type point = { x: number; value: result<number, string> };
|
||||||
|
|
||||||
|
let getFunctionImage = ({ chartSettings, fn, environment }) => {
|
||||||
|
//We adjust the count, because the count is made for distributions, which are much more expensive to estimate
|
||||||
|
let adjustedCount = chartSettings.count * 20;
|
||||||
|
|
||||||
|
let chartPointsToRender = _rangeByCount(
|
||||||
|
chartSettings.start,
|
||||||
|
chartSettings.stop,
|
||||||
|
adjustedCount
|
||||||
|
);
|
||||||
|
|
||||||
|
let chartPointsData: point[] = chartPointsToRender.map((x) => {
|
||||||
|
let result = runForeign(fn, [x], environment);
|
||||||
|
if (result.tag === "Ok") {
|
||||||
|
if (result.value.tag == "number") {
|
||||||
|
return { x, value: { tag: "Ok", value: result.value.value } };
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
x,
|
||||||
|
value: {
|
||||||
|
tag: "Error",
|
||||||
|
value: "This component expected number outputs",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
x,
|
||||||
|
value: { tag: "Error", value: errorValueToString(result.value) },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let initialPartition: [
|
||||||
|
{ x: number; value: number }[],
|
||||||
|
{ x: number; value: string }[]
|
||||||
|
] = [[], []];
|
||||||
|
|
||||||
|
let [functionImage, errors] = chartPointsData.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);
|
||||||
|
|
||||||
|
return { errors, functionImage };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FunctionChart1Number: React.FC<FunctionChart1NumberProps> = ({
|
||||||
|
fn,
|
||||||
|
chartSettings,
|
||||||
|
environment,
|
||||||
|
height,
|
||||||
|
}: FunctionChart1NumberProps) => {
|
||||||
|
let getFunctionImageMemoized = React.useMemo(
|
||||||
|
() => getFunctionImage({ chartSettings, fn, environment }),
|
||||||
|
[environment, fn]
|
||||||
|
);
|
||||||
|
|
||||||
|
let data = getFunctionImageMemoized.functionImage.map(({ x, value }) => ({
|
||||||
|
x,
|
||||||
|
y: value,
|
||||||
|
}));
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<SquiggleLineChart
|
||||||
|
data={{ facet: data }}
|
||||||
|
height={height}
|
||||||
|
actions={false}
|
||||||
|
/>
|
||||||
|
{getFunctionImageMemoized.errors.map(({ x, value }) => (
|
||||||
|
<ErrorBox key={x} heading={value}>
|
||||||
|
Error at point ${x}
|
||||||
|
</ErrorBox>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
51
packages/components/src/components/JsonEditor.tsx
Normal file
51
packages/components/src/components/JsonEditor.tsx
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import _ from "lodash";
|
||||||
|
import React, { FC } from "react";
|
||||||
|
import AceEditor from "react-ace";
|
||||||
|
|
||||||
|
import "ace-builds/src-noconflict/mode-json";
|
||||||
|
import "ace-builds/src-noconflict/theme-github";
|
||||||
|
|
||||||
|
interface CodeEditorProps {
|
||||||
|
value: string;
|
||||||
|
onChange: (value: string) => void;
|
||||||
|
oneLine?: boolean;
|
||||||
|
width?: number;
|
||||||
|
height: number;
|
||||||
|
showGutter?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export let JsonEditor: FC<CodeEditorProps> = ({
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
oneLine = false,
|
||||||
|
showGutter = false,
|
||||||
|
height,
|
||||||
|
}: CodeEditorProps) => {
|
||||||
|
let lineCount = value.split("\n").length;
|
||||||
|
let id = _.uniqueId();
|
||||||
|
return (
|
||||||
|
<AceEditor
|
||||||
|
value={value}
|
||||||
|
mode="json"
|
||||||
|
theme="github"
|
||||||
|
width={"100%"}
|
||||||
|
height={String(height) + "px"}
|
||||||
|
minLines={oneLine ? lineCount : undefined}
|
||||||
|
maxLines={oneLine ? lineCount : undefined}
|
||||||
|
showGutter={showGutter}
|
||||||
|
highlightActiveLine={false}
|
||||||
|
showPrintMargin={false}
|
||||||
|
onChange={onChange}
|
||||||
|
name={id}
|
||||||
|
editorProps={{
|
||||||
|
$blockScrolling: true,
|
||||||
|
}}
|
||||||
|
setOptions={{
|
||||||
|
enableBasicAutocompletion: false,
|
||||||
|
enableLiveAutocompletion: false,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default JsonEditor;
|
|
@ -196,7 +196,7 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({
|
||||||
<SquiggleItem
|
<SquiggleItem
|
||||||
expression={r}
|
expression={r}
|
||||||
width={width !== undefined ? width - 20 : width}
|
width={width !== undefined ? width - 20 : width}
|
||||||
height={50}
|
height={height / 3}
|
||||||
showTypes={showTypes}
|
showTypes={showTypes}
|
||||||
showSummary={showSummary}
|
showSummary={showSummary}
|
||||||
showControls={showControls}
|
showControls={showControls}
|
||||||
|
@ -232,6 +232,7 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({
|
||||||
<FunctionChart
|
<FunctionChart
|
||||||
fn={expression.value}
|
fn={expression.value}
|
||||||
chartSettings={chartSettings}
|
chartSettings={chartSettings}
|
||||||
|
height={height}
|
||||||
environment={{
|
environment={{
|
||||||
sampleCount: environment.sampleCount / 10,
|
sampleCount: environment.sampleCount / 10,
|
||||||
xyPointLength: environment.xyPointLength / 10,
|
xyPointLength: environment.xyPointLength / 10,
|
||||||
|
@ -245,6 +246,7 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({
|
||||||
<FunctionChart
|
<FunctionChart
|
||||||
fn={expression.value.fn}
|
fn={expression.value.fn}
|
||||||
chartSettings={getChartSettings(expression.value)}
|
chartSettings={getChartSettings(expression.value)}
|
||||||
|
height={height}
|
||||||
environment={{
|
environment={{
|
||||||
sampleCount: environment.sampleCount / 10,
|
sampleCount: environment.sampleCount / 10,
|
||||||
xyPointLength: environment.xyPointLength / 10,
|
xyPointLength: environment.xyPointLength / 10,
|
||||||
|
@ -297,7 +299,7 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = ({
|
||||||
squiggleString = "",
|
squiggleString = "",
|
||||||
environment,
|
environment,
|
||||||
onChange = () => {},
|
onChange = () => {},
|
||||||
height = 60,
|
height = 200,
|
||||||
bindings = defaultBindings,
|
bindings = defaultBindings,
|
||||||
jsImports = defaultImports,
|
jsImports = defaultImports,
|
||||||
showSummary = false,
|
showSummary = false,
|
||||||
|
|
|
@ -3,12 +3,12 @@ import React, { FC, ReactElement, useState } from "react";
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
import { SquiggleChart } from "./SquiggleChart";
|
import { SquiggleChart } from "./SquiggleChart";
|
||||||
import CodeEditor from "./CodeEditor";
|
import CodeEditor from "./CodeEditor";
|
||||||
|
import JsonEditor from "./JsonEditor";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import {
|
import { useForm, useWatch } from "react-hook-form";
|
||||||
defaultBindings,
|
import * as yup from "yup";
|
||||||
environment,
|
import { yupResolver } from "@hookform/resolvers/yup";
|
||||||
defaultImports,
|
import { defaultBindings, environment } from "@quri/squiggle-lang";
|
||||||
} from "@quri/squiggle-lang";
|
|
||||||
|
|
||||||
interface FieldFloatProps {
|
interface FieldFloatProps {
|
||||||
label: string;
|
label: string;
|
||||||
|
@ -68,9 +68,14 @@ const Display = styled.div<TitleProps>`
|
||||||
max-height: ${(props) => props.maxHeight}px;
|
max-height: ${(props) => props.maxHeight}px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Row = styled.div`
|
interface RowProps {
|
||||||
|
readonly leftPercentage: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Row = styled.div<RowProps>`
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 50% 50%;
|
grid-template-columns: ${(p) => p.leftPercentage}% ${(p) =>
|
||||||
|
100 - p.leftPercentage}%;
|
||||||
`;
|
`;
|
||||||
const Col = styled.div``;
|
const Col = styled.div``;
|
||||||
|
|
||||||
|
@ -87,17 +92,64 @@ interface PlaygroundProps {
|
||||||
showSummary?: boolean;
|
showSummary?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const schema = yup
|
||||||
|
.object()
|
||||||
|
.shape({
|
||||||
|
sampleCount: yup
|
||||||
|
.number()
|
||||||
|
.required()
|
||||||
|
.positive()
|
||||||
|
.integer()
|
||||||
|
.default(1000)
|
||||||
|
.min(10)
|
||||||
|
.max(1000000),
|
||||||
|
xyPointLength: yup
|
||||||
|
.number()
|
||||||
|
.required()
|
||||||
|
.positive()
|
||||||
|
.integer()
|
||||||
|
.default(1000)
|
||||||
|
.min(10)
|
||||||
|
.max(10000),
|
||||||
|
chartHeight: yup.number().required().positive().integer().default(350),
|
||||||
|
leftSizePercent: yup
|
||||||
|
.number()
|
||||||
|
.required()
|
||||||
|
.positive()
|
||||||
|
.integer()
|
||||||
|
.min(10)
|
||||||
|
.max(100)
|
||||||
|
.default(50),
|
||||||
|
showTypes: yup.boolean(),
|
||||||
|
showControls: yup.boolean(),
|
||||||
|
showSummary: yup.boolean(),
|
||||||
|
showSettingsPage: yup.boolean().default(false),
|
||||||
|
})
|
||||||
|
.required();
|
||||||
|
|
||||||
|
type InputProps = {
|
||||||
|
label: string;
|
||||||
|
children: ReactElement;
|
||||||
|
};
|
||||||
|
|
||||||
|
const InputItem: React.FC<InputProps> = ({ label, children }) => (
|
||||||
|
<div>
|
||||||
|
<label>{label}</label>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
let SquigglePlayground: FC<PlaygroundProps> = ({
|
let SquigglePlayground: FC<PlaygroundProps> = ({
|
||||||
initialSquiggleString = "",
|
initialSquiggleString = "",
|
||||||
height = 300,
|
height = 500,
|
||||||
showTypes = false,
|
showTypes = false,
|
||||||
showControls = false,
|
showControls = false,
|
||||||
showSummary = false,
|
showSummary = false,
|
||||||
}: PlaygroundProps) => {
|
}: PlaygroundProps) => {
|
||||||
let [squiggleString, setSquiggleString] = useState(initialSquiggleString);
|
let [squiggleString, setSquiggleString] = useState(initialSquiggleString);
|
||||||
let [sampleCount, setSampleCount] = useState(1000);
|
let [importString, setImportString] = useState("{}");
|
||||||
let [outputXYPoints, setOutputXYPoints] = useState(1000);
|
let [imports, setImports] = useState({});
|
||||||
let [pointDistLength, setPointDistLength] = useState(1000);
|
let [importsAreValid, setImportsAreValid] = useState(true);
|
||||||
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);
|
||||||
|
@ -106,14 +158,87 @@ let SquigglePlayground: FC<PlaygroundProps> = ({
|
||||||
stop: diagramStop,
|
stop: diagramStop,
|
||||||
count: diagramCount,
|
count: diagramCount,
|
||||||
};
|
};
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
formState: { errors },
|
||||||
|
control,
|
||||||
|
} = useForm({
|
||||||
|
resolver: yupResolver(schema),
|
||||||
|
defaultValues: {
|
||||||
|
sampleCount: 1000,
|
||||||
|
xyPointLength: 1000,
|
||||||
|
chartHeight: 150,
|
||||||
|
showTypes: showTypes,
|
||||||
|
showControls: showControls,
|
||||||
|
showSummary: showSummary,
|
||||||
|
leftSizePercent: 50,
|
||||||
|
showSettingsPage: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const vars = useWatch({
|
||||||
|
control,
|
||||||
|
});
|
||||||
let env: environment = {
|
let env: environment = {
|
||||||
sampleCount: sampleCount,
|
sampleCount: Number(vars.sampleCount),
|
||||||
xyPointLength: outputXYPoints,
|
xyPointLength: Number(vars.xyPointLength),
|
||||||
|
};
|
||||||
|
let getChangeJson = (r: string) => {
|
||||||
|
setImportString(r);
|
||||||
|
try {
|
||||||
|
setImports(JSON.parse(r));
|
||||||
|
setImportsAreValid(true);
|
||||||
|
} catch (e) {
|
||||||
|
setImportsAreValid(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<ShowBox height={height}>
|
<ShowBox height={height}>
|
||||||
<Row>
|
<input type="checkbox" {...register("showSettingsPage")} />
|
||||||
|
<Row leftPercentage={vars.leftSizePercent || 50}>
|
||||||
<Col>
|
<Col>
|
||||||
|
{vars.showSettingsPage ? (
|
||||||
|
<>
|
||||||
|
<InputItem label="Sample Count">
|
||||||
|
<input type="number" {...register("sampleCount")} />
|
||||||
|
</InputItem>
|
||||||
|
<InputItem label="XYPointLength Count">
|
||||||
|
<input type="number" {...register("xyPointLength")} />
|
||||||
|
</InputItem>
|
||||||
|
<InputItem label="Chart Height (in Pixels)">
|
||||||
|
<input type="number" {...register("chartHeight")} />
|
||||||
|
</InputItem>
|
||||||
|
<InputItem label="Show Types">
|
||||||
|
<input type="checkbox" {...register("showTypes")} />
|
||||||
|
</InputItem>
|
||||||
|
<InputItem label="Show Controls">
|
||||||
|
<input type="checkbox" {...register("showControls")} />
|
||||||
|
</InputItem>
|
||||||
|
<InputItem label="Show Summary Statistics">
|
||||||
|
<input type="checkbox" {...register("showSummary")} />
|
||||||
|
</InputItem>
|
||||||
|
<InputItem label="Editor Width">
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
min="1"
|
||||||
|
max="100"
|
||||||
|
className="slider"
|
||||||
|
{...register("leftSizePercent")}
|
||||||
|
/>
|
||||||
|
</InputItem>
|
||||||
|
<InputItem label="Json Editor for imports">
|
||||||
|
<>
|
||||||
|
<JsonEditor
|
||||||
|
value={importString}
|
||||||
|
onChange={getChangeJson}
|
||||||
|
oneLine={false}
|
||||||
|
showGutter={true}
|
||||||
|
height={100}
|
||||||
|
/>
|
||||||
|
{importsAreValid ? "Valid" : "Invalid"}
|
||||||
|
</>
|
||||||
|
</InputItem>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
value={squiggleString}
|
value={squiggleString}
|
||||||
onChange={setSquiggleString}
|
onChange={setSquiggleString}
|
||||||
|
@ -121,6 +246,7 @@ let SquigglePlayground: FC<PlaygroundProps> = ({
|
||||||
showGutter={true}
|
showGutter={true}
|
||||||
height={height - 3}
|
height={height - 3}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</Col>
|
</Col>
|
||||||
<Col>
|
<Col>
|
||||||
<Display maxHeight={height - 3}>
|
<Display maxHeight={height - 3}>
|
||||||
|
@ -128,12 +254,12 @@ let SquigglePlayground: FC<PlaygroundProps> = ({
|
||||||
squiggleString={squiggleString}
|
squiggleString={squiggleString}
|
||||||
environment={env}
|
environment={env}
|
||||||
chartSettings={chartSettings}
|
chartSettings={chartSettings}
|
||||||
height={150}
|
height={vars.chartHeight}
|
||||||
showTypes={showTypes}
|
showTypes={vars.showTypes}
|
||||||
showControls={showControls}
|
showControls={vars.showControls}
|
||||||
bindings={defaultBindings}
|
bindings={defaultBindings}
|
||||||
jsImports={defaultImports}
|
jsImports={imports}
|
||||||
showSummary={showSummary}
|
showSummary={vars.showSummary}
|
||||||
/>
|
/>
|
||||||
</Display>
|
</Display>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
|
@ -153,11 +153,11 @@ to allow large and small numbers being printed cleanly.
|
||||||
</Story>
|
</Story>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
|
|
||||||
## Functions
|
## Functions (Distribution Output)
|
||||||
|
|
||||||
<Canvas>
|
<Canvas>
|
||||||
<Story
|
<Story
|
||||||
name="Function"
|
name="Function to Distribution"
|
||||||
args={{
|
args={{
|
||||||
squiggleString: "foo(t) = normal(t,2)*normal(5,3); foo",
|
squiggleString: "foo(t) = normal(t,2)*normal(5,3); foo",
|
||||||
width,
|
width,
|
||||||
|
@ -167,6 +167,20 @@ to allow large and small numbers being printed cleanly.
|
||||||
</Story>
|
</Story>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
|
|
||||||
|
## Functions (Number Output)
|
||||||
|
|
||||||
|
<Canvas>
|
||||||
|
<Story
|
||||||
|
name="Function to Number"
|
||||||
|
args={{
|
||||||
|
squiggleString: "foo(t) = t^2; foo",
|
||||||
|
width,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{Template.bind({})}
|
||||||
|
</Story>
|
||||||
|
</Canvas>
|
||||||
|
|
||||||
## Records
|
## Records
|
||||||
|
|
||||||
<Canvas>
|
<Canvas>
|
||||||
|
|
|
@ -16,7 +16,7 @@ including sampling settings, in squiggle.
|
||||||
name="Normal"
|
name="Normal"
|
||||||
args={{
|
args={{
|
||||||
initialSquiggleString: "normal(5,2)",
|
initialSquiggleString: "normal(5,2)",
|
||||||
height: 500,
|
height: 800,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Template.bind({})}
|
{Template.bind({})}
|
||||||
|
|
|
@ -82,6 +82,9 @@
|
||||||
"y2": {
|
"y2": {
|
||||||
"scale": "yscale",
|
"scale": "yscale",
|
||||||
"value": 0
|
"value": 0
|
||||||
|
},
|
||||||
|
"fill": {
|
||||||
|
"value": "#2f65a7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
88
packages/components/src/vega-specs/spec-line-chart.json
Normal file
88
packages/components/src/vega-specs/spec-line-chart.json
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://vega.github.io/schema/vega/v5.json",
|
||||||
|
"width": 500,
|
||||||
|
"height": 200,
|
||||||
|
"padding": 5,
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"name": "facet",
|
||||||
|
"values": [],
|
||||||
|
"format": {
|
||||||
|
"type": "json",
|
||||||
|
"parse": {
|
||||||
|
"timestamp": "date"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"scales": [
|
||||||
|
{
|
||||||
|
"name": "x",
|
||||||
|
"type": "linear",
|
||||||
|
"nice": true,
|
||||||
|
"domain": {
|
||||||
|
"data": "facet",
|
||||||
|
"field": "x"
|
||||||
|
},
|
||||||
|
"range": "width"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "y",
|
||||||
|
"type": "linear",
|
||||||
|
"range": "height",
|
||||||
|
"nice": true,
|
||||||
|
"zero": true,
|
||||||
|
"domain": {
|
||||||
|
"data": "facet",
|
||||||
|
"field": "y"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"signals": [
|
||||||
|
{
|
||||||
|
"name": "mousemove",
|
||||||
|
"on": [{ "events": "mousemove", "update": "invert('x', x())" }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mouseout",
|
||||||
|
"on": [{ "events": "mouseout", "update": "invert('x', x())" }]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"axes": [
|
||||||
|
{
|
||||||
|
"orient": "bottom",
|
||||||
|
"scale": "x",
|
||||||
|
"grid": false,
|
||||||
|
"labelColor": "#727d93",
|
||||||
|
"tickColor": "#fff",
|
||||||
|
"tickOpacity": 0.0,
|
||||||
|
"domainColor": "#727d93",
|
||||||
|
"domainOpacity": 0.1,
|
||||||
|
"tickCount": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"orient": "left",
|
||||||
|
"scale": "y",
|
||||||
|
"grid": false,
|
||||||
|
"labelColor": "#727d93",
|
||||||
|
"tickColor": "#fff",
|
||||||
|
"tickOpacity": 0.0,
|
||||||
|
"domainColor": "#727d93",
|
||||||
|
"domainOpacity": 0.1,
|
||||||
|
"tickCount": 5
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"marks": [
|
||||||
|
{
|
||||||
|
"type": "line",
|
||||||
|
"from": { "data": "facet" },
|
||||||
|
"encode": {
|
||||||
|
"enter": {
|
||||||
|
"x": { "scale": "x", "field": "x" },
|
||||||
|
"y": { "scale": "y", "field": "y" },
|
||||||
|
"strokeWidth": { "value": 2 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -20,7 +20,8 @@
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"src/vega-specs/spec-distributions.json",
|
"src/vega-specs/spec-distributions.json",
|
||||||
"src/vega-specs/spec-percentiles.json"
|
"src/vega-specs/spec-percentiles.json",
|
||||||
|
"src/vega-specs/spec-line-chart.json"
|
||||||
],
|
],
|
||||||
"target": "ES6",
|
"target": "ES6",
|
||||||
"include": ["src/**/*", "src/*"],
|
"include": ["src/**/*", "src/*"],
|
||||||
|
|
62
yarn.lock
62
yarn.lock
|
@ -1245,6 +1245,13 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime "^0.13.4"
|
regenerator-runtime "^0.13.4"
|
||||||
|
|
||||||
|
"@babel/runtime@^7.15.4":
|
||||||
|
version "7.18.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.3.tgz#c7b654b57f6f63cf7f8b418ac9ca04408c4579f4"
|
||||||
|
integrity sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug==
|
||||||
|
dependencies:
|
||||||
|
regenerator-runtime "^0.13.4"
|
||||||
|
|
||||||
"@babel/template@^7.12.7", "@babel/template@^7.16.7", "@babel/template@^7.3.3":
|
"@babel/template@^7.12.7", "@babel/template@^7.16.7", "@babel/template@^7.3.3":
|
||||||
version "7.16.7"
|
version "7.16.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155"
|
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155"
|
||||||
|
@ -1839,6 +1846,11 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@hapi/hoek" "^9.0.0"
|
"@hapi/hoek" "^9.0.0"
|
||||||
|
|
||||||
|
"@hookform/resolvers@^2.8.10":
|
||||||
|
version "2.8.10"
|
||||||
|
resolved "https://registry.yarnpkg.com/@hookform/resolvers/-/resolvers-2.8.10.tgz#b66d7a7848b1b1dd5b976a73fff36bb366666e7d"
|
||||||
|
integrity sha512-DDFtNlugsbwAhCJHYp3NcN5LvJrwSsCLPi41Wo5O8UAIbUFnBfY/jW+zKnlX57BZ4jE0j/g6R9rB3JlO89ad0g==
|
||||||
|
|
||||||
"@humanwhocodes/config-array@^0.9.2":
|
"@humanwhocodes/config-array@^0.9.2":
|
||||||
version "0.9.5"
|
version "0.9.5"
|
||||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7"
|
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7"
|
||||||
|
@ -4163,7 +4175,7 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/katex/-/katex-0.11.1.tgz#34de04477dcf79e2ef6c8d23b41a3d81f9ebeaf5"
|
resolved "https://registry.yarnpkg.com/@types/katex/-/katex-0.11.1.tgz#34de04477dcf79e2ef6c8d23b41a3d81f9ebeaf5"
|
||||||
integrity sha512-DUlIj2nk0YnJdlWgsFuVKcX27MLW0KbKmGVoUHmFr+74FYYNUDAaj9ZqTADvsbE8rfxuVmSFc7KczYn5Y09ozg==
|
integrity sha512-DUlIj2nk0YnJdlWgsFuVKcX27MLW0KbKmGVoUHmFr+74FYYNUDAaj9ZqTADvsbE8rfxuVmSFc7KczYn5Y09ozg==
|
||||||
|
|
||||||
"@types/lodash@^4.14.167", "@types/lodash@^4.14.182":
|
"@types/lodash@^4.14.167", "@types/lodash@^4.14.175", "@types/lodash@^4.14.182":
|
||||||
version "4.14.182"
|
version "4.14.182"
|
||||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.182.tgz#05301a4d5e62963227eaafe0ce04dd77c54ea5c2"
|
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.182.tgz#05301a4d5e62963227eaafe0ce04dd77c54ea5c2"
|
||||||
integrity sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==
|
integrity sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==
|
||||||
|
@ -4298,10 +4310,10 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/react" "*"
|
"@types/react" "*"
|
||||||
|
|
||||||
"@types/react@*", "@types/react@^18.0.1", "@types/react@^18.0.9":
|
"@types/react@*", "@types/react@17.0.43", "@types/react@^18.0.9":
|
||||||
version "18.0.9"
|
version "17.0.43"
|
||||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.9.tgz#d6712a38bd6cd83469603e7359511126f122e878"
|
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.43.tgz#4adc142887dd4a2601ce730bc56c3436fdb07a55"
|
||||||
integrity sha512-9bjbg1hJHUm4De19L1cHiW0Jvx3geel6Qczhjd0qY5VKVE2X5+x77YxAepuCwVh4vrgZJdgEJw48zrhRIeF4Nw==
|
integrity sha512-8Q+LNpdxf057brvPu1lMtC5Vn7J119xrP1aq4qiaefNioQUYANF/CYeK4NsKorSZyUGJ66g0IM+4bbjwx45o2A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/prop-types" "*"
|
"@types/prop-types" "*"
|
||||||
"@types/scheduler" "*"
|
"@types/scheduler" "*"
|
||||||
|
@ -11601,6 +11613,11 @@ locate-path@^6.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
p-locate "^5.0.0"
|
p-locate "^5.0.0"
|
||||||
|
|
||||||
|
lodash-es@^4.17.21:
|
||||||
|
version "4.17.21"
|
||||||
|
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
|
||||||
|
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
|
||||||
|
|
||||||
lodash.assignin@^4.0.9:
|
lodash.assignin@^4.0.9:
|
||||||
version "4.2.0"
|
version "4.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2"
|
resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2"
|
||||||
|
@ -12290,6 +12307,11 @@ nano-css@^5.3.1:
|
||||||
stacktrace-js "^2.0.2"
|
stacktrace-js "^2.0.2"
|
||||||
stylis "^4.0.6"
|
stylis "^4.0.6"
|
||||||
|
|
||||||
|
nanoclone@^0.2.1:
|
||||||
|
version "0.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/nanoclone/-/nanoclone-0.2.1.tgz#dd4090f8f1a110d26bb32c49ed2f5b9235209ed4"
|
||||||
|
integrity sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==
|
||||||
|
|
||||||
nanoid@^3.3.1, nanoid@^3.3.3:
|
nanoid@^3.3.1, nanoid@^3.3.3:
|
||||||
version "3.3.4"
|
version "3.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
|
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
|
||||||
|
@ -13998,6 +14020,11 @@ prop-types@^15.0.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
|
||||||
object-assign "^4.1.1"
|
object-assign "^4.1.1"
|
||||||
react-is "^16.13.1"
|
react-is "^16.13.1"
|
||||||
|
|
||||||
|
property-expr@^2.0.4:
|
||||||
|
version "2.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.5.tgz#278bdb15308ae16af3e3b9640024524f4dc02cb4"
|
||||||
|
integrity sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA==
|
||||||
|
|
||||||
property-information@^5.0.0, property-information@^5.3.0:
|
property-information@^5.0.0, property-information@^5.3.0:
|
||||||
version "5.6.0"
|
version "5.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69"
|
resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69"
|
||||||
|
@ -14328,6 +14355,11 @@ react-helmet-async@*, react-helmet-async@^1.3.0:
|
||||||
react-fast-compare "^3.2.0"
|
react-fast-compare "^3.2.0"
|
||||||
shallowequal "^1.1.0"
|
shallowequal "^1.1.0"
|
||||||
|
|
||||||
|
react-hook-form@^7.31.2:
|
||||||
|
version "7.31.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.31.2.tgz#efb7ac469810954488b7cf40be4e5017122c6e5e"
|
||||||
|
integrity sha512-oPudn3YuyzWg//IsT9z2cMEjWocAgHWX/bmueDT8cmsYQnGY5h7/njjvMDfLVv3mbdhYBjslTRnII2MIT7eNCA==
|
||||||
|
|
||||||
react-inspector@^5.1.0:
|
react-inspector@^5.1.0:
|
||||||
version "5.1.1"
|
version "5.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-inspector/-/react-inspector-5.1.1.tgz#58476c78fde05d5055646ed8ec02030af42953c8"
|
resolved "https://registry.yarnpkg.com/react-inspector/-/react-inspector-5.1.1.tgz#58476c78fde05d5055646ed8ec02030af42953c8"
|
||||||
|
@ -14525,7 +14557,7 @@ react-vega@^7.5.1:
|
||||||
prop-types "^15.8.1"
|
prop-types "^15.8.1"
|
||||||
vega-embed "^6.5.1"
|
vega-embed "^6.5.1"
|
||||||
|
|
||||||
react@^18.0.0, react@^18.1.0:
|
react@^18.1.0:
|
||||||
version "18.1.0"
|
version "18.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/react/-/react-18.1.0.tgz#6f8620382decb17fdc5cc223a115e2adbf104890"
|
resolved "https://registry.yarnpkg.com/react/-/react-18.1.0.tgz#6f8620382decb17fdc5cc223a115e2adbf104890"
|
||||||
integrity sha512-4oL8ivCz5ZEPyclFQXaNksK3adutVS8l2xzZU0cqEFrE9Sb7fC0EFK5uEk74wIreL1DERyjvsU915j1pcT2uEQ==
|
integrity sha512-4oL8ivCz5ZEPyclFQXaNksK3adutVS8l2xzZU0cqEFrE9Sb7fC0EFK5uEk74wIreL1DERyjvsU915j1pcT2uEQ==
|
||||||
|
@ -16559,6 +16591,11 @@ topojson-client@^3.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
commander "2"
|
commander "2"
|
||||||
|
|
||||||
|
toposort@^2.0.2:
|
||||||
|
version "2.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330"
|
||||||
|
integrity sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=
|
||||||
|
|
||||||
totalist@^1.0.0:
|
totalist@^1.0.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df"
|
resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df"
|
||||||
|
@ -18440,6 +18477,19 @@ yocto-queue@^0.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
|
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
|
||||||
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
|
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
|
||||||
|
|
||||||
|
yup@^0.32.11:
|
||||||
|
version "0.32.11"
|
||||||
|
resolved "https://registry.yarnpkg.com/yup/-/yup-0.32.11.tgz#d67fb83eefa4698607982e63f7ca4c5ed3cf18c5"
|
||||||
|
integrity sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.15.4"
|
||||||
|
"@types/lodash" "^4.14.175"
|
||||||
|
lodash "^4.17.21"
|
||||||
|
lodash-es "^4.17.21"
|
||||||
|
nanoclone "^0.2.1"
|
||||||
|
property-expr "^2.0.4"
|
||||||
|
toposort "^2.0.2"
|
||||||
|
|
||||||
zwitch@^1.0.0:
|
zwitch@^1.0.0:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920"
|
resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user