diff --git a/packages/components/src/components/DistributionChart.tsx b/packages/components/src/components/DistributionChart.tsx index 4ff4d9fd..f43b642c 100644 --- a/packages/components/src/components/DistributionChart.tsx +++ b/packages/components/src/components/DistributionChart.tsx @@ -1,16 +1,18 @@ import * as React from "react"; import _ from "lodash"; -import type { Spec } from "vega"; import type { Distribution } from "@quri/squiggle-lang"; import { distributionErrorToString } from "@quri/squiggle-lang"; -import { createClassFromSpec } from "react-vega"; +import { Vega, VisualizationSpec } from "react-vega"; import * as chartSpecification from "../vega-specs/spec-distributions.json"; import { ErrorBox } from "./ErrorBox"; import { useSize } from "react-use"; - -let SquiggleVegaChart = createClassFromSpec({ - spec: chartSpecification as Spec, -}); +import { + linearXScale, + logXScale, + linearYScale, + expYScale, +} from "./DistributionVegaScales"; +import styled from "styled-components"; type DistributionChartProps = { distribution: Distribution; @@ -23,13 +25,24 @@ export const DistributionChart: React.FC = ({ height, width, }: DistributionChartProps) => { + let [isLogX, setLogX] = React.useState(false); + let [isExpY, setExpY] = React.useState(false); + let shape = distribution.pointSet(); const [sized, _] = useSize((size) => { - let shape = distribution.pointSet(); - let widthProp = width !== undefined ? width - 20 : size.width - 10; + var disableLog = false; if (shape.tag === "Ok") { - return ( + let massBelow0 = + shape.value.continuous.some((x) => x.x <= 0) || + shape.value.discrete.some((x) => x.x <= 0); + if (massBelow0) { + disableLog = true; + } + let spec = buildVegaSpec(isLogX, isExpY); + let widthProp = width ? width - 20 : size.width - 10; + var result = (
- = ({
); } else { - return ( -
- - {distributionErrorToString(shape.value)} - -
+ var result = ( + + {distributionErrorToString(shape.value)} + ); } + return ( + <> + {result} +
+ {disableLog ? ( + + ) : ( + + )} + +
+ + ); }); return sized; }; + +function buildVegaSpec(isLogX: boolean, isExpY: boolean): VisualizationSpec { + return { + ...chartSpecification, + scales: [ + isLogX ? logXScale : linearXScale, + isExpY ? expYScale : linearYScale, + ], + } as VisualizationSpec; +} + +interface CheckBoxProps { + label: string; + onChange: (x: boolean) => void; + value: boolean; + disabled?: boolean; + tooltip?: string; +} + +const Label = styled.label<{ disabled: boolean }>` + ${(props) => props.disabled && "color: #999;"} +`; + +export const CheckBox = ({ + label, + onChange, + value, + disabled = false, + tooltip, +}: CheckBoxProps) => { + return ( + + onChange(!value)} + disabled={disabled} + /> + + + ); +}; diff --git a/packages/components/src/components/DistributionVegaScales.ts b/packages/components/src/components/DistributionVegaScales.ts new file mode 100644 index 00000000..f0c5c8f6 --- /dev/null +++ b/packages/components/src/components/DistributionVegaScales.ts @@ -0,0 +1,80 @@ +import type { LogScale, LinearScale, PowScale } from "vega"; +export let linearXScale: LinearScale = { + name: "xscale", + type: "linear", + range: "width", + zero: false, + nice: false, + domain: { + fields: [ + { + data: "con", + field: "x", + }, + { + data: "dis", + field: "x", + }, + ], + }, +}; +export let linearYScale: LinearScale = { + name: "yscale", + type: "linear", + range: "height", + zero: true, + domain: { + fields: [ + { + data: "con", + field: "y", + }, + { + data: "dis", + field: "y", + }, + ], + }, +}; + +export let logXScale: LogScale = { + name: "xscale", + type: "log", + range: "width", + zero: false, + base: 10, + nice: false, + domain: { + fields: [ + { + data: "con", + field: "x", + }, + { + data: "dis", + field: "x", + }, + ], + }, +}; + +export let expYScale: PowScale = { + name: "yscale", + type: "pow", + exponent: 0.1, + range: "height", + zero: true, + nice: false, + domain: { + fields: [ + { + data: "con", + field: "y", + }, + { + data: "dis", + field: "y", + }, + ], + }, +}; diff --git a/packages/components/src/vega-specs/spec-distributions.json b/packages/components/src/vega-specs/spec-distributions.json index 5b6ed261..5ca9576f 100644 --- a/packages/components/src/vega-specs/spec-distributions.json +++ b/packages/components/src/vega-specs/spec-distributions.json @@ -3,7 +3,6 @@ "description": "A basic area chart example", "width": 500, "height": 100, - "autosize": "fit", "padding": 5, "data": [ { @@ -13,72 +12,8 @@ "name": "dis" } ], - "signals": [ - { - "name": "xscale", - "description": "The transform of the x scale", - "value": false, - "bind": { - "input": "checkbox", - "name": "log x scale" - } - }, - { - "name": "yscale", - "description": "The transform of the y scale", - "value": false, - "bind": { - "input": "checkbox", - "name": "log y scale" - } - } - ], - "scales": [ - { - "name": "xscale", - "type": "pow", - "exponent": { - "signal": "xscale ? 0.1 : 1" - }, - "range": "width", - "zero": false, - "nice": false, - "domain": { - "fields": [ - { - "data": "con", - "field": "x" - }, - { - "data": "dis", - "field": "x" - } - ] - } - }, - { - "name": "yscale", - "type": "pow", - "exponent": { - "signal": "yscale ? 0.1 : 1" - }, - "range": "height", - "nice": true, - "zero": true, - "domain": { - "fields": [ - { - "data": "con", - "field": "y" - }, - { - "data": "dis", - "field": "y" - } - ] - } - } - ], + "signals": [], + "scales": [], "axes": [ { "orient": "bottom", diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index ce4d9428..c884164a 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -11,6 +11,7 @@ export { makeSampleSetDist, errorValueToString, distributionErrorToString, + distributionError, } from "../rescript/TypescriptInterface.gen"; export type { samplingParams, @@ -26,9 +27,9 @@ import { convertRawToTypescript, } from "./rescript_interop"; import { result, resultMap, tag, tagged } from "./types"; -import { Distribution } from "./distribution"; +import { Distribution, shape } from "./distribution"; -export { Distribution, squiggleExpression, result, resultMap }; +export { Distribution, squiggleExpression, result, resultMap, shape }; export let defaultSamplingInputs: samplingParams = { sampleCount: 10000,