diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json index 29cfd882..0bc426ce 100644 --- a/packages/components/package-lock.json +++ b/packages/components/package-lock.json @@ -12,10 +12,12 @@ "@testing-library/react": "^12.1.2", "@testing-library/user-event": "^13.5.0", "@types/jest": "^27.4.0", + "@types/lodash": "^4.14.178", "@types/node": "^17.0.16", "@types/react": "^17.0.39", "@types/react-dom": "^17.0.11", "cross-env": "^7.0.3", + "lodash": "^4.17.21", "react": "^17.0.2", "react-dom": "^17.0.2", "react-scripts": "5.0.0", @@ -11544,6 +11546,11 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" }, + "node_modules/@types/lodash": { + "version": "4.14.178", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz", + "integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==" + }, "node_modules/@types/mdast": { "version": "3.0.10", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", @@ -40916,6 +40923,11 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" }, + "@types/lodash": { + "version": "4.14.178", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz", + "integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==" + }, "@types/mdast": { "version": "3.0.10", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", diff --git a/packages/components/package.json b/packages/components/package.json index f37db2fd..fb779556 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -8,10 +8,12 @@ "@testing-library/react": "^12.1.2", "@testing-library/user-event": "^13.5.0", "@types/jest": "^27.4.0", + "@types/lodash": "^4.14.178", "@types/node": "^17.0.16", "@types/react": "^17.0.39", "@types/react-dom": "^17.0.11", "cross-env": "^7.0.3", + "lodash": "^4.17.21", "react": "^17.0.2", "react-dom": "^17.0.2", "react-scripts": "5.0.0", diff --git a/packages/components/src/stories/SquiggleChart.tsx b/packages/components/src/stories/SquiggleChart.tsx index cc8f7c7a..4b3c7f11 100644 --- a/packages/components/src/stories/SquiggleChart.tsx +++ b/packages/components/src/stories/SquiggleChart.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import * as PropTypes from 'prop-types'; +import * as _ from 'lodash'; import './button.css'; import type { LinearScale, Spec } from 'vega'; import { run } from '@squiggle/squiggle-lang'; @@ -11,16 +12,24 @@ let scales : LinearScale[] = [{ "range": "width", "zero": false, "nice": false, - "domain": - {"data": "table", "field": "x"} + "domain": { + "fields": [ + { "data": "con", "field": "x"}, + { "data": "dis", "field": "x"} + ] + } }, { "name": "yscale", "type": "linear", "range": "height", "nice": true, "zero": true, - "domain": - {"data": "table", "field": "y"} + "domain": { + "fields": [ + { "data": "con", "field": "y"}, + { "data": "dis", "field": "y"} + ] + } } ] @@ -31,7 +40,7 @@ let specification : Spec = { "width": 500, "height": 200, "padding": 5, - "data": [{"name": "table"}], + "data": [{"name": "con"}, {"name": "dis"}], "signals": [ { @@ -52,7 +61,7 @@ let specification : Spec = { "marks": [ { "type": "area", - "from": {"data": "table"}, + "from": {"data": "con"}, "encode": { "enter": { "x": {"scale": "xscale", "field": "x"}, @@ -68,22 +77,37 @@ let specification : Spec = { "fillOpacity": {"value": 1} } } + }, + { + "type": "rect", + "from": {"data": "dis"}, + "encode": { + "enter": { + "x": {"scale": "xscale", "field": "x"}, + "y": {"scale": "yscale", "field": "y"}, + "y2": {"scale": "yscale", "value": 0}, + "width": {"value": 1} + } + } + }, + { + "type": "symbol", + "from": {"data": "dis"}, + "encode": { + "enter": { + "shape": {"value": "circle"}, + "x": {"scale": "xscale", "field": "x"}, + "y": {"scale": "yscale", "field": "y"}, + "width": {"value": 5}, + "tooltip": {"signal": "datum.y"}, + } + } } ] }; let SquiggleVegaChart = createClassFromSpec({'spec': specification}); -function zip(a: Array, b: Array): Array>{ - return a.map(function(e, i) { - return [e, b[i]]; - }) -} -function zip3(a: Array, b: Array, c: Array): Array>{ - return a.map(function(e, i) { - return [e, b[i], c[i]]; - }) -} /** * Primary UI component for user interaction */ @@ -106,11 +130,11 @@ export const SquiggleChart = ({ squiggleString }: { squiggleString: string}) => return total / totalY; }) console.log(cdf) - let values = zip3(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 ( ); } @@ -122,23 +146,63 @@ export const SquiggleChart = ({ squiggleString }: { squiggleString: string}) => total += y; return total / totalY; }) - let values = zip3(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 ( ); } else if(shape.tag === "Mixed"){ - console.log(shape.value.integralSumCache) - console.log(shape.value.integralCache) - let xyShape = shape.value.continuous.xyShape; - let values = zip(xyShape.xs, xyShape.ys).map(([x,y]) => ({x: x, y: y})); + console.log(shape) + console.log(shape.value.continuous.integralSumCache) + let discreteShape = shape.value.discrete.xyShape; + let totalDiscrete = discreteShape.ys.reduce((a, b) => a + b); + + let discretePoints = _.zip(discreteShape.xs, discreteShape.ys); + let continuousShape = shape.value.continuous.xyShape; + let continuousPoints = _.zip(continuousShape.xs, continuousShape.ys); + + interface labeledPoint { + 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 sortedPoints = _.sortBy(markedDisPoints.concat(markedConPoints), 'x') + + let totalContinuous = 1 - totalDiscrete; + let totalY = continuousShape.ys.reduce((a:number, b:number) => a + b); + + let total = 0; + let cdf = sortedPoints.map((point: labeledPoint) => { + if(point.type == "discrete") { + total += point.y; + return total; + } + else if (point.type == "continuous") { + total += point.y / totalY * totalContinuous; + return total; + } + }); + + interface cdfLabeledPoint { + 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") return ( ); } diff --git a/packages/components/yarn.lock b/packages/components/yarn.lock index 59d0120a..c69ef9c0 100644 --- a/packages/components/yarn.lock +++ b/packages/components/yarn.lock @@ -3085,6 +3085,11 @@ "resolved" "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" "version" "0.0.29" +"@types/lodash@^4.14.178": + "integrity" "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==" + "resolved" "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz" + "version" "4.14.178" + "@types/mdast@^3.0.0": "integrity" "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==" "resolved" "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz"