Merge pull request #193 from QURIresearch/Components-cleanup-april

Minor Components Improvements
This commit is contained in:
Ozzie Gooen 2022-04-07 08:47:41 -04:00 committed by GitHub
commit 51f2fce2c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 622 additions and 219 deletions

View File

@ -18,6 +18,7 @@
"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",
"styled-components": "^5.3.5",
"tsconfig-paths-webpack-plugin": "^3.5.2", "tsconfig-paths-webpack-plugin": "^3.5.2",
"typescript": "^4.6.3", "typescript": "^4.6.3",
"vega": "^5.21.0", "vega": "^5.21.0",

View File

@ -16,7 +16,6 @@ export let CodeEditor: FC<CodeEditorProps> = ({
value, value,
onChange, onChange,
oneLine = false, oneLine = false,
width = 500,
}: CodeEditorProps) => { }: CodeEditorProps) => {
let lineCount = value.split("\n").length; let lineCount = value.split("\n").length;
let id = _.uniqueId(); let id = _.uniqueId();
@ -25,7 +24,7 @@ export let CodeEditor: FC<CodeEditorProps> = ({
value={value} value={value}
mode="golang" mode="golang"
theme="github" theme="github"
width={width + "px"} width={"100%"}
minLines={oneLine ? lineCount : 15} minLines={oneLine ? lineCount : 15}
maxLines={oneLine ? lineCount : 15} maxLines={oneLine ? lineCount : 15}
showGutter={false} showGutter={false}

View File

@ -0,0 +1,98 @@
import * as React from "react";
import _ from "lodash";
const orderOfMagnitudeNum = (n: number) => {
return Math.pow(10, n);
};
// 105 -> 3
const orderOfMagnitude = (n: number) => {
return Math.floor(Math.log(n) / Math.LN10 + 0.000000001);
};
function withXSigFigs(number: number, sigFigs: number) {
const withPrecision = number.toPrecision(sigFigs);
const formatted = Number(withPrecision);
return `${formatted}`;
}
class NumberShowerBuilder {
number: number;
precision: number;
constructor(number: number, precision = 2) {
this.number = number;
this.precision = precision;
}
convert() {
const number = Math.abs(this.number);
const response = this.evaluate(number);
if (this.number < 0) {
response.value = "-" + response.value;
}
return response;
}
metricSystem(number: number, order: number) {
const newNumber = number / orderOfMagnitudeNum(order);
const precision = this.precision;
return `${withXSigFigs(newNumber, precision)}`;
}
evaluate(number: number) {
if (number === 0) {
return { value: this.metricSystem(0, 0) };
}
const order = orderOfMagnitude(number);
if (order < -2) {
return { value: this.metricSystem(number, order), power: order };
} else if (order < 4) {
return { value: this.metricSystem(number, 0) };
} else if (order < 6) {
return { value: this.metricSystem(number, 3), symbol: "K" };
} else if (order < 9) {
return { value: this.metricSystem(number, 6), symbol: "M" };
} else if (order < 12) {
return { value: this.metricSystem(number, 9), symbol: "B" };
} else if (order < 15) {
return { value: this.metricSystem(number, 12), symbol: "T" };
} else {
return { value: this.metricSystem(number, order), power: order };
}
}
}
export function numberShow(number: number, precision = 2) {
const ns = new NumberShowerBuilder(number, precision);
return ns.convert();
}
export interface NumberShowerProps {
number: number;
precision?: number
}
export let NumberShower: React.FC<NumberShowerProps> = ({
number,
precision = 2
}: NumberShowerProps) => {
let numberWithPresentation = numberShow(number, precision);
return (
<span>
{numberWithPresentation.value}
{numberWithPresentation.symbol}
{numberWithPresentation.power ? (
<span>
{"\u00b710"}
<span style={{ fontSize: "0.6em", verticalAlign: "super" }}>
{numberWithPresentation.power}
</span>
</span>
) : (
<></>
)}
</span>
);
}

View File

@ -11,6 +11,8 @@ import type {
import { createClassFromSpec } from "react-vega"; import { createClassFromSpec } from "react-vega";
import * as chartSpecification from "./spec-distributions.json"; import * as chartSpecification from "./spec-distributions.json";
import * as percentilesSpec from "./spec-percentiles.json"; import * as percentilesSpec from "./spec-percentiles.json";
import { NumberShower } from "./NumberShower";
import styled from "styled-components";
let SquiggleVegaChart = createClassFromSpec({ let SquiggleVegaChart = createClassFromSpec({
spec: chartSpecification as Spec, spec: chartSpecification as Spec,
@ -42,8 +44,27 @@ export interface SquiggleChartProps {
onEnvChange?(env: exportEnv): void; onEnvChange?(env: exportEnv): void;
/** CSS width of the element */ /** CSS width of the element */
width?: number; width?: number;
height?: number;
} }
const Error = styled.div`
border: 1px solid #792e2e;
background: #eee2e2;
padding: 0.4em 0.8em;
`;
const ShowError: React.FC<{ heading: string; children: React.ReactNode }> = ({
heading = "Error",
children,
}) => {
return (
<Error>
<h3>{heading}</h3>
{children}
</Error>
);
};
export const SquiggleChart: React.FC<SquiggleChartProps> = ({ export const SquiggleChart: React.FC<SquiggleChartProps> = ({
squiggleString = "", squiggleString = "",
sampleCount = 1000, sampleCount = 1000,
@ -56,6 +77,7 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = ({
environment = [], environment = [],
onEnvChange = () => {}, onEnvChange = () => {},
width = 500, width = 500,
height = 60,
}: SquiggleChartProps) => { }: SquiggleChartProps) => {
let samplingInputs: SamplingInputs = { let samplingInputs: SamplingInputs = {
sampleCount: sampleCount, sampleCount: sampleCount,
@ -71,7 +93,7 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = ({
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 <NumberShower precision={3} number={chartResult["VAL"]} />;
} else if (chartResult["NAME"] === "DistPlus") { } else if (chartResult["NAME"] === "DistPlus") {
let shape = chartResult.VAL.pointSetDist; let shape = chartResult.VAL.pointSetDist;
if (shape.tag === "Continuous") { if (shape.tag === "Continuous") {
@ -91,6 +113,7 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = ({
return ( return (
<SquiggleVegaChart <SquiggleVegaChart
width={width} width={width}
height={height}
data={{ con: values }} data={{ con: values }}
actions={false} actions={false}
/> />
@ -227,7 +250,11 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = ({
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 (
<ShowError heading={"Parse Error"}>
{result.value}
</ShowError>
);
} }
return <p>{"Invalid Response"}</p>; return <p>{"Invalid Response"}</p>;
}; };
@ -317,91 +344,3 @@ function getPercentiles(percentiles: number[], t: DistPlus) {
return bounds; return bounds;
} }
} }
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}
</span>
</span>
) : (
<></>
)}
</span>
);
}
const orderOfMagnitudeNum = (n: number) => {
return Math.pow(10, n);
};
// 105 -> 3
const orderOfMagnitude = (n: number) => {
return Math.floor(Math.log(n) / Math.LN10 + 0.000000001);
};
function withXSigFigs(number: number, sigFigs: number) {
const withPrecision = number.toPrecision(sigFigs);
const formatted = Number(withPrecision);
return `${formatted}`;
}
class NumberShower {
number: number;
precision: number;
constructor(number: number, precision = 2) {
this.number = number;
this.precision = precision;
}
convert() {
const number = Math.abs(this.number);
const response = this.evaluate(number);
if (this.number < 0) {
response.value = "-" + response.value;
}
return response;
}
metricSystem(number: number, order: number) {
const newNumber = number / orderOfMagnitudeNum(order);
const precision = this.precision;
return `${withXSigFigs(newNumber, precision)}`;
}
evaluate(number: number) {
if (number === 0) {
return { value: this.metricSystem(0, 0) };
}
const order = orderOfMagnitude(number);
if (order < -2) {
return { value: this.metricSystem(number, order), power: order };
} else if (order < 4) {
return { value: this.metricSystem(number, 0) };
} else if (order < 6) {
return { value: this.metricSystem(number, 3), symbol: "K" };
} else if (order < 9) {
return { value: this.metricSystem(number, 6), symbol: "M" };
} else if (order < 12) {
return { value: this.metricSystem(number, 9), symbol: "B" };
} else if (order < 15) {
return { value: this.metricSystem(number, 12), symbol: "T" };
} else {
return { value: this.metricSystem(number, order), power: order };
}
}
}
export function numberShow(number: number, precision = 2) {
const ns = new NumberShower(number, precision);
return ns.convert();
}

View File

@ -3,6 +3,7 @@ import * as ReactDOM from "react-dom";
import { SquiggleChart } from "./SquiggleChart"; import { SquiggleChart } from "./SquiggleChart";
import { CodeEditor } from "./CodeEditor"; import { CodeEditor } from "./CodeEditor";
import type { exportEnv } from "@quri/squiggle-lang"; import type { exportEnv } from "@quri/squiggle-lang";
import styled from 'styled-components'
export interface SquiggleEditorProps { export interface SquiggleEditorProps {
/** The input string for squiggle */ /** The input string for squiggle */
@ -27,6 +28,12 @@ export interface SquiggleEditorProps {
width: number; width: number;
} }
const Input = styled.div`
border: 1px solid #ddd;
padding: 0.3em 0.3em;
margin-bottom: 1em;
`;
export let SquiggleEditor: React.FC<SquiggleEditorProps> = ({ export let SquiggleEditor: React.FC<SquiggleEditorProps> = ({
initialSquiggleString = "", initialSquiggleString = "",
width = 500, width = 500,
@ -43,12 +50,13 @@ export let SquiggleEditor: React.FC<SquiggleEditorProps> = ({
let [expression, setExpression] = React.useState(initialSquiggleString); let [expression, setExpression] = React.useState(initialSquiggleString);
return ( return (
<div> <div>
<Input>
<CodeEditor <CodeEditor
width={width}
value={expression} value={expression}
onChange={setExpression} onChange={setExpression}
oneLine={true} oneLine={true}
/> />
</Input>
<SquiggleChart <SquiggleChart
width={width} width={width}
squiggleString={expression} squiggleString={expression}

View File

@ -55,6 +55,7 @@ let SquigglePlayground: FC<Props> = (props) => {
diagramStop={diagramStop} diagramStop={diagramStop}
diagramCount={diagramCount} diagramCount={diagramCount}
pointDistLength={pointDistLength} pointDistLength={pointDistLength}
height={150}
/> />
); );
return ( return (

View File

@ -1,18 +1,18 @@
{ {
"$schema": "https://vega.github.io/schema/vega/v5.json", "$schema": "https://vega.github.io/schema/vega/v5.json",
"description": "A basic area chart example.", "description": "A basic area chart example",
"width": 500, "width": 500,
"height": 200, "height": 100,
"padding": 5, "padding": 5,
"data": [{ "name": "con" }, { "name": "dis" }], "data": [
"signals": [
{ {
"name": "mousex", "name": "con"
"description": "x position of mouse",
"update": "0",
"on": [{ "events": "mousemove", "update": "1-x()/width" }]
}, },
{
"name": "dis"
}
],
"signals": [
{ {
"name": "xscale", "name": "xscale",
"description": "The transform of the x scale", "description": "The transform of the x scale",
@ -32,87 +32,150 @@
} }
} }
], ],
"scales": [ "scales": [
{ {
"name": "xscale", "name": "xscale",
"type": "pow", "type": "pow",
"exponent": { "signal": "xscale ? 0.1 : 1" }, "exponent": {
"signal": "xscale ? 0.1 : 1"
},
"range": "width", "range": "width",
"zero": false, "zero": false,
"nice": false, "nice": false,
"domain": { "domain": {
"fields": [ "fields": [
{ "data": "con", "field": "x" }, {
{ "data": "dis", "field": "x" } "data": "con",
"field": "x"
},
{
"data": "dis",
"field": "x"
}
] ]
} }
}, },
{ {
"name": "yscale", "name": "yscale",
"type": "pow", "type": "pow",
"exponent": { "signal": "yscale ? 0.1 : 1" }, "exponent": {
"signal": "yscale ? 0.1 : 1"
},
"range": "height", "range": "height",
"nice": true, "nice": true,
"zero": true, "zero": true,
"domain": { "domain": {
"fields": [ "fields": [
{ "data": "con", "field": "y" }, {
{ "data": "dis", "field": "y" } "data": "con",
"field": "y"
},
{
"data": "dis",
"field": "y"
}
] ]
} }
} }
], ],
"axes": [
"axes": [{ "orient": "bottom", "scale": "xscale", "tickCount": 20 }], {
"orient": "bottom",
"scale": "xscale",
"labelColor": "#666",
"tickColor": "#ddd",
"format": "~s",
"tickCount": 20
}
],
"marks": [ "marks": [
{ {
"type": "area", "type": "area",
"from": { "data": "con" }, "from": {
"data": "con"
},
"encode": { "encode": {
"enter": {
"tooltip": { "signal": "datum.cdf" }
},
"update": { "update": {
"x": { "scale": "xscale", "field": "x" }, "x": {
"y": { "scale": "yscale", "field": "y" }, "scale": "xscale",
"y2": { "scale": "yscale", "value": 0 }, "field": "x"
"fill": {
"signal": "{gradient: 'linear', x1: 1, y1: 1, x2: 0, y2: 1, stops: [ {offset: 0.0, color: '#11ac8f'}, {offset: clamp(mousex, 0, 1), color: '#11ac8f'}, {offset: clamp(mousex, 0, 1), color: '#1b6fac'}, {offset: 1.0, color: '#1b6fac'} ] }",
"color": "#000"
}, },
"interpolate": { "value": "monotone" }, "y": {
"fillOpacity": { "value": 1 } "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: '#4C78A8'}] }"
},
"interpolate": {
"value": "monotone"
},
"fillOpacity": {
"value": 1
}
} }
} }
}, },
{ {
"type": "rect", "type": "rect",
"from": { "data": "dis" }, "from": {
"data": "dis"
},
"encode": { "encode": {
"enter": { "enter": {
"y2": { "scale": "yscale", "value": 0 }, "y2": {
"width": { "value": 1 } "scale": "yscale",
"value": 0
},
"width": {
"value": 1
}
}, },
"update": { "update": {
"x": { "scale": "xscale", "field": "x" }, "x": {
"y": { "scale": "yscale", "field": "y" } "scale": "xscale",
"field": "x"
},
"y": {
"scale": "yscale",
"field": "y"
}
} }
} }
}, },
{ {
"type": "symbol", "type": "symbol",
"from": { "data": "dis" }, "from": {
"data": "dis"
},
"encode": { "encode": {
"enter": { "enter": {
"shape": { "value": "circle" }, "shape": {
"width": { "value": 5 }, "value": "circle"
"tooltip": { "signal": "datum.y" } },
"width": {
"value": 5
},
"tooltip": {
"signal": "datum.y"
}
}, },
"update": { "update": {
"x": { "scale": "xscale", "field": "x" }, "x": {
"y": { "scale": "yscale", "field": "y" } "scale": "xscale",
"field": "x"
},
"y": {
"scale": "yscale",
"field": "y"
},
"fill": {
"value": "#1e4577"
}
} }
} }
} }

View File

@ -7,7 +7,12 @@
{ {
"name": "facet", "name": "facet",
"values": [], "values": [],
"format": { "type": "json", "parse": { "timestamp": "date" } } "format": {
"type": "json",
"parse": {
"timestamp": "date"
}
}
}, },
{ {
"name": "table", "name": "table",
@ -70,7 +75,10 @@
"name": "xscale", "name": "xscale",
"type": "linear", "type": "linear",
"nice": true, "nice": true,
"domain": { "data": "facet", "field": "x" }, "domain": {
"data": "facet",
"field": "x"
},
"range": "width" "range": "width"
}, },
{ {
@ -79,7 +87,10 @@
"range": "height", "range": "height",
"nice": true, "nice": true,
"zero": true, "zero": true,
"domain": { "data": "facet", "field": "p99" } "domain": {
"data": "facet",
"field": "p99"
}
} }
], ],
"axes": [ "axes": [
@ -89,8 +100,20 @@
"grid": false, "grid": false,
"tickSize": 2, "tickSize": 2,
"encode": { "encode": {
"grid": { "enter": { "stroke": { "value": "#ccc" } } }, "grid": {
"ticks": { "enter": { "stroke": { "value": "#ccc" } } } "enter": {
"stroke": {
"value": "#ccc"
}
}
},
"ticks": {
"enter": {
"stroke": {
"value": "#ccc"
}
}
}
} }
}, },
{ {
@ -100,107 +123,249 @@
"domain": false, "domain": false,
"tickSize": 2, "tickSize": 2,
"encode": { "encode": {
"grid": { "enter": { "stroke": { "value": "#ccc" } } }, "grid": {
"ticks": { "enter": { "stroke": { "value": "#ccc" } } } "enter": {
"stroke": {
"value": "#ccc"
}
}
},
"ticks": {
"enter": {
"stroke": {
"value": "#ccc"
}
}
}
} }
} }
], ],
"marks": [ "marks": [
{ {
"type": "area", "type": "area",
"from": { "data": "table" }, "from": {
"data": "table"
},
"encode": { "encode": {
"enter": { "fill": { "value": "#4C78A8" } }, "enter": {
"fill": {
"value": "#4C78A8"
}
},
"update": { "update": {
"interpolate": { "value": "monotone" }, "interpolate": {
"x": { "scale": "xscale", "field": "x" }, "value": "monotone"
"y": { "scale": "yscale", "field": "p1" }, },
"y2": { "scale": "yscale", "field": "p99" }, "x": {
"opacity": { "value": 0.05 } "scale": "xscale",
"field": "x"
},
"y": {
"scale": "yscale",
"field": "p1"
},
"y2": {
"scale": "yscale",
"field": "p99"
},
"opacity": {
"value": 0.05
}
} }
} }
}, },
{ {
"type": "area", "type": "area",
"from": { "data": "table" }, "from": {
"data": "table"
},
"encode": { "encode": {
"enter": { "fill": { "value": "#4C78A8" } }, "enter": {
"fill": {
"value": "#4C78A8"
}
},
"update": { "update": {
"interpolate": { "value": "monotone" }, "interpolate": {
"x": { "scale": "xscale", "field": "x" }, "value": "monotone"
"y": { "scale": "yscale", "field": "p5" }, },
"y2": { "scale": "yscale", "field": "p95" }, "x": {
"opacity": { "value": 0.1 } "scale": "xscale",
"field": "x"
},
"y": {
"scale": "yscale",
"field": "p5"
},
"y2": {
"scale": "yscale",
"field": "p95"
},
"opacity": {
"value": 0.1
}
} }
} }
}, },
{ {
"type": "area", "type": "area",
"from": { "data": "table" }, "from": {
"data": "table"
},
"encode": { "encode": {
"enter": { "fill": { "value": "#4C78A8" } }, "enter": {
"fill": {
"value": "#4C78A8"
}
},
"update": { "update": {
"interpolate": { "value": "monotone" }, "interpolate": {
"x": { "scale": "xscale", "field": "x" }, "value": "monotone"
"y": { "scale": "yscale", "field": "p10" }, },
"y2": { "scale": "yscale", "field": "p90" }, "x": {
"opacity": { "value": 0.15 } "scale": "xscale",
"field": "x"
},
"y": {
"scale": "yscale",
"field": "p10"
},
"y2": {
"scale": "yscale",
"field": "p90"
},
"opacity": {
"value": 0.15
}
} }
} }
}, },
{ {
"type": "area", "type": "area",
"from": { "data": "table" }, "from": {
"data": "table"
},
"encode": { "encode": {
"enter": { "fill": { "value": "#4C78A8" } }, "enter": {
"fill": {
"value": "#4C78A8"
}
},
"update": { "update": {
"interpolate": { "value": "monotone" }, "interpolate": {
"x": { "scale": "xscale", "field": "x" }, "value": "monotone"
"y": { "scale": "yscale", "field": "p20" }, },
"y2": { "scale": "yscale", "field": "p80" }, "x": {
"opacity": { "value": 0.2 } "scale": "xscale",
"field": "x"
},
"y": {
"scale": "yscale",
"field": "p20"
},
"y2": {
"scale": "yscale",
"field": "p80"
},
"opacity": {
"value": 0.2
}
} }
} }
}, },
{ {
"type": "area", "type": "area",
"from": { "data": "table" }, "from": {
"data": "table"
},
"encode": { "encode": {
"enter": { "fill": { "value": "#4C78A8" } }, "enter": {
"fill": {
"value": "#4C78A8"
}
},
"update": { "update": {
"interpolate": { "value": "monotone" }, "interpolate": {
"x": { "scale": "xscale", "field": "x" }, "value": "monotone"
"y": { "scale": "yscale", "field": "p30" }, },
"y2": { "scale": "yscale", "field": "p70" }, "x": {
"opacity": { "value": 0.2 } "scale": "xscale",
"field": "x"
},
"y": {
"scale": "yscale",
"field": "p30"
},
"y2": {
"scale": "yscale",
"field": "p70"
},
"opacity": {
"value": 0.2
}
} }
} }
}, },
{ {
"type": "area", "type": "area",
"from": { "data": "table" }, "from": {
"data": "table"
},
"encode": { "encode": {
"enter": { "fill": { "value": "#4C78A8" } }, "enter": {
"fill": {
"value": "#4C78A8"
}
},
"update": { "update": {
"interpolate": { "value": "monotone" }, "interpolate": {
"x": { "scale": "xscale", "field": "x" }, "value": "monotone"
"y": { "scale": "yscale", "field": "p40" }, },
"y2": { "scale": "yscale", "field": "p60" }, "x": {
"opacity": { "value": 0.2 } "scale": "xscale",
"field": "x"
},
"y": {
"scale": "yscale",
"field": "p40"
},
"y2": {
"scale": "yscale",
"field": "p60"
},
"opacity": {
"value": 0.2
}
} }
} }
}, },
{ {
"type": "line", "type": "line",
"from": { "data": "table" }, "from": {
"data": "table"
},
"encode": { "encode": {
"update": { "update": {
"interpolate": { "value": "monotone" }, "interpolate": {
"stroke": { "value": "#4C78A8" }, "value": "monotone"
"strokeWidth": { "value": 2 }, },
"opacity": { "value": 0.8 }, "stroke": {
"x": { "scale": "xscale", "field": "x" }, "value": "#4C78A8"
"y": { "scale": "yscale", "field": "p50" } },
"strokeWidth": {
"value": 2
},
"opacity": {
"value": 0.8
},
"x": {
"scale": "xscale",
"field": "x"
},
"y": {
"scale": "yscale",
"field": "p50"
}
} }
} }
} }

View File

@ -2,8 +2,5 @@ import { Meta } from "@storybook/addon-docs";
<Meta title="Squiggle/Introduction" /> <Meta title="Squiggle/Introduction" />
This is the component library for Squiggle. All of these components are react This is the component library for Squiggle. These are React
components, and can be used in any application that you see fit. components, and can be used in any application that you see fit.
Currently, the only component that is provided is the SquiggleChart component.
This component allows you to render the result of a squiggle expression.

View File

@ -0,0 +1,60 @@
import { NumberShower } from "../NumberShower";
import { Canvas, Meta, Story, Props } from "@storybook/addon-docs";
<Meta title="Squiggle/NumberShower" component={NumberShower} />
# Number Shower
The number shower is a simple component to display a number.
It uses the symbols "K", "M", "B", and "T", to represent thousands, millions, billions, and trillions. Outside of that range, it uses scientific notation.
<Canvas>
<Story
name="Ten Thousand"
args={{
number: 10000,
precision: 2
}}
>
{args => <NumberShower {...args}/>}
</Story>
</Canvas>
<Canvas>
<Story
name="Ten Billion"
args={{
number: 10000000000,
precision: 2
}}
>
{args => <NumberShower {...args}/>}
</Story>
</Canvas>
<Canvas>
<Story
name="1.2*10^15"
args={{
number: 1200000000000000,
precision: 2
}}
>
{args => <NumberShower {...args}/>}
</Story>
</Canvas>
<Canvas>
<Story
name="1.35*10^-13"
args={{
number: 0.000000000000135,
precision: 2
}}
>
{args => <NumberShower {...args}/>}
</Story>
</Canvas>
<Props of={NumberShower} />

View File

@ -18,7 +18,7 @@ could be continuous, discrete or mixed.
## Distributions ## Distributions
An example of a normal distribution is: ### Continuous Distributions
<Canvas> <Canvas>
<Story <Story
@ -31,26 +31,26 @@ An example of a normal distribution is:
</Story> </Story>
</Canvas> </Canvas>
An example of a Discrete distribution is: ### Discrete Distributions
<Canvas> <Canvas>
<Story <Story
name="Discrete" name="Discrete"
args={{ args={{
squiggleString: "mm(0, 1, [0.5, 0.5])", squiggleString: "mm(0, 1, 3, 5, 8, 10, [0.1, 0.8, 0.5, 0.3, 0.2, 0.1])",
}} }}
> >
{Template.bind({})} {Template.bind({})}
</Story> </Story>
</Canvas> </Canvas>
An example of a Mixed distribution is: ## Mixed distributions
<Canvas> <Canvas>
<Story <Story
name="Mixed" name="Mixed"
args={{ args={{
squiggleString: "mm(0, 5 to 10, [0.5, 0.5])", squiggleString: "mm(0, 1, 3, 5, 8, normal(8, 1), [0.1, 0.3, 0.4, 0.35, 0.2, 0.8])",
}} }}
> >
{Template.bind({})} {Template.bind({})}
@ -66,7 +66,7 @@ to allow large and small numbers being printed cleanly.
<Story <Story
name="Constant" name="Constant"
args={{ args={{
squiggleString: "500000 * 5000000", squiggleString: "500000000",
}} }}
> >
{Template.bind({})} {Template.bind({})}
@ -75,14 +75,28 @@ to allow large and small numbers being printed cleanly.
## Functions ## Functions
Finally, a function can be returned, and this shows how the distribution changes Full functions can be returned. These plot out the results of distributions between a set of x-coordinates.
over the axis between x = 0 and 10.
The default is show 10 points between 0 and 10.
<Canvas> <Canvas>
<Story <Story
name="Function" name="Function"
args={{ args={{
squiggleString: "f(x) = normal(x,x)\nf", squiggleString: "f(x) = normal(x^2,x^1.8)\nf",
}}
>
{Template.bind({})}
</Story>
</Canvas>
## Errors
<Canvas>
<Story
name="Error"
args={{
squiggleString: "f(x) = normal(",
}} }}
> >
{Template.bind({})} {Template.bind({})}

View File

@ -283,7 +283,7 @@
jsesc "^2.5.1" jsesc "^2.5.1"
source-map "^0.5.0" source-map "^0.5.0"
"@babel/helper-annotate-as-pure@^7.16.7": "@babel/helper-annotate-as-pure@^7.16.0", "@babel/helper-annotate-as-pure@^7.16.7":
version "7.16.7" version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862"
integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw== integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==
@ -409,7 +409,7 @@
dependencies: dependencies:
"@babel/types" "^7.17.0" "@babel/types" "^7.17.0"
"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7": "@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.0", "@babel/helper-module-imports@^7.16.7":
version "7.16.7" version "7.16.7"
resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz" resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz"
integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==
@ -1354,7 +1354,7 @@
"@babel/parser" "^7.16.7" "@babel/parser" "^7.16.7"
"@babel/types" "^7.16.7" "@babel/types" "^7.16.7"
"@babel/traverse@^7.1.6", "@babel/traverse@^7.12.11", "@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.9": "@babel/traverse@^7.1.6", "@babel/traverse@^7.12.11", "@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.9", "@babel/traverse@^7.4.5":
version "7.17.9" version "7.17.9"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.9.tgz#1f9b207435d9ae4a8ed6998b2b82300d83c37a0d" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.9.tgz#1f9b207435d9ae4a8ed6998b2b82300d83c37a0d"
integrity sha512-PQO8sDIJ8SIwipTPiR71kJQCKQYB5NGImbOviK8K+kg5xkNSYXLBupuX9QhatFowrsvo9Hj8WgArg3W7ijNAQw== integrity sha512-PQO8sDIJ8SIwipTPiR71kJQCKQYB5NGImbOviK8K+kg5xkNSYXLBupuX9QhatFowrsvo9Hj8WgArg3W7ijNAQw==
@ -1914,11 +1914,23 @@
dependencies: dependencies:
"@emotion/memoize" "0.7.4" "@emotion/memoize" "0.7.4"
"@emotion/is-prop-valid@^1.1.0":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.1.2.tgz#34ad6e98e871aa6f7a20469b602911b8b11b3a95"
integrity sha512-3QnhqeL+WW88YjYbQL5gUIkthuMw7a0NGbZ7wfFVk2kg/CK5w8w5FFa0RzWjyY1+sujN0NWbtSHH6OJmWHtJpQ==
dependencies:
"@emotion/memoize" "^0.7.4"
"@emotion/memoize@0.7.4": "@emotion/memoize@0.7.4":
version "0.7.4" version "0.7.4"
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb"
integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==
"@emotion/memoize@^0.7.4":
version "0.7.5"
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50"
integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==
"@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16": "@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16":
version "0.11.16" version "0.11.16"
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.16.tgz#dee05f9e96ad2fb25a5206b6d759b2d1ed3379ad" resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.16.tgz#dee05f9e96ad2fb25a5206b6d759b2d1ed3379ad"
@ -1953,12 +1965,12 @@
"@emotion/styled-base" "^10.3.0" "@emotion/styled-base" "^10.3.0"
babel-plugin-emotion "^10.0.27" babel-plugin-emotion "^10.0.27"
"@emotion/stylis@0.8.5": "@emotion/stylis@0.8.5", "@emotion/stylis@^0.8.4":
version "0.8.5" version "0.8.5"
resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04" resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04"
integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ== integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==
"@emotion/unitless@0.7.5": "@emotion/unitless@0.7.5", "@emotion/unitless@^0.7.4":
version "0.7.5" version "0.7.5"
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
@ -5418,6 +5430,17 @@ babel-plugin-react-docgen@^4.1.0, babel-plugin-react-docgen@^4.2.1:
lodash "^4.17.15" lodash "^4.17.15"
react-docgen "^5.0.0" react-docgen "^5.0.0"
"babel-plugin-styled-components@>= 1.12.0":
version "2.0.6"
resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-2.0.6.tgz#6f76c7f7224b7af7edc24a4910351948c691fc90"
integrity sha512-Sk+7o/oa2HfHv3Eh8sxoz75/fFvEdHsXV4grdeHufX0nauCmymlnN0rGhIvfpMQSJMvGutJ85gvCGea4iqmDpg==
dependencies:
"@babel/helper-annotate-as-pure" "^7.16.0"
"@babel/helper-module-imports" "^7.16.0"
babel-plugin-syntax-jsx "^6.18.0"
lodash "^4.17.11"
picomatch "^2.3.0"
babel-plugin-syntax-jsx@^6.18.0: babel-plugin-syntax-jsx@^6.18.0:
version "6.18.0" version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946"
@ -6002,6 +6025,11 @@ camelcase@^6.2.0, camelcase@^6.2.1:
resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz"
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
camelize@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b"
integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=
caniuse-api@^3.0.0: caniuse-api@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0"
@ -6790,6 +6818,11 @@ css-blank-pseudo@^3.0.3:
dependencies: dependencies:
postcss-selector-parser "^6.0.9" postcss-selector-parser "^6.0.9"
css-color-keywords@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
integrity sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=
css-declaration-sorter@^6.2.2: css-declaration-sorter@^6.2.2:
version "6.2.2" version "6.2.2"
resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.2.2.tgz#bfd2f6f50002d6a3ae779a87d3a0c5d5b10e0f02" resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.2.2.tgz#bfd2f6f50002d6a3ae779a87d3a0c5d5b10e0f02"
@ -6904,6 +6937,15 @@ css-select@~1.2.0:
domutils "1.5.1" domutils "1.5.1"
nth-check "~1.0.1" nth-check "~1.0.1"
css-to-react-native@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.0.0.tgz#62dbe678072a824a689bcfee011fc96e02a7d756"
integrity sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ==
dependencies:
camelize "^1.0.0"
css-color-keywords "^1.0.0"
postcss-value-parser "^4.0.2"
css-tree@1.0.0-alpha.37: css-tree@1.0.0-alpha.37:
version "1.0.0-alpha.37" version "1.0.0-alpha.37"
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22"
@ -9395,7 +9437,7 @@ hmac-drbg@^1.0.1:
minimalistic-assert "^1.0.0" minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1" minimalistic-crypto-utils "^1.0.1"
hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0: hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0:
version "3.3.2" version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
@ -11268,7 +11310,7 @@ lodash.uniq@4.5.0, lodash.uniq@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
lodash@4.17.21, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.7.0: lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.7.0:
version "4.17.21" version "4.17.21"
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@ -13266,7 +13308,7 @@ postcss-unique-selectors@^5.1.1:
dependencies: dependencies:
postcss-selector-parser "^6.0.5" postcss-selector-parser "^6.0.5"
postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
version "4.2.0" version "4.2.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
@ -15836,6 +15878,22 @@ style-to-object@0.3.0, style-to-object@^0.3.0:
dependencies: dependencies:
inline-style-parser "0.1.1" inline-style-parser "0.1.1"
styled-components@^5.3.5:
version "5.3.5"
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.3.5.tgz#a750a398d01f1ca73af16a241dec3da6deae5ec4"
integrity sha512-ndETJ9RKaaL6q41B69WudeqLzOpY1A/ET/glXkNZ2T7dPjPqpPCXXQjDFYZWwNnE5co0wX+gTCqx9mfxTmSIPg==
dependencies:
"@babel/helper-module-imports" "^7.0.0"
"@babel/traverse" "^7.4.5"
"@emotion/is-prop-valid" "^1.1.0"
"@emotion/stylis" "^0.8.4"
"@emotion/unitless" "^0.7.4"
babel-plugin-styled-components ">= 1.12.0"
css-to-react-native "^3.0.0"
hoist-non-react-statics "^3.0.0"
shallowequal "^1.1.0"
supports-color "^5.5.0"
stylehacks@^5.1.0: stylehacks@^5.1.0:
version "5.1.0" version "5.1.0"
resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.0.tgz#a40066490ca0caca04e96c6b02153ddc39913520" resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.0.tgz#a40066490ca0caca04e96c6b02153ddc39913520"
@ -15849,7 +15907,7 @@ supports-color@^2.0.0:
resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
supports-color@^5.3.0: supports-color@^5.3.0, supports-color@^5.5.0:
version "5.5.0" version "5.5.0"
resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz"
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==