Merge pull request #148 from QURIresearch/components-cleanup

Move Playground to components
This commit is contained in:
Ozzie Gooen 2022-04-05 22:00:28 -04:00 committed by GitHub
commit 952ce9da11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 532 additions and 34993 deletions

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ yarn-error.log
.parcel-cache .parcel-cache
.DS_Store .DS_Store
**/.sync.ffs_db **/.sync.ffs_db
.direnv

View File

@ -8,7 +8,7 @@
"packages/*" "packages/*"
], ],
"resolutions": { "resolutions": {
"@types/react": "17.0.39" "@types/react": "^17.0.43"
}, },
"packageManager": "yarn@1.22.17" "packageManager": "yarn@1.22.17"
} }

View File

@ -4,7 +4,7 @@ const custom = require('../webpack.config.js');
module.exports = { module.exports = {
webpackFinal: async (config) => { webpackFinal: async (config) => {
config.resolve.alias = custom.resolve.alias; config.resolve.alias = custom.resolve.alias;
return { ...config, module: { ...config.module, rules: config.module.rules.concat(custom.module.rules) } }; return { ...config, module: { ...config.module, rules: config.module.rules.concat(custom.module.rules.filter(x => x.loader === "ts-loader")) } };
}, },
"stories": [ "stories": [
"../src/**/*.stories.mdx", "../src/**/*.stories.mdx",

View File

@ -6,4 +6,4 @@ export const parameters = {
date: /Date$/, date: /Date$/,
}, },
}, },
} }

View File

@ -1,25 +1,29 @@
# Squiggle Components # Squiggle Components
This package contains all the components for squiggle. These can be used either as a library or hosted as a [storybook](https://storybook.js.org/). This package contains all the components for squiggle. These can be used either as a library or hosted as a [storybook](https://storybook.js.org/).
# Build for development # Build for development
We assume that you had run `yarn` at monorepo level, installing dependencies.
You need to _prepare_ by building and bundling `squiggle-lang` We assume that you had run `yarn` at monorepo level, installing dependencies.
``` sh
You need to _prepare_ by building and bundling `squiggle-lang`
```sh
cd ../squiggle-lang cd ../squiggle-lang
yarn build yarn build
``` ```
If you've otherwise done this recently you can skip those. If you've otherwise done this recently you can skip those.
Run a development server Run a development server
``` sh ```sh
yarn start yarn start
``` ```
And build artefacts for production, And build artefacts for production,
``` sh ```sh
yarn bundle # builds components library yarn bundle # builds components library
yarn build # builds storybook app yarn build # builds storybook app
``` ```

View File

@ -1,6 +1,6 @@
{ {
"name": "@quri/squiggle-components", "name": "@quri/squiggle-components",
"version": "0.1.6", "version": "0.1.8",
"dependencies": { "dependencies": {
"@quri/squiggle-lang": "0.2.2", "@quri/squiggle-lang": "0.2.2",
"@testing-library/jest-dom": "^5.16.3", "@testing-library/jest-dom": "^5.16.3",
@ -9,11 +9,12 @@
"@types/jest": "^27.4.0", "@types/jest": "^27.4.0",
"@types/lodash": "^4.14.178", "@types/lodash": "^4.14.178",
"@types/node": "^17.0.16", "@types/node": "^17.0.16",
"@types/react": "^17.0.43",
"@types/react-dom": "^17.0.14", "@types/react-dom": "^17.0.14",
"antd": "^4.19.3",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"react": "^17.0.2", "react": "^17.0.2",
"react-ace": "^9.5.0",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-scripts": "5.0.0", "react-scripts": "5.0.0",
"react-vega": "^7.4.4", "react-vega": "^7.4.4",
@ -27,7 +28,7 @@
}, },
"scripts": { "scripts": {
"start": "cross-env REACT_APP_FAST_REFRESH=false && start-storybook -p 6006 -s public", "start": "cross-env REACT_APP_FAST_REFRESH=false && start-storybook -p 6006 -s public",
"build": "build-storybook -s public", "build": "tsc -b && build-storybook -s public",
"bundle": "webpack", "bundle": "webpack",
"all": "yarn bundle && yarn build" "all": "yarn bundle && yarn build"
}, },
@ -68,9 +69,10 @@
"@storybook/node-logger": "^6.4.18", "@storybook/node-logger": "^6.4.18",
"@storybook/preset-create-react-app": "^4.0.0", "@storybook/preset-create-react-app": "^4.0.0",
"@storybook/react": "^6.4.18", "@storybook/react": "^6.4.18",
"@types/webpack": "^5.28.0", "@types/styled-components": "^5.1.24",
"css-loader": "^6.7.1",
"prettier": "^2.6.0", "prettier": "^2.6.0",
"react-codejar": "^1.1.2", "style-loader": "^3.3.1",
"ts-loader": "^9.2.8", "ts-loader": "^9.2.8",
"webpack": "^5.70.0", "webpack": "^5.70.0",
"webpack-cli": "^4.9.2", "webpack-cli": "^4.9.2",

View File

@ -0,0 +1,46 @@
import _ from "lodash";
import React, { FC } from "react";
import AceEditor from "react-ace";
import "ace-builds/src-noconflict/mode-golang";
import "ace-builds/src-noconflict/theme-github";
interface CodeEditorProps {
value: string;
onChange: (value: string) => void;
oneLine?: boolean;
width?: number;
}
export let CodeEditor: FC<CodeEditorProps> = ({
value,
onChange,
oneLine = false,
width = 500,
}: CodeEditorProps) => {
let lineCount = value.split("\n").length;
let id = _.uniqueId();
return (
<AceEditor
value={value}
mode="golang"
theme="github"
width={width + "px"}
minLines={oneLine ? lineCount : 15}
maxLines={oneLine ? lineCount : 15}
showGutter={false}
highlightActiveLine={false}
showPrintMargin={false}
onChange={onChange}
name={id}
editorProps={{
$blockScrolling: true,
}}
setOptions={{
enableBasicAutocompletion: false,
enableLiveAutocompletion: false,
}}
/>
);
};
export default CodeEditor;

View File

@ -13,16 +13,16 @@ import * as chartSpecification from "./spec-distributions.json";
import * as percentilesSpec from "./spec-percentiles.json"; import * as percentilesSpec from "./spec-percentiles.json";
let SquiggleVegaChart = createClassFromSpec({ let SquiggleVegaChart = createClassFromSpec({
spec: chartSpecification as Spec spec: chartSpecification as Spec,
}); });
let SquigglePercentilesChart = createClassFromSpec({ let SquigglePercentilesChart = createClassFromSpec({
spec: percentilesSpec as Spec spec: percentilesSpec as Spec,
}); });
export interface SquiggleChartProps { export interface SquiggleChartProps {
/** The input string for squiggle */ /** The input string for squiggle */
squiggleString: string; squiggleString?: 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; sampleCount?: number;
@ -40,21 +40,35 @@ export interface SquiggleChartProps {
environment?: exportEnv; environment?: exportEnv;
/** When the environment changes */ /** When the environment changes */
onEnvChange?(env: exportEnv): void; onEnvChange?(env: exportEnv): void;
/** CSS width of the element */
width?: number;
} }
export const SquiggleChart: React.FC<SquiggleChartProps> = (props) => { export const SquiggleChart: React.FC<SquiggleChartProps> = ({
squiggleString = "",
sampleCount = 1000,
outputXYPoints = 1000,
kernelWidth,
pointDistLength = 1000,
diagramStart = 0,
diagramStop = 10,
diagramCount = 20,
environment = [],
onEnvChange = () => {},
width = 500,
}: SquiggleChartProps) => {
let samplingInputs: SamplingInputs = { let samplingInputs: SamplingInputs = {
sampleCount: props.sampleCount, sampleCount: sampleCount,
outputXYPoints: props.outputXYPoints, outputXYPoints: outputXYPoints,
kernelWidth: props.kernelWidth, kernelWidth: kernelWidth,
pointDistLength: props.pointDistLength, pointDistLength: pointDistLength,
}; };
let result = run(props.squiggleString, samplingInputs, props.environment); let result = run(squiggleString, samplingInputs, environment);
if (result.tag === "Ok") { if (result.tag === "Ok") {
let environment = result.value.environment; let environment = result.value.environment;
let exports = result.value.exports; let exports = result.value.exports;
if (props.onEnvChange) props.onEnvChange(environment); onEnvChange(environment);
let chartResults = exports.map((chartResult: exportDistribution) => { let chartResults = exports.map((chartResult: exportDistribution) => {
if (chartResult["NAME"] === "Float") { if (chartResult["NAME"] === "Float") {
return <MakeNumberShower precision={3} number={chartResult["VAL"]} />; return <MakeNumberShower precision={3} number={chartResult["VAL"]} />;
@ -74,7 +88,13 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = (props) => {
y: y, y: y,
})); }));
return <SquiggleVegaChart data={{ con: values }} actions={false}/>; return (
<SquiggleVegaChart
width={width}
data={{ con: values }}
actions={false}
/>
);
} else if (shape.tag === "Discrete") { } else if (shape.tag === "Discrete") {
let xyShape = shape.value.xyShape; let xyShape = shape.value.xyShape;
let totalY = xyShape.ys.reduce((a, b) => a + b); let totalY = xyShape.ys.reduce((a, b) => a + b);
@ -89,7 +109,7 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = (props) => {
y: y, y: y,
})); }));
return <SquiggleVegaChart data={{ dis: values }} actions={false}/>; return <SquiggleVegaChart data={{ dis: values }} actions={false} />;
} else if (shape.tag === "Mixed") { } else if (shape.tag === "Mixed") {
let discreteShape = shape.value.discrete.xyShape; let discreteShape = shape.value.discrete.xyShape;
let totalDiscrete = discreteShape.ys.reduce((a, b) => a + b); let totalDiscrete = discreteShape.ys.reduce((a, b) => a + b);
@ -123,10 +143,10 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = (props) => {
let total = 0; let total = 0;
let cdf = sortedPoints.map((point: labeledPoint) => { let cdf = sortedPoints.map((point: labeledPoint) => {
if (point.type == "discrete") { if (point.type === "discrete") {
total += point.y; total += point.y;
return total; return total;
} else if (point.type == "continuous") { } else if (point.type === "continuous") {
total += (point.y / totalY) * totalContinuous; total += (point.y / totalY) * totalContinuous;
return total; return total;
} }
@ -147,10 +167,10 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = (props) => {
}) })
); );
let continuousValues = cdfLabeledPoint.filter( let continuousValues = cdfLabeledPoint.filter(
(x) => x.type == "continuous" (x) => x.type === "continuous"
); );
let discreteValues = cdfLabeledPoint.filter( let discreteValues = cdfLabeledPoint.filter(
(x) => x.type == "discrete" (x) => x.type === "discrete"
); );
return ( return (
@ -162,14 +182,14 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = (props) => {
} }
} else if (chartResult.NAME === "Function") { } else if (chartResult.NAME === "Function") {
// We are looking at a function. In this case, we draw a Percentiles chart // We are looking at a function. In this case, we draw a Percentiles chart
let start = props.diagramStart ? props.diagramStart : 0; let start = diagramStart;
let stop = props.diagramStop ? props.diagramStop : 10; let stop = diagramStop;
let count = props.diagramCount ? props.diagramCount : 100; let count = diagramCount;
let step = (stop - start) / count; let step = (stop - start) / count;
let data = _.range(start, stop, step).map((x) => { let data = _.range(start, stop, step).map((x) => {
if (chartResult.NAME == "Function") { if (chartResult.NAME === "Function") {
let result = chartResult.VAL(x); let result = chartResult.VAL(x);
if (result.tag == "Ok") { if (result.tag === "Ok") {
let percentileArray = [ let percentileArray = [
0.01, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.95, 0.01, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.95,
0.99, 0.99,
@ -196,14 +216,16 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = (props) => {
return null; return null;
} }
}); });
return <SquigglePercentilesChart return (
data={{ facet: data.filter(x => x !== null) }} <SquigglePercentilesChart
data={{ facet: data.filter((x) => x !== null) }}
actions={false} actions={false}
/>; />
);
} }
}); });
return <>{chartResults}</>; return <>{chartResults}</>;
} else if (result.tag == "Error") { } else if (result.tag === "Error") {
// At this point, we came across an error. What was our error? // At this point, we came across an error. What was our error?
return <p>{"Error parsing Squiggle: " + result.value}</p>; return <p>{"Error parsing Squiggle: " + result.value}</p>;
} }
@ -211,7 +233,7 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = (props) => {
}; };
function getPercentiles(percentiles: number[], t: DistPlus) { function getPercentiles(percentiles: number[], t: DistPlus) {
if (t.pointSetDist.tag == "Discrete") { if (t.pointSetDist.tag === "Discrete") {
let total = 0; let total = 0;
let maxX = _.max(t.pointSetDist.value.xyShape.xs); let maxX = _.max(t.pointSetDist.value.xyShape.xs);
let bounds = percentiles.map((_) => maxX); let bounds = percentiles.map((_) => maxX);
@ -221,14 +243,14 @@ function getPercentiles(percentiles: number[], t: DistPlus) {
(x, y) => { (x, y) => {
total += y; total += y;
percentiles.forEach((v, i) => { percentiles.forEach((v, i) => {
if (total > v && bounds[i] == maxX) { if (total > v && bounds[i] === maxX) {
bounds[i] = x; bounds[i] = x;
} }
}); });
} }
); );
return bounds; return bounds;
} else if (t.pointSetDist.tag == "Continuous") { } else if (t.pointSetDist.tag === "Continuous") {
let total = 0; let total = 0;
let maxX = _.max(t.pointSetDist.value.xyShape.xs); let maxX = _.max(t.pointSetDist.value.xyShape.xs);
let totalY = _.sum(t.pointSetDist.value.xyShape.ys); let totalY = _.sum(t.pointSetDist.value.xyShape.ys);
@ -239,14 +261,14 @@ function getPercentiles(percentiles: number[], t: DistPlus) {
(x, y) => { (x, y) => {
total += y / totalY; total += y / totalY;
percentiles.forEach((v, i) => { percentiles.forEach((v, i) => {
if (total > v && bounds[i] == maxX) { if (total > v && bounds[i] === maxX) {
bounds[i] = x; bounds[i] = x;
} }
}); });
} }
); );
return bounds; return bounds;
} else if (t.pointSetDist.tag == "Mixed") { } else if (t.pointSetDist.tag === "Mixed") {
let discreteShape = t.pointSetDist.value.discrete.xyShape; let discreteShape = t.pointSetDist.value.discrete.xyShape;
let totalDiscrete = discreteShape.ys.reduce((a, b) => a + b); let totalDiscrete = discreteShape.ys.reduce((a, b) => a + b);
@ -280,13 +302,13 @@ function getPercentiles(percentiles: number[], t: DistPlus) {
let maxX = _.max(sortedPoints.map((x) => x.x)); let maxX = _.max(sortedPoints.map((x) => x.x));
let bounds = percentiles.map((_) => maxX); let bounds = percentiles.map((_) => maxX);
sortedPoints.map((point: labeledPoint) => { sortedPoints.map((point: labeledPoint) => {
if (point.type == "discrete") { if (point.type === "discrete") {
total += point.y; total += point.y;
} else if (point.type == "continuous") { } else if (point.type === "continuous") {
total += (point.y / totalY) * totalContinuous; total += (point.y / totalY) * totalContinuous;
} }
percentiles.forEach((v, i) => { percentiles.forEach((v, i) => {
if (total > v && bounds[i] == maxX) { if (total > v && bounds[i] === maxX) {
bounds[i] = total; bounds[i] = total;
} }
}); });

View File

@ -1,7 +1,7 @@
import * as React from "react"; import * as React from "react";
import * as ReactDOM from "react-dom"; import * as ReactDOM from "react-dom";
import { SquiggleChart } from "./SquiggleChart"; import { SquiggleChart } from "./SquiggleChart";
import { ReactCodeJar } from "react-codejar"; import { CodeEditor } from "./CodeEditor";
import type { exportEnv } from "@quri/squiggle-lang"; import type { exportEnv } from "@quri/squiggle-lang";
export interface SquiggleEditorProps { export interface SquiggleEditorProps {
@ -23,67 +23,50 @@ export interface SquiggleEditorProps {
environment?: exportEnv; environment?: exportEnv;
/** when the environment changes. Used again for notebook magic*/ /** when the environment changes. Used again for notebook magic*/
onEnvChange?(env: exportEnv): void; onEnvChange?(env: exportEnv): void;
/** The width of the element */
width: number;
} }
const highlight = (_: HTMLInputElement) => {}; export let SquiggleEditor: React.FC<SquiggleEditorProps> = ({
initialSquiggleString = "",
width = 500,
sampleCount,
outputXYPoints,
kernelWidth,
pointDistLength,
diagramStart,
diagramStop,
diagramCount,
onEnvChange,
environment,
}: SquiggleEditorProps) => {
let [expression, setExpression] = React.useState(initialSquiggleString);
return (
<div>
<CodeEditor
width={width}
value={expression}
onChange={setExpression}
oneLine={true}
/>
<SquiggleChart
width={width}
squiggleString={expression}
sampleCount={sampleCount}
outputXYPoints={outputXYPoints}
kernelWidth={kernelWidth}
pointDistLength={pointDistLength}
diagramStart={diagramStart}
diagramStop={diagramStop}
diagramCount={diagramCount}
environment={environment}
onEnvChange={onEnvChange}
/>
</div>
);
};
interface SquiggleEditorState { export function renderSquiggleEditorToDom(props: SquiggleEditorProps) {
expression: string;
env: exportEnv;
}
export class SquiggleEditor extends React.Component<
SquiggleEditorProps,
SquiggleEditorState
> {
constructor(props: SquiggleEditorProps) {
super(props);
let code = props.initialSquiggleString ? props.initialSquiggleString : "";
this.state = { expression: code, env: props.environment };
}
render() {
let { expression, env } = this.state;
let props = this.props;
return (
<div>
<ReactCodeJar
code={expression}
onUpdate={(e) => {
this.setState({ expression: e });
}}
style={{
borderRadius: "6px",
width: "530px",
border: "1px solid grey",
fontFamily: "'Source Code Pro', monospace",
fontSize: "14px",
fontWeight: "400",
letterSpacing: "normal",
lineHeight: "20px",
padding: "10px",
tabSize: "4",
}}
highlight={highlight}
lineNumbers={false}
/>
<SquiggleChart
squiggleString={expression}
sampleCount={props.sampleCount}
outputXYPoints={props.outputXYPoints}
kernelWidth={props.kernelWidth}
pointDistLength={props.pointDistLength}
diagramStart={props.diagramStart}
diagramStop={props.diagramStop}
diagramCount={props.diagramCount}
environment={env}
onEnvChange={props.onEnvChange}
/>
</div>
);
}
}
export function renderSquiggleEditor(props: SquiggleEditorProps) {
let parent = document.createElement("div"); let parent = document.createElement("div");
ReactDOM.render( ReactDOM.render(
<SquiggleEditor <SquiggleEditor

View File

@ -0,0 +1,130 @@
import _ from "lodash";
import React, { FC, useState } from "react";
import ReactDOM from "react-dom";
import { SquiggleChart } from "./SquiggleChart";
import CodeEditor from "./CodeEditor";
import { Form, Input, Card, Row, Col } from "antd";
import "antd/dist/antd.css";
interface FieldFloatProps {
label: string;
className?: string;
value: number;
onChange: (value: number) => void;
}
function FieldFloat(Props: FieldFloatProps) {
let [contents, setContents] = useState(Props.value + "");
return (
<Form.Item label={Props.label}>
<Input
value={contents}
className={Props.className ? Props.className : ""}
onChange={(e) => {
setContents(e.target.value);
let result = parseFloat(contents);
if (_.isFinite(result)) {
Props.onChange(result);
}
}}
/>
</Form.Item>
);
}
interface Props {
initialSquiggleString: string;
}
let SquigglePlayground: FC<Props> = (props) => {
let [squiggleString, setSquiggleString] = useState(
props.initialSquiggleString
);
let [sampleCount, setSampleCount] = useState(1000);
let [outputXYPoints, setOutputXYPoints] = useState(1000);
let [pointDistLength, setPointDistLength] = useState(1000);
let [diagramStart, setDiagramStart] = useState(0);
let [diagramStop, setDiagramStop] = useState(10);
let [diagramCount, setDiagramCount] = useState(20);
var demoDist = (
<SquiggleChart
squiggleString={squiggleString}
sampleCount={sampleCount}
outputXYPoints={outputXYPoints}
diagramStart={diagramStart}
diagramStop={diagramStop}
diagramCount={diagramCount}
pointDistLength={pointDistLength}
/>
);
return (
<Row>
<Col span={12}>
<Card title="Distribution Form">
<Form>
<Row gutter={16}>
<Col span={24}>
<CodeEditor
value={squiggleString}
onChange={setSquiggleString}
oneLine={false}
/>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<FieldFloat
value={sampleCount}
label="Sample Count"
onChange={setSampleCount}
/>
</Col>
<Col span={12}>
<FieldFloat
value={outputXYPoints}
onChange={setOutputXYPoints}
label="Output XY-points"
/>
</Col>
<Col span={12}>
<FieldFloat
value={pointDistLength}
onChange={setPointDistLength}
label="Downsample To"
/>
</Col>
<Col span={12}>
<FieldFloat
value={diagramStart}
onChange={setDiagramStart}
label="Diagram Start"
/>
</Col>
<Col span={12}>
<FieldFloat
value={diagramStop}
onChange={setDiagramStop}
label="Diagram Stop"
/>
</Col>
<Col span={12}>
<FieldFloat
value={diagramCount}
onChange={setDiagramCount}
label="Diagram Count"
/>
</Col>
</Row>
</Form>
</Card>
</Col>
<Col span={12}>{demoDist}</Col>
</Row>
);
};
export default SquigglePlayground;
export function renderSquigglePlaygroundToDom(props: Props) {
let parent = document.createElement("div");
ReactDOM.render(<SquigglePlayground {...props} />, parent);
return parent;
}

View File

@ -1,2 +1,6 @@
export { SquiggleChart } from "./SquiggleChart"; export { SquiggleChart } from "./SquiggleChart";
export { SquiggleEditor, renderSquiggleEditor } from "./SquiggleEditor"; export { SquiggleEditor, renderSquiggleEditorToDom } from "./SquiggleEditor";
import SquigglePlayground, {
renderSquigglePlaygroundToDom,
} from "./SquigglePlayground";
export { SquigglePlayground, renderSquigglePlaygroundToDom };

View File

@ -16,21 +16,19 @@
{ {
"name": "xscale", "name": "xscale",
"description": "The transform of the x scale", "description": "The transform of the x scale",
"value": 1.0, "value": false,
"bind": { "bind": {
"input": "range", "input": "checkbox",
"min": 0.1, "name": "log x scale"
"max": 1
} }
}, },
{ {
"name": "yscale", "name": "yscale",
"description": "The transform of the y scale", "description": "The transform of the y scale",
"value": 1.0, "value": false,
"bind": { "bind": {
"input": "range", "input": "checkbox",
"min": 0.1, "name": "log y scale"
"max": 1
} }
} }
], ],
@ -39,7 +37,7 @@
{ {
"name": "xscale", "name": "xscale",
"type": "pow", "type": "pow",
"exponent": { "signal": "xscale" }, "exponent": { "signal": "xscale ? 0.1 : 1" },
"range": "width", "range": "width",
"zero": false, "zero": false,
"nice": false, "nice": false,
@ -53,7 +51,7 @@
{ {
"name": "yscale", "name": "yscale",
"type": "pow", "type": "pow",
"exponent": { "signal": "yscale" }, "exponent": { "signal": "yscale ? 0.1 : 1" },
"range": "height", "range": "height",
"nice": true, "nice": true,
"zero": true, "zero": true,
@ -66,10 +64,7 @@
} }
], ],
"axes": [ "axes": [{ "orient": "bottom", "scale": "xscale", "tickCount": 20 }],
{ "orient": "bottom", "scale": "xscale", "tickCount": 20 },
{ "orient": "left", "scale": "yscale" }
],
"marks": [ "marks": [
{ {

View File

@ -20,3 +20,16 @@ the distribution.
{Template.bind({})} {Template.bind({})}
</Story> </Story>
</Canvas> </Canvas>
You can also name variables like so:
<Canvas>
<Story
name="Variables"
args={{
initialSquiggleString: "x = 2\nnormal(x,2)",
}}
>
{Template.bind({})}
</Story>
</Canvas>

View File

@ -0,0 +1,22 @@
import SquigglePlayground from "../SquigglePlayground";
import { Canvas, Meta, Story, Props } from "@storybook/addon-docs";
<Meta title="Squiggle/SquigglePlayground" component={SquigglePlayground} />
export const Template = (props) => <SquigglePlayground {...props} />;
# Squiggle Playground
A Squiggle playground is an environment where you can play around with all settings,
including sampling settings, in squiggle.
<Canvas>
<Story
name="Normal"
args={{
initialSquiggleString: "normal(5,2)",
}}
>
{Template.bind({})}
</Story>
</Canvas>

View File

@ -16,10 +16,10 @@
"declaration": true, "declaration": true,
"sourceMap": true "sourceMap": true
}, },
"files": ["src/spec-distributions.json","src/spec-percentiles.json"], "files": ["src/spec-distributions.json", "src/spec-percentiles.json"],
"target": "ES6", "target": "ES6",
"include": ["src/**/*", "src/*"], "include": ["src/**/*", "src/*"],
"exclude": ["node_modules", "**/*.spec.ts"], "exclude": ["node_modules", "**/*.spec.ts", "webpack.config.js"],
"references": [ "references": [
{ {
"path": "../squiggle-lang" "path": "../squiggle-lang"

View File

@ -12,12 +12,16 @@ module.exports = {
options: { projectReferences: true }, options: { projectReferences: true },
exclude: /node_modules/, exclude: /node_modules/,
}, },
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
], ],
}, },
resolve: { resolve: {
extensions: [".js", ".tsx", ".ts"], extensions: [".js", ".tsx", ".ts"],
alias: { alias: {
"@quri/squiggle-lang": path.resolve(__dirname, '../squiggle-lang/src/js') "@quri/squiggle-lang": path.resolve(__dirname, "../squiggle-lang/src/js"),
}, },
}, },
output: { output: {

View File

@ -1,16 +0,0 @@
.DS_Store
.merlin
.bsb.lock
npm-debug.log
/node_modules/
.cache
.cache/*
dist
lib/*
*.cache
build
yarn-error.log
*.bs.js
# Local Netlify folder
.netlify
.idea

View File

@ -1,21 +0,0 @@
# TODO: REVIVE PLAYGROUND.
# Squiggle Playground
This repository contains the squiggle playground, a small web interface
for playing around with squiggle concepts.
It depends on `@quri/squiggle-components` and `@quri/squiggle-lang` so both of them will
need to be packaged for this to work. This can be done from the root directory
with
```
yarn build:lang
yarn build:components
```
Then, starting the playground can be done with:
```
yarn parcel
```

View File

@ -1,4 +0,0 @@
[[redirects]]
from = "/*"
to = "/index.html"
status = 200

View File

@ -1,54 +0,0 @@
{
"name": "@quri/squiggle-playground",
"version": "0.1.0",
"homepage": "https://foretold-app.github.io/estiband/",
"scripts": {
"parcel": "parcel ./src/index.html",
"parcel-build": "parcel build ./src/index.html --no-source-maps --no-autoinstall --no-scope-hoist",
"deploy": "gh-pages -d dist",
"ci": "yarn parcel-build"
},
"keywords": [],
"author": "",
"license": "MIT",
"dependencies": {
"@emotion/react": "^11.8.1",
"@quri/squiggle-lang": "^0.2.2",
"ace-builds": "^1.4.12",
"antd": "^4.18.5",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
"binary-search-tree": "0.2.6",
"css-loader": "^6.7.1",
"gh-pages": "3.2.3",
"jstat": "1.9.5",
"lenses-ppx": "6.1.10",
"less": "4.1.2",
"lodash": "4.17.21",
"mathjs": "10.4.1",
"moduleserve": "0.9.1",
"moment": "2.29.1",
"pdfast": "^0.2.0",
"rationale": "0.2.0",
"react": "17.0.2",
"react-ace": "^9.2.0",
"react-dom": "^17.0.2",
"react-use": "^17.3.2",
"react-vega": "^7.4.4",
"vega": "*",
"vega-embed": "6.20.8",
"vega-lite": "*"
},
"devDependencies": {
"@emotion/babel-plugin": "^11.7.2",
"@parcel/core": "^2.4.0",
"@types/react": "^17.0.43",
"autoprefixer": "^10.4.2",
"docsify": "^4.12.2",
"jest": "^27.5.1",
"parcel": "^2.4.0",
"postcss": "^8.4.7",
"postcss-cli": "^9.1.0",
"tailwindcss": "^3.0.23",
"typescript": "^4.6.3"
}
}

View File

@ -1,6 +0,0 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

View File

@ -1,9 +0,0 @@
import React from 'react'
import { render } from "react-dom"
import DistBuilder from "./components/DistBuilder"
var root = document.querySelector("#app")
if (!(root == null)) {
render(<DistBuilder />, root)
}

View File

@ -1,34 +0,0 @@
import React, {FC} from "react";
import AceEditor from "react-ace";
import "ace-builds/src-noconflict/mode-golang";
import "ace-builds/src-noconflict/theme-github";
import "ace-builds/src-noconflict/ext-language_tools";
import "ace-builds/src-noconflict/keybinding-vim";
interface CodeEditorProps {
value : string,
onChange : (value: string) => void
}
export let CodeEditor : FC<CodeEditorProps> = (props) =>
<AceEditor
value={props.value}
mode="golang"
height="400px"
width="100%"
theme="github"
showGutter={false}
highlightActiveLine={false}
showPrintMargin={false}
onChange={props.onChange}
name="UNIQUE_ID_OF_DIV"
editorProps={{
$blockScrolling: true,
}}
setOptions={{
enableBasicAutocompletion: false,
enableLiveAutocompletion: true,
enableSnippets: true,
}}
/>

View File

@ -1,171 +0,0 @@
import { FC, useState } from "react"
import { SquiggleChart } from "@quri/squiggle-components"
import { CodeEditor } from "./CodeEditor"
import { Form, Input, Card, Row, Col } from "antd"
import { css } from '@emotion/react'
interface FieldFloatProps {
label : string,
className? : string,
value : number,
onChange : (value: number) => void,
}
function FieldFloat(Props: FieldFloatProps) {
let [contents, setContents] = useState(Props.value + "");
return <Form.Item label={Props.label}>
<Input
value={contents}
className={Props.className ? Props.className : ""}
onChange={(e) => setContents(e.target.value)}
onBlur={(_) => {
let result = parseFloat(contents);
if(result != NaN) {
Props.onChange(result)
}
}}
/>
</Form.Item>
}
let rows = css`
>.antCol:firstChild {
paddingLeft: 0.25em;
paddingRight: 0.125em;
}
>.antCol:lastChild {
paddingLeft: 0.125em;
paddingRight: 0.25em;
}
>.antCol:not(:lastChild):not(:lastChild) {
paddingLeft: 0.125em;
paddingRight: 0.125em;
}
`
let parent = css`
.antImportNumber {
width: 100%;
}
.anticon {
verticalAlign: "zero";
}
`
var form = css`
backgroundColor: #eee;
padding: 1em;
`
var dist = css`
padding: 1em;
`
var spacer = css`
marginTop: 1em;
`
var groupA = css`
.antInputNumberInputs {
backgroundColor: #fff7db;
}
`
var groupB = css`
.antInputNumberInput {
backgroundColor: #eaf4ff;
}
`
var Styles = {
rows: rows,
parent: parent,
form: form,
dist: dist,
spacer: spacer,
groupA: groupA,
groupB: groupB
};
let DistBuilder : FC<{}> = (_: {}) => {
let [squiggleString, setSquiggleString] = useState("mm(normal(5,2), normal(10,2))")
let [sampleCount, setSampleCount] = useState(1000)
let [outputXYPoints, setOutputXYPoints] = useState(1000)
let [pointDistLength, setPointDistLength] = useState(undefined)
let [kernelWidth, setKernelWidth] = useState(undefined)
let [diagramStart, setDiagramStart] = useState(0)
let [diagramStop, setDiagramStop] = useState(10)
let [diagramCount, setDiagramCount] = useState(20)
var demoDist =
<SquiggleChart
squiggleString={squiggleString}
sampleCount={sampleCount}
outputXYPoints={outputXYPoints}
diagramStart={diagramStart}
diagramStop={diagramStop}
diagramCount={diagramCount}
pointDistLength={pointDistLength}
/>
return (
<div className="grid grid-cols-2 gap-4">
<div>
<Card
title="Distribution Form">
<Form>
<Row css={Styles.rows}>
<Col span={24}>
<CodeEditor value={squiggleString} onChange={setSquiggleString} /> </Col>
</Row>
<Row css={Styles.rows}>
<Col span={12}>
<FieldFloat
value={sampleCount}
label="Sample Count"
onChange={setSampleCount}
/> </Col>
<Col span={12}>
<FieldFloat
value={outputXYPoints}
onChange={setOutputXYPoints}
label="Output XY-points" />
</Col>
<Col span={12}>
<FieldFloat
value={pointDistLength}
onChange={setPointDistLength}
label="Downsample To"
/>
</Col>
<Col span={12}>
<FieldFloat
value={kernelWidth}
onChange={setKernelWidth}
label="Kernel Width"
/> </Col>
<Col span={12}>
<FieldFloat
value={diagramStart}
onChange={setDiagramStart}
label="Diagram Start"
/>
</Col>
<Col span={12}>
<FieldFloat
value={diagramStop}
onChange={setDiagramStop}
label="Diagram Stop"
/> </Col>
<Col span={12}>
<FieldFloat
value={diagramCount}
onChange={setDiagramCount}
label="Diagram Count"
/>
</Col>
</Row>
</Form>
</Card>
</div>
{demoDist}
</div>
)
}
export default DistBuilder

View File

@ -1,17 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Squiggle Language</title>
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,700,900" rel="stylesheet">
<link href="./styles/antd.css" rel="stylesheet">
<link href="./styles/index.css" rel="stylesheet">
<script type="module" src="./Index.tsx" defer></script>
</head>
<body>
<div id="app" style="height: 100%"></div>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@ -1,9 +0,0 @@
module.exports = {
content: [
"./src/components/*.tsx"
],
theme: {
extend: {},
},
plugins: [],
}

View File

@ -1,19 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"jsx": "react-jsx",
"jsxImportSource": "@emotion/react",
"noImplicitAny": false,
"removeComments": true,
"preserveConstEnums": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"outDir": "./dist",
"declarationDir": "./dist",
"declaration": true,
"sourceMap": true
},
"target": "ES6",
"include": ["src/**/*"],
"exclude": ["node_modules", "**/*.spec.ts"]
}

File diff suppressed because it is too large Load Diff

View File

@ -29,7 +29,6 @@
"devDependencies": { "devDependencies": {
"@glennsl/rescript-jest": "^0.9.0", "@glennsl/rescript-jest": "^0.9.0",
"@types/jest": "^27.4.0", "@types/jest": "^27.4.0",
"@types/webpack": "^5.28.0",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2", "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
"docsify": "^4.12.2", "docsify": "^4.12.2",
"gentype": "^4.3.0", "gentype": "^4.3.0",

1638
yarn.lock

File diff suppressed because it is too large Load Diff