Merge pull request #148 from QURIresearch/components-cleanup
Move Playground to components
This commit is contained in:
commit
952ce9da11
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -5,3 +5,4 @@ yarn-error.log
|
|||
.parcel-cache
|
||||
.DS_Store
|
||||
**/.sync.ffs_db
|
||||
.direnv
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
"packages/*"
|
||||
],
|
||||
"resolutions": {
|
||||
"@types/react": "17.0.39"
|
||||
"@types/react": "^17.0.43"
|
||||
},
|
||||
"packageManager": "yarn@1.22.17"
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ const custom = require('../webpack.config.js');
|
|||
module.exports = {
|
||||
webpackFinal: async (config) => {
|
||||
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": [
|
||||
"../src/**/*.stories.mdx",
|
||||
|
|
|
@ -1,25 +1,29 @@
|
|||
# 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/).
|
||||
|
||||
# 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`
|
||||
``` sh
|
||||
|
||||
```sh
|
||||
cd ../squiggle-lang
|
||||
yarn build
|
||||
```
|
||||
|
||||
If you've otherwise done this recently you can skip those.
|
||||
|
||||
Run a development server
|
||||
|
||||
``` sh
|
||||
```sh
|
||||
yarn start
|
||||
```
|
||||
|
||||
And build artefacts for production,
|
||||
|
||||
``` sh
|
||||
```sh
|
||||
yarn bundle # builds components library
|
||||
yarn build # builds storybook app
|
||||
```
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@quri/squiggle-components",
|
||||
"version": "0.1.6",
|
||||
"version": "0.1.8",
|
||||
"dependencies": {
|
||||
"@quri/squiggle-lang": "0.2.2",
|
||||
"@testing-library/jest-dom": "^5.16.3",
|
||||
|
@ -9,11 +9,12 @@
|
|||
"@types/jest": "^27.4.0",
|
||||
"@types/lodash": "^4.14.178",
|
||||
"@types/node": "^17.0.16",
|
||||
"@types/react": "^17.0.43",
|
||||
"@types/react-dom": "^17.0.14",
|
||||
"antd": "^4.19.3",
|
||||
"cross-env": "^7.0.3",
|
||||
"lodash": "^4.17.21",
|
||||
"react": "^17.0.2",
|
||||
"react-ace": "^9.5.0",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-scripts": "5.0.0",
|
||||
"react-vega": "^7.4.4",
|
||||
|
@ -27,7 +28,7 @@
|
|||
},
|
||||
"scripts": {
|
||||
"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",
|
||||
"all": "yarn bundle && yarn build"
|
||||
},
|
||||
|
@ -68,9 +69,10 @@
|
|||
"@storybook/node-logger": "^6.4.18",
|
||||
"@storybook/preset-create-react-app": "^4.0.0",
|
||||
"@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",
|
||||
"react-codejar": "^1.1.2",
|
||||
"style-loader": "^3.3.1",
|
||||
"ts-loader": "^9.2.8",
|
||||
"webpack": "^5.70.0",
|
||||
"webpack-cli": "^4.9.2",
|
||||
|
|
46
packages/components/src/CodeEditor.tsx
Normal file
46
packages/components/src/CodeEditor.tsx
Normal 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;
|
|
@ -13,16 +13,16 @@ import * as chartSpecification from "./spec-distributions.json";
|
|||
import * as percentilesSpec from "./spec-percentiles.json";
|
||||
|
||||
let SquiggleVegaChart = createClassFromSpec({
|
||||
spec: chartSpecification as Spec
|
||||
spec: chartSpecification as Spec,
|
||||
});
|
||||
|
||||
let SquigglePercentilesChart = createClassFromSpec({
|
||||
spec: percentilesSpec as Spec
|
||||
spec: percentilesSpec as Spec,
|
||||
});
|
||||
|
||||
export interface SquiggleChartProps {
|
||||
/** The input string for squiggle */
|
||||
squiggleString: string;
|
||||
squiggleString?: string;
|
||||
|
||||
/** If the output requires monte carlo sampling, the amount of samples */
|
||||
sampleCount?: number;
|
||||
|
@ -40,21 +40,35 @@ export interface SquiggleChartProps {
|
|||
environment?: exportEnv;
|
||||
/** When the environment changes */
|
||||
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 = {
|
||||
sampleCount: props.sampleCount,
|
||||
outputXYPoints: props.outputXYPoints,
|
||||
kernelWidth: props.kernelWidth,
|
||||
pointDistLength: props.pointDistLength,
|
||||
sampleCount: sampleCount,
|
||||
outputXYPoints: outputXYPoints,
|
||||
kernelWidth: kernelWidth,
|
||||
pointDistLength: pointDistLength,
|
||||
};
|
||||
|
||||
let result = run(props.squiggleString, samplingInputs, props.environment);
|
||||
let result = run(squiggleString, samplingInputs, environment);
|
||||
if (result.tag === "Ok") {
|
||||
let environment = result.value.environment;
|
||||
let exports = result.value.exports;
|
||||
if (props.onEnvChange) props.onEnvChange(environment);
|
||||
onEnvChange(environment);
|
||||
let chartResults = exports.map((chartResult: exportDistribution) => {
|
||||
if (chartResult["NAME"] === "Float") {
|
||||
return <MakeNumberShower precision={3} number={chartResult["VAL"]} />;
|
||||
|
@ -74,7 +88,13 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = (props) => {
|
|||
y: y,
|
||||
}));
|
||||
|
||||
return <SquiggleVegaChart data={{ con: values }} actions={false}/>;
|
||||
return (
|
||||
<SquiggleVegaChart
|
||||
width={width}
|
||||
data={{ con: values }}
|
||||
actions={false}
|
||||
/>
|
||||
);
|
||||
} else if (shape.tag === "Discrete") {
|
||||
let xyShape = shape.value.xyShape;
|
||||
let totalY = xyShape.ys.reduce((a, b) => a + b);
|
||||
|
@ -89,7 +109,7 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = (props) => {
|
|||
y: y,
|
||||
}));
|
||||
|
||||
return <SquiggleVegaChart data={{ dis: values }} actions={false}/>;
|
||||
return <SquiggleVegaChart data={{ dis: values }} actions={false} />;
|
||||
} else if (shape.tag === "Mixed") {
|
||||
let discreteShape = shape.value.discrete.xyShape;
|
||||
let totalDiscrete = discreteShape.ys.reduce((a, b) => a + b);
|
||||
|
@ -123,10 +143,10 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = (props) => {
|
|||
|
||||
let total = 0;
|
||||
let cdf = sortedPoints.map((point: labeledPoint) => {
|
||||
if (point.type == "discrete") {
|
||||
if (point.type === "discrete") {
|
||||
total += point.y;
|
||||
return total;
|
||||
} else if (point.type == "continuous") {
|
||||
} else if (point.type === "continuous") {
|
||||
total += (point.y / totalY) * totalContinuous;
|
||||
return total;
|
||||
}
|
||||
|
@ -147,10 +167,10 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = (props) => {
|
|||
})
|
||||
);
|
||||
let continuousValues = cdfLabeledPoint.filter(
|
||||
(x) => x.type == "continuous"
|
||||
(x) => x.type === "continuous"
|
||||
);
|
||||
let discreteValues = cdfLabeledPoint.filter(
|
||||
(x) => x.type == "discrete"
|
||||
(x) => x.type === "discrete"
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -162,14 +182,14 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = (props) => {
|
|||
}
|
||||
} else if (chartResult.NAME === "Function") {
|
||||
// We are looking at a function. In this case, we draw a Percentiles chart
|
||||
let start = props.diagramStart ? props.diagramStart : 0;
|
||||
let stop = props.diagramStop ? props.diagramStop : 10;
|
||||
let count = props.diagramCount ? props.diagramCount : 100;
|
||||
let start = diagramStart;
|
||||
let stop = diagramStop;
|
||||
let count = diagramCount;
|
||||
let step = (stop - start) / count;
|
||||
let data = _.range(start, stop, step).map((x) => {
|
||||
if (chartResult.NAME == "Function") {
|
||||
if (chartResult.NAME === "Function") {
|
||||
let result = chartResult.VAL(x);
|
||||
if (result.tag == "Ok") {
|
||||
if (result.tag === "Ok") {
|
||||
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.99,
|
||||
|
@ -196,14 +216,16 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = (props) => {
|
|||
return null;
|
||||
}
|
||||
});
|
||||
return <SquigglePercentilesChart
|
||||
data={{ facet: data.filter(x => x !== null) }}
|
||||
return (
|
||||
<SquigglePercentilesChart
|
||||
data={{ facet: data.filter((x) => x !== null) }}
|
||||
actions={false}
|
||||
/>;
|
||||
/>
|
||||
);
|
||||
}
|
||||
});
|
||||
return <>{chartResults}</>;
|
||||
} else if (result.tag == "Error") {
|
||||
} else if (result.tag === "Error") {
|
||||
// At this point, we came across an error. What was our error?
|
||||
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) {
|
||||
if (t.pointSetDist.tag == "Discrete") {
|
||||
if (t.pointSetDist.tag === "Discrete") {
|
||||
let total = 0;
|
||||
let maxX = _.max(t.pointSetDist.value.xyShape.xs);
|
||||
let bounds = percentiles.map((_) => maxX);
|
||||
|
@ -221,14 +243,14 @@ function getPercentiles(percentiles: number[], t: DistPlus) {
|
|||
(x, y) => {
|
||||
total += y;
|
||||
percentiles.forEach((v, i) => {
|
||||
if (total > v && bounds[i] == maxX) {
|
||||
if (total > v && bounds[i] === maxX) {
|
||||
bounds[i] = x;
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
return bounds;
|
||||
} else if (t.pointSetDist.tag == "Continuous") {
|
||||
} else if (t.pointSetDist.tag === "Continuous") {
|
||||
let total = 0;
|
||||
let maxX = _.max(t.pointSetDist.value.xyShape.xs);
|
||||
let totalY = _.sum(t.pointSetDist.value.xyShape.ys);
|
||||
|
@ -239,14 +261,14 @@ function getPercentiles(percentiles: number[], t: DistPlus) {
|
|||
(x, y) => {
|
||||
total += y / totalY;
|
||||
percentiles.forEach((v, i) => {
|
||||
if (total > v && bounds[i] == maxX) {
|
||||
if (total > v && bounds[i] === maxX) {
|
||||
bounds[i] = x;
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
return bounds;
|
||||
} else if (t.pointSetDist.tag == "Mixed") {
|
||||
} else if (t.pointSetDist.tag === "Mixed") {
|
||||
let discreteShape = t.pointSetDist.value.discrete.xyShape;
|
||||
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 bounds = percentiles.map((_) => maxX);
|
||||
sortedPoints.map((point: labeledPoint) => {
|
||||
if (point.type == "discrete") {
|
||||
if (point.type === "discrete") {
|
||||
total += point.y;
|
||||
} else if (point.type == "continuous") {
|
||||
} else if (point.type === "continuous") {
|
||||
total += (point.y / totalY) * totalContinuous;
|
||||
}
|
||||
percentiles.forEach((v, i) => {
|
||||
if (total > v && bounds[i] == maxX) {
|
||||
if (total > v && bounds[i] === maxX) {
|
||||
bounds[i] = total;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import { SquiggleChart } from "./SquiggleChart";
|
||||
import { ReactCodeJar } from "react-codejar";
|
||||
import { CodeEditor } from "./CodeEditor";
|
||||
import type { exportEnv } from "@quri/squiggle-lang";
|
||||
|
||||
export interface SquiggleEditorProps {
|
||||
|
@ -23,67 +23,50 @@ export interface SquiggleEditorProps {
|
|||
environment?: exportEnv;
|
||||
/** when the environment changes. Used again for notebook magic*/
|
||||
onEnvChange?(env: exportEnv): void;
|
||||
/** The width of the element */
|
||||
width: number;
|
||||
}
|
||||
|
||||
const highlight = (_: HTMLInputElement) => {};
|
||||
|
||||
interface SquiggleEditorState {
|
||||
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;
|
||||
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>
|
||||
<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}
|
||||
<CodeEditor
|
||||
width={width}
|
||||
value={expression}
|
||||
onChange={setExpression}
|
||||
oneLine={true}
|
||||
/>
|
||||
<SquiggleChart
|
||||
width={width}
|
||||
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}
|
||||
sampleCount={sampleCount}
|
||||
outputXYPoints={outputXYPoints}
|
||||
kernelWidth={kernelWidth}
|
||||
pointDistLength={pointDistLength}
|
||||
diagramStart={diagramStart}
|
||||
diagramStop={diagramStop}
|
||||
diagramCount={diagramCount}
|
||||
environment={environment}
|
||||
onEnvChange={onEnvChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export function renderSquiggleEditor(props: SquiggleEditorProps) {
|
||||
export function renderSquiggleEditorToDom(props: SquiggleEditorProps) {
|
||||
let parent = document.createElement("div");
|
||||
ReactDOM.render(
|
||||
<SquiggleEditor
|
||||
|
|
130
packages/components/src/SquigglePlayground.tsx
Normal file
130
packages/components/src/SquigglePlayground.tsx
Normal 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;
|
||||
}
|
|
@ -1,2 +1,6 @@
|
|||
export { SquiggleChart } from "./SquiggleChart";
|
||||
export { SquiggleEditor, renderSquiggleEditor } from "./SquiggleEditor";
|
||||
export { SquiggleEditor, renderSquiggleEditorToDom } from "./SquiggleEditor";
|
||||
import SquigglePlayground, {
|
||||
renderSquigglePlaygroundToDom,
|
||||
} from "./SquigglePlayground";
|
||||
export { SquigglePlayground, renderSquigglePlaygroundToDom };
|
||||
|
|
|
@ -16,21 +16,19 @@
|
|||
{
|
||||
"name": "xscale",
|
||||
"description": "The transform of the x scale",
|
||||
"value": 1.0,
|
||||
"value": false,
|
||||
"bind": {
|
||||
"input": "range",
|
||||
"min": 0.1,
|
||||
"max": 1
|
||||
"input": "checkbox",
|
||||
"name": "log x scale"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "yscale",
|
||||
"description": "The transform of the y scale",
|
||||
"value": 1.0,
|
||||
"value": false,
|
||||
"bind": {
|
||||
"input": "range",
|
||||
"min": 0.1,
|
||||
"max": 1
|
||||
"input": "checkbox",
|
||||
"name": "log y scale"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -39,7 +37,7 @@
|
|||
{
|
||||
"name": "xscale",
|
||||
"type": "pow",
|
||||
"exponent": { "signal": "xscale" },
|
||||
"exponent": { "signal": "xscale ? 0.1 : 1" },
|
||||
"range": "width",
|
||||
"zero": false,
|
||||
"nice": false,
|
||||
|
@ -53,7 +51,7 @@
|
|||
{
|
||||
"name": "yscale",
|
||||
"type": "pow",
|
||||
"exponent": { "signal": "yscale" },
|
||||
"exponent": { "signal": "yscale ? 0.1 : 1" },
|
||||
"range": "height",
|
||||
"nice": true,
|
||||
"zero": true,
|
||||
|
@ -66,10 +64,7 @@
|
|||
}
|
||||
],
|
||||
|
||||
"axes": [
|
||||
{ "orient": "bottom", "scale": "xscale", "tickCount": 20 },
|
||||
{ "orient": "left", "scale": "yscale" }
|
||||
],
|
||||
"axes": [{ "orient": "bottom", "scale": "xscale", "tickCount": 20 }],
|
||||
|
||||
"marks": [
|
||||
{
|
||||
|
|
|
@ -20,3 +20,16 @@ the distribution.
|
|||
{Template.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
You can also name variables like so:
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Variables"
|
||||
args={{
|
||||
initialSquiggleString: "x = 2\nnormal(x,2)",
|
||||
}}
|
||||
>
|
||||
{Template.bind({})}
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
|
|
@ -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>
|
|
@ -16,10 +16,10 @@
|
|||
"declaration": true,
|
||||
"sourceMap": true
|
||||
},
|
||||
"files": ["src/spec-distributions.json","src/spec-percentiles.json"],
|
||||
"files": ["src/spec-distributions.json", "src/spec-percentiles.json"],
|
||||
"target": "ES6",
|
||||
"include": ["src/**/*", "src/*"],
|
||||
"exclude": ["node_modules", "**/*.spec.ts"],
|
||||
"exclude": ["node_modules", "**/*.spec.ts", "webpack.config.js"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../squiggle-lang"
|
||||
|
|
|
@ -12,12 +12,16 @@ module.exports = {
|
|||
options: { projectReferences: true },
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
{
|
||||
test: /\.css$/i,
|
||||
use: ["style-loader", "css-loader"],
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: [".js", ".tsx", ".ts"],
|
||||
alias: {
|
||||
"@quri/squiggle-lang": path.resolve(__dirname, '../squiggle-lang/src/js')
|
||||
"@quri/squiggle-lang": path.resolve(__dirname, "../squiggle-lang/src/js"),
|
||||
},
|
||||
},
|
||||
output: {
|
||||
|
|
16
packages/playground/.gitignore
vendored
16
packages/playground/.gitignore
vendored
|
@ -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
|
|
@ -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
|
||||
```
|
|
@ -1,4 +0,0 @@
|
|||
[[redirects]]
|
||||
from = "/*"
|
||||
to = "/index.html"
|
||||
status = 200
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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,
|
||||
}}
|
||||
/>
|
|
@ -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
|
|
@ -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
|
@ -1,3 +0,0 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
|
@ -1,9 +0,0 @@
|
|||
module.exports = {
|
||||
content: [
|
||||
"./src/components/*.tsx"
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
|
@ -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
|
@ -29,7 +29,6 @@
|
|||
"devDependencies": {
|
||||
"@glennsl/rescript-jest": "^0.9.0",
|
||||
"@types/jest": "^27.4.0",
|
||||
"@types/webpack": "^5.28.0",
|
||||
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
|
||||
"docsify": "^4.12.2",
|
||||
"gentype": "^4.3.0",
|
||||
|
|
Loading…
Reference in New Issue
Block a user