Add prettier and format

This commit is contained in:
Sam Nolan 2022-03-23 11:38:01 +11:00
parent f122b5fd7f
commit 15c9fbd13b
13 changed files with 395 additions and 57387 deletions

View File

@ -0,0 +1,5 @@
dist
build
node_modules
storybook-static
.storybook

View File

@ -0,0 +1 @@
{}

File diff suppressed because it is too large Load Diff

View File

@ -69,6 +69,7 @@
"@storybook/preset-create-react-app": "^4.0.0",
"@storybook/react": "^6.4.18",
"@types/webpack": "^5.28.0",
"prettier": "^2.6.0",
"react-codejar": "^1.1.2",
"ts-loader": "^9.2.8",
"webpack": "^5.70.0",

View File

@ -5,10 +5,7 @@
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Squiggle components"
/>
<meta name="description" content="Squiggle components" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<title>Squiggle Components</title>
</head>

View File

@ -1,92 +1,96 @@
import * as React from 'react';
import _ from 'lodash';
import type { Spec } from 'vega';
import { run } from '@quri/squiggle-lang';
import type { DistPlus, SamplingInputs, exportEnv, exportDistribution } from '@quri/squiggle-lang';
import { createClassFromSpec } from 'react-vega';
import * as chartSpecification from './spec-distributions.json'
import * as percentilesSpec from './spec-pertentiles.json'
import * as React from "react";
import _ from "lodash";
import type { Spec } from "vega";
import { run } from "@quri/squiggle-lang";
import type {
DistPlus,
SamplingInputs,
exportEnv,
exportDistribution,
} from "@quri/squiggle-lang";
import { createClassFromSpec } from "react-vega";
import * as chartSpecification from "./spec-distributions.json";
import * as percentilesSpec from "./spec-pertentiles.json";
let SquiggleVegaChart = createClassFromSpec({'spec': chartSpecification as Spec});
let SquiggleVegaChart = createClassFromSpec({
spec: chartSpecification as Spec,
});
let SquigglePercentilesChart = createClassFromSpec({'spec': percentilesSpec as Spec});
let SquigglePercentilesChart = createClassFromSpec({
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,
sampleCount?: number;
/** The amount of points returned to draw the distribution */
outputXYPoints? : number,
kernelWidth? : number,
pointDistLength? : number,
outputXYPoints?: number;
kernelWidth?: number;
pointDistLength?: number;
/** If the result is a function, where the function starts */
diagramStart? : number,
diagramStart?: number;
/** If the result is a function, where the function ends */
diagramStop? : number,
diagramStop?: number;
/** If the result is a function, how many points along the function it samples */
diagramCount? : number,
diagramCount?: number;
/** variables declared before this expression */
environment? : exportEnv,
environment?: exportEnv;
/** When the environment changes */
onEnvChange?(env: exportEnv): void
onEnvChange?(env: exportEnv): void;
}
export const SquiggleChart : React.FC<SquiggleChartProps> = props => {
let samplingInputs : SamplingInputs = {
sampleCount : props.sampleCount,
outputXYPoints : props.outputXYPoints,
kernelWidth : props.kernelWidth,
pointDistLength : props.pointDistLength
}
export const SquiggleChart: React.FC<SquiggleChartProps> = (props) => {
let samplingInputs: SamplingInputs = {
sampleCount: props.sampleCount,
outputXYPoints: props.outputXYPoints,
kernelWidth: props.kernelWidth,
pointDistLength: props.pointDistLength,
};
let result = run(props.squiggleString, samplingInputs, props.environment);
if (result.tag === "Ok") {
let environment = result.value.environment
let exports = result.value.exports
if(props.onEnvChange)
props.onEnvChange(environment)
let chartResults = exports.map((chartResult:exportDistribution )=> {
if(chartResult["NAME"] === "Float"){
let environment = result.value.environment;
let exports = result.value.exports;
if (props.onEnvChange) props.onEnvChange(environment);
let chartResults = exports.map((chartResult: exportDistribution) => {
if (chartResult["NAME"] === "Float") {
return <MakeNumberShower precision={3} number={chartResult["VAL"]} />;
}
else if(chartResult["NAME"] === "DistPlus"){
} else if (chartResult["NAME"] === "DistPlus") {
let shape = chartResult.VAL.pointSetDist;
if(shape.tag === "Continuous"){
if (shape.tag === "Continuous") {
let xyShape = shape.value.xyShape;
let totalY = xyShape.ys.reduce((a, b) => a + b);
let total = 0;
let cdf = xyShape.ys.map(y => {
let cdf = xyShape.ys.map((y) => {
total += y;
return total / totalY;
})
let values = _.zip(cdf, xyShape.xs, xyShape.ys).map(([c, x, y ]) => ({cdf: (c * 100).toFixed(2) + "%", x: x, y: y}));
});
let values = _.zip(cdf, xyShape.xs, xyShape.ys).map(([c, x, y]) => ({
cdf: (c * 100).toFixed(2) + "%",
x: x,
y: y,
}));
return (
<SquiggleVegaChart
data={{"con": values}}
/>
);
}
else if(shape.tag === "Discrete"){
return <SquiggleVegaChart data={{ con: values }} />;
} else if (shape.tag === "Discrete") {
let xyShape = shape.value.xyShape;
let totalY = xyShape.ys.reduce((a, b) => a + b);
let total = 0;
let cdf = xyShape.ys.map(y => {
let cdf = xyShape.ys.map((y) => {
total += y;
return total / totalY;
})
let values = _.zip(cdf, xyShape.xs, xyShape.ys).map(([c, x,y]) => ({cdf: (c * 100).toFixed(2) + "%", x: x, y: y}));
});
let values = _.zip(cdf, xyShape.xs, xyShape.ys).map(([c, x, y]) => ({
cdf: (c * 100).toFixed(2) + "%",
x: x,
y: y,
}));
return (
<SquiggleVegaChart
data={{"dis": values}}
/>
);
}
else if(shape.tag === "Mixed"){
return <SquiggleVegaChart data={{ dis: values }} />;
} else if (shape.tag === "Mixed") {
let discreteShape = shape.value.discrete.xyShape;
let totalDiscrete = discreteShape.ys.reduce((a, b) => a + b);
@ -95,141 +99,150 @@ export const SquiggleChart : React.FC<SquiggleChartProps> = props => {
let continuousPoints = _.zip(continuousShape.xs, continuousShape.ys);
interface labeledPoint {
x: number,
y: number,
type: "discrete" | "continuous"
};
x: number;
y: number;
type: "discrete" | "continuous";
}
let markedDisPoints : labeledPoint[] = discretePoints.map(([x,y]) => ({x: x, y: y, type: "discrete"}))
let markedConPoints : labeledPoint[] = continuousPoints.map(([x,y]) => ({x: x, y: y, type: "continuous"}))
let markedDisPoints: labeledPoint[] = discretePoints.map(
([x, y]) => ({ x: x, y: y, type: "discrete" })
);
let markedConPoints: labeledPoint[] = continuousPoints.map(
([x, y]) => ({ x: x, y: y, type: "continuous" })
);
let sortedPoints = _.sortBy(markedDisPoints.concat(markedConPoints), 'x')
let sortedPoints = _.sortBy(
markedDisPoints.concat(markedConPoints),
"x"
);
let totalContinuous = 1 - totalDiscrete;
let totalY = continuousShape.ys.reduce((a:number, b:number) => a + b);
let totalY = continuousShape.ys.reduce(
(a: number, b: number) => a + b
);
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") {
total += point.y / totalY * totalContinuous;
} else if (point.type == "continuous") {
total += (point.y / totalY) * totalContinuous;
return total;
}
});
interface cdfLabeledPoint {
cdf: string,
x: number,
y: number,
type: "discrete" | "continuous"
cdf: string;
x: number;
y: number;
type: "discrete" | "continuous";
}
let cdfLabeledPoint : cdfLabeledPoint[] = _.zipWith(cdf, sortedPoints, (c: number, point: labeledPoint) => ({...point, cdf: (c * 100).toFixed(2) + "%"}))
let continuousValues = cdfLabeledPoint.filter(x => x.type == "continuous")
let discreteValues = cdfLabeledPoint.filter(x => x.type == "discrete")
let cdfLabeledPoint: cdfLabeledPoint[] = _.zipWith(
cdf,
sortedPoints,
(c: number, point: labeledPoint) => ({
...point,
cdf: (c * 100).toFixed(2) + "%",
})
);
let continuousValues = cdfLabeledPoint.filter(
(x) => x.type == "continuous"
);
let discreteValues = cdfLabeledPoint.filter(
(x) => x.type == "discrete"
);
return (
<SquiggleVegaChart
data={{"con": continuousValues, "dis": discreteValues}}
/>
<SquiggleVegaChart
data={{ con: continuousValues, dis: discreteValues }}
/>
);
}
}
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 : 0.1
let step = (stop - start)/ count
let data = _.range(start, stop, step).map(x => {
if(chartResult.NAME=="Function"){
let result = chartResult.VAL(x);
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
]
let percentiles = getPercentiles(percentileArray, result.value);
return {
"x": x,
"p1": percentiles[0],
"p5": percentiles[1],
"p10": percentiles[2],
"p20": percentiles[3],
"p30": percentiles[4],
"p40": percentiles[5],
"p50": percentiles[6],
"p60": percentiles[7],
"p70": percentiles[8],
"p80": percentiles[9],
"p90": percentiles[10],
"p95": percentiles[11],
"p99": percentiles[12]
}
}
}
return 0;
})
return <SquigglePercentilesChart data={{"facet": data}} />
}
})
return <>{chartResults}</>;
}
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>)
} 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 : 0.1;
let step = (stop - start) / count;
let data = _.range(start, stop, step).map((x) => {
if (chartResult.NAME == "Function") {
let result = chartResult.VAL(x);
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,
];
let percentiles = getPercentiles(percentileArray, result.value);
return {
x: x,
p1: percentiles[0],
p5: percentiles[1],
p10: percentiles[2],
p20: percentiles[3],
p30: percentiles[4],
p40: percentiles[5],
p50: percentiles[6],
p60: percentiles[7],
p70: percentiles[8],
p80: percentiles[9],
p90: percentiles[10],
p95: percentiles[11],
p99: percentiles[12],
};
}
}
return 0;
});
return <SquigglePercentilesChart data={{ facet: data }} />;
}
});
return <>{chartResults}</>;
} 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>;
}
return (<p>{"Invalid Response"}</p>)
return <p>{"Invalid Response"}</p>;
};
function getPercentiles(percentiles:number[], t : DistPlus) {
if(t.pointSetDist.tag == "Discrete") {
function getPercentiles(percentiles: number[], t: DistPlus) {
if (t.pointSetDist.tag == "Discrete") {
let total = 0;
let maxX = _.max(t.pointSetDist.value.xyShape.xs)
let bounds = percentiles.map(_ => maxX);
_.zipWith(t.pointSetDist.value.xyShape.xs,t.pointSetDist.value.xyShape.ys, (x,y) => {
total += y
let maxX = _.max(t.pointSetDist.value.xyShape.xs);
let bounds = percentiles.map((_) => maxX);
_.zipWith(
t.pointSetDist.value.xyShape.xs,
t.pointSetDist.value.xyShape.ys,
(x, y) => {
total += y;
percentiles.forEach((v, i) => {
if(total > v && bounds[i] == maxX){
bounds[i] = x
}
})
});
return bounds;
}
else if(t.pointSetDist.tag == "Continuous"){
if (total > v && bounds[i] == maxX) {
bounds[i] = x;
}
});
}
);
return bounds;
} 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)
let bounds = percentiles.map(_ => maxX);
_.zipWith(t.pointSetDist.value.xyShape.xs,t.pointSetDist.value.xyShape.ys, (x,y) => {
let maxX = _.max(t.pointSetDist.value.xyShape.xs);
let totalY = _.sum(t.pointSetDist.value.xyShape.ys);
let bounds = percentiles.map((_) => maxX);
_.zipWith(
t.pointSetDist.value.xyShape.xs,
t.pointSetDist.value.xyShape.ys,
(x, y) => {
total += y / totalY;
percentiles.forEach((v, i) => {
if(total > v && bounds[i] == maxX){
bounds[i] = x
}
})
});
return bounds;
}
else if(t.pointSetDist.tag == "Mixed"){
if (total > v && bounds[i] == maxX) {
bounds[i] = x;
}
});
}
);
return bounds;
} else if (t.pointSetDist.tag == "Mixed") {
let discreteShape = t.pointSetDist.value.discrete.xyShape;
let totalDiscrete = discreteShape.ys.reduce((a, b) => a + b);
@ -238,80 +251,87 @@ function getPercentiles(percentiles:number[], t : DistPlus) {
let continuousPoints = _.zip(continuousShape.xs, continuousShape.ys);
interface labeledPoint {
x: number,
y: number,
type: "discrete" | "continuous"
};
x: number;
y: number;
type: "discrete" | "continuous";
}
let markedDisPoints : labeledPoint[] = discretePoints.map(([x,y]) => ({x: x, y: y, type: "discrete"}))
let markedConPoints : labeledPoint[] = continuousPoints.map(([x,y]) => ({x: x, y: y, type: "continuous"}))
let markedDisPoints: labeledPoint[] = discretePoints.map(([x, y]) => ({
x: x,
y: y,
type: "discrete",
}));
let markedConPoints: labeledPoint[] = continuousPoints.map(([x, y]) => ({
x: x,
y: y,
type: "continuous",
}));
let sortedPoints = _.sortBy(markedDisPoints.concat(markedConPoints), 'x')
let sortedPoints = _.sortBy(markedDisPoints.concat(markedConPoints), "x");
let totalContinuous = 1 - totalDiscrete;
let totalY = continuousShape.ys.reduce((a:number, b:number) => a + b);
let totalY = continuousShape.ys.reduce((a: number, b: number) => a + b);
let total = 0;
let maxX = _.max(sortedPoints.map(x => x.x));
let bounds = percentiles.map(_ => maxX);
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") {
total += (point.y / totalY) * totalContinuous;
}
else if (point.type == "continuous") {
total += point.y / totalY * totalContinuous;
}
percentiles.forEach((v,i) => {
if(total > v && bounds[i] == maxX){
percentiles.forEach((v, i) => {
if (total > v && bounds[i] == maxX) {
bounds[i] = total;
}
})
});
return total;
});
return bounds;
}
}
function MakeNumberShower(props: {number: number, precision :number}){
function MakeNumberShower(props: { number: number; precision: number }) {
let numberWithPresentation = numberShow(props.number, props.precision);
return (
<span>
{numberWithPresentation.value}
{numberWithPresentation.symbol}
{numberWithPresentation.power ?
<span>
{'\u00b710'}
<span style={{fontSize: "0.6em", verticalAlign: "super"}}>
{numberWithPresentation.power}
{numberWithPresentation.power ? (
<span>
{"\u00b710"}
<span style={{ fontSize: "0.6em", verticalAlign: "super" }}>
{numberWithPresentation.power}
</span>
</span>
</span>
: <></>}
) : (
<></>
)}
</span>
);
);
}
const orderOfMagnitudeNum = (n:number) => {
const orderOfMagnitudeNum = (n: number) => {
return Math.pow(10, n);
};
// 105 -> 3
const orderOfMagnitude = (n:number) => {
const orderOfMagnitude = (n: number) => {
return Math.floor(Math.log(n) / Math.LN10 + 0.000000001);
};
function withXSigFigs(number:number, sigFigs:number) {
function withXSigFigs(number: number, sigFigs: number) {
const withPrecision = number.toPrecision(sigFigs);
const formatted = Number(withPrecision);
return `${formatted}`;
}
class NumberShower {
number: number
precision: number
number: number;
precision: number;
constructor(number:number, precision = 2) {
constructor(number: number, precision = 2) {
this.number = number;
this.precision = precision;
}
@ -320,9 +340,9 @@ class NumberShower {
const number = Math.abs(this.number);
const response = this.evaluate(number);
if (this.number < 0) {
response.value = '-' + response.value;
response.value = "-" + response.value;
}
return response
return response;
}
metricSystem(number: number, order: number) {
@ -333,7 +353,7 @@ class NumberShower {
evaluate(number: number) {
if (number === 0) {
return { value: this.metricSystem(0, 0) }
return { value: this.metricSystem(0, 0) };
}
const order = orderOfMagnitude(number);
@ -342,13 +362,13 @@ class NumberShower {
} else if (order < 4) {
return { value: this.metricSystem(number, 0) };
} else if (order < 6) {
return { value: this.metricSystem(number, 3), symbol: 'K' };
return { value: this.metricSystem(number, 3), symbol: "K" };
} else if (order < 9) {
return { value: this.metricSystem(number, 6), symbol: 'M' };
return { value: this.metricSystem(number, 6), symbol: "M" };
} else if (order < 12) {
return { value: this.metricSystem(number, 9), symbol: 'B' };
return { value: this.metricSystem(number, 9), symbol: "B" };
} else if (order < 15) {
return { value: this.metricSystem(number, 12), symbol: 'T' };
return { value: this.metricSystem(number, 12), symbol: "T" };
} else {
return { value: this.metricSystem(number, order), power: order };
}

View File

@ -1,30 +1,28 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { SquiggleChart } from './SquiggleChart'
import * as React from "react";
import * as ReactDOM from "react-dom";
import { SquiggleChart } from "./SquiggleChart";
import { ReactCodeJar } from "react-codejar";
import type { exportEnv } from '@quri/squiggle-lang'
import type { exportEnv } from "@quri/squiggle-lang";
export interface SquiggleEditorProps {
/** The input string for squiggle */
initialSquiggleString? : string,
initialSquiggleString?: string;
/** If the output requires monte carlo sampling, the amount of samples */
sampleCount? : number,
sampleCount?: number;
/** The amount of points returned to draw the distribution */
outputXYPoints? : number,
kernelWidth? : number,
pointDistLength? : number,
outputXYPoints?: number;
kernelWidth?: number;
pointDistLength?: number;
/** If the result is a function, where the function starts */
diagramStart? : number,
diagramStart?: number;
/** If the result is a function, where the function ends */
diagramStop? : number,
diagramStop?: number;
/** If the result is a function, how many points along the function it samples */
diagramCount? : number,
diagramCount?: number;
/** The environment, other variables that were already declared */
environment?: exportEnv,
environment?: exportEnv;
/** when the environment changes. Used again for notebook magic*/
onEnvChange?(env: exportEnv) : void
onEnvChange?(env: exportEnv): void;
}
const highlight = (editor: HTMLInputElement) => {
@ -34,28 +32,30 @@ const highlight = (editor: HTMLInputElement) => {
};
interface SquiggleEditorState {
expression: string,
env: exportEnv
expression: string;
env: exportEnv;
}
export class SquiggleEditor extends React.Component<SquiggleEditorProps, SquiggleEditorState>{
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 }
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
let { expression, env } = this.state;
let props = this.props;
return (
<div>
<ReactCodeJar
code={expression}
onUpdate={e => {
this.setState({expression: e})
<div>
<ReactCodeJar
code={expression}
onUpdate={(e) => {
this.setState({ expression: e });
}}
style={{
style={{
borderRadius: "6px",
width: "530px",
border: "1px solid grey",
@ -65,39 +65,43 @@ export class SquiggleEditor extends React.Component<SquiggleEditorProps, Squiggl
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}
tabSize: "4",
}}
highlight={highlight}
lineNumbers={false}
/>
</div>
)
<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")
ReactDOM.render(<SquiggleEditor {...props} onEnvChange={env => {
// I can set the value here because I need it for creating notebooks
// @ts-ignore
parent.value = env
export function renderSquiggleEditor(props: SquiggleEditorProps) {
let parent = document.createElement("div");
ReactDOM.render(
<SquiggleEditor
{...props}
onEnvChange={(env) => {
// I can set the value here because I need it for creating notebooks
// @ts-ignore
parent.value = env;
parent.dispatchEvent(new CustomEvent("input"))
if(props.onEnvChange)
props.onEnvChange(env)
}} /> , parent)
return parent
parent.dispatchEvent(new CustomEvent("input"));
if (props.onEnvChange) props.onEnvChange(env);
}}
/>,
parent
);
return parent;
}

View File

@ -1,2 +1,2 @@
export { SquiggleChart } from './SquiggleChart';
export { SquiggleEditor, renderSquiggleEditor } from './SquiggleEditor';
export { SquiggleChart } from "./SquiggleChart";
export { SquiggleEditor, renderSquiggleEditor } from "./SquiggleEditor";

View File

@ -4,14 +4,14 @@
"width": 500,
"height": 200,
"padding": 5,
"data": [{"name": "con"}, {"name": "dis"}],
"data": [{ "name": "con" }, { "name": "dis" }],
"signals": [
{
"name": "mousex",
"description": "x position of mouse",
"update": "0",
"on": [{"events": "mousemove", "update": "1-x()/width"}]
"on": [{ "events": "mousemove", "update": "1-x()/width" }]
},
{
"name": "xscale",
@ -21,7 +21,7 @@
"input": "range",
"min": 0.1,
"max": 1
}
}
},
{
"name": "yscale",
@ -31,90 +31,92 @@
"input": "range",
"min": 0.1,
"max": 1
}
}
}
],
"scales": [{
"name": "xscale",
"type": "pow",
"exponent": {"signal": "xscale"},
"range": "width",
"zero": false,
"nice": false,
"domain": {
"fields": [
{ "data": "con", "field": "x"},
{ "data": "dis", "field": "x"}
"scales": [
{
"name": "xscale",
"type": "pow",
"exponent": { "signal": "xscale" },
"range": "width",
"zero": false,
"nice": false,
"domain": {
"fields": [
{ "data": "con", "field": "x" },
{ "data": "dis", "field": "x" }
]
}
}, {
"name": "yscale",
"type": "pow",
"exponent": {"signal": "yscale"},
"range": "height",
"nice": true,
"zero": true,
"domain": {
"fields": [
{ "data": "con", "field": "y"},
{ "data": "dis", "field": "y"}
},
{
"name": "yscale",
"type": "pow",
"exponent": { "signal": "yscale" },
"range": "height",
"nice": true,
"zero": true,
"domain": {
"fields": [
{ "data": "con", "field": "y" },
{ "data": "dis", "field": "y" }
]
}
}
}
],
"axes": [
{"orient": "bottom", "scale": "xscale", "tickCount": 20},
{"orient": "left", "scale": "yscale"}
{ "orient": "bottom", "scale": "xscale", "tickCount": 20 },
{ "orient": "left", "scale": "yscale" }
],
"marks": [
{
"type": "area",
"from": {"data": "con"},
"from": { "data": "con" },
"encode": {
"enter": {
"tooltip": {"signal": "datum.cdf"}
"tooltip": { "signal": "datum.cdf" }
},
"update": {
"x": {"scale": "xscale", "field": "x"},
"y": {"scale": "yscale", "field": "y"},
"y2": {"scale": "yscale", "value": 0},
"x": { "scale": "xscale", "field": "x" },
"y": { "scale": "yscale", "field": "y" },
"y2": { "scale": "yscale", "value": 0 },
"fill": {
"signal": "{gradient: 'linear', x1: 1, y1: 1, x2: 0, y2: 1, stops: [ {offset: 0.0, color: 'steelblue'}, {offset: clamp(mousex, 0, 1), color: 'steelblue'}, {offset: clamp(mousex, 0, 1), color: 'blue'}, {offset: 1.0, color: 'blue'} ] }"
},
"interpolate": {"value": "monotone"},
"fillOpacity": {"value": 1}
"signal": "{gradient: 'linear', x1: 1, y1: 1, x2: 0, y2: 1, stops: [ {offset: 0.0, color: 'steelblue'}, {offset: clamp(mousex, 0, 1), color: 'steelblue'}, {offset: clamp(mousex, 0, 1), color: 'blue'}, {offset: 1.0, color: 'blue'} ] }"
},
"interpolate": { "value": "monotone" },
"fillOpacity": { "value": 1 }
}
}
},
{
"type": "rect",
"from": {"data": "dis"},
"from": { "data": "dis" },
"encode": {
"enter": {
"y2": {"scale": "yscale", "value": 0},
"width": {"value": 1}
"y2": { "scale": "yscale", "value": 0 },
"width": { "value": 1 }
},
"update": {
"x": {"scale": "xscale", "field": "x"},
"y": {"scale": "yscale", "field": "y"}
"x": { "scale": "xscale", "field": "x" },
"y": { "scale": "yscale", "field": "y" }
}
}
},
{
"type": "symbol",
"from": {"data": "dis"},
"from": { "data": "dis" },
"encode": {
"enter": {
"shape": {"value": "circle"},
"width": {"value": 5},
"tooltip": {"signal": "datum.y"}
"shape": { "value": "circle" },
"width": { "value": 5 },
"tooltip": { "signal": "datum.y" }
},
"update": {
"x": {"scale": "xscale", "field": "x"},
"y": {"scale": "yscale", "field": "y"}
"x": { "scale": "xscale", "field": "x" },
"y": { "scale": "yscale", "field": "y" }
}
}
}

View File

@ -1,8 +1,8 @@
import { Meta } from '@storybook/addon-docs';
import { Meta } from "@storybook/addon-docs";
<Meta title="Squiggle/Introduction" />
This is the component library for Squiggle. All of these components are react
This is the component library for Squiggle. All of these components are react
components, and can be used in any application that you see fit.
Currently, the only component that is provided is the SquiggleChart component.

View File

@ -1,9 +1,9 @@
import { SquiggleChart } from '../SquiggleChart'
import { Canvas, Meta, Story, Props } from '@storybook/addon-docs';
import { SquiggleChart } from "../SquiggleChart";
import { Canvas, Meta, Story, Props } from "@storybook/addon-docs";
<Meta title="Squiggle/SquiggleChart" component={ SquiggleChart } />
<Meta title="Squiggle/SquiggleChart" component={SquiggleChart} />
export const Template = SquiggleChart
export const Template = SquiggleChart;
# Squiggle Chart
@ -19,53 +19,62 @@ could be continuous, discrete or mixed.
## Distributions
An example of a normal distribution is:
<Canvas>
<Story
name="Normal"
args={{
squiggleString: "normal(5,2)"
}}>
squiggleString: "normal(5,2)",
}}
>
{Template.bind({})}
</Story>
</Canvas>
An example of a Discrete distribution is:
<Canvas>
<Story
name="Discrete"
args={{
squiggleString: "mm(0, 1, [0.5, 0.5])"
}}>
squiggleString: "mm(0, 1, [0.5, 0.5])",
}}
>
{Template.bind({})}
</Story>
</Canvas>
An example of a Mixed distribution is:
<Canvas>
<Story
name="Mixed"
args={{
squiggleString: "mm(0, 5 to 10, [0.5, 0.5])"
}}>
squiggleString: "mm(0, 5 to 10, [0.5, 0.5])",
}}
>
{Template.bind({})}
</Story>
</Canvas>
## Constants
A constant is a simple number as a result. This has special formatting rules
to allow large and small numbers being printed cleanly.
<Canvas>
<Story
name="Constant"
args={{
squiggleString: "500000 * 5000000"
}}>
squiggleString: "500000 * 5000000",
}}
>
{Template.bind({})}
</Story>
</Canvas>
## Functions
Finally, a function can be returned, and this shows how the distribution changes
over the axis between x = 0 and 10.
@ -73,8 +82,9 @@ over the axis between x = 0 and 10.
<Story
name="Function"
args={{
squiggleString: "f(x) = normal(x,x)\nf"
}}>
squiggleString: "f(x) = normal(x,x)\nf",
}}
>
{Template.bind({})}
</Story>
</Canvas>

View File

@ -1,32 +1,32 @@
const path = require('path');
const path = require("path");
module.exports = {
mode: 'production',
devtool: 'source-map',
entry: './src/index.ts',
mode: "production",
devtool: "source-map",
entry: "./src/index.ts",
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
use: "ts-loader",
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.js', '.tsx', '.ts'],
extensions: [".js", ".tsx", ".ts"],
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
filename: "bundle.js",
path: path.resolve(__dirname, "dist"),
library: {
name: 'squiggle_components',
type: 'umd',
name: "squiggle_components",
type: "umd",
},
},
devServer: {
static: {
directory: path.join(__dirname, 'public'),
directory: path.join(__dirname, "public"),
},
compress: true,
port: 9000,

View File

@ -14370,6 +14370,11 @@ prepend-http@^2.0.0:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.0.tgz#b6a5bf1284026ae640f17f7ff5658a7567fc0d18"
integrity sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==
prettier@^2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.0.tgz#12f8f504c4d8ddb76475f441337542fa799207d4"
integrity sha512-m2FgJibYrBGGgQXNzfd0PuDGShJgRavjUoRCw1mZERIWVSXF0iLzLm+aOqTAbLnC3n6JzUhAA8uZnFVghHJ86A==
pretty-bytes@^5.3.0, pretty-bytes@^5.4.1:
version "5.6.0"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"