diff --git a/packages/components/src/components/DistributionChart.tsx b/packages/components/src/components/DistributionChart.tsx index 6bef36c7..4fe063a5 100644 --- a/packages/components/src/components/DistributionChart.tsx +++ b/packages/components/src/components/DistributionChart.tsx @@ -1,16 +1,16 @@ 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 { distributionErrorToString, result, shape } from "@quri/squiggle-lang"; +import { Vega, VisualizationSpec } from "react-vega"; import * as chartSpecification from "../vega-specs/spec-distributions.json"; import { ErrorBox } from "./ErrorBox"; -import styled from "styled-components"; - -let SquiggleVegaChart = createClassFromSpec({ - spec: chartSpecification as Spec, -}); +import { + linearXScale, + logXScale, + linearYScale, + expYScale, +} from "./DistributionVegaScales"; type DistributionChartProps = { distribution: Distribution; @@ -23,17 +23,30 @@ export const DistributionChart: React.FC = ({ width, height, }: DistributionChartProps) => { + let [isLogX, setLogX] = React.useState(false); + let [isExpY, setExpY] = React.useState(false); let shape = distribution.pointSet(); if (shape.tag === "Ok") { - let widthProp = width ? width - 20 : undefined; - var result = ( - - ); + let spec = buildSpec(isLogX, isExpY, shape.value); + if (spec.tag == "Ok") { + let widthProp = width ? width - 20 : undefined; + var result = ( +
+ +
+ ); + } else { + // Log scales don't work when you have points below 0 + var result = ( + {spec.value.error} + ); + } } else { var result = ( @@ -41,5 +54,55 @@ export const DistributionChart: React.FC = ({ ); } - return result; + return ( + <> + {result} +
+ + +
+ + ); +}; + +type ViewError = { heading: string; error: string }; + +function buildSpec( + isLogX: boolean, + isExpY: boolean, + shape: shape +): result { + let someBelow0 = + shape.continuous.some((x) => x.x <= 0) || + shape.discrete.some((x) => x.x <= 0); + if (!(isLogX && someBelow0)) { + return { + tag: "Ok", + value: { + ...chartSpecification, + scales: [ + isLogX ? logXScale : linearXScale, + isExpY ? expYScale : linearYScale, + ], + } as VisualizationSpec, + }; + } else { + return { + tag: "Error", + value: { + heading: "Log Viewing error", + error: + "Distribution contains values lower than or equal to 0. Cannot view", + }, + }; + } +} + +export const CheckBox = ({ label, onChange, value }) => { + return ( + + onChange(!value)} /> + + + ); }; 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..7140cbc7 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,