From 7b357c41406a67e79ec76af0b513dbecced87d38 Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Sun, 12 Mar 2023 22:07:11 -0600 Subject: [PATCH 001/241] moving chromatic and stories to visyn_core --- .github/workflows/chromatic.yml | 55 ++++ src/vis/stories/Vis/Bar/BarDocs.stories.mdx | 25 ++ src/vis/stories/Vis/Bar/BarRandom.stories.tsx | 242 +++++++++++++++++ .../stories/Vis/Hexbin/HexbinDocs.stories.mdx | 24 ++ .../Vis/Hexbin/HexbinRandom.stories.tsx | 248 ++++++++++++++++++ .../Vis/Scatter/ScatterDocs.stories.mdx | 23 ++ .../Vis/Scatter/ScatterIris.stories.tsx | 198 ++++++++++++++ .../Scatter/ScatterRandom.stories.tsx} | 52 ++-- .../stories/Vis/Violin/ViolinDocs.stories.mdx | 19 ++ .../Violin/ViolinIris.stories.tsx} | 59 ++--- src/vis/stories/fetchIrisData.tsx | 52 ++++ 11 files changed, 925 insertions(+), 72 deletions(-) create mode 100644 .github/workflows/chromatic.yml create mode 100644 src/vis/stories/Vis/Bar/BarDocs.stories.mdx create mode 100644 src/vis/stories/Vis/Bar/BarRandom.stories.tsx create mode 100644 src/vis/stories/Vis/Hexbin/HexbinDocs.stories.mdx create mode 100644 src/vis/stories/Vis/Hexbin/HexbinRandom.stories.tsx create mode 100644 src/vis/stories/Vis/Scatter/ScatterDocs.stories.mdx create mode 100644 src/vis/stories/Vis/Scatter/ScatterIris.stories.tsx rename src/vis/stories/{Random.stories.tsx => Vis/Scatter/ScatterRandom.stories.tsx} (78%) create mode 100644 src/vis/stories/Vis/Violin/ViolinDocs.stories.mdx rename src/vis/stories/{Iris.stories.tsx => Vis/Violin/ViolinIris.stories.tsx} (74%) create mode 100644 src/vis/stories/fetchIrisData.tsx diff --git a/.github/workflows/chromatic.yml b/.github/workflows/chromatic.yml new file mode 100644 index 000000000..1021cfc10 --- /dev/null +++ b/.github/workflows/chromatic.yml @@ -0,0 +1,55 @@ +# .github/workflows/chromatic.yml + +# Workflow name +name: 'Chromatic' + +# Event for the workflow +on: + pull_request: + branches: + - develop + +# List of jobs +jobs: + chromatic-deployment: + name: 'Chromatic Deployment' + # Operating System + runs-on: ubuntu-latest + # Job steps + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 # 👈 Required to retrieve git history + + - name: Setup LTS Node + uses: actions/setup-node@v3 + with: + node-version: 'lts/*' + cache: 'yarn' + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT + + - name: Cache yarn dependencies + uses: actions/cache@v3 + id: yarn-cache + with: + path: | + ${{ steps.yarn-cache-dir-path.outputs.dir }} + **\node_modules + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + - name: Install dependencies + if: steps.yarn-cache.outputs.cache-hit != 'true' + run: yarn install + + # 👇 Adds Chromatic as a step in the workflow + - name: Publish to Chromatic + uses: chromaui/action@v1 + # Chromatic GitHub Action options + with: + # 👇 Chromatic projectToken, refer to the manage page to obtain it. + projectToken: 99ef83e5432c diff --git a/src/vis/stories/Vis/Bar/BarDocs.stories.mdx b/src/vis/stories/Vis/Bar/BarDocs.stories.mdx new file mode 100644 index 000000000..1894d4967 --- /dev/null +++ b/src/vis/stories/Vis/Bar/BarDocs.stories.mdx @@ -0,0 +1,25 @@ + + +import { Meta, Story } from '@storybook/addon-docs/blocks'; +import { Vis } from '../../../LazyVis'; + + + + +### Config props + +| Name | Type | Description | +|--- |--- |--- | +| type | 'Bar chart' | | +| multiples | ColumnInfo | Column used for small multiples. Cannot be the same as catColumnSelected | +| group | ColumnInfo | Column used to group the bar chart. Cannot be the same as catColumnSelected | +| catColumnSelected | ColumnInfo | Main column used for the bar chart. | +| groupType | 'Stacked' \| 'Grouped' | If a group column is given, determines whether the group column is displayed with a stacked bar chart or a grouped bar chart. | +| display | 'Absolute' \| 'Normalized' | If group column is given, and groupType is 'Stacked', determines whether the resulting bar chart is normalized. | +| direction | 'Vertical' \| 'Horizontal' | Direction of the bar chart. | +| aggregateType | 'Count' \| 'Minimum' \| 'Average' \| 'Median' \| 'Maximum' | Aggregate type used on the catColumnSelected. If anything other than 'Count' is used, must also define an aggregateColumn| +| aggregateColumn | ColumnInfo | Column used for aggregate types other than 'Count' | + diff --git a/src/vis/stories/Vis/Bar/BarRandom.stories.tsx b/src/vis/stories/Vis/Bar/BarRandom.stories.tsx new file mode 100644 index 000000000..f9e9ed891 --- /dev/null +++ b/src/vis/stories/Vis/Bar/BarRandom.stories.tsx @@ -0,0 +1,242 @@ +import React from 'react'; +import { ComponentStory, ComponentMeta, Meta } from '@storybook/react'; +import { Vis } from '../../../LazyVis'; +import { + EAggregateTypes, + EBarDirection, + EBarDisplayType, + EBarGroupingType, + EColumnTypes, + EHexbinOptions, + ENumericalColorScaleType, + EScatterSelectSettings, + ESupportedPlotlyVis, + EViolinOverlay, + VisColumn, +} from '../../../interfaces'; + +function fetchData(numberOfPoints: number): VisColumn[] { + const dataGetter = async () => ({ + value: Array(numberOfPoints) + .fill(null) + .map(() => Math.random() * 100), + pca_x: Array(numberOfPoints) + .fill(null) + .map(() => Math.random() * 100), + pca_y: Array(numberOfPoints) + .fill(null) + .map(() => Math.random() * 100), + category: Array(numberOfPoints) + .fill(null) + .map(() => parseInt((Math.random() * 10).toString(), 10).toString()), + category2: Array(numberOfPoints) + .fill(null) + .map(() => parseInt((Math.random() * 5).toString(), 5).toString()), + category3: Array(numberOfPoints) + .fill(null) + .map(() => parseInt((Math.random() * 2).toString(), 2).toString()), + }); + + const dataPromise = dataGetter(); + + return [ + { + info: { + description: '', + id: 'pca_x', + name: 'pca_x', + }, + type: EColumnTypes.NUMERICAL, + domain: [0, undefined], + values: () => dataPromise.then((data) => data.pca_x.map((val, i) => ({ id: i.toString(), val }))), + }, + { + info: { + description: '', + id: 'pca_y', + name: 'pca_y', + }, + type: EColumnTypes.NUMERICAL, + domain: [0, undefined], + values: () => dataPromise.then((data) => data.pca_y.map((val, i) => ({ id: i.toString(), val }))), + }, + { + info: { + description: '', + id: 'value', + name: 'value', + }, + domain: [0, 100], + + type: EColumnTypes.NUMERICAL, + values: () => dataPromise.then((data) => data.value.map((val, i) => ({ id: i.toString(), val }))), + }, + { + info: { + description: '', + id: 'category', + name: 'category', + }, + type: EColumnTypes.CATEGORICAL, + values: () => dataPromise.then((data) => data.category.map((val, i) => ({ id: i.toString(), val }))), + }, + { + info: { + description: '', + id: 'category2', + name: 'category2', + }, + type: EColumnTypes.CATEGORICAL, + values: () => dataPromise.then((data) => data.category2.map((val, i) => ({ id: i.toString(), val }))), + }, + { + info: { + description: '', + id: 'category3', + name: 'category3', + }, + type: EColumnTypes.CATEGORICAL, + values: () => dataPromise.then((data) => data.category3.map((val, i) => ({ id: i.toString(), val }))), + }, + ]; +} + +// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export +export default { + title: 'Vis/Bar', + component: Vis, + argTypes: { + pointCount: { control: 'number' }, + }, + args: { + pointCount: 10000, + }, +} as ComponentMeta; + +// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args +// eslint-disable-next-line react/function-component-definition +const Template: ComponentStory = (args) => { + // @ts-ignore TODO: The pointCount is an injected property, but we are using typeof Vis such that this prop does not exist. + const columns = React.useMemo(() => fetchData(args.pointCount), [args.pointCount]); + + return ( +
+
+ +
+
+ ); +}; +// More on args: https://storybook.js.org/docs/react/writing-stories/args + +export const Basic = Template.bind({}) as typeof Template; +Basic.args = { + externalConfig: { + type: ESupportedPlotlyVis.BAR, + catColumnSelected: { + description: '', + id: 'category', + name: 'category', + }, + multiples: null, + group: null, + groupType: EBarGroupingType.GROUP, + direction: EBarDirection.HORIZONTAL, + display: EBarDisplayType.ABSOLUTE, + aggregateType: EAggregateTypes.COUNT, + aggregateColumn: null, + numColumnsSelected: [], + }, +}; + +export const Vertical = Template.bind({}) as typeof Template; +Vertical.args = { + externalConfig: { + type: ESupportedPlotlyVis.BAR, + catColumnSelected: { + description: '', + id: 'category', + name: 'category', + }, + multiples: null, + group: null, + groupType: EBarGroupingType.GROUP, + direction: EBarDirection.VERTICAL, + display: EBarDisplayType.ABSOLUTE, + aggregateType: EAggregateTypes.COUNT, + aggregateColumn: null, + numColumnsSelected: [], + }, +}; + +export const Grouped = Template.bind({}) as typeof Template; +Grouped.args = { + externalConfig: { + type: ESupportedPlotlyVis.BAR, + catColumnSelected: { + description: '', + id: 'category', + name: 'category', + }, + multiples: null, + group: { + description: '', + id: 'category2', + name: 'category2', + }, + groupType: EBarGroupingType.GROUP, + direction: EBarDirection.HORIZONTAL, + display: EBarDisplayType.ABSOLUTE, + aggregateType: EAggregateTypes.COUNT, + aggregateColumn: null, + numColumnsSelected: [], + }, +}; + +export const Multiples = Template.bind({}) as typeof Template; +Multiples.args = { + externalConfig: { + type: ESupportedPlotlyVis.BAR, + catColumnSelected: { + description: '', + id: 'category', + name: 'category', + }, + multiples: { + description: '', + id: 'category2', + name: 'category2', + }, + group: null, + groupType: EBarGroupingType.GROUP, + direction: EBarDirection.HORIZONTAL, + display: EBarDisplayType.ABSOLUTE, + aggregateType: EAggregateTypes.COUNT, + aggregateColumn: null, + numColumnsSelected: [], + }, +}; + +export const AggregateAverage = Template.bind({}) as typeof Template; +AggregateAverage.args = { + externalConfig: { + type: ESupportedPlotlyVis.BAR, + catColumnSelected: { + description: '', + id: 'category', + name: 'category', + }, + multiples: null, + group: null, + groupType: EBarGroupingType.GROUP, + direction: EBarDirection.HORIZONTAL, + display: EBarDisplayType.ABSOLUTE, + aggregateType: EAggregateTypes.AVG, + aggregateColumn: { + description: '', + id: 'value', + name: 'value', + }, + numColumnsSelected: [], + }, +}; diff --git a/src/vis/stories/Vis/Hexbin/HexbinDocs.stories.mdx b/src/vis/stories/Vis/Hexbin/HexbinDocs.stories.mdx new file mode 100644 index 000000000..34be421cc --- /dev/null +++ b/src/vis/stories/Vis/Hexbin/HexbinDocs.stories.mdx @@ -0,0 +1,24 @@ + + +import { Meta, Story } from '@storybook/addon-docs/blocks'; +import { Vis } from '../../../LazyVis'; + + + + +### Config props + +| Name | Type | Description | +|--- |--- |--- | +| type | 'Hexbin plot' | | +| numColumnsSelected | ColumnInfo [ ] | List of selected columns. If more than two, columns will be shown in a small multiples grid. | +| color | ColumnInfo | Column used as the color scale. Must be a categorical column. | +| hexRadius | number | Maximum size of each hex. | +| isOpacityScale | boolean | Whether or not hexes opacity is used as a scale. | +| isSizeScale | boolean | Whether or not hexes size is used as a scale. | +| dragMode | 'select' \| 'lasso' \| 'zoom' \| 'pan' | | +| hexbinOptions | 'Color' \| 'Pie' \| 'Bins' | If a color is selected, decides how the color column is displayed. | + diff --git a/src/vis/stories/Vis/Hexbin/HexbinRandom.stories.tsx b/src/vis/stories/Vis/Hexbin/HexbinRandom.stories.tsx new file mode 100644 index 000000000..f86185677 --- /dev/null +++ b/src/vis/stories/Vis/Hexbin/HexbinRandom.stories.tsx @@ -0,0 +1,248 @@ +import React from 'react'; +import { ComponentStory, ComponentMeta, Meta } from '@storybook/react'; +import { Vis } from '../../../LazyVis'; +import { + EAggregateTypes, + EBarDirection, + EBarDisplayType, + EBarGroupingType, + EColumnTypes, + EHexbinOptions, + ENumericalColorScaleType, + EScatterSelectSettings, + ESupportedPlotlyVis, + EViolinOverlay, + VisColumn, +} from '../../../interfaces'; + +function fetchData(numberOfPoints: number): VisColumn[] { + const dataGetter = async () => ({ + value: Array(numberOfPoints) + .fill(null) + .map(() => Math.random() * 100), + pca_x: Array(numberOfPoints) + .fill(null) + .map(() => Math.random() * 100), + pca_y: Array(numberOfPoints) + .fill(null) + .map(() => Math.random() * 100), + category: Array(numberOfPoints) + .fill(null) + .map(() => parseInt((Math.random() * 10).toString(), 10).toString()), + }); + + const dataPromise = dataGetter(); + + return [ + { + info: { + description: '', + id: 'pca_x', + name: 'pca_x', + }, + type: EColumnTypes.NUMERICAL, + domain: [0, undefined], + values: () => dataPromise.then((data) => data.pca_x.map((val, i) => ({ id: i.toString(), val }))), + }, + { + info: { + description: '', + id: 'pca_y', + name: 'pca_y', + }, + type: EColumnTypes.NUMERICAL, + domain: [0, undefined], + values: () => dataPromise.then((data) => data.pca_y.map((val, i) => ({ id: i.toString(), val }))), + }, + { + info: { + description: '', + id: 'value', + name: 'value', + }, + domain: [0, 100], + + type: EColumnTypes.NUMERICAL, + values: () => dataPromise.then((data) => data.value.map((val, i) => ({ id: i.toString(), val }))), + }, + { + info: { + description: '', + id: 'category', + name: 'category', + }, + type: EColumnTypes.CATEGORICAL, + values: () => dataPromise.then((data) => data.category.map((val, i) => ({ id: i.toString(), val }))), + }, + ]; +} + +// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export +export default { + title: 'Vis/Hexbin', + component: Vis, + argTypes: { + pointCount: { control: 'number' }, + }, + args: { + pointCount: 10000, + }, +} as ComponentMeta; + +// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args +// eslint-disable-next-line react/function-component-definition +const Template: ComponentStory = (args) => { + // @ts-ignore TODO: The pointCount is an injected property, but we are using typeof Vis such that this prop does not exist. + const columns = React.useMemo(() => fetchData(args.pointCount), [args.pointCount]); + + return ( +
+
+ +
+
+ ); +}; +// More on args: https://storybook.js.org/docs/react/writing-stories/args + +export const LargeData = Template.bind({}) as typeof Template; +LargeData.args = { + externalConfig: { + type: ESupportedPlotlyVis.HEXBIN, + numColumnsSelected: [ + { + description: '', + id: 'pca_x', + name: 'pca_x', + }, + { + description: '', + id: 'pca_y', + name: 'pca_y', + }, + ], + color: null, + dragMode: EScatterSelectSettings.RECTANGLE, + hexRadius: 20, + isOpacityScale: true, + isSizeScale: false, + hexbinOptions: EHexbinOptions.COLOR, + }, +}; + +export const LargeDataMultiples = Template.bind({}) as typeof Template; +LargeDataMultiples.args = { + externalConfig: { + type: ESupportedPlotlyVis.HEXBIN, + numColumnsSelected: [ + { + description: '', + id: 'pca_x', + name: 'pca_x', + }, + { + description: '', + id: 'pca_y', + name: 'pca_y', + }, + { + description: '', + id: 'value', + name: 'value', + }, + ], + color: null, + dragMode: EScatterSelectSettings.RECTANGLE, + hexRadius: 20, + isOpacityScale: true, + isSizeScale: false, + hexbinOptions: EHexbinOptions.COLOR, + }, +}; + +export const ColorByCategory = Template.bind({}) as typeof Template; +ColorByCategory.args = { + externalConfig: { + type: ESupportedPlotlyVis.HEXBIN, + numColumnsSelected: [ + { + description: '', + id: 'pca_x', + name: 'pca_x', + }, + { + description: '', + id: 'pca_y', + name: 'pca_y', + }, + ], + color: { + description: '', + id: 'category', + name: 'category', + }, + dragMode: EScatterSelectSettings.RECTANGLE, + hexRadius: 20, + isOpacityScale: true, + isSizeScale: false, + hexbinOptions: EHexbinOptions.COLOR, + }, +}; + +export const PieCharts = Template.bind({}) as typeof Template; +PieCharts.args = { + externalConfig: { + type: ESupportedPlotlyVis.HEXBIN, + numColumnsSelected: [ + { + description: '', + id: 'pca_x', + name: 'pca_x', + }, + { + description: '', + id: 'pca_y', + name: 'pca_y', + }, + ], + color: { + description: '', + id: 'category', + name: 'category', + }, + dragMode: EScatterSelectSettings.RECTANGLE, + hexRadius: 20, + isOpacityScale: true, + isSizeScale: false, + hexbinOptions: EHexbinOptions.PIE, + }, +}; + +export const ColorBins = Template.bind({}) as typeof Template; +ColorBins.args = { + externalConfig: { + type: ESupportedPlotlyVis.HEXBIN, + numColumnsSelected: [ + { + description: '', + id: 'pca_x', + name: 'pca_x', + }, + { + description: '', + id: 'pca_y', + name: 'pca_y', + }, + ], + color: { + description: '', + id: 'category', + name: 'category', + }, + dragMode: EScatterSelectSettings.RECTANGLE, + hexRadius: 20, + isOpacityScale: true, + isSizeScale: false, + hexbinOptions: EHexbinOptions.BINS, + }, +}; diff --git a/src/vis/stories/Vis/Scatter/ScatterDocs.stories.mdx b/src/vis/stories/Vis/Scatter/ScatterDocs.stories.mdx new file mode 100644 index 000000000..a2d5ca89f --- /dev/null +++ b/src/vis/stories/Vis/Scatter/ScatterDocs.stories.mdx @@ -0,0 +1,23 @@ + + +import { Meta, Story } from '@storybook/addon-docs/blocks'; +import { Vis } from '../../../LazyVis'; + + + + +### Config props + +| Name | Type | Description | +|--- |--- |--- | +| type | 'Scatter Plot' | column 3 | +| numColorScaleType | 'Sequential' \| 'Divergent' | Color scale type when a numerical column is selected. | +| alphaSliderVal | number | Opacity slider value | +| dragMode | 'select' \| 'lasso' \| 'zoom' \| 'pan' | | +| shape | ColumnInfo | Column used for the shape scale. Must be a categorical column. | +| numColumnsSelected | ColumnInfo [ ] | List of selected columns. If more than two, columns will be shown in a small multiples grid. | +| color | ColumnInfo | Column used for the color scale. Can be a numerical or categorical column. | + diff --git a/src/vis/stories/Vis/Scatter/ScatterIris.stories.tsx b/src/vis/stories/Vis/Scatter/ScatterIris.stories.tsx new file mode 100644 index 000000000..4a76ed523 --- /dev/null +++ b/src/vis/stories/Vis/Scatter/ScatterIris.stories.tsx @@ -0,0 +1,198 @@ +import React from 'react'; +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { Vis } from '../../../LazyVis'; +import { + EAggregateTypes, + EBarDirection, + EBarDisplayType, + EBarGroupingType, + EColumnTypes, + ENumericalColorScaleType, + EScatterSelectSettings, + ESupportedPlotlyVis, + EViolinOverlay, + VisColumn, +} from '../../../interfaces'; + +function fetchIrisData(): VisColumn[] { + const dataPromise = import('../../irisData').then((m) => m.iris); + + return [ + { + info: { + description: '', + id: 'sepalLength', + name: 'Sepal Length', + }, + type: EColumnTypes.NUMERICAL, + values: () => dataPromise.then((data) => data.map((r) => r.sepalLength).map((val, i) => ({ id: i.toString(), val }))), + }, + { + info: { + description: '', + id: 'sepalWidth', + name: 'Sepal Width', + }, + type: EColumnTypes.NUMERICAL, + values: () => dataPromise.then((data) => data.map((r) => r.sepalWidth).map((val, i) => ({ id: i.toString(), val }))), + }, + { + info: { + description: '', + id: 'petalLength', + name: 'Petal Length', + }, + type: EColumnTypes.NUMERICAL, + values: () => dataPromise.then((data) => data.map((r) => r.petalLength).map((val, i) => ({ id: i.toString(), val }))), + }, + { + info: { + description: '', + id: 'petalWidth', + name: 'Petal Width', + }, + type: EColumnTypes.NUMERICAL, + values: () => dataPromise.then((data) => data.map((r) => r.petalWidth).map((val, i) => ({ id: i.toString(), val }))), + }, + { + info: { + description: '', + id: 'species', + name: 'Species', + }, + type: EColumnTypes.CATEGORICAL, + values: () => dataPromise.then((data) => data.map((r) => r.species).map((val, i) => ({ id: i.toString(), val }))), + }, + ]; +} + +// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export +export default { + title: 'Vis/Scatter', + component: Vis, + // More on argTypes: https://storybook.js.org/docs/react/api/argtypes +} as ComponentMeta; + +// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args +// eslint-disable-next-line react/function-component-definition +const Template: ComponentStory = (args) => { + const columns = React.useMemo(() => fetchIrisData(), []); + return ( +
+
+ +
+
+ ); +}; + +// More on args: https://storybook.js.org/docs/react/writing-stories/args + +export const Basic = Template.bind({}) as typeof Template; +Basic.args = { + externalConfig: { + type: ESupportedPlotlyVis.SCATTER, + numColumnsSelected: [ + { + description: '', + id: 'sepalLength', + name: 'Sepal Length', + }, + { + description: '', + id: 'sepalWidth', + name: 'Sepal Width', + }, + ], + color: null, + numColorScaleType: ENumericalColorScaleType.SEQUENTIAL, + shape: null, + dragMode: EScatterSelectSettings.RECTANGLE, + alphaSliderVal: 1, + }, +}; + +export const ColorByCategory = Template.bind({}) as typeof Template; +ColorByCategory.args = { + externalConfig: { + type: ESupportedPlotlyVis.SCATTER, + numColumnsSelected: [ + { + description: '', + id: 'sepalLength', + name: 'Sepal Length', + }, + { + description: '', + id: 'sepalWidth', + name: 'Sepal Width', + }, + ], + color: { + description: '', + id: 'species', + name: 'Species', + }, + numColorScaleType: ENumericalColorScaleType.SEQUENTIAL, + shape: null, + dragMode: EScatterSelectSettings.RECTANGLE, + alphaSliderVal: 0.5, + }, +}; + +export const ColorByNumerical = Template.bind({}) as typeof Template; +ColorByNumerical.args = { + externalConfig: { + type: ESupportedPlotlyVis.SCATTER, + numColumnsSelected: [ + { + description: '', + id: 'sepalLength', + name: 'Sepal Length', + }, + { + description: '', + id: 'sepalWidth', + name: 'Sepal Width', + }, + ], + color: { + description: '', + id: 'petalLength', + name: 'Petal Length', + }, + numColorScaleType: ENumericalColorScaleType.SEQUENTIAL, + shape: null, + dragMode: EScatterSelectSettings.RECTANGLE, + alphaSliderVal: 0.5, + }, +}; + +export const SmallMultiples = Template.bind({}) as typeof Template; +SmallMultiples.args = { + externalConfig: { + type: ESupportedPlotlyVis.SCATTER, + numColumnsSelected: [ + { + description: '', + id: 'sepalLength', + name: 'Sepal Length', + }, + { + description: '', + id: 'sepalWidth', + name: 'Sepal Width', + }, + { + description: '', + id: 'petalLength', + name: 'Petal Length', + }, + ], + color: null, + numColorScaleType: ENumericalColorScaleType.SEQUENTIAL, + shape: null, + dragMode: EScatterSelectSettings.RECTANGLE, + alphaSliderVal: 0.5, + }, +}; diff --git a/src/vis/stories/Random.stories.tsx b/src/vis/stories/Vis/Scatter/ScatterRandom.stories.tsx similarity index 78% rename from src/vis/stories/Random.stories.tsx rename to src/vis/stories/Vis/Scatter/ScatterRandom.stories.tsx index da24d67d1..4e9ee3385 100644 --- a/src/vis/stories/Random.stories.tsx +++ b/src/vis/stories/Vis/Scatter/ScatterRandom.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; -import { Vis } from '../LazyVis'; +import { ComponentStory, ComponentMeta, Meta } from '@storybook/react'; +import { Vis } from '../../../LazyVis'; import { EAggregateTypes, EBarDirection, @@ -12,7 +12,7 @@ import { ESupportedPlotlyVis, EViolinOverlay, VisColumn, -} from '../interfaces'; +} from '../../../interfaces'; function fetchData(numberOfPoints: number): VisColumn[] { const dataGetter = async () => ({ @@ -78,7 +78,7 @@ function fetchData(numberOfPoints: number): VisColumn[] { // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export export default { - title: 'Example/Vis/RandomData', + title: 'Vis/Scatter', component: Vis, argTypes: { pointCount: { control: 'number' }, @@ -104,8 +104,8 @@ const Template: ComponentStory = (args) => { }; // More on args: https://storybook.js.org/docs/react/writing-stories/args -export const ScatterPlot = Template.bind({}) as typeof Template; -ScatterPlot.args = { +export const LargeData = Template.bind({}) as typeof Template; +LargeData.args = { externalConfig: { type: ESupportedPlotlyVis.SCATTER, numColumnsSelected: [ @@ -124,34 +124,14 @@ ScatterPlot.args = { numColorScaleType: ENumericalColorScaleType.SEQUENTIAL, shape: null, dragMode: EScatterSelectSettings.RECTANGLE, - alphaSliderVal: 1, + alphaSliderVal: 0.2, }, }; -export const BarChart = Template.bind({}) as typeof Template; -BarChart.args = { +export const LargeDataMuliples = Template.bind({}) as typeof Template; +LargeDataMuliples.args = { externalConfig: { - type: ESupportedPlotlyVis.BAR, - multiples: null, - group: null, - direction: EBarDirection.VERTICAL, - display: EBarDisplayType.ABSOLUTE, - groupType: EBarGroupingType.GROUP, - numColumnsSelected: [], - catColumnSelected: { - description: '', - id: 'category', - name: 'category', - }, - aggregateColumn: null, - aggregateType: EAggregateTypes.COUNT, - }, -}; - -export const ViolinPlot = Template.bind({}) as typeof Template; -ViolinPlot.args = { - externalConfig: { - type: ESupportedPlotlyVis.VIOLIN, + type: ESupportedPlotlyVis.SCATTER, numColumnsSelected: [ { description: '', @@ -163,8 +143,16 @@ ViolinPlot.args = { id: 'pca_y', name: 'pca_y', }, + { + description: '', + id: 'value', + name: 'value', + }, ], - catColumnsSelected: [], - violinOverlay: EViolinOverlay.NONE, + color: null, + numColorScaleType: ENumericalColorScaleType.SEQUENTIAL, + shape: null, + dragMode: EScatterSelectSettings.RECTANGLE, + alphaSliderVal: 0.2, }, }; diff --git a/src/vis/stories/Vis/Violin/ViolinDocs.stories.mdx b/src/vis/stories/Vis/Violin/ViolinDocs.stories.mdx new file mode 100644 index 000000000..07ca8ec43 --- /dev/null +++ b/src/vis/stories/Vis/Violin/ViolinDocs.stories.mdx @@ -0,0 +1,19 @@ + + +import { Meta, Story } from '@storybook/addon-docs/blocks'; +import { Vis } from '../../../LazyVis'; + + + + +### Config props + +| Name | Type | Description | +|--- |--- |--- | +| type | 'Violin plot' | | +| numColumnsSelected | ColumnInfo [ ] | List of selected numerical columns. Each numerical column is displayed on its own row | +| catColumnsSelected | ColumnInfo [ ] | List of selected categorical columns. Each categorical column is displayed as a column on each row. | +| violinOverlay | 'None' \| 'Box' | Overlay type displayed in addition to violin. | diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Vis/Violin/ViolinIris.stories.tsx similarity index 74% rename from src/vis/stories/Iris.stories.tsx rename to src/vis/stories/Vis/Violin/ViolinIris.stories.tsx index e5fbd43ab..db962a7d8 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Vis/Violin/ViolinIris.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { ComponentStory, ComponentMeta } from '@storybook/react'; -import { Vis } from '../LazyVis'; +import { Vis } from '../../../LazyVis'; import { EAggregateTypes, EBarDirection, @@ -12,10 +12,10 @@ import { ESupportedPlotlyVis, EViolinOverlay, VisColumn, -} from '../interfaces'; +} from '../../../interfaces'; -export function fetchIrisData(): VisColumn[] { - const dataPromise = import('./irisData.js').then((m) => m.iris); +function fetchIrisData(): VisColumn[] { + const dataPromise = import('../../irisData').then((m) => m.iris); return [ { @@ -68,7 +68,7 @@ export function fetchIrisData(): VisColumn[] { // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export export default { - title: 'Example/Vis/IrisData', + title: 'Vis/Violin', component: Vis, // More on argTypes: https://storybook.js.org/docs/react/api/argtypes } as ComponentMeta; @@ -88,10 +88,10 @@ const Template: ComponentStory = (args) => { // More on args: https://storybook.js.org/docs/react/writing-stories/args -export const ScatterPlot = Template.bind({}) as typeof Template; -ScatterPlot.args = { +export const Basic = Template.bind({}) as typeof Template; +Basic.args = { externalConfig: { - type: ESupportedPlotlyVis.SCATTER, + type: ESupportedPlotlyVis.VIOLIN, numColumnsSelected: [ { description: '', @@ -104,40 +104,19 @@ ScatterPlot.args = { name: 'Sepal Width', }, ], - color: { - description: '', - id: 'species', - name: 'Species', - }, - numColorScaleType: ENumericalColorScaleType.SEQUENTIAL, - shape: null, - dragMode: EScatterSelectSettings.RECTANGLE, - alphaSliderVal: 1, - }, -}; - -export const BarChart = Template.bind({}) as typeof Template; -BarChart.args = { - externalConfig: { - type: ESupportedPlotlyVis.BAR, - multiples: null, - group: null, - direction: EBarDirection.VERTICAL, - display: EBarDisplayType.ABSOLUTE, - groupType: EBarGroupingType.GROUP, - numColumnsSelected: [], - catColumnSelected: { - description: '', - id: 'species', - name: 'Species', - }, - aggregateColumn: null, - aggregateType: EAggregateTypes.COUNT, + catColumnsSelected: [ + { + description: '', + id: 'species', + name: 'Species', + }, + ], + violinOverlay: EViolinOverlay.NONE, }, }; -export const ViolinPlot = Template.bind({}) as typeof Template; -ViolinPlot.args = { +export const BoxplotOverlay = Template.bind({}) as typeof Template; +BoxplotOverlay.args = { externalConfig: { type: ESupportedPlotlyVis.VIOLIN, numColumnsSelected: [ @@ -159,6 +138,6 @@ ViolinPlot.args = { name: 'Species', }, ], - violinOverlay: EViolinOverlay.NONE, + violinOverlay: EViolinOverlay.BOX, }, }; diff --git a/src/vis/stories/fetchIrisData.tsx b/src/vis/stories/fetchIrisData.tsx new file mode 100644 index 000000000..9f1681b5d --- /dev/null +++ b/src/vis/stories/fetchIrisData.tsx @@ -0,0 +1,52 @@ +import { EColumnTypes, VisColumn } from '../interfaces'; +import { iris as dataPromise } from './irisData'; + +export function fetchIrisData(): VisColumn[] { + return [ + { + info: { + description: '', + id: 'sepalLength', + name: 'Sepal Length', + }, + type: EColumnTypes.NUMERICAL, + values: () => dataPromise.map((r) => r.sepalLength).map((val, i) => ({ id: i.toString(), val })), + }, + { + info: { + description: '', + id: 'sepalWidth', + name: 'Sepal Width', + }, + type: EColumnTypes.NUMERICAL, + values: () => dataPromise.map((r) => r.sepalWidth).map((val, i) => ({ id: i.toString(), val })), + }, + { + info: { + description: '', + id: 'petalLength', + name: 'Petal Length', + }, + type: EColumnTypes.NUMERICAL, + values: () => dataPromise.map((r) => r.petalLength).map((val, i) => ({ id: i.toString(), val })), + }, + { + info: { + description: '', + id: 'petalWidth', + name: 'Petal Width', + }, + type: EColumnTypes.NUMERICAL, + values: () => dataPromise.map((r) => r.petalWidth).map((val, i) => ({ id: i.toString(), val })), + }, + { + info: { + description: '', + id: 'species', + name: 'Species', + }, + type: EColumnTypes.CATEGORICAL, + values: () => dataPromise.map((r) => r.species).map((val, i) => ({ id: i.toString(), val })), + }, + ]; +} From c28e91e5cafc918ba99881df29f6544956eb8910 Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Mon, 13 Mar 2023 00:09:59 -0600 Subject: [PATCH 002/241] fixing import issue --- src/demo/MainApp.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/demo/MainApp.tsx b/src/demo/MainApp.tsx index 474444795..242a93562 100644 --- a/src/demo/MainApp.tsx +++ b/src/demo/MainApp.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { Menu, SimpleGrid } from '@mantine/core'; import { Vis, ESupportedPlotlyVis, ENumericalColorScaleType, EScatterSelectSettings, IVisConfig } from '../vis'; -import { fetchIrisData } from '../vis/stories/Iris.stories'; +import { fetchIrisData } from '../vis/stories/fetchIrisData'; import { iris } from '../vis/stories/irisData'; import { useVisynAppContext, VisynApp, VisynHeader } from '../app'; import { LoginUtils } from '../security'; From 138110dcec0ae631d5cd8be9faf7e20434e4729f Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Mon, 13 Mar 2023 00:13:50 -0600 Subject: [PATCH 003/241] fixing weird import --- .../Vis/Scatter/ScatterIris.stories.tsx | 53 +------------------ .../stories/Vis/Violin/ViolinIris.stories.tsx | 53 +------------------ 2 files changed, 2 insertions(+), 104 deletions(-) diff --git a/src/vis/stories/Vis/Scatter/ScatterIris.stories.tsx b/src/vis/stories/Vis/Scatter/ScatterIris.stories.tsx index 4a76ed523..3d7656cb2 100644 --- a/src/vis/stories/Vis/Scatter/ScatterIris.stories.tsx +++ b/src/vis/stories/Vis/Scatter/ScatterIris.stories.tsx @@ -13,58 +13,7 @@ import { EViolinOverlay, VisColumn, } from '../../../interfaces'; - -function fetchIrisData(): VisColumn[] { - const dataPromise = import('../../irisData').then((m) => m.iris); - - return [ - { - info: { - description: '', - id: 'sepalLength', - name: 'Sepal Length', - }, - type: EColumnTypes.NUMERICAL, - values: () => dataPromise.then((data) => data.map((r) => r.sepalLength).map((val, i) => ({ id: i.toString(), val }))), - }, - { - info: { - description: '', - id: 'sepalWidth', - name: 'Sepal Width', - }, - type: EColumnTypes.NUMERICAL, - values: () => dataPromise.then((data) => data.map((r) => r.sepalWidth).map((val, i) => ({ id: i.toString(), val }))), - }, - { - info: { - description: '', - id: 'petalLength', - name: 'Petal Length', - }, - type: EColumnTypes.NUMERICAL, - values: () => dataPromise.then((data) => data.map((r) => r.petalLength).map((val, i) => ({ id: i.toString(), val }))), - }, - { - info: { - description: '', - id: 'petalWidth', - name: 'Petal Width', - }, - type: EColumnTypes.NUMERICAL, - values: () => dataPromise.then((data) => data.map((r) => r.petalWidth).map((val, i) => ({ id: i.toString(), val }))), - }, - { - info: { - description: '', - id: 'species', - name: 'Species', - }, - type: EColumnTypes.CATEGORICAL, - values: () => dataPromise.then((data) => data.map((r) => r.species).map((val, i) => ({ id: i.toString(), val }))), - }, - ]; -} +import { fetchIrisData } from '../../fetchIrisData'; // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export export default { diff --git a/src/vis/stories/Vis/Violin/ViolinIris.stories.tsx b/src/vis/stories/Vis/Violin/ViolinIris.stories.tsx index db962a7d8..ca4c0856c 100644 --- a/src/vis/stories/Vis/Violin/ViolinIris.stories.tsx +++ b/src/vis/stories/Vis/Violin/ViolinIris.stories.tsx @@ -13,58 +13,7 @@ import { EViolinOverlay, VisColumn, } from '../../../interfaces'; - -function fetchIrisData(): VisColumn[] { - const dataPromise = import('../../irisData').then((m) => m.iris); - - return [ - { - info: { - description: '', - id: 'sepalLength', - name: 'Sepal Length', - }, - type: EColumnTypes.NUMERICAL, - values: () => dataPromise.then((data) => data.map((r) => r.sepalLength).map((val, i) => ({ id: i.toString(), val }))), - }, - { - info: { - description: '', - id: 'sepalWidth', - name: 'Sepal Width', - }, - type: EColumnTypes.NUMERICAL, - values: () => dataPromise.then((data) => data.map((r) => r.sepalWidth).map((val, i) => ({ id: i.toString(), val }))), - }, - { - info: { - description: '', - id: 'petalLength', - name: 'Petal Length', - }, - type: EColumnTypes.NUMERICAL, - values: () => dataPromise.then((data) => data.map((r) => r.petalLength).map((val, i) => ({ id: i.toString(), val }))), - }, - { - info: { - description: '', - id: 'petalWidth', - name: 'Petal Width', - }, - type: EColumnTypes.NUMERICAL, - values: () => dataPromise.then((data) => data.map((r) => r.petalWidth).map((val, i) => ({ id: i.toString(), val }))), - }, - { - info: { - description: '', - id: 'species', - name: 'Species', - }, - type: EColumnTypes.CATEGORICAL, - values: () => dataPromise.then((data) => data.map((r) => r.species).map((val, i) => ({ id: i.toString(), val }))), - }, - ]; -} +import { fetchIrisData } from '../../fetchIrisData'; // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export export default { From 4cc4531b9c5a88ed63de14c4637ad77af5afa8e6 Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Wed, 10 May 2023 12:35:22 +0200 Subject: [PATCH 004/241] inno day stuff --- package.json | 1 + src/vis/Vis.tsx | 3 +- src/vis/barGood/BarVis.tsx | 107 ++++++++++++++++++++++++++++++ src/vis/barGood/GroupedBars.tsx | 90 +++++++++++++++++++++++++ src/vis/barGood/SimpleBars.tsx | 112 ++++++++++++++++++++++++++++++++ src/vis/barGood/SingleBar.tsx | 10 +++ src/vis/barGood/XAxis.tsx | 38 +++++++++++ src/vis/barGood/YAxis.tsx | 41 ++++++++++++ src/vis/barGood/utils.ts | 25 +++++++ src/vis/hexbin/Hexplot.tsx | 1 - src/vis/hexbin/SingleHex.tsx | 1 - 11 files changed, 426 insertions(+), 3 deletions(-) create mode 100644 src/vis/barGood/BarVis.tsx create mode 100644 src/vis/barGood/GroupedBars.tsx create mode 100644 src/vis/barGood/SimpleBars.tsx create mode 100644 src/vis/barGood/SingleBar.tsx create mode 100644 src/vis/barGood/XAxis.tsx create mode 100644 src/vis/barGood/YAxis.tsx create mode 100644 src/vis/barGood/utils.ts diff --git a/package.json b/package.json index 5ebb0a75a..c4b5b450e 100644 --- a/package.json +++ b/package.json @@ -147,6 +147,7 @@ "@types/react": "^16.9.23", "@types/react-dom": "^16.9.5", "@types/react-plotly.js": "^2.5.0", + "arquero": "^5.2.0", "d3-hexbin": "^0.2.2", "d3v7": "npm:d3@^7.4.0", "i18next": "^19.8.4", diff --git a/src/vis/Vis.tsx b/src/vis/Vis.tsx index c9c846b38..04aba6d45 100644 --- a/src/vis/Vis.tsx +++ b/src/vis/Vis.tsx @@ -17,12 +17,13 @@ import { EAggregateTypes, } from './interfaces'; import { isScatter, scatterMergeDefaultConfig, ScatterVis } from './scatter'; -import { barMergeDefaultConfig, isBar, BarVis } from './bar'; +import { barMergeDefaultConfig, isBar } from './bar'; import { isViolin, violinMergeDefaultConfig, ViolinVis } from './violin'; import { getCssValue } from '../utils'; import { useSyncedRef } from '../hooks/useSyncedRef'; import { hexinbMergeDefaultConfig, isHexbin } from './hexbin/utils'; import { HexbinVis } from './hexbin/HexbinVis'; +import { BarVis } from './barGood/BarVis'; const DEFAULT_SHAPES = ['circle', 'square', 'triangle-up', 'star']; diff --git a/src/vis/barGood/BarVis.tsx b/src/vis/barGood/BarVis.tsx new file mode 100644 index 000000000..6d5db3cbf --- /dev/null +++ b/src/vis/barGood/BarVis.tsx @@ -0,0 +1,107 @@ +import React, { useEffect, useMemo, useRef } from 'react'; +import { merge, uniqueId } from 'lodash'; +import { ActionIcon, Container, Tooltip } from '@mantine/core'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faGear } from '@fortawesome/free-solid-svg-icons'; +import { useSyncedRef } from '../../hooks/useSyncedRef'; +import { IBarConfig, IVisConfig, Scales, VisColumn } from '../interfaces'; +import { i18n } from '../../i18n/I18nextManager'; +import { SimpleBars } from './SimpleBars'; +import { VisSidebarWrapper } from '../VisSidebarWrapper'; +import { BarVisSidebar } from '../bar/BarVisSidebar'; + +const defaultExtensions = { + prePlot: null, + postPlot: null, + preSidebar: null, + postSidebar: null, +}; + +export function BarVis({ + config, + optionsConfig, + extensions, + columns, + setConfig, + scales, + selectionCallback = () => null, + selectedMap = {}, + selectedList = [], + enableSidebar, + showSidebar, + setShowSidebar, + showCloseButton = false, + closeButtonCallback = () => null, +}: { + config: IBarConfig; + optionsConfig?: { + group?: { + enable?: boolean; + customComponent?: React.ReactNode; + }; + multiples?: { + enable?: boolean; + customComponent?: React.ReactNode; + }; + direction?: { + enable?: boolean; + customComponent?: React.ReactNode; + }; + groupingType?: { + enable?: boolean; + customComponent?: React.ReactNode; + }; + display?: { + enable?: boolean; + customComponent?: React.ReactNode; + }; + }; + extensions?: { + prePlot?: React.ReactNode; + postPlot?: React.ReactNode; + preSidebar?: React.ReactNode; + postSidebar?: React.ReactNode; + }; + columns: VisColumn[]; + closeButtonCallback?: () => void; + showCloseButton?: boolean; + selectionCallback?: (ids: string[]) => void; + selectedMap?: { [key: string]: boolean }; + selectedList: string[]; + setConfig: (config: IVisConfig) => void; + scales: Scales; + showSidebar?: boolean; + setShowSidebar?(show: boolean): void; + enableSidebar?: boolean; +}) { + const mergedExtensions = useMemo(() => { + return merge({}, defaultExtensions, extensions); + }, [extensions]); + + const setShowSidebarRef = useSyncedRef(setShowSidebar); + // Cheating to open the sidebar after the first render, since it requires the container to be mounted + useEffect(() => { + setShowSidebarRef.current(true); + }, [setShowSidebarRef]); + + const ref = useRef(); + const id = React.useMemo(() => uniqueId('HexbinVis'), []); + + return ( + + {enableSidebar ? ( + + setShowSidebar(true)}> + + + + ) : null} + + {showSidebar ? ( + setShowSidebar(false)}> + + + ) : null} + + ); +} diff --git a/src/vis/barGood/GroupedBars.tsx b/src/vis/barGood/GroupedBars.tsx new file mode 100644 index 000000000..9f852e95b --- /dev/null +++ b/src/vis/barGood/GroupedBars.tsx @@ -0,0 +1,90 @@ +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { all, desc, op, table } from 'arquero'; +import * as d3 from 'd3v7'; +import { IBarConfig, IVisConfig, Scales, VisColumn } from '../interfaces'; +import { useSyncedRef } from '../../hooks/useSyncedRef'; +import { useAsync } from '../../hooks/useAsync'; +import { getBarData } from './utils'; +import { YAxis } from './YAxis'; +import { XAxis } from './XAxis'; +import { SingleBar } from './SingleBar'; + +const defaultExtensions = { + prePlot: null, + postPlot: null, + preSidebar: null, + postSidebar: null, +}; + +const margin = { + top: 25, + bottom: 25, + left: 25, + right: 25, +}; + +const barPadding = 10; + +export function SimpleBars({ config, columns }: { config: IBarConfig; columns: VisColumn[] }) { + const { value: allColumns, status: colsStatus } = useAsync(getBarData, [columns, config.catColumnSelected, config.group]); + + console.log(allColumns); + + const [height, setHeight] = useState(600); + const [width, setWidth] = useState(600); + + const aggregatedTable = useMemo(() => { + if (colsStatus === 'success') { + const myTable = table({ category: allColumns.catColVals.resolvedValues.map((val) => val.val) }); + + const grouped = myTable.groupby('category').count(); + + return grouped; + } + + return null; + }, [allColumns?.catColVals.resolvedValues, colsStatus]); + + const countScale = useMemo(() => { + if (!aggregatedTable) return null; + return d3 + .scaleLinear() + .range([height + margin.top, margin.top]) + .domain([0, +d3.max(aggregatedTable.array('count'))]); + }, [aggregatedTable, height]); + + const categoryScale = useMemo(() => { + if (!aggregatedTable) return null; + return d3 + .scaleBand() + .range([width + margin.left, margin.left]) + .domain(aggregatedTable.array('category')); + }, [aggregatedTable, width]); + + return ( + + + {countScale && categoryScale ? ( + + ) : null} + {categoryScale && countScale ? ( + + ) : null} + {aggregatedTable + ? aggregatedTable.objects().map((row: { category: string; count: number }) => { + return ( + + ); + }) + : null} + + + ); +} diff --git a/src/vis/barGood/SimpleBars.tsx b/src/vis/barGood/SimpleBars.tsx new file mode 100644 index 000000000..85fc04e48 --- /dev/null +++ b/src/vis/barGood/SimpleBars.tsx @@ -0,0 +1,112 @@ +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { all, desc, op, table } from 'arquero'; +import * as d3 from 'd3v7'; +import { IBarConfig, IVisConfig, Scales, VisColumn } from '../interfaces'; +import { useSyncedRef } from '../../hooks/useSyncedRef'; +import { useAsync } from '../../hooks/useAsync'; +import { getBarData } from './utils'; +import { YAxis } from './YAxis'; +import { XAxis } from './XAxis'; +import { SingleBar } from './SingleBar'; + +const defaultExtensions = { + prePlot: null, + postPlot: null, + preSidebar: null, + postSidebar: null, +}; + +const margin = { + top: 25, + bottom: 25, + left: 25, + right: 25, +}; + +const barPadding = 10; + +export function SimpleBars({ config, columns }: { config: IBarConfig; columns: VisColumn[] }) { + const { value: allColumns, status: colsStatus } = useAsync(getBarData, [columns, config.catColumnSelected, config.group]); + + const [height, setHeight] = useState(600); + const [width, setWidth] = useState(600); + + const aggregatedTable = useMemo(() => { + if (colsStatus === 'success') { + const myTable = table({ category: allColumns.catColVals.resolvedValues.map((val) => val.val) }); + + const grouped = myTable.groupby('category').count(); + + return grouped; + } + + return null; + }, [allColumns?.catColVals.resolvedValues, colsStatus]); + + const groupedTable = useMemo(() => { + if (colsStatus === 'success' && allColumns.groupColVals) { + const myTable = table({ + category: allColumns.catColVals.resolvedValues.map((val) => val.val), + group: allColumns.groupColVals.resolvedValues.map((val) => val.val), + }); + + myTable.print(); + const grouped = myTable.groupby('category', 'group').count(); + + grouped.print(); + return grouped; + } + + return null; + }, [allColumns, colsStatus]); + + const countScale = useMemo(() => { + if (!aggregatedTable) return null; + return d3 + .scaleLinear() + .range([height + margin.top, margin.top]) + .domain([0, +d3.max(aggregatedTable.array('count'))]); + }, [aggregatedTable, height]); + + const categoryScale = useMemo(() => { + if (!aggregatedTable) return null; + return d3 + .scaleBand() + .range([width + margin.left, margin.left]) + .domain(aggregatedTable.array('category')); + }, [aggregatedTable, width]); + + const groupScale = useMemo(() => { + if (!aggregatedTable || !groupedTable) return null; + const newGroup = groupedTable.ungroup().groupby('group').count(); + + return d3.scaleBand().range([0, categoryScale.bandwidth()]).domain(newGroup.array('group')); + }, [aggregatedTable, categoryScale, groupedTable]); + + return ( + + + {countScale && categoryScale ? ( + + ) : null} + {categoryScale && countScale ? ( + + ) : null} + {aggregatedTable + ? aggregatedTable.objects().map((row: { category: string; count: number }) => { + return ( + + ); + }) + : null} + + + ); +} diff --git a/src/vis/barGood/SingleBar.tsx b/src/vis/barGood/SingleBar.tsx new file mode 100644 index 000000000..e63bac271 --- /dev/null +++ b/src/vis/barGood/SingleBar.tsx @@ -0,0 +1,10 @@ +import { Tooltip } from '@mantine/core'; +import React, { useEffect, useMemo, useRef, useState } from 'react'; + +export function SingleBar({ x, width, y, height, value }: { x: number; width: number; y: number; height: number; value: number }) { + return ( + + + + ); +} diff --git a/src/vis/barGood/XAxis.tsx b/src/vis/barGood/XAxis.tsx new file mode 100644 index 000000000..1dc5a9915 --- /dev/null +++ b/src/vis/barGood/XAxis.tsx @@ -0,0 +1,38 @@ +import * as React from 'react'; +import { useMemo } from 'react'; +import * as d3 from 'd3v7'; + +// code taken from https://wattenberger.com/blog/react-and-d3 +export function XAxis({ xScale, yRange, vertPosition }: { xScale: d3.ScaleBand; yRange: [number, number]; vertPosition: number }) { + const ticks = useMemo(() => { + console.log(xScale); + return xScale.domain().map((value) => ({ + value, + xOffset: xScale(value) + xScale.bandwidth() / 2, + })); + }, [xScale]); + + return ( + <> + + + + {ticks.map(({ value, xOffset }) => ( + + + + + {value} + + + ))} + + ); +} diff --git a/src/vis/barGood/YAxis.tsx b/src/vis/barGood/YAxis.tsx new file mode 100644 index 000000000..bef8157b1 --- /dev/null +++ b/src/vis/barGood/YAxis.tsx @@ -0,0 +1,41 @@ +import * as React from 'react'; +import { useMemo } from 'react'; + +// code taken from https://wattenberger.com/blog/react-and-d3 +export function YAxis({ yScale, xRange, horizontalPosition }) { + const ticks = useMemo(() => { + return yScale.ticks(5).map((value) => ({ + value, + yOffset: yScale(value), + })); + }, [yScale]); + + return ( + <> + + + {ticks.map(({ value, yOffset }) => ( + + + + + {value} + + + ))} + + ); +} diff --git a/src/vis/barGood/utils.ts b/src/vis/barGood/utils.ts new file mode 100644 index 000000000..d08457492 --- /dev/null +++ b/src/vis/barGood/utils.ts @@ -0,0 +1,25 @@ +import { resolveColumnValues, resolveSingleColumn } from '../general/layoutUtils'; +import { ColumnInfo, EColumnTypes, VisCategoricalValue, VisColumn, VisNumericalColumn, VisNumericalValue } from '../interfaces'; + +export async function getBarData( + columns: VisColumn[], + catColumn: ColumnInfo, + groupColumn: ColumnInfo | null, +): Promise<{ + catColVals: { + resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; + type: EColumnTypes.NUMERICAL | EColumnTypes.CATEGORICAL; + info: ColumnInfo; + }; + groupColVals: { + resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; + type: EColumnTypes.NUMERICAL | EColumnTypes.CATEGORICAL; + info: ColumnInfo; + }; +}> { + const catColVals = await resolveSingleColumn(columns.find((col) => col.info.id === catColumn.id)); + + const groupColVals = await resolveSingleColumn(groupColumn ? columns.find((col) => col.info.id === groupColumn.id) : null); + + return { catColVals, groupColVals }; +} diff --git a/src/vis/hexbin/Hexplot.tsx b/src/vis/hexbin/Hexplot.tsx index 0d4ffa50a..4f19373e6 100644 --- a/src/vis/hexbin/Hexplot.tsx +++ b/src/vis/hexbin/Hexplot.tsx @@ -148,7 +148,6 @@ export function Hexplot({ config, columns, selectionCallback = () => null, selec // resize observer for setting size of the svg and updating on size change useEffect(() => { const ro = new ResizeObserver((entries: ResizeObserverEntry[]) => { - console.log(entries); setHeight(entries[0].contentRect.height - margin.top - margin.bottom); setWidth(entries[0].contentRect.width - margin.left - margin.right); }); diff --git a/src/vis/hexbin/SingleHex.tsx b/src/vis/hexbin/SingleHex.tsx index 43fdc6564..1fc703023 100644 --- a/src/vis/hexbin/SingleHex.tsx +++ b/src/vis/hexbin/SingleHex.tsx @@ -2,7 +2,6 @@ import * as React from 'react'; import * as hex from 'd3-hexbin'; import * as d3v7 from 'd3v7'; import { useMemo } from 'react'; -import { Tooltip } from '@mantine/core'; import { PieChart } from './PieChart'; import { cutHex } from './utils'; import { EHexbinOptions } from '../interfaces'; From 492046bd8b1c78917088ca099ecd58a51d2adc67 Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Fri, 12 May 2023 12:26:48 +0200 Subject: [PATCH 005/241] adding stacked/grouped bar charts --- src/vis/barGood/BarChart.tsx | 181 +++++++++++++++++++++++++++++++ src/vis/barGood/BarVis.tsx | 4 +- src/vis/barGood/GroupedBars.tsx | 125 +++++++++++++++------ src/vis/barGood/SimpleBars.tsx | 114 ++++++++++--------- src/vis/barGood/SingleBar.tsx | 18 ++- src/vis/barGood/XAxis.tsx | 1 - src/vis/barGood/utils.ts | 9 +- src/vis/stories/Iris.stories.tsx | 15 ++- 8 files changed, 366 insertions(+), 101 deletions(-) create mode 100644 src/vis/barGood/BarChart.tsx diff --git a/src/vis/barGood/BarChart.tsx b/src/vis/barGood/BarChart.tsx new file mode 100644 index 000000000..dbbf3ad60 --- /dev/null +++ b/src/vis/barGood/BarChart.tsx @@ -0,0 +1,181 @@ +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { all, desc, op, table } from 'arquero'; +import * as d3 from 'd3v7'; +import { Box, SimpleGrid } from '@mantine/core'; +import { EBarGroupingType, IBarConfig, IVisConfig, Scales, VisColumn } from '../interfaces'; +import { useSyncedRef } from '../../hooks/useSyncedRef'; +import { useAsync } from '../../hooks/useAsync'; +import { getBarData } from './utils'; +import { YAxis } from './YAxis'; +import { XAxis } from './XAxis'; +import { SingleBar } from './SingleBar'; +import { GroupedBars } from './GroupedBars'; +import { SimpleBars } from './SimpleBars'; + +const defaultExtensions = { + prePlot: null, + postPlot: null, + preSidebar: null, + postSidebar: null, +}; + +const margin = { + top: 25, + bottom: 25, + left: 25, + right: 100, +}; + +export function BarChart({ config, columns }: { config: IBarConfig; columns: VisColumn[] }) { + const { value: allColumns, status: colsStatus } = useAsync(getBarData, [columns, config.catColumnSelected, config.group, config.multiples]); + + const ref = useRef(null); + + // const aggregatedTable = useMemo(() => { + // if (colsStatus === 'success') { + // const myTable = table({ category: allColumns.catColVals.resolvedValues.map((val) => val.val) }); + + // const grouped = myTable.groupby('category').count().orderby('category'); + + // return grouped; + // } + + // return null; + // }, [allColumns?.catColVals.resolvedValues, colsStatus]); + + // const groupedTable = useMemo(() => { + // if (colsStatus === 'success' && allColumns.groupColVals) { + // const myTable = table({ + // category: allColumns.catColVals.resolvedValues.map((val) => val.val), + // group: allColumns.groupColVals.resolvedValues.map((val) => val.val), + // }); + + // const grouped = myTable.groupby('category', 'group').count().orderby('category'); + + // return grouped; + // } + + // return null; + // }, [allColumns, colsStatus]); + + // const multiplesAndGroupTable = useMemo(() => { + // if (colsStatus === 'success' && allColumns.groupColVals && allColumns.multiplesColVals) { + // const myTable = table({ + // category: allColumns.catColVals.resolvedValues.map((val) => val.val), + // group: allColumns.groupColVals.resolvedValues.map((val) => val.val), + // multiples: allColumns.multiplesColVals.resolvedValues.map((val) => val.val), + // }); + + // const grouped = myTable.groupby('category', 'group', 'multiples').count().orderby('category'); + + // grouped.print(); + + // return grouped; + // } + + // return null; + // }, [allColumns, colsStatus]); + + // const multiplesTable = useMemo(() => { + // if (colsStatus === 'success' && allColumns.multiplesColVals) { + // const myTable = table({ + // category: allColumns.catColVals.resolvedValues.map((val) => val.val), + // multiples: allColumns.multiplesColVals.resolvedValues.map((val) => val.val), + // }); + + // const grouped = myTable.groupby('category', 'multiples').count().orderby('category'); + + // grouped.print(); + + // return grouped; + // } + + // return null; + // }, [allColumns, colsStatus]); + + // const groupColorScale = useMemo(() => { + // if (!groupedTable) return null; + + // const newGroup = groupedTable.ungroup().groupby('group').count(); + + // return d3.scaleOrdinal().domain(newGroup.array('group')).range(d3.schemeCategory10); + // }, [groupedTable]); + + // const groupScale = useMemo(() => { + // if (!aggregatedTable || !groupedTable) return null; + // const newGroup = groupedTable.ungroup().groupby('category', 'group').count(); + + // return d3.scaleBand().range([0, categoryScale.bandwidth()]).domain(newGroup.array('group')).padding(0.1); + // }, [aggregatedTable, categoryScale, groupedTable]); + + // const bars = useMemo(() => { + // if (config.group && groupedTable && config.groupType === EBarGroupingType.GROUP) { + // return groupedTable + // .groupby('category') + // .objects() + // .map((row: { category: string; group: string; count: number }) => { + // return ( + // + // ); + // }); + // } + // if (config.group && groupedTable && config.groupType === EBarGroupingType.STACK) { + // let heightSoFar = 0; + // let currentCategory = ''; + // return groupedTable.objects().map((row: { category: string; group: string; count: number }) => { + // if (currentCategory !== row.category) { + // heightSoFar = 0; + // currentCategory = row.category; + // } + + // const myHeight = heightSoFar; + // heightSoFar = myHeight + height + margin.top - countScale(row.count); + + // return ( + // + // ); + // }); + // } + // if (aggregatedTable) { + // return aggregatedTable.objects().map((row: { category: string; count: number }) => { + // return ( + // + // ); + // }); + // } + + // return null; + // }, [aggregatedTable, categoryScale, config.group, config.groupType, countScale, groupColorScale, groupScale, groupedTable, height]); + + console.log('looping?'); + return ( + + 2 ? config.numColumnsSelected.length : 1}> + {config.group ? : } + + + ); +} diff --git a/src/vis/barGood/BarVis.tsx b/src/vis/barGood/BarVis.tsx index 6d5db3cbf..7883ab2f4 100644 --- a/src/vis/barGood/BarVis.tsx +++ b/src/vis/barGood/BarVis.tsx @@ -6,7 +6,7 @@ import { faGear } from '@fortawesome/free-solid-svg-icons'; import { useSyncedRef } from '../../hooks/useSyncedRef'; import { IBarConfig, IVisConfig, Scales, VisColumn } from '../interfaces'; import { i18n } from '../../i18n/I18nextManager'; -import { SimpleBars } from './SimpleBars'; +import { BarChart } from './BarChart'; import { VisSidebarWrapper } from '../VisSidebarWrapper'; import { BarVisSidebar } from '../bar/BarVisSidebar'; @@ -96,7 +96,7 @@ export function BarVis({ ) : null} - + {showSidebar ? ( setShowSidebar(false)}> diff --git a/src/vis/barGood/GroupedBars.tsx b/src/vis/barGood/GroupedBars.tsx index 9f852e95b..0cd785f42 100644 --- a/src/vis/barGood/GroupedBars.tsx +++ b/src/vis/barGood/GroupedBars.tsx @@ -1,7 +1,8 @@ import React, { useEffect, useMemo, useRef, useState } from 'react'; import { all, desc, op, table } from 'arquero'; import * as d3 from 'd3v7'; -import { IBarConfig, IVisConfig, Scales, VisColumn } from '../interfaces'; +import { Box, SimpleGrid } from '@mantine/core'; +import { EBarGroupingType, IBarConfig, IVisConfig, Scales, VisColumn } from '../interfaces'; import { useSyncedRef } from '../../hooks/useSyncedRef'; import { useAsync } from '../../hooks/useAsync'; import { getBarData } from './utils'; @@ -20,24 +21,38 @@ const margin = { top: 25, bottom: 25, left: 25, - right: 25, + right: 100, }; -const barPadding = 10; - -export function SimpleBars({ config, columns }: { config: IBarConfig; columns: VisColumn[] }) { - const { value: allColumns, status: colsStatus } = useAsync(getBarData, [columns, config.catColumnSelected, config.group]); - - console.log(allColumns); +export function GroupedBars({ config, columns }: { config: IBarConfig; columns: VisColumn[] }) { + const { value: allColumns, status: colsStatus } = useAsync(getBarData, [columns, config.catColumnSelected, config.group, config.multiples]); const [height, setHeight] = useState(600); const [width, setWidth] = useState(600); + const ref = useRef(null); + + // resize observer for setting size of the svg and updating on size change + useEffect(() => { + const ro = new ResizeObserver((entries: ResizeObserverEntry[]) => { + setHeight(entries[0].contentRect.height - margin.top - margin.bottom); + setWidth(entries[0].contentRect.width - margin.left - margin.right); + }); + + if (ref) { + ro.observe(ref.current); + } + + return () => { + ro.disconnect(); + }; + }, []); + const aggregatedTable = useMemo(() => { if (colsStatus === 'success') { const myTable = table({ category: allColumns.catColVals.resolvedValues.map((val) => val.val) }); - const grouped = myTable.groupby('category').count(); + const grouped = myTable.groupby('category').count().orderby('category'); return grouped; } @@ -58,33 +73,75 @@ export function SimpleBars({ config, columns }: { config: IBarConfig; columns: V return d3 .scaleBand() .range([width + margin.left, margin.left]) - .domain(aggregatedTable.array('category')); + .domain(aggregatedTable.array('category')) + .padding(0.2); }, [aggregatedTable, width]); + const groupedTable = useMemo(() => { + if (colsStatus === 'success' && allColumns.groupColVals) { + const myTable = table({ + category: allColumns.catColVals.resolvedValues.map((val) => val.val), + group: allColumns.groupColVals.resolvedValues.map((val) => val.val), + }); + + const grouped = myTable.groupby('category', 'group').count().orderby('category'); + + return grouped; + } + + return null; + }, [allColumns, colsStatus]); + + const groupColorScale = useMemo(() => { + if (!groupedTable) return null; + + const newGroup = groupedTable.ungroup().groupby('group').count(); + + return d3.scaleOrdinal().domain(newGroup.array('group')).range(d3.schemeCategory10); + }, [groupedTable]); + + const groupScale = useMemo(() => { + if (!groupedTable) return null; + const newGroup = groupedTable.ungroup().groupby('category', 'group').count(); + + return d3.scaleBand().range([0, categoryScale.bandwidth()]).domain(newGroup.array('group')).padding(0.1); + }, [categoryScale, groupedTable]); + + const bars = useMemo(() => { + if (groupedTable) { + return groupedTable + .groupby('category') + .objects() + .map((row: { category: string; group: string; count: number }) => { + return ( + + ); + }); + } + return null; + }, [categoryScale, countScale, groupColorScale, groupScale, groupedTable, height]); + return ( - - - {countScale && categoryScale ? ( - - ) : null} - {categoryScale && countScale ? ( - - ) : null} - {aggregatedTable - ? aggregatedTable.objects().map((row: { category: string; count: number }) => { - return ( - - ); - }) - : null} - - + + + + {countScale && categoryScale ? ( + + ) : null} + {categoryScale && countScale ? ( + + ) : null} + {bars} + + + ); } diff --git a/src/vis/barGood/SimpleBars.tsx b/src/vis/barGood/SimpleBars.tsx index 85fc04e48..87ce2a218 100644 --- a/src/vis/barGood/SimpleBars.tsx +++ b/src/vis/barGood/SimpleBars.tsx @@ -1,64 +1,58 @@ import React, { useEffect, useMemo, useRef, useState } from 'react'; import { all, desc, op, table } from 'arquero'; import * as d3 from 'd3v7'; -import { IBarConfig, IVisConfig, Scales, VisColumn } from '../interfaces'; +import { Box, SimpleGrid } from '@mantine/core'; +import { EBarGroupingType, IBarConfig, IVisConfig, Scales, VisColumn } from '../interfaces'; import { useSyncedRef } from '../../hooks/useSyncedRef'; import { useAsync } from '../../hooks/useAsync'; import { getBarData } from './utils'; import { YAxis } from './YAxis'; import { XAxis } from './XAxis'; import { SingleBar } from './SingleBar'; - -const defaultExtensions = { - prePlot: null, - postPlot: null, - preSidebar: null, - postSidebar: null, -}; +import { GroupedBars } from './GroupedBars'; const margin = { top: 25, bottom: 25, left: 25, - right: 25, + right: 100, }; -const barPadding = 10; - export function SimpleBars({ config, columns }: { config: IBarConfig; columns: VisColumn[] }) { - const { value: allColumns, status: colsStatus } = useAsync(getBarData, [columns, config.catColumnSelected, config.group]); + const { value: allColumns, status: colsStatus } = useAsync(getBarData, [columns, config.catColumnSelected, config.group, config.multiples]); const [height, setHeight] = useState(600); const [width, setWidth] = useState(600); - const aggregatedTable = useMemo(() => { - if (colsStatus === 'success') { - const myTable = table({ category: allColumns.catColVals.resolvedValues.map((val) => val.val) }); + const ref = useRef(null); - const grouped = myTable.groupby('category').count(); + // resize observer for setting size of the svg and updating on size change + useEffect(() => { + const ro = new ResizeObserver((entries: ResizeObserverEntry[]) => { + setHeight(entries[0].contentRect.height - margin.top - margin.bottom); + setWidth(entries[0].contentRect.width - margin.left - margin.right); + }); - return grouped; + if (ref) { + ro.observe(ref.current); } - return null; - }, [allColumns?.catColVals.resolvedValues, colsStatus]); + return () => { + ro.disconnect(); + }; + }, []); - const groupedTable = useMemo(() => { - if (colsStatus === 'success' && allColumns.groupColVals) { - const myTable = table({ - category: allColumns.catColVals.resolvedValues.map((val) => val.val), - group: allColumns.groupColVals.resolvedValues.map((val) => val.val), - }); + const aggregatedTable = useMemo(() => { + if (colsStatus === 'success') { + const myTable = table({ category: allColumns.catColVals.resolvedValues.map((val) => val.val) }); - myTable.print(); - const grouped = myTable.groupby('category', 'group').count(); + const grouped = myTable.groupby('category').count().orderby('category'); - grouped.print(); return grouped; } return null; - }, [allColumns, colsStatus]); + }, [allColumns?.catColVals.resolvedValues, colsStatus]); const countScale = useMemo(() => { if (!aggregatedTable) return null; @@ -73,40 +67,42 @@ export function SimpleBars({ config, columns }: { config: IBarConfig; columns: V return d3 .scaleBand() .range([width + margin.left, margin.left]) - .domain(aggregatedTable.array('category')); + .domain(aggregatedTable.array('category')) + .padding(0.2); }, [aggregatedTable, width]); - const groupScale = useMemo(() => { - if (!aggregatedTable || !groupedTable) return null; - const newGroup = groupedTable.ungroup().groupby('group').count(); + const bars = useMemo(() => { + if (aggregatedTable && categoryScale && countScale) { + return aggregatedTable.objects().map((row: { category: string; count: number }) => { + return ( + + ); + }); + } - return d3.scaleBand().range([0, categoryScale.bandwidth()]).domain(newGroup.array('group')); - }, [aggregatedTable, categoryScale, groupedTable]); + return null; + }, [aggregatedTable, categoryScale, countScale, height]); return ( - - - {countScale && categoryScale ? ( - - ) : null} - {categoryScale && countScale ? ( - - ) : null} - {aggregatedTable - ? aggregatedTable.objects().map((row: { category: string; count: number }) => { - return ( - - ); - }) - : null} - - + + + + {countScale && categoryScale ? ( + + ) : null} + {categoryScale && countScale ? ( + + ) : null} + {bars} + + + ); } diff --git a/src/vis/barGood/SingleBar.tsx b/src/vis/barGood/SingleBar.tsx index e63bac271..ab264d6e1 100644 --- a/src/vis/barGood/SingleBar.tsx +++ b/src/vis/barGood/SingleBar.tsx @@ -1,10 +1,24 @@ import { Tooltip } from '@mantine/core'; import React, { useEffect, useMemo, useRef, useState } from 'react'; -export function SingleBar({ x, width, y, height, value }: { x: number; width: number; y: number; height: number; value: number }) { +export function SingleBar({ + x, + width, + y, + height, + value, + color = 'cornflowerblue', +}: { + x: number; + width: number; + y: number; + height: number; + value: number; + color?: string; +}) { return ( - + ); } diff --git a/src/vis/barGood/XAxis.tsx b/src/vis/barGood/XAxis.tsx index 1dc5a9915..9a7bd80b4 100644 --- a/src/vis/barGood/XAxis.tsx +++ b/src/vis/barGood/XAxis.tsx @@ -5,7 +5,6 @@ import * as d3 from 'd3v7'; // code taken from https://wattenberger.com/blog/react-and-d3 export function XAxis({ xScale, yRange, vertPosition }: { xScale: d3.ScaleBand; yRange: [number, number]; vertPosition: number }) { const ticks = useMemo(() => { - console.log(xScale); return xScale.domain().map((value) => ({ value, xOffset: xScale(value) + xScale.bandwidth() / 2, diff --git a/src/vis/barGood/utils.ts b/src/vis/barGood/utils.ts index d08457492..a185c9255 100644 --- a/src/vis/barGood/utils.ts +++ b/src/vis/barGood/utils.ts @@ -5,6 +5,7 @@ export async function getBarData( columns: VisColumn[], catColumn: ColumnInfo, groupColumn: ColumnInfo | null, + multiplesColumn: ColumnInfo | null, ): Promise<{ catColVals: { resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; @@ -16,10 +17,16 @@ export async function getBarData( type: EColumnTypes.NUMERICAL | EColumnTypes.CATEGORICAL; info: ColumnInfo; }; + multiplesColVals: { + resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; + type: EColumnTypes.NUMERICAL | EColumnTypes.CATEGORICAL; + info: ColumnInfo; + }; }> { const catColVals = await resolveSingleColumn(columns.find((col) => col.info.id === catColumn.id)); const groupColVals = await resolveSingleColumn(groupColumn ? columns.find((col) => col.info.id === groupColumn.id) : null); + const multiplesColVals = await resolveSingleColumn(multiplesColumn ? columns.find((col) => col.info.id === multiplesColumn.id) : null); - return { catColVals, groupColVals }; + return { catColVals, groupColVals, multiplesColVals }; } diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index 1327dc8ba..0280d28f7 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -15,7 +15,9 @@ import { } from '../interfaces'; export function fetchIrisData(): VisColumn[] { - const dataPromise = import('./irisData.js').then((m) => m.iris); + const dataPromise = import('./irisData.js').then((m) => + m.iris.map((currIris) => ({ ...currIris, randomCategory: Math.round(Math.random() * 4), anotherRandomCategory: Math.round(Math.random() * 4) })), + ); return [ { @@ -43,7 +45,16 @@ export function fetchIrisData(): VisColumn[] { name: 'Random Thing', }, type: EColumnTypes.CATEGORICAL, - values: () => dataPromise.then((data) => data.map((r) => Math.round(Math.random() * 4)).map((val, i) => ({ id: i.toString(), val: val.toString() }))), + values: () => dataPromise.then((data) => data.map((r) => r.randomCategory).map((val, i) => ({ id: i.toString(), val: val.toString() }))), + }, + { + info: { + description: '', + id: 'randomThing2', + name: 'Random Thing2', + }, + type: EColumnTypes.CATEGORICAL, + values: () => dataPromise.then((data) => data.map((r) => r.anotherRandomCategory).map((val, i) => ({ id: i.toString(), val: val.toString() }))), }, { info: { From 144ef74cb274fca4c644b4bf91d53e0f05488261 Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Fri, 12 May 2023 14:28:50 +0200 Subject: [PATCH 006/241] workin --- src/vis/barGood/GroupedBars.tsx | 43 +++++++++++++++++++++------------ src/vis/barGood/SimpleBars.tsx | 43 +++++++++++++++++++++------------ 2 files changed, 56 insertions(+), 30 deletions(-) diff --git a/src/vis/barGood/GroupedBars.tsx b/src/vis/barGood/GroupedBars.tsx index 0cd785f42..ecea230b2 100644 --- a/src/vis/barGood/GroupedBars.tsx +++ b/src/vis/barGood/GroupedBars.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useMemo, useRef, useState } from 'react'; import { all, desc, op, table } from 'arquero'; import * as d3 from 'd3v7'; -import { Box, SimpleGrid } from '@mantine/core'; +import { Box, Container, SimpleGrid } from '@mantine/core'; import { EBarGroupingType, IBarConfig, IVisConfig, Scales, VisColumn } from '../interfaces'; import { useSyncedRef } from '../../hooks/useSyncedRef'; import { useAsync } from '../../hooks/useAsync'; @@ -27,8 +27,8 @@ const margin = { export function GroupedBars({ config, columns }: { config: IBarConfig; columns: VisColumn[] }) { const { value: allColumns, status: colsStatus } = useAsync(getBarData, [columns, config.catColumnSelected, config.group, config.multiples]); - const [height, setHeight] = useState(600); - const [width, setWidth] = useState(600); + const [height, setHeight] = useState(0); + const [width, setWidth] = useState(0); const ref = useRef(null); @@ -130,18 +130,31 @@ export function GroupedBars({ config, columns }: { config: IBarConfig; columns: }, [categoryScale, countScale, groupColorScale, groupScale, groupedTable, height]); return ( - - - - {countScale && categoryScale ? ( - - ) : null} - {categoryScale && countScale ? ( - - ) : null} - {bars} - - + + + + + {countScale && categoryScale ? ( + + ) : null} + {categoryScale && countScale ? ( + + ) : null} + {bars} + + + ); } diff --git a/src/vis/barGood/SimpleBars.tsx b/src/vis/barGood/SimpleBars.tsx index 87ce2a218..34d515de7 100644 --- a/src/vis/barGood/SimpleBars.tsx +++ b/src/vis/barGood/SimpleBars.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useMemo, useRef, useState } from 'react'; import { all, desc, op, table } from 'arquero'; import * as d3 from 'd3v7'; -import { Box, SimpleGrid } from '@mantine/core'; +import { Box, Container, SimpleGrid } from '@mantine/core'; import { EBarGroupingType, IBarConfig, IVisConfig, Scales, VisColumn } from '../interfaces'; import { useSyncedRef } from '../../hooks/useSyncedRef'; import { useAsync } from '../../hooks/useAsync'; @@ -13,7 +13,7 @@ import { GroupedBars } from './GroupedBars'; const margin = { top: 25, - bottom: 25, + bottom: 50, left: 25, right: 100, }; @@ -21,8 +21,8 @@ const margin = { export function SimpleBars({ config, columns }: { config: IBarConfig; columns: VisColumn[] }) { const { value: allColumns, status: colsStatus } = useAsync(getBarData, [columns, config.catColumnSelected, config.group, config.multiples]); - const [height, setHeight] = useState(600); - const [width, setWidth] = useState(600); + const [height, setHeight] = useState(0); + const [width, setWidth] = useState(0); const ref = useRef(null); @@ -92,17 +92,30 @@ export function SimpleBars({ config, columns }: { config: IBarConfig; columns: V return ( - - - {countScale && categoryScale ? ( - - ) : null} - {categoryScale && countScale ? ( - - ) : null} - {bars} - - + + + + {countScale && categoryScale ? ( + + ) : null} + {categoryScale && countScale ? ( + + ) : null} + {bars} + + + ); } From 02cb75d91462dfcd5a093896a5fb372283e375fa Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Tue, 16 May 2023 11:53:57 +0200 Subject: [PATCH 007/241] some small changes to violin vis --- src/vis/bar/BarVis.tsx | 2 +- src/vis/violin/ViolinVis.tsx | 2 +- src/vis/violin/utils.ts | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/vis/bar/BarVis.tsx b/src/vis/bar/BarVis.tsx index 84c340e74..289e95380 100644 --- a/src/vis/bar/BarVis.tsx +++ b/src/vis/bar/BarVis.tsx @@ -180,7 +180,7 @@ export function BarVis({ dragmode: false, }; - setLayout({ ...layout, ...beautifyLayout(finalTraces, innerLayout, null) }); + setLayout({ ...layout, ...beautifyLayout(finalTraces, innerLayout, null, true) }); // WARNING: Do not update when layout changes, that would be an infinite loop. // eslint-disable-next-line react-hooks/exhaustive-deps }, [finalTraces, config.groupType]); diff --git a/src/vis/violin/ViolinVis.tsx b/src/vis/violin/ViolinVis.tsx index f02d7303d..1191a6daf 100644 --- a/src/vis/violin/ViolinVis.tsx +++ b/src/vis/violin/ViolinVis.tsx @@ -111,7 +111,7 @@ export function ViolinVis({ shapes: [], }; - setLayout({ ...layout, ...beautifyLayout(traces, innerLayout, layout) }); + setLayout({ ...layout, ...beautifyLayout(traces, innerLayout, layout, true) }); // WARNING: Do not update when layout changes, that would be an infinite loop. // eslint-disable-next-line react-hooks/exhaustive-deps }, [traces]); diff --git a/src/vis/violin/utils.ts b/src/vis/violin/utils.ts index 30c2cf391..002087d9f 100644 --- a/src/vis/violin/utils.ts +++ b/src/vis/violin/utils.ts @@ -76,10 +76,11 @@ export async function createViolinTraces(columns: VisColumn[], config: IViolinCo box: { visible: config.violinOverlay === EViolinOverlay.BOX, }, - spanmode: 'hard', - meanline: { - visible: true, + marker: { + color: 'gray', }, + + spanmode: 'hard', name: `${columnNameWithDescription(numCurr.info)}`, hoverinfo: 'y', scalemode: 'width', @@ -101,18 +102,17 @@ export async function createViolinTraces(columns: VisColumn[], config: IViolinCo xaxis: plotCounter === 1 ? 'x' : `x${plotCounter}`, yaxis: plotCounter === 1 ? 'y' : `y${plotCounter}`, type: 'violin', + marker: { + color: 'gray', + }, // @ts-ignore hoveron: 'violins', hoverinfo: 'y', - meanline: { - visible: true, - }, name: `${columnNameWithDescription(catCurr.info)} + ${columnNameWithDescription(numCurr.info)}`, scalemode: 'width', pointpos: 0, jitter: 0.3, spanmode: 'hard', - points: false, box: { visible: config.violinOverlay === EViolinOverlay.BOX, From 87f527719622e05492ea73983575db9cbaf017f7 Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Tue, 16 May 2023 16:36:19 +0200 Subject: [PATCH 008/241] adding changes to labels --- src/vis/Vis.tsx | 3 + src/vis/bar/BarVis.tsx | 5 +- src/vis/sidebar/CategoricalColumnSelect.tsx | 5 +- src/vis/sidebar/ColorSelect.tsx | 5 +- src/vis/sidebar/GroupSelect.tsx | 7 ++- src/vis/sidebar/NumericalColumnSelect.tsx | 10 +++- src/vis/sidebar/SingleColumnSelect.tsx | 4 +- src/vis/sidebar/utils.tsx | 63 +++++++++++++++++++++ src/vis/stories/Iris.stories.tsx | 10 ++-- src/vis/violin/ViolinVis.tsx | 45 ++++++++++++++- src/vis/violin/utils.ts | 19 +++++-- 11 files changed, 153 insertions(+), 23 deletions(-) diff --git a/src/vis/Vis.tsx b/src/vis/Vis.tsx index 90165c620..e5a44fc27 100644 --- a/src/vis/Vis.tsx +++ b/src/vis/Vis.tsx @@ -241,6 +241,9 @@ export function EagerVis({ {isViolin(visConfig) ? ( { const ro = new ResizeObserver(() => { - Plotly.Plots.resize(document.getElementById(`plotlyDiv${id}`)); + const plotDiv = document.getElementById(`plotlyDiv${id}`); + if (plotDiv) { + Plotly.Plots.resize(plotDiv); + } }); if (plotlyDivRef) { diff --git a/src/vis/sidebar/CategoricalColumnSelect.tsx b/src/vis/sidebar/CategoricalColumnSelect.tsx index 7d4fb1a30..5677be627 100644 --- a/src/vis/sidebar/CategoricalColumnSelect.tsx +++ b/src/vis/sidebar/CategoricalColumnSelect.tsx @@ -1,6 +1,7 @@ import { MultiSelect } from '@mantine/core'; import * as React from 'react'; import { ColumnInfo, EColumnTypes, VisColumn } from '../interfaces'; +import { SelectDropdownItem, SelectLabelComponent } from './utils'; interface CategoricalColumnSelectProps { callback: (s: ColumnInfo[]) => void; @@ -10,12 +11,14 @@ interface CategoricalColumnSelectProps { export function CategoricalColumnSelect({ callback, columns, currentSelected }: CategoricalColumnSelectProps) { const selectCatOptions = React.useMemo(() => { - return columns.filter((c) => c.type === EColumnTypes.CATEGORICAL).map((c) => ({ value: c.info.id, label: c.info.name })); + return columns.filter((c) => c.type === EColumnTypes.CATEGORICAL).map((c) => ({ value: c.info.id, label: c.info.name, description: c.info.description })); }, [columns]); return ( null, currentNum groupColumnSelectCallback(columns.find((c) => c.info.id === e)?.info)} - data={columns.filter((c) => c.type === EColumnTypes.CATEGORICAL).map((c) => ({ value: c.info.id, label: c.info.name }))} + data={columns + .filter((c) => c.type === EColumnTypes.CATEGORICAL) + .map((c) => ({ value: c.info.id, label: c.info.name, description: c.info.description }))} value={currentSelected?.id} /> {currentSelected ? ( diff --git a/src/vis/sidebar/NumericalColumnSelect.tsx b/src/vis/sidebar/NumericalColumnSelect.tsx index 45a652991..3be1e9ca6 100644 --- a/src/vis/sidebar/NumericalColumnSelect.tsx +++ b/src/vis/sidebar/NumericalColumnSelect.tsx @@ -1,6 +1,8 @@ import * as React from 'react'; -import { MultiSelect } from '@mantine/core'; +import { Group, MultiSelect, Stack, Text, Tooltip } from '@mantine/core'; +import { forwardRef } from 'react'; import { ColumnInfo, EColumnTypes, VisColumn } from '../interfaces'; +import { SelectDropdownItem, SelectLabelComponent } from './utils'; interface NumericalColumnSelectProps { callback: (s: ColumnInfo[]) => void; @@ -8,15 +10,19 @@ interface NumericalColumnSelectProps { currentSelected: ColumnInfo[]; } +// SelectItem.displayName('SelectItem'); + export function NumericalColumnSelect({ callback, columns, currentSelected }: NumericalColumnSelectProps) { const selectNumOptions = React.useMemo(() => { - return columns.filter((c) => c.type === EColumnTypes.NUMERICAL).map((c) => ({ value: c.info.id, label: c.info.name })); + return columns.filter((c) => c.type === EColumnTypes.NUMERICAL).map((c) => ({ value: c.info.id, label: c.info.name, description: c.info.description })); }, [columns]); return ( { callback(columns.filter((c) => e.includes(c.info.id)).map((c) => c.info)); diff --git a/src/vis/sidebar/SingleColumnSelect.tsx b/src/vis/sidebar/SingleColumnSelect.tsx index 980431ab6..174d041ea 100644 --- a/src/vis/sidebar/SingleColumnSelect.tsx +++ b/src/vis/sidebar/SingleColumnSelect.tsx @@ -1,6 +1,7 @@ import { Select } from '@mantine/core'; import * as React from 'react'; import { ColumnInfo, EColumnTypes, VisColumn } from '../interfaces'; +import { SelectDropdownItem } from './utils'; interface SingleColumnSelectProps { callback: (s: ColumnInfo) => void; @@ -12,12 +13,13 @@ interface SingleColumnSelectProps { export function SingleColumnSelect({ callback, columns, currentSelected, label, type }: SingleColumnSelectProps) { const filteredColumnsByType = React.useMemo(() => { - return columns.filter((c) => type.includes(c.type)).map((c) => ({ value: c.info.id, label: c.info.name })); + return columns.filter((c) => type.includes(c.type)).map((c) => ({ value: c.info.id, label: c.info.name, description: c.info.description })); }, [columns, type]); return ( + + + + `, + ); + + const filterMissing = findFilterMissing(node); + const input = node.querySelector('input[type="text"]'); + + this.enableLivePreviews([filterMissing, input]); + + if (!this.showLivePreviews()) { + return; + } + input.addEventListener( + 'input', + debounce(() => this.submit(), 100), + { + passive: true, + }, + ); + } +} diff --git a/src/ranking/smiles/SMILESRenderer.tsx b/src/ranking/smiles/SMILESRenderer.tsx new file mode 100644 index 000000000..355e39a38 --- /dev/null +++ b/src/ranking/smiles/SMILESRenderer.tsx @@ -0,0 +1,123 @@ +import { + ICellRendererFactory, + ERenderMode, + ICellRenderer, + IDataRow, + IRenderContext, + IGroupCellRenderer, + IOrderedGroup, + renderMissingDOM, + ISummaryRenderer, +} from 'lineupjs'; +import { abortAble } from 'lineupengine'; +import { SMILESColumn } from './SMILESColumn'; + +const template = '
'; + +function getImageURL(structure: string, substructure: string | null = null, align: string | null = null): string { + return `/api/rdkit/?structure=${encodeURIComponent(structure)}${substructure ? `&substructure=${encodeURIComponent(substructure)}` : ''}${ + align ? `&align=${encodeURIComponent(align)}` : '' + }`; +} + +async function fetchImage({ url, data, method }: { url: string; data?: any; method?: string }): Promise { + const response = await fetch(url, { + headers: { + 'Content-Type': 'application/json', + }, + // mode: '*cors', // no-cors, *cors, same-origin + method, + redirect: 'follow', + ...(data + ? { + body: JSON.stringify(data), + } + : {}), + }); + if (!response.ok) { + throw Error((await response.json().catch(() => null))?.message || response.statusText); + } + return response.text(); +} + +async function getReducedImages(structures: string[]): Promise { + // maximum common substructure + if (structures.length > 2) { + return fetchImage({ url: '/api/rdkit/mcs/', data: structures, method: 'POST' }); + } + + // similarity + if (structures.length === 2) { + const reference = structures[0]; + const probe = structures.length > 1 ? structures[1] : structures[0]; + return fetchImage({ url: `/api/rdkit/similarity/?structure=${encodeURIComponent(probe)}&reference=${encodeURIComponent(reference)}`, method: 'GET' }); + } + + // single = first structure + return fetchImage({ url: `/api/rdkit/?structure=${encodeURIComponent(structures[0])}`, method: 'GET' }); +} + +function svgToImageSrc(svg: string): string { + return `data:image/svg+xml;base64,${btoa(svg)}`; +} + +function svgToCSSBackground(svg: string): string { + return `url('${svgToImageSrc(svg)}')`; +} + +export class SMILESRenderer implements ICellRendererFactory { + readonly title: string = 'SMILES'; + + canRender(col: SMILESColumn, mode: ERenderMode): boolean { + return col instanceof SMILESColumn && (mode === ERenderMode.CELL || mode === ERenderMode.GROUP); + } + + create(col: SMILESColumn): ICellRenderer { + return { + template, + update: (n: HTMLLinkElement, d: IDataRow) => { + if (!renderMissingDOM(n, col, d)) { + if (d.v.images?.[0]) { + n.style.backgroundImage = svgToCSSBackground(d.v.images[0]); + return null; + } + const value = col?.getValue(d); + // Load aysnc to avoid triggering + return abortAble( + new Promise((resolve) => { + window.setTimeout(() => resolve(value), 500); + }), + ).then((image) => { + if (typeof image === 'symbol') { + return; + } + n.style.backgroundImage = `url('${getImageURL(value, col.getFilter()?.filter, col.getAlign())}')`; + n.title = value; + }); + } + return null; + }, + }; + } + + createGroup(col: SMILESColumn, context: IRenderContext): IGroupCellRenderer { + return { + template, + update: (n: HTMLImageElement, group: IOrderedGroup) => { + context.tasks.groupRows(col, group, 'SMILESRendererGroup', (rows) => { + return abortAble(getReducedImages(Array.from(rows.map((row) => col.getLabel(row))))).then((res: any) => { + n.style.backgroundImage = res ? svgToCSSBackground(res) : ''; + }); + }); + }, + }; + } + + createSummary(): ISummaryRenderer { + // no renderer + return { + template: `
`, + update: () => {}, + }; + } +} diff --git a/src/ranking/smiles/index.ts b/src/ranking/smiles/index.ts new file mode 100644 index 000000000..dd42bc417 --- /dev/null +++ b/src/ranking/smiles/index.ts @@ -0,0 +1,5 @@ +export * from './SMILESColumn'; +export * from './SMILESColumnBuilder'; +export * from './SMILESFilterDialog'; +export * from './SMILESRenderer'; +export * from './utils'; diff --git a/src/ranking/smiles/utils.ts b/src/ranking/smiles/utils.ts new file mode 100644 index 000000000..2e80c308e --- /dev/null +++ b/src/ranking/smiles/utils.ts @@ -0,0 +1,73 @@ +import { ALineUp, Column, DataBuilder, IRankingHeaderContext, LocalDataProvider, defaultOptions, dialogContext } from 'lineupjs'; +import { uniqueId } from 'lodash'; +import { SMILESColumn } from './SMILESColumn'; +import { SMILESRenderer } from './SMILESRenderer'; +import { SMILESFilterDialog } from './SMILESFilterDialog'; + +export function registerSMILESColumn(builder: DataBuilder, { setDynamicHeight = false }: { setDynamicHeight?: boolean } = {}) { + builder.registerColumnType('smiles', SMILESColumn); + builder.registerRenderer('smiles', new SMILESRenderer()); + builder.registerToolbarAction( + 'filterSMILES', + // TODO remove default string filter; use `filterString` as key would override the default string filter, but also for string columns + { + title: 'Filter …', // the toolbar icon is derived from this string! (= transformed to `lu-action-filter`) + onClick: (col: SMILESColumn, evt: MouseEvent, ctx: IRankingHeaderContext, level: number, viaShortcut: boolean) => { + const dialog = new SMILESFilterDialog(col, dialogContext(ctx, level, evt), ctx); + dialog.open(); + }, + options: { + mode: 'menu+shortcut', + featureCategory: 'ranking', + featureLevel: 'basic', + }, + }, + ); + + if (setDynamicHeight) { + builder.dynamicHeight((d, ranking) => { + const DEFAULT_ROW_HEIGHT = defaultOptions().rowHeight; // LineUp default rowHeight = 18 + + // get list of smiles columns from the current ranking + const smilesColumns = ranking.children.filter((col) => col instanceof SMILESColumn); + + if (smilesColumns.length === 0) { + return { defaultHeight: DEFAULT_ROW_HEIGHT, height: () => DEFAULT_ROW_HEIGHT, padding: () => 0 }; + } + + const maxColumnHeight = Math.max(DEFAULT_ROW_HEIGHT, ...smilesColumns.map((col) => col.getWidth())); // squared image -> use col width as height + + return { + defaultHeight: maxColumnHeight, + height: () => maxColumnHeight, + padding: () => 0, + }; + }); + } +} + +export function autosizeWithSMILESColumn({ provider, lineup }: { provider: LocalDataProvider; lineup: ALineUp }) { + const uid = uniqueId('smiles-column'); + + const addWidthChangedListener = (col: Column) => { + if (col instanceof SMILESColumn) { + col.on(`${Column.EVENT_WIDTH_CHANGED}.${uid}`, () => { + // trigger a re-render of LineUp using the new calculated row height in `dynamicHeight()` + lineup.update(); + }); + } + }; + + // Add width changed listener for new smiles columns + provider.on(`${LocalDataProvider.EVENT_ADD_COLUMN}.${uid}`, (col) => addWidthChangedListener(col)); + + // And remove it again when the column is removed + provider.on(`${LocalDataProvider.EVENT_REMOVE_COLUMN}.${uid}`, (col) => { + if (col instanceof SMILESColumn) { + col.on(`${Column.EVENT_WIDTH_CHANGED}.${uid}`, null); // remove event listener when column is removed + } + }); + + // Add width changed listener for existing smiles columns + provider.getRankings().forEach((ranking) => ranking.flatColumns.forEach((col) => addWidthChangedListener(col))); +} From e9b2f458678ba0295b2d0cbdc4653a3c8b0eb2a5 Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Mon, 22 May 2023 00:33:06 +0200 Subject: [PATCH 014/241] reworking some code --- src/vis/barGood/BarChart.tsx | 177 +----------------- src/vis/barGood/GroupedBars.tsx | 158 +++------------- src/vis/barGood/SimpleBars.tsx | 119 ++---------- src/vis/barGood/SingleBar.tsx | 2 +- src/vis/barGood/SingleBarChart.tsx | 88 +++++++++ src/vis/barGood/StackedBars.tsx | 53 ++++++ src/vis/barGood/hooks/useGetBarScales.ts | 44 +++++ .../barGood/hooks/useGetGroupedBarScales.ts | 55 ++++++ src/vis/barGood/utils.ts | 4 +- 9 files changed, 291 insertions(+), 409 deletions(-) create mode 100644 src/vis/barGood/SingleBarChart.tsx create mode 100644 src/vis/barGood/StackedBars.tsx create mode 100644 src/vis/barGood/hooks/useGetBarScales.ts create mode 100644 src/vis/barGood/hooks/useGetGroupedBarScales.ts diff --git a/src/vis/barGood/BarChart.tsx b/src/vis/barGood/BarChart.tsx index dbbf3ad60..3d6f2ead6 100644 --- a/src/vis/barGood/BarChart.tsx +++ b/src/vis/barGood/BarChart.tsx @@ -1,180 +1,13 @@ -import React, { useEffect, useMemo, useRef, useState } from 'react'; -import { all, desc, op, table } from 'arquero'; -import * as d3 from 'd3v7'; +import React from 'react'; import { Box, SimpleGrid } from '@mantine/core'; -import { EBarGroupingType, IBarConfig, IVisConfig, Scales, VisColumn } from '../interfaces'; -import { useSyncedRef } from '../../hooks/useSyncedRef'; -import { useAsync } from '../../hooks/useAsync'; -import { getBarData } from './utils'; -import { YAxis } from './YAxis'; -import { XAxis } from './XAxis'; -import { SingleBar } from './SingleBar'; -import { GroupedBars } from './GroupedBars'; -import { SimpleBars } from './SimpleBars'; - -const defaultExtensions = { - prePlot: null, - postPlot: null, - preSidebar: null, - postSidebar: null, -}; - -const margin = { - top: 25, - bottom: 25, - left: 25, - right: 100, -}; +import { IBarConfig, VisColumn } from '../interfaces'; +import { SingleBarChart } from './SingleBarChart'; export function BarChart({ config, columns }: { config: IBarConfig; columns: VisColumn[] }) { - const { value: allColumns, status: colsStatus } = useAsync(getBarData, [columns, config.catColumnSelected, config.group, config.multiples]); - - const ref = useRef(null); - - // const aggregatedTable = useMemo(() => { - // if (colsStatus === 'success') { - // const myTable = table({ category: allColumns.catColVals.resolvedValues.map((val) => val.val) }); - - // const grouped = myTable.groupby('category').count().orderby('category'); - - // return grouped; - // } - - // return null; - // }, [allColumns?.catColVals.resolvedValues, colsStatus]); - - // const groupedTable = useMemo(() => { - // if (colsStatus === 'success' && allColumns.groupColVals) { - // const myTable = table({ - // category: allColumns.catColVals.resolvedValues.map((val) => val.val), - // group: allColumns.groupColVals.resolvedValues.map((val) => val.val), - // }); - - // const grouped = myTable.groupby('category', 'group').count().orderby('category'); - - // return grouped; - // } - - // return null; - // }, [allColumns, colsStatus]); - - // const multiplesAndGroupTable = useMemo(() => { - // if (colsStatus === 'success' && allColumns.groupColVals && allColumns.multiplesColVals) { - // const myTable = table({ - // category: allColumns.catColVals.resolvedValues.map((val) => val.val), - // group: allColumns.groupColVals.resolvedValues.map((val) => val.val), - // multiples: allColumns.multiplesColVals.resolvedValues.map((val) => val.val), - // }); - - // const grouped = myTable.groupby('category', 'group', 'multiples').count().orderby('category'); - - // grouped.print(); - - // return grouped; - // } - - // return null; - // }, [allColumns, colsStatus]); - - // const multiplesTable = useMemo(() => { - // if (colsStatus === 'success' && allColumns.multiplesColVals) { - // const myTable = table({ - // category: allColumns.catColVals.resolvedValues.map((val) => val.val), - // multiples: allColumns.multiplesColVals.resolvedValues.map((val) => val.val), - // }); - - // const grouped = myTable.groupby('category', 'multiples').count().orderby('category'); - - // grouped.print(); - - // return grouped; - // } - - // return null; - // }, [allColumns, colsStatus]); - - // const groupColorScale = useMemo(() => { - // if (!groupedTable) return null; - - // const newGroup = groupedTable.ungroup().groupby('group').count(); - - // return d3.scaleOrdinal().domain(newGroup.array('group')).range(d3.schemeCategory10); - // }, [groupedTable]); - - // const groupScale = useMemo(() => { - // if (!aggregatedTable || !groupedTable) return null; - // const newGroup = groupedTable.ungroup().groupby('category', 'group').count(); - - // return d3.scaleBand().range([0, categoryScale.bandwidth()]).domain(newGroup.array('group')).padding(0.1); - // }, [aggregatedTable, categoryScale, groupedTable]); - - // const bars = useMemo(() => { - // if (config.group && groupedTable && config.groupType === EBarGroupingType.GROUP) { - // return groupedTable - // .groupby('category') - // .objects() - // .map((row: { category: string; group: string; count: number }) => { - // return ( - // - // ); - // }); - // } - // if (config.group && groupedTable && config.groupType === EBarGroupingType.STACK) { - // let heightSoFar = 0; - // let currentCategory = ''; - // return groupedTable.objects().map((row: { category: string; group: string; count: number }) => { - // if (currentCategory !== row.category) { - // heightSoFar = 0; - // currentCategory = row.category; - // } - - // const myHeight = heightSoFar; - // heightSoFar = myHeight + height + margin.top - countScale(row.count); - - // return ( - // - // ); - // }); - // } - // if (aggregatedTable) { - // return aggregatedTable.objects().map((row: { category: string; count: number }) => { - // return ( - // - // ); - // }); - // } - - // return null; - // }, [aggregatedTable, categoryScale, config.group, config.groupType, countScale, groupColorScale, groupScale, groupedTable, height]); - - console.log('looping?'); return ( - + 2 ? config.numColumnsSelected.length : 1}> - {config.group ? : } + ); diff --git a/src/vis/barGood/GroupedBars.tsx b/src/vis/barGood/GroupedBars.tsx index ecea230b2..223145d26 100644 --- a/src/vis/barGood/GroupedBars.tsx +++ b/src/vis/barGood/GroupedBars.tsx @@ -1,112 +1,27 @@ -import React, { useEffect, useMemo, useRef, useState } from 'react'; -import { all, desc, op, table } from 'arquero'; +import React, { useMemo } from 'react'; import * as d3 from 'd3v7'; -import { Box, Container, SimpleGrid } from '@mantine/core'; -import { EBarGroupingType, IBarConfig, IVisConfig, Scales, VisColumn } from '../interfaces'; -import { useSyncedRef } from '../../hooks/useSyncedRef'; -import { useAsync } from '../../hooks/useAsync'; -import { getBarData } from './utils'; -import { YAxis } from './YAxis'; -import { XAxis } from './XAxis'; -import { SingleBar } from './SingleBar'; - -const defaultExtensions = { - prePlot: null, - postPlot: null, - preSidebar: null, - postSidebar: null, -}; - -const margin = { - top: 25, - bottom: 25, - left: 25, - right: 100, -}; - -export function GroupedBars({ config, columns }: { config: IBarConfig; columns: VisColumn[] }) { - const { value: allColumns, status: colsStatus } = useAsync(getBarData, [columns, config.catColumnSelected, config.group, config.multiples]); - - const [height, setHeight] = useState(0); - const [width, setWidth] = useState(0); - - const ref = useRef(null); - - // resize observer for setting size of the svg and updating on size change - useEffect(() => { - const ro = new ResizeObserver((entries: ResizeObserverEntry[]) => { - setHeight(entries[0].contentRect.height - margin.top - margin.bottom); - setWidth(entries[0].contentRect.width - margin.left - margin.right); - }); - - if (ref) { - ro.observe(ref.current); - } - - return () => { - ro.disconnect(); - }; - }, []); - - const aggregatedTable = useMemo(() => { - if (colsStatus === 'success') { - const myTable = table({ category: allColumns.catColVals.resolvedValues.map((val) => val.val) }); - - const grouped = myTable.groupby('category').count().orderby('category'); - - return grouped; - } - return null; - }, [allColumns?.catColVals.resolvedValues, colsStatus]); - - const countScale = useMemo(() => { - if (!aggregatedTable) return null; - return d3 - .scaleLinear() - .range([height + margin.top, margin.top]) - .domain([0, +d3.max(aggregatedTable.array('count'))]); - }, [aggregatedTable, height]); - - const categoryScale = useMemo(() => { - if (!aggregatedTable) return null; - return d3 - .scaleBand() - .range([width + margin.left, margin.left]) - .domain(aggregatedTable.array('category')) - .padding(0.2); - }, [aggregatedTable, width]); - - const groupedTable = useMemo(() => { - if (colsStatus === 'success' && allColumns.groupColVals) { - const myTable = table({ - category: allColumns.catColVals.resolvedValues.map((val) => val.val), - group: allColumns.groupColVals.resolvedValues.map((val) => val.val), - }); - - const grouped = myTable.groupby('category', 'group').count().orderby('category'); - - return grouped; - } +import ColumnTable from 'arquero/dist/types/table/column-table'; - return null; - }, [allColumns, colsStatus]); - - const groupColorScale = useMemo(() => { - if (!groupedTable) return null; - - const newGroup = groupedTable.ungroup().groupby('group').count(); - - return d3.scaleOrdinal().domain(newGroup.array('group')).range(d3.schemeCategory10); - }, [groupedTable]); - - const groupScale = useMemo(() => { - if (!groupedTable) return null; - const newGroup = groupedTable.ungroup().groupby('category', 'group').count(); - - return d3.scaleBand().range([0, categoryScale.bandwidth()]).domain(newGroup.array('group')).padding(0.1); - }, [categoryScale, groupedTable]); +import { SingleBar } from './SingleBar'; +export function GroupedBars({ + groupedTable, + categoryScale, + countScale, + height, + margin, + groupScale, + groupColorScale, +}: { + groupedTable: ColumnTable; + categoryScale: d3.ScaleBand; + countScale: d3.ScaleLinear; + groupScale: d3.ScaleBand; + groupColorScale: d3.ScaleOrdinal; + height: number; + margin: { top: number; bottom: number; left: number; right: number }; +}) { const bars = useMemo(() => { if (groupedTable) { return groupedTable @@ -120,41 +35,14 @@ export function GroupedBars({ config, columns }: { config: IBarConfig; columns: width={groupScale.bandwidth()} y={countScale(row.count)} value={row.count} - height={height + margin.top - countScale(row.count)} + height={height - margin.bottom - countScale(row.count)} color={groupColorScale(row.group)} /> ); }); } return null; - }, [categoryScale, countScale, groupColorScale, groupScale, groupedTable, height]); + }, [categoryScale, countScale, groupColorScale, groupScale, groupedTable, height, margin.bottom]); - return ( - - - - - {countScale && categoryScale ? ( - - ) : null} - {categoryScale && countScale ? ( - - ) : null} - {bars} - - - - - ); + return {bars}; } diff --git a/src/vis/barGood/SimpleBars.tsx b/src/vis/barGood/SimpleBars.tsx index 34d515de7..ca6a61e23 100644 --- a/src/vis/barGood/SimpleBars.tsx +++ b/src/vis/barGood/SimpleBars.tsx @@ -1,76 +1,24 @@ -import React, { useEffect, useMemo, useRef, useState } from 'react'; -import { all, desc, op, table } from 'arquero'; -import * as d3 from 'd3v7'; -import { Box, Container, SimpleGrid } from '@mantine/core'; -import { EBarGroupingType, IBarConfig, IVisConfig, Scales, VisColumn } from '../interfaces'; -import { useSyncedRef } from '../../hooks/useSyncedRef'; -import { useAsync } from '../../hooks/useAsync'; -import { getBarData } from './utils'; -import { YAxis } from './YAxis'; -import { XAxis } from './XAxis'; -import { SingleBar } from './SingleBar'; -import { GroupedBars } from './GroupedBars'; - -const margin = { - top: 25, - bottom: 50, - left: 25, - right: 100, -}; - -export function SimpleBars({ config, columns }: { config: IBarConfig; columns: VisColumn[] }) { - const { value: allColumns, status: colsStatus } = useAsync(getBarData, [columns, config.catColumnSelected, config.group, config.multiples]); - - const [height, setHeight] = useState(0); - const [width, setWidth] = useState(0); - - const ref = useRef(null); - - // resize observer for setting size of the svg and updating on size change - useEffect(() => { - const ro = new ResizeObserver((entries: ResizeObserverEntry[]) => { - setHeight(entries[0].contentRect.height - margin.top - margin.bottom); - setWidth(entries[0].contentRect.width - margin.left - margin.right); - }); - - if (ref) { - ro.observe(ref.current); - } +import React, { useMemo } from 'react'; - return () => { - ro.disconnect(); - }; - }, []); - - const aggregatedTable = useMemo(() => { - if (colsStatus === 'success') { - const myTable = table({ category: allColumns.catColVals.resolvedValues.map((val) => val.val) }); - - const grouped = myTable.groupby('category').count().orderby('category'); - - return grouped; - } - - return null; - }, [allColumns?.catColVals.resolvedValues, colsStatus]); +import * as d3 from 'd3v7'; - const countScale = useMemo(() => { - if (!aggregatedTable) return null; - return d3 - .scaleLinear() - .range([height + margin.top, margin.top]) - .domain([0, +d3.max(aggregatedTable.array('count'))]); - }, [aggregatedTable, height]); +import ColumnTable from 'arquero/dist/types/table/column-table'; - const categoryScale = useMemo(() => { - if (!aggregatedTable) return null; - return d3 - .scaleBand() - .range([width + margin.left, margin.left]) - .domain(aggregatedTable.array('category')) - .padding(0.2); - }, [aggregatedTable, width]); +import { SingleBar } from './SingleBar'; +export function SimpleBars({ + aggregatedTable, + categoryScale, + countScale, + height, + margin, +}: { + aggregatedTable: ColumnTable; + categoryScale: d3.ScaleBand; + countScale: d3.ScaleLinear; + height: number; + margin: { top: number; bottom: number; left: number; right: number }; +}) { const bars = useMemo(() => { if (aggregatedTable && categoryScale && countScale) { return aggregatedTable.objects().map((row: { category: string; count: number }) => { @@ -81,41 +29,14 @@ export function SimpleBars({ config, columns }: { config: IBarConfig; columns: V width={categoryScale.bandwidth()} y={countScale(row.count)} value={row.count} - height={height + margin.top - countScale(row.count)} + height={height - margin.bottom - countScale(row.count)} /> ); }); } return null; - }, [aggregatedTable, categoryScale, countScale, height]); + }, [aggregatedTable, categoryScale, countScale, height, margin.bottom]); - return ( - - - - - {countScale && categoryScale ? ( - - ) : null} - {categoryScale && countScale ? ( - - ) : null} - {bars} - - - - - ); + return {bars}; } diff --git a/src/vis/barGood/SingleBar.tsx b/src/vis/barGood/SingleBar.tsx index ab264d6e1..8b9e21a78 100644 --- a/src/vis/barGood/SingleBar.tsx +++ b/src/vis/barGood/SingleBar.tsx @@ -1,5 +1,5 @@ import { Tooltip } from '@mantine/core'; -import React, { useEffect, useMemo, useRef, useState } from 'react'; +import React from 'react'; export function SingleBar({ x, diff --git a/src/vis/barGood/SingleBarChart.tsx b/src/vis/barGood/SingleBarChart.tsx new file mode 100644 index 000000000..7417452d8 --- /dev/null +++ b/src/vis/barGood/SingleBarChart.tsx @@ -0,0 +1,88 @@ +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { all, desc, op, table } from 'arquero'; +import * as d3 from 'd3v7'; +import { Box, Container, SimpleGrid } from '@mantine/core'; +import { useResizeObserver } from '@mantine/hooks'; +import { EBarGroupingType, IBarConfig, IVisConfig, Scales, VisColumn } from '../interfaces'; +import { useSyncedRef } from '../../hooks/useSyncedRef'; +import { useAsync } from '../../hooks/useAsync'; +import { getBarData } from './utils'; +import { YAxis } from './YAxis'; +import { XAxis } from './XAxis'; +import { GroupedBars } from './GroupedBars'; +import { useGetGroupedBarScales } from './hooks/useGetGroupedBarScales'; +import { SimpleBars } from './SimpleBars'; +import { StackedBars } from './StackedBars'; + +const margin = { + top: 25, + bottom: 50, + left: 25, + right: 100, +}; + +export function SingleBarChart({ config, columns }: { config: IBarConfig; columns: VisColumn[] }) { + const { value: allColumns, status: colsStatus } = useAsync(getBarData, [columns, config.catColumnSelected, config.group, config.multiples]); + + const [ref, { height, width }] = useResizeObserver(); + + const { aggregatedTable, categoryScale, countScale, groupColorScale, groupScale, groupedTable } = useGetGroupedBarScales( + allColumns, + colsStatus, + height, + width, + margin, + ); + + return ( + + + + + {countScale && categoryScale ? ( + + ) : null} + {categoryScale && countScale ? ( + + ) : null} + {config.group ? ( + config.groupType === EBarGroupingType.GROUP ? ( + + ) : ( + + ) + ) : ( + + )} + + + + + ); +} diff --git a/src/vis/barGood/StackedBars.tsx b/src/vis/barGood/StackedBars.tsx new file mode 100644 index 000000000..580abbe07 --- /dev/null +++ b/src/vis/barGood/StackedBars.tsx @@ -0,0 +1,53 @@ +import React, { useMemo } from 'react'; +import * as d3 from 'd3v7'; + +import ColumnTable from 'arquero/dist/types/table/column-table'; + +import { SingleBar } from './SingleBar'; + +export function StackedBars({ + groupedTable, + categoryScale, + countScale, + height, + margin, + groupColorScale, +}: { + groupedTable: ColumnTable; + categoryScale: d3.ScaleBand; + countScale: d3.ScaleLinear; + groupColorScale: d3.ScaleOrdinal; + height: number; + margin: { top: number; bottom: number; left: number; right: number }; +}) { + const bars = useMemo(() => { + if (groupedTable) { + let heightSoFar = 0; + let currentCategory = ''; + return groupedTable.objects().map((row: { category: string; group: string; count: number }) => { + if (currentCategory !== row.category) { + heightSoFar = 0; + currentCategory = row.category; + } + + const myHeight = heightSoFar; + heightSoFar = myHeight + height - margin.bottom - countScale(row.count); + + return ( + + ); + }); + } + return null; + }, [categoryScale, countScale, groupColorScale, groupedTable, height, margin.bottom]); + + return {bars}; +} diff --git a/src/vis/barGood/hooks/useGetBarScales.ts b/src/vis/barGood/hooks/useGetBarScales.ts new file mode 100644 index 000000000..d024ad344 --- /dev/null +++ b/src/vis/barGood/hooks/useGetBarScales.ts @@ -0,0 +1,44 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +import ColumnTable from 'arquero/dist/types/table/column-table'; +import { table } from 'arquero'; +import { useMemo } from 'react'; +import * as d3 from 'd3v7'; + +export function useGetBarScales( + allColumns: any, + colsStatus: any, + height: number, + width: number, + margin: { top: number; left: number; bottom: number; right: number }, +): { aggregatedTable: ColumnTable; countScale: d3.ScaleLinear; categoryScale: d3.ScaleBand } { + const aggregatedTable = useMemo(() => { + if (colsStatus === 'success') { + const myTable = table({ category: allColumns.catColVals.resolvedValues.map((val) => val.val) }); + + const grouped = myTable.groupby('category').count().orderby('category'); + + return grouped; + } + + return null; + }, [allColumns?.catColVals.resolvedValues, colsStatus]); + + const countScale = useMemo(() => { + if (!aggregatedTable) return null; + return d3 + .scaleLinear() + .range([height - margin.bottom, margin.top]) + .domain([0, +d3.max(aggregatedTable.array('count'))]); + }, [aggregatedTable, height, margin.bottom, margin.top]); + + const categoryScale = useMemo(() => { + if (!aggregatedTable) return null; + return d3 + .scaleBand() + .range([width - margin.right, margin.left]) + .domain(aggregatedTable.array('category')) + .padding(0.2); + }, [aggregatedTable, margin.left, margin.right, width]); + + return { aggregatedTable, countScale, categoryScale }; +} diff --git a/src/vis/barGood/hooks/useGetGroupedBarScales.ts b/src/vis/barGood/hooks/useGetGroupedBarScales.ts new file mode 100644 index 000000000..45b620273 --- /dev/null +++ b/src/vis/barGood/hooks/useGetGroupedBarScales.ts @@ -0,0 +1,55 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +import ColumnTable from 'arquero/dist/types/table/column-table'; +import { table } from 'arquero'; +import { useMemo } from 'react'; +import * as d3 from 'd3v7'; +import { useGetBarScales } from './useGetBarScales'; + +export function useGetGroupedBarScales( + allColumns: any, + colsStatus: any, + height: number, + width: number, + margin: { top: number; left: number; bottom: number; right: number }, +): { + aggregatedTable: ColumnTable; + countScale: d3.ScaleLinear; + categoryScale: d3.ScaleBand; + groupedTable: ColumnTable; + groupColorScale: d3.ScaleOrdinal; + groupScale: d3.ScaleBand; +} { + const { aggregatedTable, categoryScale, countScale } = useGetBarScales(allColumns, colsStatus, height, width, margin); + + const groupedTable = useMemo(() => { + if (colsStatus === 'success' && allColumns.groupColVals) { + const myTable = table({ + category: allColumns.catColVals.resolvedValues.map((val) => val.val), + group: allColumns.groupColVals.resolvedValues.map((val) => val.val), + }); + + const grouped = myTable.groupby('category', 'group').count().orderby('category'); + + return grouped; + } + + return null; + }, [allColumns, colsStatus]); + + const groupColorScale = useMemo(() => { + if (!groupedTable) return null; + + const newGroup = groupedTable.ungroup().groupby('group').count(); + + return d3.scaleOrdinal().domain(newGroup.array('group')).range(d3.schemeCategory10); + }, [groupedTable]); + + const groupScale = useMemo(() => { + if (!groupedTable) return null; + const newGroup = groupedTable.ungroup().groupby('category', 'group').count(); + + return d3.scaleBand().range([0, categoryScale.bandwidth()]).domain(newGroup.array('group')).padding(0.1); + }, [categoryScale, groupedTable]); + + return { aggregatedTable, countScale, categoryScale, groupColorScale, groupScale, groupedTable }; +} diff --git a/src/vis/barGood/utils.ts b/src/vis/barGood/utils.ts index a185c9255..2d75594fb 100644 --- a/src/vis/barGood/utils.ts +++ b/src/vis/barGood/utils.ts @@ -1,5 +1,5 @@ -import { resolveColumnValues, resolveSingleColumn } from '../general/layoutUtils'; -import { ColumnInfo, EColumnTypes, VisCategoricalValue, VisColumn, VisNumericalColumn, VisNumericalValue } from '../interfaces'; +import { resolveSingleColumn } from '../general/layoutUtils'; +import { ColumnInfo, EColumnTypes, VisCategoricalValue, VisColumn, VisNumericalValue } from '../interfaces'; export async function getBarData( columns: VisColumn[], From 0aace0735f36feb9e7989b3721e86d7f98b1cf2c Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Mon, 22 May 2023 01:13:56 +0200 Subject: [PATCH 015/241] adding custom color options to columns --- src/vis/bar/BarVis.tsx | 2 +- src/vis/bar/utils.ts | 4 ++-- src/vis/hexbin/Hexplot.tsx | 6 ++++-- src/vis/hexbin/utils.tsx | 1 + src/vis/interfaces.ts | 2 ++ src/vis/scatter/utils.ts | 14 +++++++++++--- src/vis/stories/Iris.stories.tsx | 1 + src/vis/violin/ViolinVis.tsx | 1 - 8 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/vis/bar/BarVis.tsx b/src/vis/bar/BarVis.tsx index 4bf0d9f30..9288da1c6 100644 --- a/src/vis/bar/BarVis.tsx +++ b/src/vis/bar/BarVis.tsx @@ -4,7 +4,7 @@ import merge from 'lodash/merge'; import uniqueId from 'lodash/uniqueId'; import difference from 'lodash/difference'; import { useEffect, useMemo, useState } from 'react'; -import { ActionIcon, Container, Space, Stack, Tooltip } from '@mantine/core'; +import { ActionIcon, Space, Stack, Tooltip } from '@mantine/core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faGear } from '@fortawesome/free-solid-svg-icons/faGear'; import { Scales, VisColumn, IVisConfig, IBarConfig, EBarGroupingType } from '../interfaces'; diff --git a/src/vis/bar/utils.ts b/src/vis/bar/utils.ts index ee5691289..5bd0d7430 100644 --- a/src/vis/bar/utils.ts +++ b/src/vis/bar/utils.ts @@ -201,7 +201,7 @@ async function setPlotsWithGroupsAndMultiples( type: 'bar', name: uniqueGroup, marker: { - color: scales.color(uniqueGroup), + color: currGroupColumn.color ? currGroupColumn.color[uniqueGroup] : scales.color(uniqueGroup), }, // @ts-ignore selected: { @@ -298,7 +298,7 @@ async function setPlotsWithGroups( type: 'bar', name: uniqueVal, marker: { - color: scales.color(uniqueVal), + color: groupColumn.color ? groupColumn.color[uniqueVal] : scales.color(uniqueVal), }, // @ts-ignore selected: { diff --git a/src/vis/hexbin/Hexplot.tsx b/src/vis/hexbin/Hexplot.tsx index 4f19373e6..71aef3026 100644 --- a/src/vis/hexbin/Hexplot.tsx +++ b/src/vis/hexbin/Hexplot.tsx @@ -261,8 +261,10 @@ export function Hexplot({ config, columns, selectionCallback = () => null, selec const colorOptions = currentColorColumn.allValues.map((val) => val.val as string); - return d3v7.scaleOrdinal(d3v7.schemeCategory10).domain(Array.from(new Set(colorOptions))); - }, [colsStatus, currentColorColumn?.allValues]); + return d3v7 + .scaleOrdinal(allColumns.colorColVals.color ? Object.keys(allColumns.colorColVals.color) : d3v7.schemeCategory10) + .domain(allColumns.colorColVals.color ? Object.values(allColumns.colorColVals.color) : Array.from(new Set(colorOptions))); + }, [allColumns, colsStatus, currentColorColumn]); // memoize the actual hexes since they do not need to change on zoom/drag const hexObjects = React.useMemo(() => { diff --git a/src/vis/hexbin/utils.tsx b/src/vis/hexbin/utils.tsx index 7ea6834cb..d3c9c97bd 100644 --- a/src/vis/hexbin/utils.tsx +++ b/src/vis/hexbin/utils.tsx @@ -59,6 +59,7 @@ export async function getHexData( colorColVals: { resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; type: EColumnTypes.NUMERICAL | EColumnTypes.CATEGORICAL; + color?: Record; info: ColumnInfo; }; }> { diff --git a/src/vis/interfaces.ts b/src/vis/interfaces.ts index 12380ab97..45e99396a 100644 --- a/src/vis/interfaces.ts +++ b/src/vis/interfaces.ts @@ -145,10 +145,12 @@ export interface VisCommonColumn { export interface VisNumericalColumn extends VisCommonColumn { type: EColumnTypes.NUMERICAL; domain?: [number | undefined, number | undefined]; + color?: Record; } export interface VisCategoricalColumn extends VisCommonColumn { type: EColumnTypes.CATEGORICAL; + color?: Record; } export type VisColumn = VisNumericalColumn | VisCategoricalColumn; diff --git a/src/vis/scatter/utils.ts b/src/vis/scatter/utils.ts index 735d50278..229ae2fa1 100644 --- a/src/vis/scatter/utils.ts +++ b/src/vis/scatter/utils.ts @@ -182,7 +182,9 @@ export async function createScatterTraces( symbol: shapeCol ? shapeCol.resolvedValues.map((v) => shapeScale(v.val as string)) : 'circle', color: colorCol - ? colorCol.resolvedValues.map((v) => (colorCol.type === EColumnTypes.NUMERICAL ? numericalColorScale(v.val as number) : scales.color(v.val))) + ? colorCol.resolvedValues.map((v) => + colorCol.type === EColumnTypes.NUMERICAL ? numericalColorScale(v.val as number) : colorCol.color ? colorCol.color[v.val] : scales.color(v.val), + ) : SELECT_COLOR, }, // plotly is stupid and doesnt know its own types @@ -267,7 +269,13 @@ export async function createScatterTraces( text: validCols[0].resolvedValues.map((v) => v.id.toString()), marker: { color: colorCol - ? colorCol.resolvedValues.map((v) => (colorCol.type === EColumnTypes.NUMERICAL ? numericalColorScale(v.val as number) : scales.color(v.val))) + ? colorCol.resolvedValues.map((v) => + colorCol.type === EColumnTypes.NUMERICAL + ? numericalColorScale(v.val as number) + : colorCol.color + ? colorCol.color[v.val] + : scales.color(v.val), + ) : SELECT_COLOR, }, // plotly is stupid and doesnt know its own types @@ -332,7 +340,7 @@ export async function createScatterTraces( }, symbol: 'circle', size: 8, - color: colorCol ? colorCol.resolvedValues.map((v) => scales.color(v.val)) : DEFAULT_COLOR, + color: colorCol ? colorCol.resolvedValues.map((v) => (colorCol.color ? colorCol.color[v.val] : scales.color(v.val))) : DEFAULT_COLOR, opacity: 1, }, transforms: [ diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index c7a0e0e43..80fc5928d 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -43,6 +43,7 @@ export function fetchIrisData(): VisColumn[] { name: 'Random Thing', }, type: EColumnTypes.CATEGORICAL, + color: { 1: 'cornflowerblue' }, values: () => dataPromise.then((data) => data.map((r) => Math.round(Math.random() * 4)).map((val, i) => ({ id: i.toString(), val: val.toString() }))), }, { diff --git a/src/vis/violin/ViolinVis.tsx b/src/vis/violin/ViolinVis.tsx index f67372749..f925b7723 100644 --- a/src/vis/violin/ViolinVis.tsx +++ b/src/vis/violin/ViolinVis.tsx @@ -80,7 +80,6 @@ export function ViolinVis({ const plotlyDivRef = React.useRef(null); const onClick = (e: Readonly | null) => { - console.log(e); if (!e || !e.points || !e.points[0]) { selectionCallback([]); return; From 66ed81e38fde6e4beab3f73990ac19db5623910e Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Mon, 22 May 2023 10:22:51 +0200 Subject: [PATCH 016/241] making bars color grey if not passed in --- src/vis/bar/utils.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/vis/bar/utils.ts b/src/vis/bar/utils.ts index 5bd0d7430..e862ea4a2 100644 --- a/src/vis/bar/utils.ts +++ b/src/vis/bar/utils.ts @@ -45,6 +45,7 @@ const defaultConfig: IBarConfig = { }; const TICK_LABEL_LENGTH = 8; +const DEFAULT_GRAY = '#878E95'; export function barMergeDefaultConfig(columns: VisColumn[], config: IBarConfig): IVisConfig { const merged = merge({}, defaultConfig, config); @@ -201,7 +202,7 @@ async function setPlotsWithGroupsAndMultiples( type: 'bar', name: uniqueGroup, marker: { - color: currGroupColumn.color ? currGroupColumn.color[uniqueGroup] : scales.color(uniqueGroup), + color: currGroupColumn.color ? currGroupColumn.color[uniqueGroup] || DEFAULT_GRAY : scales.color(uniqueGroup), }, // @ts-ignore selected: { @@ -298,7 +299,7 @@ async function setPlotsWithGroups( type: 'bar', name: uniqueVal, marker: { - color: groupColumn.color ? groupColumn.color[uniqueVal] : scales.color(uniqueVal), + color: groupColumn.color ? groupColumn.color[uniqueVal] || DEFAULT_GRAY : scales.color(uniqueVal), }, // @ts-ignore selected: { @@ -379,7 +380,7 @@ async function setPlotsWithMultiples( type: 'bar', name: uniqueVal, marker: { - color: '#878E95', + color: DEFAULT_GRAY, }, // @ts-ignore selected: { @@ -448,7 +449,7 @@ async function setPlotsBasic( hoverinfo: vertFlag ? 'y+text' : 'x+text', ids: valArr, marker: { - color: '#878E95', + color: DEFAULT_GRAY, }, // @ts-ignore selected: { From e38d414de67f1537ecdd2cc31b8b8b2776e57da1 Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Mon, 22 May 2023 10:41:16 +0200 Subject: [PATCH 017/241] adding violin selection --- src/vis/sidebar/GroupSelect.tsx | 1 + src/vis/violin/ViolinVis.tsx | 3 ++- src/vis/violin/utils.ts | 16 +++++++++++++--- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/vis/sidebar/GroupSelect.tsx b/src/vis/sidebar/GroupSelect.tsx index 9f3466e2f..da3e8123f 100644 --- a/src/vis/sidebar/GroupSelect.tsx +++ b/src/vis/sidebar/GroupSelect.tsx @@ -28,6 +28,7 @@ export function GroupSelect({ { + { + if (newValue === 'none') { const p = permission.clone(); setGetter(p).clear(); setPermission(p); - }} - /> - - { + } else if (newValue === 'read') { const p = permission.clone(); setGetter(p).clear(); setGetter(p).add(EPermission.READ); setPermission(p); - }} - /> - - { + } else if (newValue === 'write') { const p = permission.clone(); setGetter(p).clear(); setGetter(p).add(EPermission.READ); setGetter(p).add(EPermission.WRITE); setPermission(p); - }} - /> - - + } + }} + data={[ + { + label: ( + <> + {i18n.t('visyn:permission.noPermission')} + + ), + value: 'none', + }, + { + label: ( + <> + {i18n.t('visyn:permission.read')} + + ), + value: 'read', + }, + { + label: ( + <> + {i18n.t('visyn:permission.write')} + + ), + value: 'write', + }, + ]} + /> ); } -export function PermissionChooser({ - permission, - buddies, - group, - setPermission, - setBuddies, - setGroup, - extra = null, -}: { +interface PermissionChooserProps extends DefaultProps { permission: Permission; buddies: string[]; group: string; @@ -87,104 +84,118 @@ export function PermissionChooser({ setBuddies: (buddies: string[]) => void; setGroup: (group: string) => void; extra?: React.ReactNode; -}) { - const id = React.useMemo(() => uniqueId('PermissionChooser'), []); - const user = userSession.currentUser(); - const roles = user ? user.roles : UserUtils.ANONYMOUS_USER.roles; - const [advancedOpen, setAdvancedOpen] = React.useState(false); +} - return ( - <> -
- { - const p = permission.clone(); - p.others.clear(); - setPermission(p); - }} - /> - -
-
- { - const p = permission.clone(); - p.others.clear(); - p.others.add(EPermission.READ); - setPermission(p); - }} - /> - -
+export const PermissionChooser = React.forwardRef & PermissionChooserProps>( + ({ permission, buddies, group, setPermission, setBuddies, setGroup, extra, ...others }, ref) => { + const id = React.useMemo(() => uniqueId('PermissionChooser'), []); + const user = userSession.currentUser(); + const roles = user ? user.roles : UserUtils.ANONYMOUS_USER.roles; + const [advancedOpen, setAdvancedOpen] = React.useState(false); + + return ( + + + { + if (value === 'private') { + const p = permission.clone(); + p.others.clear(); + setPermission(p); + } else { + const p = permission.clone(); + p.others.clear(); + p.others.add(EPermission.READ); + setPermission(p); + } + }} + > + + + {i18n.t('visyn:permission.private')} + + } + /> + + {i18n.t('visyn:permission.publicMsg')} + + } + /> + + - - {extra} -
-
- {/* eslint-disable-next-line jsx-a11y/label-has-associated-control */} - - - p.others} /> -
+ + -

{i18n.t('visyn:permission.definePermissions')}

+ {extra} -
- - - p.group} /> -
+ {i18n.t('visyn:permission.public')} +
+ p.others} /> -

{i18n.t('visyn:permission.specifyRole')}

+ + {i18n.t('visyn:permission.definePermissions')} + -
- - setBuddies(e.currentTarget.value.split(';'))} - /> - p.buddies} /> -
-

{i18n.t('visyn:permission.buddiesDescription')}

-
- - ); -} + {i18n.t('visyn:permission.group')} + { - setLoading(true); - // eslint-disable-next-line no-promise-executor-return - await new Promise((resolve) => setTimeout(resolve, 1000)); - createScoreColumnFunc.current(({ data }) => { - return value === 'number' ? MyNumberScore(value) : MyStringScore(value); - }); - setLoading(false); - }} - rightSection={loading ? : null} - data={[ - { value: 'number', label: 'Number' }, - { value: 'category', label: 'Category' }, - ]} - /> - (createScoreColumnFunc.current = createScoreColumn)} - /> - - { - setSelection(s.map((i) => iris[+i])); - }} - /> - - ) : null} + + ); } diff --git a/src/vis/Vis.tsx b/src/vis/Vis.tsx index 3f996e8bd..a98b35010 100644 --- a/src/vis/Vis.tsx +++ b/src/vis/Vis.tsx @@ -23,6 +23,7 @@ import { getCssValue } from '../utils'; import { useSyncedRef } from '../hooks/useSyncedRef'; import { hexinbMergeDefaultConfig, isHexbin } from './hexbin/utils'; import { HexbinVis } from './hexbin/HexbinVis'; +import { CorrelationMatrix, isCorrelation } from './correlation'; const DEFAULT_SHAPES = ['circle', 'square', 'triangle-up', 'star']; @@ -284,6 +285,8 @@ export function EagerVis({ {...commonProps} /> ) : null} + + {isCorrelation(visConfig) ? : null} ); } diff --git a/src/vis/correlation/CorrelationMatrix.tsx b/src/vis/correlation/CorrelationMatrix.tsx new file mode 100644 index 000000000..c544f66ed --- /dev/null +++ b/src/vis/correlation/CorrelationMatrix.tsx @@ -0,0 +1,18 @@ +import * as React from 'react'; +import { ICorrelationConfig, IVisConfig, VisColumn } from '../interfaces'; + +export function CorrelationMatrix({ + config, + columns, + setConfig, +}: { + config: ICorrelationConfig; + columns: VisColumn[]; + setConfig: (config: IVisConfig) => void; +}) { + return ( +
+

Correlation Matrix

+
+ ); +} diff --git a/src/vis/correlation/index.ts b/src/vis/correlation/index.ts new file mode 100644 index 000000000..3019af66b --- /dev/null +++ b/src/vis/correlation/index.ts @@ -0,0 +1,2 @@ +export * from './CorrelationMatrix'; +export * from './utils'; diff --git a/src/vis/correlation/utils.ts b/src/vis/correlation/utils.ts new file mode 100644 index 000000000..69d319a56 --- /dev/null +++ b/src/vis/correlation/utils.ts @@ -0,0 +1,17 @@ +import merge from 'lodash/merge'; +import { ESupportedPlotlyVis, ICorrelationConfig, IVisConfig, VisColumn } from '../interfaces'; + +export function isCorrelation(s: IVisConfig): s is ICorrelationConfig { + return s.type === ESupportedPlotlyVis.BAR; +} + +const defaultConfig: ICorrelationConfig = { + type: ESupportedPlotlyVis.CORRELATION, + numColumnsSelected: [], +}; + +export function correlationMergeDefaultConfig(columns: VisColumn[], config: ICorrelationConfig): IVisConfig { + const merged = merge({}, defaultConfig, config); + + return merged; +} diff --git a/src/vis/interfaces.ts b/src/vis/interfaces.ts index 45e99396a..1b30aaef2 100644 --- a/src/vis/interfaces.ts +++ b/src/vis/interfaces.ts @@ -5,6 +5,7 @@ export enum ESupportedPlotlyVis { VIOLIN = 'Violin plot', BAR = 'Bar chart', HEXBIN = 'Hexbin plot', + CORRELATION = 'Correlation plot', } export const allVisTypes: ESupportedPlotlyVis[] = [ @@ -12,9 +13,10 @@ export const allVisTypes: ESupportedPlotlyVis[] = [ ESupportedPlotlyVis.BAR, ESupportedPlotlyVis.VIOLIN, ESupportedPlotlyVis.HEXBIN, + ESupportedPlotlyVis.CORRELATION, ]; -export type IVisConfig = IScatterConfig | IViolinConfig | IBarConfig | IHexbinConfig; +export type IVisConfig = IScatterConfig | IViolinConfig | IBarConfig | IHexbinConfig | ICorrelationConfig; export enum EBarDisplayType { ABSOLUTE = 'Absolute', @@ -86,6 +88,11 @@ export interface IViolinConfig { violinOverlay: EViolinOverlay; } +export interface ICorrelationConfig { + type: ESupportedPlotlyVis.CORRELATION; + numColumnsSelected: ColumnInfo[]; +} + export interface IScatterConfig { type: ESupportedPlotlyVis.SCATTER; numColumnsSelected: ColumnInfo[]; From 4909fb6ae8f5ce98ef02301f1ceca6e983df7148 Mon Sep 17 00:00:00 2001 From: Daniela Date: Mon, 19 Jun 2023 11:26:05 +0200 Subject: [PATCH 065/241] add sidebar --- src/vis/Vis.tsx | 32 ++++++ src/vis/parallelCoordinates/ParallelVis.tsx | 94 ++++++++++++++++ .../ParallelVisSidebar.tsx | 100 ++++++++++++++++++ src/vis/stories/Iris.stories.tsx | 27 +++++ 4 files changed, 253 insertions(+) create mode 100644 src/vis/parallelCoordinates/ParallelVis.tsx create mode 100644 src/vis/parallelCoordinates/ParallelVisSidebar.tsx diff --git a/src/vis/Vis.tsx b/src/vis/Vis.tsx index 3f996e8bd..38678a145 100644 --- a/src/vis/Vis.tsx +++ b/src/vis/Vis.tsx @@ -23,6 +23,8 @@ import { getCssValue } from '../utils'; import { useSyncedRef } from '../hooks/useSyncedRef'; import { hexinbMergeDefaultConfig, isHexbin } from './hexbin/utils'; import { HexbinVis } from './hexbin/HexbinVis'; +import { isParallelCoordinates, parallelCoordinatesMergeDefaultConfig } from './parallelCoordinates/utils'; +import { ParallelVis } from './parallelCoordinates/ParallelVis'; const DEFAULT_SHAPES = ['circle', 'square', 'triangle-up', 'star']; @@ -157,6 +159,11 @@ export function EagerVis({ const newConfig = hexinbMergeDefaultConfig(columns, inconsistentVisConfig); _setVisConfig({ current: newConfig, consistent: newConfig }); } + if (isParallelCoordinates(inconsistentVisConfig)) { + // todo + const newConfig = parallelCoordinatesMergeDefaultConfig(columns, inconsistentVisConfig); + _setVisConfig({ current: newConfig, consistent: newConfig }); + } // DANGER:: this useEffect should only occur when the visConfig.type changes. adding visconfig into the dep array will cause an infinite loop. // eslint-disable-next-line react-hooks/exhaustive-deps }, [inconsistentVisConfig.type]); @@ -238,6 +245,31 @@ export function EagerVis({ /> ) : null} + {isParallelCoordinates(visConfig) ? ( + + ) : null} + {isViolin(visConfig) ? ( void; + showSidebar?: boolean; + setShowSidebar?(show: boolean): void; + enableSidebar?: boolean; +}) { + return ( + + {enableSidebar ? setShowSidebar(!showSidebar)} isOpen={showSidebar} /> : null} + + + {config.numColumnsSelected.length > 1 ? 'hello world' : null} + + {showSidebar ? ( + + + + ) : null} + + ); +} diff --git a/src/vis/parallelCoordinates/ParallelVisSidebar.tsx b/src/vis/parallelCoordinates/ParallelVisSidebar.tsx new file mode 100644 index 000000000..27a748377 --- /dev/null +++ b/src/vis/parallelCoordinates/ParallelVisSidebar.tsx @@ -0,0 +1,100 @@ +import * as React from 'react'; +import { useMemo } from 'react'; +import merge from 'lodash/merge'; +import { Container, Divider, Stack } from '@mantine/core'; +import { ColumnInfo, EFilterOptions, ESupportedPlotlyVis, IVisConfig, VisColumn, ICommonVisSideBarProps, IParallelCoordinatesConfig } from '../interfaces'; +import { VisTypeSelect } from '../sidebar/VisTypeSelect'; +import { NumericalColumnSelect } from '../sidebar/NumericalColumnSelect'; +import { FilterButtons } from '../sidebar/FilterButtons'; +import { CategoricalColumnSelect } from '../sidebar/CategoricalColumnSelect'; + +const defaultConfig = { + color: { + enable: true, + customComponent: null, + }, + shape: { + enable: true, + customComponent: null, + }, + filter: { + enable: true, + customComponent: null, + }, +}; + +const defaultExtensions = { + prePlot: null, + postPlot: null, + preSidebar: null, + postSidebar: null, +}; + +export function ParallelVisSidebar({ + config, + optionsConfig, + extensions, + columns, + filterCallback = () => null, + setConfig, +}: { + config: IParallelCoordinatesConfig; + optionsConfig?: { + color?: { + enable?: boolean; + customComponent?: React.ReactNode; + }; + shape?: { + enable?: boolean; + customComponent?: React.ReactNode; + }; + filter?: { + enable?: boolean; + customComponent?: React.ReactNode; + }; + }; + extensions?: { + prePlot?: React.ReactNode; + postPlot?: React.ReactNode; + preSidebar?: React.ReactNode; + postSidebar?: React.ReactNode; + }; + columns: VisColumn[]; + filterCallback?: (s: EFilterOptions) => void; + setConfig: (config: IVisConfig) => void; +} & ICommonVisSideBarProps) { + const mergedOptionsConfig = useMemo(() => { + return merge({}, defaultConfig, optionsConfig); + }, [optionsConfig]); + + const mergedExtensions = useMemo(() => { + return merge({}, defaultExtensions, extensions); + }, [extensions]); + + return ( + + + setConfig({ ...(config as any), type })} currentSelected={config.type} /> + + setConfig({ ...config, numColumnsSelected })} + columns={columns} + currentSelected={config.numColumnsSelected || []} + /> + + setConfig({ ...config, catColumnsSelected })} + columns={columns} + currentSelected={config.catColumnsSelected || []} + /> + + {mergedExtensions.preSidebar} + + + + {mergedOptionsConfig.filter.enable ? mergedOptionsConfig.filter.customComponent || : null} + {mergedExtensions.postSidebar} + + + ); +} diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index 288fe7e79..aa00f52cf 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -175,3 +175,30 @@ ViolinPlot.args = { violinOverlay: EViolinOverlay.NONE, }, }; + +export const ParallelPlot: typeof Template = Template.bind({}); +ParallelPlot.args = { + externalConfig: { + type: ESupportedPlotlyVis.PARALLEL_COORDINATES, + color: null, // todo + numColumnsSelected: [ + { + description: '', + id: 'sepalLength', + name: 'Sepal Length', + }, + { + description: '', + id: 'sepalWidth', + name: 'Sepal Width', + }, + ], + catColumnsSelected: [ + { + description: '', + id: 'species', + name: 'Species', + }, + ], + }, +}; From 98eb46544ebfd4d3acb7837450ddae937a0ce6c3 Mon Sep 17 00:00:00 2001 From: oltionchampari Date: Mon, 19 Jun 2023 13:00:36 +0200 Subject: [PATCH 066/241] Add line component --- src/vis/parallelCoordinates/Line.tsx | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/vis/parallelCoordinates/Line.tsx diff --git a/src/vis/parallelCoordinates/Line.tsx b/src/vis/parallelCoordinates/Line.tsx new file mode 100644 index 000000000..2590ed7c8 --- /dev/null +++ b/src/vis/parallelCoordinates/Line.tsx @@ -0,0 +1,5 @@ +import React from 'react'; + +export function Line({ x1, y1, x2, y2, label }: { x1: number; y1: number; x2: number; y2: number; label: string }) { + ; +} From bf0dff64b28cf8685bebf22294ef4f38ce1fc78f Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Mon, 19 Jun 2023 13:26:17 +0200 Subject: [PATCH 067/241] adding heatmap data --- src/vis/stories/Iris.stories.tsx | 119 ++++++++++++++++--------------- 1 file changed, 62 insertions(+), 57 deletions(-) diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index 288fe7e79..a73db19ef 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -13,67 +13,72 @@ import { EViolinOverlay, VisColumn, } from '../interfaces'; +import { data } from './heatmapData'; export function fetchIrisData(): VisColumn[] { const dataPromise = import('./irisData').then((m) => m.iris); - return [ - { - info: { - description: 'data from description', - id: 'sepalLength', - name: 'Sepal Length', - }, - type: EColumnTypes.NUMERICAL, - values: () => dataPromise.then((data) => data.map((r) => r.sepalLength).map((val, i) => ({ id: i.toString(), val }))), - }, - { - info: { - description: 'data from description', - id: 'sepalWidth', - name: 'Sepal Width', - }, - type: EColumnTypes.NUMERICAL, - values: () => dataPromise.then((data) => data.map((r) => r.sepalWidth).map((val, i) => ({ id: i.toString(), val }))), - }, - { - info: { - description: '', - id: 'randomThing', - name: 'Random Thing', - }, - type: EColumnTypes.CATEGORICAL, - color: { 1: 'cornflowerblue' }, - values: () => dataPromise.then((data) => data.map((r) => Math.round(Math.random() * 4)).map((val, i) => ({ id: i.toString(), val: val.toString() }))), - }, - { - info: { - description: 'data from description', - id: 'petalLength', - name: 'Petal Length PEtal length petal length', - }, - type: EColumnTypes.NUMERICAL, - values: () => dataPromise.then((data) => data.map((r) => r.petalLength).map((val, i) => ({ id: i.toString(), val }))), - }, - { - info: { - description: 'data from description', - id: 'petalWidth', - name: 'Petal Width', - }, - type: EColumnTypes.NUMERICAL, - values: () => dataPromise.then((data) => data.map((r) => r.petalWidth).map((val, i) => ({ id: i.toString(), val }))), - }, - { - info: { - description: 'data from description', - id: 'species', - name: 'Species', - }, - type: EColumnTypes.CATEGORICAL, - values: () => dataPromise.then((data) => data.map((r) => r.species).map((val, i) => ({ id: i.toString(), val }))), - }, - ]; + const heatmapData = data; + + heatmapData.forEach(); + + // return [ + // { + // info: { + // description: 'data from description', + // id: 'sepalLength', + // name: 'Sepal Length', + // }, + // type: EColumnTypes.NUMERICAL, + // values: () => dataPromise.then((data) => data.map((r) => r.sepalLength).map((val, i) => ({ id: i.toString(), val }))), + // }, + // { + // info: { + // description: 'data from description', + // id: 'sepalWidth', + // name: 'Sepal Width', + // }, + // type: EColumnTypes.NUMERICAL, + // values: () => dataPromise.then((data) => data.map((r) => r.sepalWidth).map((val, i) => ({ id: i.toString(), val }))), + // }, + // { + // info: { + // description: '', + // id: 'randomThing', + // name: 'Random Thing', + // }, + // type: EColumnTypes.CATEGORICAL, + // color: { 1: 'cornflowerblue' }, + // values: () => dataPromise.then((data) => data.map((r) => Math.round(Math.random() * 4)).map((val, i) => ({ id: i.toString(), val: val.toString() }))), + // }, + // { + // info: { + // description: 'data from description', + // id: 'petalLength', + // name: 'Petal Length PEtal length petal length', + // }, + // type: EColumnTypes.NUMERICAL, + // values: () => dataPromise.then((data) => data.map((r) => r.petalLength).map((val, i) => ({ id: i.toString(), val }))), + // }, + // { + // info: { + // description: 'data from description', + // id: 'petalWidth', + // name: 'Petal Width', + // }, + // type: EColumnTypes.NUMERICAL, + // values: () => dataPromise.then((data) => data.map((r) => r.petalWidth).map((val, i) => ({ id: i.toString(), val }))), + // }, + // { + // info: { + // description: 'data from description', + // id: 'species', + // name: 'Species', + // }, + // type: EColumnTypes.CATEGORICAL, + // values: () => dataPromise.then((data) => data.map((r) => r.species).map((val, i) => ({ id: i.toString(), val }))), + // }, + // ]; } // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export From 43d92901aa666a4015499c8a4d25839de8e8e9e4 Mon Sep 17 00:00:00 2001 From: Daniela Date: Mon, 19 Jun 2023 13:33:06 +0200 Subject: [PATCH 068/241] add data loading --- src/vis/parallelCoordinates/ParallelPlot.tsx | 41 +++++++++++++++++++ src/vis/parallelCoordinates/ParallelVis.tsx | 5 ++- .../ParallelVisSidebar.tsx | 2 - src/vis/parallelCoordinates/XAxis.tsx | 36 ++++++++++++++++ src/vis/parallelCoordinates/YAxis.tsx | 41 +++++++++++++++++++ src/vis/parallelCoordinates/utils.ts | 33 +++++++++++++++ 6 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 src/vis/parallelCoordinates/ParallelPlot.tsx create mode 100644 src/vis/parallelCoordinates/XAxis.tsx create mode 100644 src/vis/parallelCoordinates/YAxis.tsx diff --git a/src/vis/parallelCoordinates/ParallelPlot.tsx b/src/vis/parallelCoordinates/ParallelPlot.tsx new file mode 100644 index 000000000..4aec45b76 --- /dev/null +++ b/src/vis/parallelCoordinates/ParallelPlot.tsx @@ -0,0 +1,41 @@ +import * as React from 'react'; +import merge from 'lodash/merge'; +import uniqueId from 'lodash/uniqueId'; +import { useEffect, useState } from 'react'; +import { Center, Group, Stack } from '@mantine/core'; +import * as d3 from 'd3v7'; +import { EFilterOptions, IVisConfig, Scales, IScatterConfig, VisColumn, EScatterSelectSettings, IParallelCoordinatesConfig } from '../interfaces'; +import { InvalidCols } from '../general/InvalidCols'; +import { beautifyLayout } from '../general/layoutUtils'; +import { BrushOptionButtons } from '../sidebar/BrushOptionButtons'; +import { PlotlyComponent } from '../../plotly'; +import { Plotly } from '../../plotly/full'; +import { useAsync } from '../../hooks'; +import { VisSidebarWrapper } from '../VisSidebarWrapper'; +import { CloseButton } from '../sidebar/CloseButton'; +import { i18n } from '../../i18n'; +import { VisSidebarOpenButton } from '../VisSidebarOpenButton'; +import { ScatterVisSidebar } from '../scatter/ScatterVisSidebar'; +import { ParallelVisSidebar } from './ParallelVisSidebar'; + +const defaultExtensions = { + prePlot: null, + postPlot: null, + preSidebar: null, + postSidebar: null, +}; + +const margin = { + top: 30, + right: 10, + bottom: 10, + left: 10, +}; + +export function ParallelPlot() { + return ( + + + + ); +} diff --git a/src/vis/parallelCoordinates/ParallelVis.tsx b/src/vis/parallelCoordinates/ParallelVis.tsx index 79af5ec57..ffdf9a8aa 100644 --- a/src/vis/parallelCoordinates/ParallelVis.tsx +++ b/src/vis/parallelCoordinates/ParallelVis.tsx @@ -17,6 +17,7 @@ import { i18n } from '../../i18n'; import { VisSidebarOpenButton } from '../VisSidebarOpenButton'; import { ScatterVisSidebar } from '../scatter/ScatterVisSidebar'; import { ParallelVisSidebar } from './ParallelVisSidebar'; +import { ParallelPlot } from './ParallelPlot'; const defaultExtensions = { prePlot: null, @@ -62,6 +63,8 @@ export function ParallelVis({ setShowSidebar?(show: boolean): void; enableSidebar?: boolean; }) { + const { value: allColumns, status: colsStatus } = useAsync(getParallelData, [columns, config.numColumnsSelected, config.color]); + return ( setShowSidebar(!showSidebar)} isOpen={showSidebar} /> : null} - {config.numColumnsSelected.length > 1 ? 'hello world' : null} + {config.numColumnsSelected.length > 1 ? : null} {showSidebar ? ( diff --git a/src/vis/parallelCoordinates/ParallelVisSidebar.tsx b/src/vis/parallelCoordinates/ParallelVisSidebar.tsx index 27a748377..790051ce5 100644 --- a/src/vis/parallelCoordinates/ParallelVisSidebar.tsx +++ b/src/vis/parallelCoordinates/ParallelVisSidebar.tsx @@ -89,9 +89,7 @@ export function ParallelVisSidebar({ /> {mergedExtensions.preSidebar} - - {mergedOptionsConfig.filter.enable ? mergedOptionsConfig.filter.customComponent || : null} {mergedExtensions.postSidebar} diff --git a/src/vis/parallelCoordinates/XAxis.tsx b/src/vis/parallelCoordinates/XAxis.tsx new file mode 100644 index 000000000..14facd59d --- /dev/null +++ b/src/vis/parallelCoordinates/XAxis.tsx @@ -0,0 +1,36 @@ +import * as React from 'react'; +import { useMemo } from 'react'; + +// code taken from https://wattenberger.com/blog/react-and-d3 +export function XAxis({ xScale, yRange, vertPosition }) { + const ticks = useMemo(() => { + return xScale.ticks(5).map((value) => ({ + value, + xOffset: xScale(value), + })); + }, [xScale]); + + return ( + <> + + + + {ticks.map(({ value, xOffset }) => ( + + + + + {value} + + + ))} + + ); +} diff --git a/src/vis/parallelCoordinates/YAxis.tsx b/src/vis/parallelCoordinates/YAxis.tsx new file mode 100644 index 000000000..5837e6e67 --- /dev/null +++ b/src/vis/parallelCoordinates/YAxis.tsx @@ -0,0 +1,41 @@ +import * as React from 'react'; +import { useMemo } from 'react'; + +// code taken from https://wattenberger.com/blog/react-and-d3 +export function YAxis({ yScale, xRange, horizontalPosition }) { + const ticks = useMemo(() => { + return yScale.ticks(5).map((value) => ({ + value, + yOffset: yScale(value), + })); + }, [yScale]); + + return ( + <> + + + {ticks.map(({ value, yOffset }) => ( + + + + + {value} + + + ))} + + ); +} diff --git a/src/vis/parallelCoordinates/utils.ts b/src/vis/parallelCoordinates/utils.ts index 0665394d9..774ae2f3b 100644 --- a/src/vis/parallelCoordinates/utils.ts +++ b/src/vis/parallelCoordinates/utils.ts @@ -1,5 +1,6 @@ import { merge } from 'lodash'; import { + ColumnInfo, EColumnTypes, ENumericalColorScaleType, EScatterSelectSettings, @@ -7,8 +8,13 @@ import { IParallelCoordinatesConfig, IScatterConfig, IVisConfig, + VisCategoricalColumn, + VisCategoricalValue, VisColumn, + VisNumericalColumn, + VisNumericalValue, } from '../interfaces'; +import { resolveColumnValues } from '../general/layoutUtils'; export function isParallelCoordinates(s: IVisConfig): s is IParallelCoordinatesConfig { return s.type === ESupportedPlotlyVis.PARALLEL_COORDINATES; @@ -26,3 +32,30 @@ export function parallelCoordinatesMergeDefaultConfig(columns: VisColumn[], conf return merged; } + +export async function getParallelData( + columns: VisColumn[], + numColumnsSelected: ColumnInfo[], + catColumnsSelected: ColumnInfo[], +): Promise<{ + numColVals: { + resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; // this is a workaround for the types + type: EColumnTypes.NUMERICAL | EColumnTypes.CATEGORICAL; + info: ColumnInfo; + }[]; + catColVals: { + resolvedValues: (VisCategoricalValue | VisNumericalValue)[]; // this is a workaround for the types + type: EColumnTypes.NUMERICAL | EColumnTypes.CATEGORICAL; + info: ColumnInfo; + }[]; +}> { + const numCols: VisNumericalColumn[] = numColumnsSelected.map((col) => columns.find((c) => c.info.id === col.id)) as VisNumericalColumn[]; + const catCols: VisCategoricalColumn[] = catColumnsSelected.map((col) => columns.find((c) => c.info.id === col.id)) as VisCategoricalColumn[]; + + const numColVals = await resolveColumnValues(numCols); + const catColVals = await resolveColumnValues(catCols); + + // const colorColVals = await resolveSingleColumn(colorColumn ? columns.find((col) => col.info.id === colorColumn.id) : null); + + return { numColVals, catColVals }; +} From 42f3763b744d04196574756fdcf92282f6a4c499 Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Mon, 19 Jun 2023 14:05:59 +0200 Subject: [PATCH 069/241] working on it --- package.json | 1 + src/vis/stories/Iris.stories.tsx | 117 +- src/vis/stories/heatmapData.tsx | 21676 +++++++++++++++++++++++++++++ 3 files changed, 21721 insertions(+), 73 deletions(-) create mode 100644 src/vis/stories/heatmapData.tsx diff --git a/package.json b/package.json index 20bba166d..1dd93fb9d 100644 --- a/package.json +++ b/package.json @@ -160,6 +160,7 @@ "react-dom": "^18.2.0", "react-highlight-words": "^0.17.0", "react-plotly.js": "^2.5.1", + "react-spring": "^9.7.1", "use-deep-compare-effect": "^1.8.0", "visyn_scripts": "git+ssh://git@github.com/datavisyn/visyn_scripts#develop" }, diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index a73db19ef..3779d8d9b 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -20,65 +20,47 @@ export function fetchIrisData(): VisColumn[] { const heatmapData = data; - heatmapData.forEach(); + const myData: Record = {}; - // return [ - // { - // info: { - // description: 'data from description', - // id: 'sepalLength', - // name: 'Sepal Length', - // }, - // type: EColumnTypes.NUMERICAL, - // values: () => dataPromise.then((data) => data.map((r) => r.sepalLength).map((val, i) => ({ id: i.toString(), val }))), - // }, - // { - // info: { - // description: 'data from description', - // id: 'sepalWidth', - // name: 'Sepal Width', - // }, - // type: EColumnTypes.NUMERICAL, - // values: () => dataPromise.then((data) => data.map((r) => r.sepalWidth).map((val, i) => ({ id: i.toString(), val }))), - // }, - // { - // info: { - // description: '', - // id: 'randomThing', - // name: 'Random Thing', - // }, - // type: EColumnTypes.CATEGORICAL, - // color: { 1: 'cornflowerblue' }, - // values: () => dataPromise.then((data) => data.map((r) => Math.round(Math.random() * 4)).map((val, i) => ({ id: i.toString(), val: val.toString() }))), - // }, - // { - // info: { - // description: 'data from description', - // id: 'petalLength', - // name: 'Petal Length PEtal length petal length', - // }, - // type: EColumnTypes.NUMERICAL, - // values: () => dataPromise.then((data) => data.map((r) => r.petalLength).map((val, i) => ({ id: i.toString(), val }))), - // }, - // { - // info: { - // description: 'data from description', - // id: 'petalWidth', - // name: 'Petal Width', - // }, - // type: EColumnTypes.NUMERICAL, - // values: () => dataPromise.then((data) => data.map((r) => r.petalWidth).map((val, i) => ({ id: i.toString(), val }))), - // }, - // { - // info: { - // description: 'data from description', - // id: 'species', - // name: 'Species', - // }, - // type: EColumnTypes.CATEGORICAL, - // values: () => dataPromise.then((data) => data.map((r) => r.species).map((val, i) => ({ id: i.toString(), val }))), - // }, - // ]; + let counter = 0; + heatmapData.forEach((state) => { + for (let i = 0; i < Math.round(state.value / 100); i++) { + myData[counter] = { year: state.x.toString(), state: state.y }; + counter += 1; + } + }); + + console.log(myData); + + return [ + { + info: { + description: '', + id: 'state', + name: 'US States', + }, + type: EColumnTypes.CATEGORICAL, + values: () => Object.keys(myData).map((d) => ({ val: myData[d].state, id: d })), + }, + { + info: { + description: 'data from description', + id: 'petalLength', + name: 'Petal Length PEtal length petal length', + }, + type: EColumnTypes.NUMERICAL, + values: () => dataPromise.then((d) => d.map((r) => r.petalLength).map((val, i) => ({ id: i.toString(), val }))), + }, + { + info: { + description: '', + id: 'year', + name: 'Years', + }, + type: EColumnTypes.CATEGORICAL, + values: () => Object.keys(myData).map((d) => ({ val: myData[d].year, id: d })), + }, + ]; } // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export @@ -160,23 +142,12 @@ ViolinPlot.args = { type: ESupportedPlotlyVis.VIOLIN, numColumnsSelected: [ { - description: '', - id: 'sepalLength', - name: 'Sepal Length', - }, - { - description: '', - id: 'sepalWidth', - name: 'Sepal Width', - }, - ], - catColumnsSelected: [ - { - description: '', - id: 'species', - name: 'Species', + description: 'data from description', + id: 'petalLength', + name: 'Petal Length PEtal length petal length', }, ], + catColumnsSelected: [], violinOverlay: EViolinOverlay.NONE, }, }; diff --git a/src/vis/stories/heatmapData.tsx b/src/vis/stories/heatmapData.tsx new file mode 100644 index 000000000..f2f2f8c0d --- /dev/null +++ b/src/vis/stories/heatmapData.tsx @@ -0,0 +1,21676 @@ +// Data from https://www.tycho.pitt.edu/data/ +// Original publication: Battling Infectious Diseases in the 20th Century: The Impact of Vaccines by Tynan DeBold and Dov Friedman. +export type Dataset = { x: number; y: string; value: number | null }[]; + +export const data: Dataset = [ + { + x: 1928, + y: 'Alaska', + value: null, + }, + { + x: 1928, + y: 'Ala.', + value: 334.9621212, + }, + { + x: 1928, + y: 'Ark.', + value: 481.8083378, + }, + { + x: 1928, + y: 'Ariz.', + value: 200.7109005, + }, + { + x: 1928, + y: 'Calif.', + value: 69.18974551, + }, + { + x: 1928, + y: 'Colo.', + value: 206.9526627, + }, + { + x: 1928, + y: 'Conn.', + value: 634.9714648, + }, + { + x: 1928, + y: 'D.C.', + value: 535.5949896, + }, + { + x: 1928, + y: 'Del.', + value: 256.0085837, + }, + { + x: 1928, + y: 'Fla.', + value: 119.5743196, + }, + { + x: 1928, + y: 'Ga.', + value: 159.7140889, + }, + { + x: 1928, + y: 'Hawaii', + value: null, + }, + { + x: 1928, + y: 'Iowa', + value: 28.65306122, + }, + { + x: 1928, + y: 'Idaho', + value: 19.59910913, + }, + { + x: 1928, + y: 'Ill.', + value: 98.25105597, + }, + { + x: 1928, + y: 'Ind.', + value: 263.6830635, + }, + { + x: 1928, + y: 'Kan.', + value: 136.9189189, + }, + { + x: 1928, + y: 'Ky.', + value: 216.2446436, + }, + { + x: 1928, + y: 'La.', + value: 260.2955426, + }, + { + x: 1928, + y: 'Mass.', + value: 981.0528812, + }, + { + x: 1928, + y: 'Md.', + value: 1089.347826, + }, + { + x: 1928, + y: 'Maine', + value: 401.944793, + }, + { + x: 1928, + y: 'Mich.', + value: 547.5669882, + }, + { + x: 1928, + y: 'Minn.', + value: 79.16666667, + }, + { + x: 1928, + y: 'Mo.', + value: 198.6670369, + }, + { + x: 1928, + y: 'Miss.', + value: 0, + }, + { + x: 1928, + y: 'Mont.', + value: 139.9260628, + }, + { + x: 1928, + y: 'N.C.', + value: 1823.718365, + }, + { + x: 1928, + y: 'N.D.', + value: 55.78947368, + }, + { + x: 1928, + y: 'Neb.', + value: 78.95696572, + }, + { + x: 1928, + y: 'N.H.', + value: 272.1153846, + }, + { + x: 1928, + y: 'N.J.', + value: 797.1522177, + }, + { + x: 1928, + y: 'N.M', + value: 663.4615385, + }, + { + x: 1928, + y: 'Nev.', + value: null, + }, + { + x: 1928, + y: 'N.Y.', + value: 649.9741357, + }, + { + x: 1928, + y: 'Ohio', + value: 355.9549031, + }, + { + x: 1928, + y: 'Okla.', + value: 268.6860068, + }, + { + x: 1928, + y: 'Ore.', + value: 223.1303419, + }, + { + x: 1928, + y: 'Pa.', + value: 583.9318506, + }, + { + x: 1928, + y: 'R.I.', + value: 735.3244838, + }, + { + x: 1928, + y: 'S.C.', + value: 1138.470385, + }, + { + x: 1928, + y: 'S.D.', + value: 160.1459854, + }, + { + x: 1928, + y: 'Tenn.', + value: 315.3963415, + }, + { + x: 1928, + y: 'Texas', + value: 97.33920705, + }, + { + x: 1928, + y: 'Utah', + value: 16.76587302, + }, + { + x: 1928, + y: 'Va.', + value: null, + }, + { + x: 1928, + y: 'Vt.', + value: 334.7765363, + }, + { + x: 1928, + y: 'Wash.', + value: 344.8098001, + }, + { + x: 1928, + y: 'Wis.', + value: 124.58091, + }, + { + x: 1928, + y: 'W.Va.', + value: 195.9316038, + }, + { + x: 1928, + y: 'Wyo.', + value: 227.0454545, + }, + { + x: 1929, + y: 'Alaska', + value: null, + }, + { + x: 1929, + y: 'Ala.', + value: 111.913767, + }, + { + x: 1929, + y: 'Ark.', + value: 67.22462203, + }, + { + x: 1929, + y: 'Ariz.', + value: 54.88372093, + }, + { + x: 1929, + y: 'Calif.', + value: 72.75357078, + }, + { + x: 1929, + y: 'Colo.', + value: 74.20634921, + }, + { + x: 1929, + y: 'Conn.', + value: 614.8055207, + }, + { + x: 1929, + y: 'D.C.', + value: 94.20289855, + }, + { + x: 1929, + y: 'Del.', + value: 239.8305085, + }, + { + x: 1929, + y: 'Fla.', + value: 77.99307958, + }, + { + x: 1929, + y: 'Ga.', + value: 40.64760592, + }, + { + x: 1929, + y: 'Hawaii', + value: null, + }, + { + x: 1929, + y: 'Iowa', + value: 82.96747967, + }, + { + x: 1929, + y: 'Idaho', + value: 160.4026846, + }, + { + x: 1929, + y: 'Ill.', + value: 506.2187747, + }, + { + x: 1929, + y: 'Ind.', + value: 322.1016739, + }, + { + x: 1929, + y: 'Kan.', + value: 555.4365292, + }, + { + x: 1929, + y: 'Ky.', + value: 43.1696086, + }, + { + x: 1929, + y: 'La.', + value: 88.83029722, + }, + { + x: 1929, + y: 'Mass.', + value: 351.406952, + }, + { + x: 1929, + y: 'Md.', + value: 126.0333128, + }, + { + x: 1929, + y: 'Maine', + value: 719.1969887, + }, + { + x: 1929, + y: 'Mich.', + value: 376.4754953, + }, + { + x: 1929, + y: 'Minn.', + value: 492.340591, + }, + { + x: 1929, + y: 'Mo.', + value: 183.4345665, + }, + { + x: 1929, + y: 'Miss.', + value: null, + }, + { + x: 1929, + y: 'Mont.', + value: 817.7480916, + }, + { + x: 1929, + y: 'N.C.', + value: 38.52537504, + }, + { + x: 1929, + y: 'N.D.', + value: 339.1691395, + }, + { + x: 1929, + y: 'Neb.', + value: 302.9818182, + }, + { + x: 1929, + y: 'N.H.', + value: 344.5396146, + }, + { + x: 1929, + y: 'N.J.', + value: 181.8250188, + }, + { + x: 1929, + y: 'N.M', + value: 54.76190476, + }, + { + x: 1929, + y: 'Nev.', + value: null, + }, + { + x: 1929, + y: 'N.Y.', + value: 249.1003204, + }, + { + x: 1929, + y: 'Ohio', + value: 561.1379414, + }, + { + x: 1929, + y: 'Okla.', + value: 46.16357504, + }, + { + x: 1929, + y: 'Ore.', + value: 492.2914467, + }, + { + x: 1929, + y: 'Pa.', + value: 489.6122596, + }, + { + x: 1929, + y: 'R.I.', + value: 270.6140351, + }, + { + x: 1929, + y: 'S.C.', + value: 12.13341001, + }, + { + x: 1929, + y: 'S.D.', + value: 167.826087, + }, + { + x: 1929, + y: 'Tenn.', + value: 33.02611367, + }, + { + x: 1929, + y: 'Texas', + value: 71.27733426, + }, + { + x: 1929, + y: 'Utah', + value: 68.8976378, + }, + { + x: 1929, + y: 'Va.', + value: null, + }, + { + x: 1929, + y: 'Vt.', + value: 105.2924791, + }, + { + x: 1929, + y: 'Wash.', + value: 248.6173633, + }, + { + x: 1929, + y: 'Wis.', + value: 1016.530334, + }, + { + x: 1929, + y: 'W.Va.', + value: 380.1397787, + }, + { + x: 1929, + y: 'Wyo.', + value: 312.1076233, + }, + { + x: 1930, + y: 'Alaska', + value: null, + }, + { + x: 1930, + y: 'Ala.', + value: 157.0079335, + }, + { + x: 1930, + y: 'Ark.', + value: 53.46960732, + }, + { + x: 1930, + y: 'Ariz.', + value: 466.359447, + }, + { + x: 1930, + y: 'Calif.', + value: 760.2171248, + }, + { + x: 1930, + y: 'Colo.', + value: 1132.788462, + }, + { + x: 1930, + y: 'Conn.', + value: 112.2132672, + }, + { + x: 1930, + y: 'D.C.', + value: 182.1721311, + }, + { + x: 1930, + y: 'Del.', + value: 109.2050209, + }, + { + x: 1930, + y: 'Fla.', + value: 356.5601632, + }, + { + x: 1930, + y: 'Ga.', + value: 153.2302405, + }, + { + x: 1930, + y: 'Hawaii', + value: null, + }, + { + x: 1930, + y: 'Iowa', + value: 395.5959596, + }, + { + x: 1930, + y: 'Idaho', + value: 196.6442953, + }, + { + x: 1930, + y: 'Ill.', + value: 216.0779696, + }, + { + x: 1930, + y: 'Ind.', + value: 120.7587909, + }, + { + x: 1930, + y: 'Kan.', + value: 666.7551779, + }, + { + x: 1930, + y: 'Ky.', + value: 70.186809, + }, + { + x: 1930, + y: 'La.', + value: 86.27078385, + }, + { + x: 1930, + y: 'Mass.', + value: 630.2823529, + }, + { + x: 1930, + y: 'Md.', + value: 73.8997555, + }, + { + x: 1930, + y: 'Maine', + value: 198.875, + }, + { + x: 1930, + y: 'Mich.', + value: 583.6367398, + }, + { + x: 1930, + y: 'Minn.', + value: 218.9829193, + }, + { + x: 1930, + y: 'Mo.', + value: 149.8080088, + }, + { + x: 1930, + y: 'Miss.', + value: null, + }, + { + x: 1930, + y: 'Mont.', + value: 117.4397032, + }, + { + x: 1930, + y: 'N.C.', + value: 41.1746132, + }, + { + x: 1930, + y: 'N.D.', + value: 117.0087977, + }, + { + x: 1930, + y: 'Neb.', + value: 745.3623188, + }, + { + x: 1930, + y: 'N.H.', + value: 126.3948498, + }, + { + x: 1930, + y: 'N.J.', + value: 602.8761062, + }, + { + x: 1930, + y: 'N.M', + value: 529.2740047, + }, + { + x: 1930, + y: 'Nev.', + value: null, + }, + { + x: 1930, + y: 'N.Y.', + value: 315.3870483, + }, + { + x: 1930, + y: 'Ohio', + value: 277.51426, + }, + { + x: 1930, + y: 'Okla.', + value: 164.9312786, + }, + { + x: 1930, + y: 'Ore.', + value: 276.3598326, + }, + { + x: 1930, + y: 'Pa.', + value: 356.5550834, + }, + { + x: 1930, + y: 'R.I.', + value: 39.21282799, + }, + { + x: 1930, + y: 'S.C.', + value: 14.44126074, + }, + { + x: 1930, + y: 'S.D.', + value: 346.3203463, + }, + { + x: 1930, + y: 'Tenn.', + value: 179.9159985, + }, + { + x: 1930, + y: 'Texas', + value: 73.15195072, + }, + { + x: 1930, + y: 'Utah', + value: 1044.793713, + }, + { + x: 1930, + y: 'Va.', + value: null, + }, + { + x: 1930, + y: 'Vt.', + value: 236.6666667, + }, + { + x: 1930, + y: 'Wash.', + value: 631.6326531, + }, + { + x: 1930, + y: 'Wis.', + value: 748.5423729, + }, + { + x: 1930, + y: 'W.Va.', + value: 157.7034045, + }, + { + x: 1930, + y: 'Wyo.', + value: 341.5929204, + }, + { + x: 1931, + y: 'Alaska', + value: null, + }, + { + x: 1931, + y: 'Ala.', + value: 337.2593431, + }, + { + x: 1931, + y: 'Ark.', + value: 45.94155844, + }, + { + x: 1931, + y: 'Ariz.', + value: 497.6689977, + }, + { + x: 1931, + y: 'Calif.', + value: 477.4553571, + }, + { + x: 1931, + y: 'Colo.', + value: 453.3143939, + }, + { + x: 1931, + y: 'Conn.', + value: 790.4791155, + }, + { + x: 1931, + y: 'D.C.', + value: 832.9365079, + }, + { + x: 1931, + y: 'Del.', + value: 1003.305785, + }, + { + x: 1931, + y: 'Fla.', + value: 260.8171467, + }, + { + x: 1931, + y: 'Ga.', + value: 104.4117647, + }, + { + x: 1931, + y: 'Hawaii', + value: null, + }, + { + x: 1931, + y: 'Iowa', + value: 34.28686543, + }, + { + x: 1931, + y: 'Idaho', + value: 25.99118943, + }, + { + x: 1931, + y: 'Ill.', + value: 516.950696, + }, + { + x: 1931, + y: 'Ind.', + value: 541.2342647, + }, + { + x: 1931, + y: 'Kan.', + value: 93.46092504, + }, + { + x: 1931, + y: 'Ky.', + value: 181.0331825, + }, + { + x: 1931, + y: 'La.', + value: 11.48775895, + }, + { + x: 1931, + y: 'Mass.', + value: 386.7937853, + }, + { + x: 1931, + y: 'Md.', + value: 1264.876282, + }, + { + x: 1931, + y: 'Maine', + value: 434.3246592, + }, + { + x: 1931, + y: 'Mich.', + value: 133.4514381, + }, + { + x: 1931, + y: 'Minn.', + value: 123.5271614, + }, + { + x: 1931, + y: 'Mo.', + value: 369.7925088, + }, + { + x: 1931, + y: 'Miss.', + value: null, + }, + { + x: 1931, + y: 'Mont.', + value: 284.8148148, + }, + { + x: 1931, + y: 'N.C.', + value: 480.4962312, + }, + { + x: 1931, + y: 'N.D.', + value: 142.0588235, + }, + { + x: 1931, + y: 'Neb.', + value: 24.92774566, + }, + { + x: 1931, + y: 'N.H.', + value: 299.1489362, + }, + { + x: 1931, + y: 'N.J.', + value: 494.1990291, + }, + { + x: 1931, + y: 'N.M', + value: 324.5412844, + }, + { + x: 1931, + y: 'Nev.', + value: null, + }, + { + x: 1931, + y: 'N.Y.', + value: 423.2254047, + }, + { + x: 1931, + y: 'Ohio', + value: 291.3056468, + }, + { + x: 1931, + y: 'Okla.', + value: 32.20973783, + }, + { + x: 1931, + y: 'Ore.', + value: 242.5465839, + }, + { + x: 1931, + y: 'Pa.', + value: 821.5514577, + }, + { + x: 1931, + y: 'R.I.', + value: 665.051395, + }, + { + x: 1931, + y: 'S.C.', + value: 189.9600685, + }, + { + x: 1931, + y: 'S.D.', + value: 212.3919308, + }, + { + x: 1931, + y: 'Tenn.', + value: 134.7760632, + }, + { + x: 1931, + y: 'Texas', + value: 39.546301, + }, + { + x: 1931, + y: 'Utah', + value: 29.8245614, + }, + { + x: 1931, + y: 'Va.', + value: null, + }, + { + x: 1931, + y: 'Vt.', + value: 318.3844011, + }, + { + x: 1931, + y: 'Wash.', + value: 197.4067046, + }, + { + x: 1931, + y: 'Wis.', + value: 506.5551839, + }, + { + x: 1931, + y: 'W.Va.', + value: 291.3793103, + }, + { + x: 1931, + y: 'Wyo.', + value: 60.69868996, + }, + { + x: 1932, + y: 'Alaska', + value: null, + }, + { + x: 1932, + y: 'Ala.', + value: 10.17715793, + }, + { + x: 1932, + y: 'Ark.', + value: 5.392156863, + }, + { + x: 1932, + y: 'Ariz.', + value: 20.18779343, + }, + { + x: 1932, + y: 'Calif.', + value: 214.0821174, + }, + { + x: 1932, + y: 'Colo.', + value: 222.8893058, + }, + { + x: 1932, + y: 'Conn.', + value: 348.2590104, + }, + { + x: 1932, + y: 'D.C.', + value: 53.21637427, + }, + { + x: 1932, + y: 'Del.', + value: 15.91836735, + }, + { + x: 1932, + y: 'Fla.', + value: 13.60946746, + }, + { + x: 1932, + y: 'Ga.', + value: 34.37819421, + }, + { + x: 1932, + y: 'Hawaii', + value: null, + }, + { + x: 1932, + y: 'Iowa', + value: 6.347930896, + }, + { + x: 1932, + y: 'Idaho', + value: 8.71459695, + }, + { + x: 1932, + y: 'Ill.', + value: 208.2859359, + }, + { + x: 1932, + y: 'Ind.', + value: 88.81438586, + }, + { + x: 1932, + y: 'Kan.', + value: 326.606479, + }, + { + x: 1932, + y: 'Ky.', + value: 72.98206278, + }, + { + x: 1932, + y: 'La.', + value: 67.42459397, + }, + { + x: 1932, + y: 'Mass.', + value: 463.183846, + }, + { + x: 1932, + y: 'Md.', + value: 65.13706794, + }, + { + x: 1932, + y: 'Maine', + value: 1086.257669, + }, + { + x: 1932, + y: 'Mich.', + value: 881.0878661, + }, + { + x: 1932, + y: 'Minn.', + value: 95.08692366, + }, + { + x: 1932, + y: 'Mo.', + value: 43.19273892, + }, + { + x: 1932, + y: 'Miss.', + value: null, + }, + { + x: 1932, + y: 'Mont.', + value: 1007.962963, + }, + { + x: 1932, + y: 'N.C.', + value: 423.086458, + }, + { + x: 1932, + y: 'N.D.', + value: 318.0473373, + }, + { + x: 1932, + y: 'Neb.', + value: 31.6017316, + }, + { + x: 1932, + y: 'N.H.', + value: 151.2658228, + }, + { + x: 1932, + y: 'N.J.', + value: 373.9563107, + }, + { + x: 1932, + y: 'N.M', + value: 271.8820862, + }, + { + x: 1932, + y: 'Nev.', + value: null, + }, + { + x: 1932, + y: 'N.Y.', + value: 465.0719175, + }, + { + x: 1932, + y: 'Ohio', + value: 539.3479232, + }, + { + x: 1932, + y: 'Okla.', + value: 43.19131161, + }, + { + x: 1932, + y: 'Ore.', + value: 514.1975309, + }, + { + x: 1932, + y: 'Pa.', + value: 470.6780008, + }, + { + x: 1932, + y: 'R.I.', + value: 1472.67356, + }, + { + x: 1932, + y: 'S.C.', + value: 182.6086957, + }, + { + x: 1932, + y: 'S.D.', + value: 96.38728324, + }, + { + x: 1932, + y: 'Tenn.', + value: 68.97823681, + }, + { + x: 1932, + y: 'Texas', + value: 76.56433484, + }, + { + x: 1932, + y: 'Utah', + value: 13.92649903, + }, + { + x: 1932, + y: 'Va.', + value: 53.38499184, + }, + { + x: 1932, + y: 'Vt.', + value: 1146.089385, + }, + { + x: 1932, + y: 'Wash.', + value: 631.8813131, + }, + { + x: 1932, + y: 'Wis.', + value: 935.286329, + }, + { + x: 1932, + y: 'W.Va.', + value: 599.6565541, + }, + { + x: 1932, + y: 'Wyo.', + value: 242.173913, + }, + { + x: 1933, + y: 'Alaska', + value: null, + }, + { + x: 1933, + y: 'Ala.', + value: 65.20105224, + }, + { + x: 1933, + y: 'Ark.', + value: 293.3117584, + }, + { + x: 1933, + y: 'Ariz.', + value: 296.0093897, + }, + { + x: 1933, + y: 'Calif.', + value: 445.2624518, + }, + { + x: 1933, + y: 'Colo.', + value: 27.73109244, + }, + { + x: 1933, + y: 'Conn.', + value: 330.6942753, + }, + { + x: 1933, + y: 'D.C.', + value: 100.7561437, + }, + { + x: 1933, + y: 'Del.', + value: 82.66129032, + }, + { + x: 1933, + y: 'Fla.', + value: 63.98195876, + }, + { + x: 1933, + y: 'Ga.', + value: 156.8813559, + }, + { + x: 1933, + y: 'Hawaii', + value: null, + }, + { + x: 1933, + y: 'Iowa', + value: 33.0260521, + }, + { + x: 1933, + y: 'Idaho', + value: 193.5344828, + }, + { + x: 1933, + y: 'Ill.', + value: 155.6642636, + }, + { + x: 1933, + y: 'Ind.', + value: 108.0508475, + }, + { + x: 1933, + y: 'Kan.', + value: 335.0559403, + }, + { + x: 1933, + y: 'Ky.', + value: 57.82060786, + }, + { + x: 1933, + y: 'La.', + value: 42.7456382, + }, + { + x: 1933, + y: 'Mass.', + value: 351.8682858, + }, + { + x: 1933, + y: 'Md.', + value: 41.14521842, + }, + { + x: 1933, + y: 'Maine', + value: 13.39829476, + }, + { + x: 1933, + y: 'Mich.', + value: 462.1129707, + }, + { + x: 1933, + y: 'Minn.', + value: 752.3381968, + }, + { + x: 1933, + y: 'Mo.', + value: 152.9552081, + }, + { + x: 1933, + y: 'Miss.', + value: null, + }, + { + x: 1933, + y: 'Mont.', + value: 419.5933457, + }, + { + x: 1933, + y: 'N.C.', + value: 495.624235, + }, + { + x: 1933, + y: 'N.D.', + value: 373.5905045, + }, + { + x: 1933, + y: 'Neb.', + value: 117.3285199, + }, + { + x: 1933, + y: 'N.H.', + value: 218.4486373, + }, + { + x: 1933, + y: 'N.J.', + value: 726.9296323, + }, + { + x: 1933, + y: 'N.M', + value: 148.7750557, + }, + { + x: 1933, + y: 'Nev.', + value: null, + }, + { + x: 1933, + y: 'N.Y.', + value: 548.9638885, + }, + { + x: 1933, + y: 'Ohio', + value: 233.694362, + }, + { + x: 1933, + y: 'Okla.', + value: 101.8812709, + }, + { + x: 1933, + y: 'Ore.', + value: 230.3680982, + }, + { + x: 1933, + y: 'Pa.', + value: 336.3859362, + }, + { + x: 1933, + y: 'R.I.', + value: 9.333333333, + }, + { + x: 1933, + y: 'S.C.', + value: 360.673516, + }, + { + x: 1933, + y: 'S.D.', + value: 299.1304348, + }, + { + x: 1933, + y: 'Tenn.', + value: 133.4910812, + }, + { + x: 1933, + y: 'Texas', + value: 361.3900898, + }, + { + x: 1933, + y: 'Utah', + value: 402.1153846, + }, + { + x: 1933, + y: 'Va.', + value: 351.8699187, + }, + { + x: 1933, + y: 'Vt.', + value: 312.605042, + }, + { + x: 1933, + y: 'Wash.', + value: 155.8417085, + }, + { + x: 1933, + y: 'Wis.', + value: 317.4671053, + }, + { + x: 1933, + y: 'W.Va.', + value: 303.3675799, + }, + { + x: 1933, + y: 'Wyo.', + value: 249.1304348, + }, + { + x: 1934, + y: 'Alaska', + value: null, + }, + { + x: 1934, + y: 'Ala.', + value: 590.2793296, + }, + { + x: 1934, + y: 'Ark.', + value: 384.5580405, + }, + { + x: 1934, + y: 'Ariz.', + value: 238.7850467, + }, + { + x: 1934, + y: 'Calif.', + value: 423.2673267, + }, + { + x: 1934, + y: 'Colo.', + value: 1204.27907, + }, + { + x: 1934, + y: 'Conn.', + value: 282.3636364, + }, + { + x: 1934, + y: 'D.C.', + value: 1137.5, + }, + { + x: 1934, + y: 'Del.', + value: 1225.2, + }, + { + x: 1934, + y: 'Fla.', + value: 505.6782334, + }, + { + x: 1934, + y: 'Ga.', + value: 774.7975709, + }, + { + x: 1934, + y: 'Hawaii', + value: null, + }, + { + x: 1934, + y: 'Iowa', + value: 346.374502, + }, + { + x: 1934, + y: 'Idaho', + value: 252.4312896, + }, + { + x: 1934, + y: 'Ill.', + value: 574.8327329, + }, + { + x: 1934, + y: 'Ind.', + value: 631.0033143, + }, + { + x: 1934, + y: 'Kan.', + value: 538.8650964, + }, + { + x: 1934, + y: 'Ky.', + value: 422.5202057, + }, + { + x: 1934, + y: 'La.', + value: 220.9809264, + }, + { + x: 1934, + y: 'Mass.', + value: 1039.465738, + }, + { + x: 1934, + y: 'Md.', + value: 1575.906433, + }, + { + x: 1934, + y: 'Maine', + value: 78.04583836, + }, + { + x: 1934, + y: 'Mich.', + value: 132.4510213, + }, + { + x: 1934, + y: 'Minn.', + value: 313.580705, + }, + { + x: 1934, + y: 'Mo.', + value: 539.4820296, + }, + { + x: 1934, + y: 'Miss.', + value: null, + }, + { + x: 1934, + y: 'Mont.', + value: 355.9633028, + }, + { + x: 1934, + y: 'N.C.', + value: 1685.35109, + }, + { + x: 1934, + y: 'N.D.', + value: 657.5892857, + }, + { + x: 1934, + y: 'Neb.', + value: 331.0419682, + }, + { + x: 1934, + y: 'N.H.', + value: 846.6666667, + }, + { + x: 1934, + y: 'N.J.', + value: 359.9413059, + }, + { + x: 1934, + y: 'N.M', + value: 731.8872017, + }, + { + x: 1934, + y: 'Nev.', + value: null, + }, + { + x: 1934, + y: 'N.Y.', + value: 258.1151437, + }, + { + x: 1934, + y: 'Ohio', + value: 410.5021478, + }, + { + x: 1934, + y: 'Okla.', + value: 378.0844835, + }, + { + x: 1934, + y: 'Ore.', + value: 193.5025381, + }, + { + x: 1934, + y: 'Pa.', + value: 848.1470138, + }, + { + x: 1934, + y: 'R.I.', + value: 65.77777778, + }, + { + x: 1934, + y: 'S.C.', + value: 637.6136364, + }, + { + x: 1934, + y: 'S.D.', + value: 1373.900293, + }, + { + x: 1934, + y: 'Tenn.', + value: 647.8448276, + }, + { + x: 1934, + y: 'Texas', + value: 490.6492648, + }, + { + x: 1934, + y: 'Utah', + value: 2184.8659, + }, + { + x: 1934, + y: 'Va.', + value: 1158.752515, + }, + { + x: 1934, + y: 'Vt.', + value: 380.6722689, + }, + { + x: 1934, + y: 'Wash.', + value: 473.7888199, + }, + { + x: 1934, + y: 'Wis.', + value: 1332.874918, + }, + { + x: 1934, + y: 'W.Va.', + value: 231.7899492, + }, + { + x: 1934, + y: 'Wyo.', + value: 967.3819742, + }, + { + x: 1935, + y: 'Alaska', + value: null, + }, + { + x: 1935, + y: 'Ala.', + value: 265.3181317, + }, + { + x: 1935, + y: 'Ark.', + value: 80.31746032, + }, + { + x: 1935, + y: 'Ariz.', + value: 135.0230415, + }, + { + x: 1935, + y: 'Calif.', + value: 466.3805668, + }, + { + x: 1935, + y: 'Colo.', + value: 1186.085343, + }, + { + x: 1935, + y: 'Conn.', + value: 1449.519808, + }, + { + x: 1935, + y: 'D.C.', + value: 152.7960526, + }, + { + x: 1935, + y: 'Del.', + value: 412.6984127, + }, + { + x: 1935, + y: 'Fla.', + value: 72.78363298, + }, + { + x: 1935, + y: 'Ga.', + value: 1.049069374, + }, + { + x: 1935, + y: 'Hawaii', + value: null, + }, + { + x: 1935, + y: 'Iowa', + value: 865.6497623, + }, + { + x: 1935, + y: 'Idaho', + value: 182.3284823, + }, + { + x: 1935, + y: 'Ill.', + value: 746.8128767, + }, + { + x: 1935, + y: 'Ind.', + value: 299.1296519, + }, + { + x: 1935, + y: 'Kan.', + value: 1399.038462, + }, + { + x: 1935, + y: 'Ky.', + value: 533.7336245, + }, + { + x: 1935, + y: 'La.', + value: 117.2800718, + }, + { + x: 1935, + y: 'Mass.', + value: 286.7372784, + }, + { + x: 1935, + y: 'Md.', + value: 133.1405437, + }, + { + x: 1935, + y: 'Maine', + value: 857.7751196, + }, + { + x: 1935, + y: 'Mich.', + value: 1600.888797, + }, + { + x: 1935, + y: 'Minn.', + value: 1062.01693, + }, + { + x: 1935, + y: 'Mo.', + value: 345.1816746, + }, + { + x: 1935, + y: 'Miss.', + value: null, + }, + { + x: 1935, + y: 'Mont.', + value: 1422.545455, + }, + { + x: 1935, + y: 'N.C.', + value: 323.8940716, + }, + { + x: 1935, + y: 'N.D.', + value: 290.4477612, + }, + { + x: 1935, + y: 'Neb.', + value: 639.6363636, + }, + { + x: 1935, + y: 'N.H.', + value: 55.09355509, + }, + { + x: 1935, + y: 'N.J.', + value: 792.9498164, + }, + { + x: 1935, + y: 'N.M', + value: 148, + }, + { + x: 1935, + y: 'Nev.', + value: null, + }, + { + x: 1935, + y: 'N.Y.', + value: 516.4336449, + }, + { + x: 1935, + y: 'Ohio', + value: 544.8062472, + }, + { + x: 1935, + y: 'Okla.', + value: 102.9337804, + }, + { + x: 1935, + y: 'Ore.', + value: 705.3946054, + }, + { + x: 1935, + y: 'Pa.', + value: 917.3419276, + }, + { + x: 1935, + y: 'R.I.', + value: 994.100295, + }, + { + x: 1935, + y: 'S.C.', + value: 46.24081402, + }, + { + x: 1935, + y: 'S.D.', + value: 167.2106825, + }, + { + x: 1935, + y: 'Tenn.', + value: 51.32237312, + }, + { + x: 1935, + y: 'Texas', + value: 64.06990038, + }, + { + x: 1935, + y: 'Utah', + value: 50.19011407, + }, + { + x: 1935, + y: 'Va.', + value: 727.3412698, + }, + { + x: 1935, + y: 'Vt.', + value: 389.3557423, + }, + { + x: 1935, + y: 'Wash.', + value: 525.475752, + }, + { + x: 1935, + y: 'Wis.', + value: 1415.407166, + }, + { + x: 1935, + y: 'W.Va.', + value: 605.9085842, + }, + { + x: 1935, + y: 'Wyo.', + value: 935.443038, + }, + { + x: 1936, + y: 'Alaska', + value: null, + }, + { + x: 1936, + y: 'Ala.', + value: 20.7801677, + }, + { + x: 1936, + y: 'Ark.', + value: 5.655391121, + }, + { + x: 1936, + y: 'Ariz.', + value: 525.5079007, + }, + { + x: 1936, + y: 'Calif.', + value: 773.537297, + }, + { + x: 1936, + y: 'Colo.', + value: 54.7706422, + }, + { + x: 1936, + y: 'Conn.', + value: 228.9473684, + }, + { + x: 1936, + y: 'D.C.', + value: 335.6120827, + }, + { + x: 1936, + y: 'Del.', + value: 555.9288538, + }, + { + x: 1936, + y: 'Fla.', + value: 18.2616596, + }, + { + x: 1936, + y: 'Ga.', + value: 0.268636669, + }, + { + x: 1936, + y: 'Hawaii', + value: null, + }, + { + x: 1936, + y: 'Iowa', + value: 7.971303308, + }, + { + x: 1936, + y: 'Idaho', + value: 262.6262626, + }, + { + x: 1936, + y: 'Ill.', + value: 15.38903061, + }, + { + x: 1936, + y: 'Ind.', + value: 21.08721625, + }, + { + x: 1936, + y: 'Kan.', + value: 23.16746923, + }, + { + x: 1936, + y: 'Ky.', + value: 79.66040462, + }, + { + x: 1936, + y: 'La.', + value: 57.70258237, + }, + { + x: 1936, + y: 'Mass.', + value: 613.7887486, + }, + { + x: 1936, + y: 'Md.', + value: 405.3295129, + }, + { + x: 1936, + y: 'Maine', + value: 891.9047619, + }, + { + x: 1936, + y: 'Mich.', + value: 47.70914297, + }, + { + x: 1936, + y: 'Minn.', + value: 283.0285296, + }, + { + x: 1936, + y: 'Mo.', + value: 17.35069718, + }, + { + x: 1936, + y: 'Miss.', + value: null, + }, + { + x: 1936, + y: 'Mont.', + value: 81.58844765, + }, + { + x: 1936, + y: 'N.C.', + value: 40.25702331, + }, + { + x: 1936, + y: 'N.D.', + value: 16.56626506, + }, + { + x: 1936, + y: 'Neb.', + value: 86.34020619, + }, + { + x: 1936, + y: 'N.H.', + value: 185.3430353, + }, + { + x: 1936, + y: 'N.J.', + value: 215.0587659, + }, + { + x: 1936, + y: 'N.M', + value: 234.9693252, + }, + { + x: 1936, + y: 'Nev.', + value: null, + }, + { + x: 1936, + y: 'N.Y.', + value: 477.453453, + }, + { + x: 1936, + y: 'Ohio', + value: 136.5240406, + }, + { + x: 1936, + y: 'Okla.', + value: 15.22198732, + }, + { + x: 1936, + y: 'Ore.', + value: 919.1219512, + }, + { + x: 1936, + y: 'Pa.', + value: 243.5036347, + }, + { + x: 1936, + y: 'R.I.', + value: 368.6588921, + }, + { + x: 1936, + y: 'S.C.', + value: 48.23133071, + }, + { + x: 1936, + y: 'S.D.', + value: 33.63363363, + }, + { + x: 1936, + y: 'Tenn.', + value: 50.16123253, + }, + { + x: 1936, + y: 'Texas', + value: 125.5813953, + }, + { + x: 1936, + y: 'Utah', + value: 117.8368121, + }, + { + x: 1936, + y: 'Va.', + value: 127.8409091, + }, + { + x: 1936, + y: 'Vt.', + value: 2974.789916, + }, + { + x: 1936, + y: 'Wash.', + value: 463.7023593, + }, + { + x: 1936, + y: 'Wis.', + value: 126.541207, + }, + { + x: 1936, + y: 'W.Va.', + value: 63.27433628, + }, + { + x: 1936, + y: 'Wyo.', + value: 57.5, + }, + { + x: 1937, + y: 'Alaska', + value: null, + }, + { + x: 1937, + y: 'Ala.', + value: 22.44750181, + }, + { + x: 1937, + y: 'Ark.', + value: 16.9206516, + }, + { + x: 1937, + y: 'Ariz.', + value: 837.3068433, + }, + { + x: 1937, + y: 'Calif.', + value: 78.23223039, + }, + { + x: 1937, + y: 'Colo.', + value: 93.02536232, + }, + { + x: 1937, + y: 'Conn.', + value: 606.7342074, + }, + { + x: 1937, + y: 'D.C.', + value: 333.2792208, + }, + { + x: 1937, + y: 'Del.', + value: 707.0866142, + }, + { + x: 1937, + y: 'Fla.', + value: 23.05441779, + }, + { + x: 1937, + y: 'Ga.', + value: null, + }, + { + x: 1937, + y: 'Hawaii', + value: null, + }, + { + x: 1937, + y: 'Iowa', + value: 10.76861489, + }, + { + x: 1937, + y: 'Idaho', + value: 243.1952663, + }, + { + x: 1937, + y: 'Ill.', + value: 146.9390353, + }, + { + x: 1937, + y: 'Ind.', + value: 210.0770599, + }, + { + x: 1937, + y: 'Kan.', + value: 42.13362069, + }, + { + x: 1937, + y: 'Ky.', + value: 245.7614943, + }, + { + x: 1937, + y: 'La.', + value: 20.73548959, + }, + { + x: 1937, + y: 'Mass.', + value: 478.3386875, + }, + { + x: 1937, + y: 'Md.', + value: 698.1755986, + }, + { + x: 1937, + y: 'Maine', + value: 134.3230404, + }, + { + x: 1937, + y: 'Mich.', + value: 115.599839, + }, + { + x: 1937, + y: 'Minn.', + value: 25.12745812, + }, + { + x: 1937, + y: 'Mo.', + value: 186.4259357, + }, + { + x: 1937, + y: 'Miss.', + value: 0, + }, + { + x: 1937, + y: 'Mont.', + value: 111.732852, + }, + { + x: 1937, + y: 'N.C.', + value: 226.05613, + }, + { + x: 1937, + y: 'N.D.', + value: 8.396946565, + }, + { + x: 1937, + y: 'Neb.', + value: 34.50336072, + }, + { + x: 1937, + y: 'N.H.', + value: 393.1392931, + }, + { + x: 1937, + y: 'N.J.', + value: 1108.953033, + }, + { + x: 1937, + y: 'N.M', + value: 487.2763419, + }, + { + x: 1937, + y: 'Nev.', + value: null, + }, + { + x: 1937, + y: 'N.Y.', + value: 202.8273259, + }, + { + x: 1937, + y: 'Ohio', + value: 366.3386694, + }, + { + x: 1937, + y: 'Okla.', + value: 45.62982005, + }, + { + x: 1937, + y: 'Ore.', + value: 38.16793893, + }, + { + x: 1937, + y: 'Pa.', + value: 390.9090909, + }, + { + x: 1937, + y: 'R.I.', + value: 679.2507205, + }, + { + x: 1937, + y: 'S.C.', + value: 99.16759156, + }, + { + x: 1937, + y: 'S.D.', + value: 9.908536585, + }, + { + x: 1937, + y: 'Tenn.', + value: 106.4042934, + }, + { + x: 1937, + y: 'Texas', + value: 235.104, + }, + { + x: 1937, + y: 'Utah', + value: 396.7863894, + }, + { + x: 1937, + y: 'Va.', + value: 337.4131274, + }, + { + x: 1937, + y: 'Vt.', + value: 289.3258427, + }, + { + x: 1937, + y: 'Wash.', + value: 103.3313504, + }, + { + x: 1937, + y: 'Wis.', + value: 66.54792746, + }, + { + x: 1937, + y: 'W.Va.', + value: 110.03861, + }, + { + x: 1937, + y: 'Wyo.', + value: 69.95884774, + }, + { + x: 1938, + y: 'Alaska', + value: null, + }, + { + x: 1938, + y: 'Ala.', + value: 496.4298529, + }, + { + x: 1938, + y: 'Ark.', + value: 356.716805, + }, + { + x: 1938, + y: 'Ariz.', + value: 149.3562232, + }, + { + x: 1938, + y: 'Calif.', + value: 278.3052885, + }, + { + x: 1938, + y: 'Colo.', + value: 823.6960432, + }, + { + x: 1938, + y: 'Conn.', + value: 107.5415677, + }, + { + x: 1938, + y: 'D.C.', + value: 115.5956113, + }, + { + x: 1938, + y: 'Del.', + value: 235.9922179, + }, + { + x: 1938, + y: 'Fla.', + value: 517.8430265, + }, + { + x: 1938, + y: 'Ga.', + value: 299.935296, + }, + { + x: 1938, + y: 'Hawaii', + value: null, + }, + { + x: 1938, + y: 'Iowa', + value: 223.1956696, + }, + { + x: 1938, + y: 'Idaho', + value: 425.7309942, + }, + { + x: 1938, + y: 'Ill.', + value: 1145.156369, + }, + { + x: 1938, + y: 'Ind.', + value: 523.1836976, + }, + { + x: 1938, + y: 'Kan.', + value: 583.0618893, + }, + { + x: 1938, + y: 'Ky.', + value: 393.4821429, + }, + { + x: 1938, + y: 'La.', + value: 44.74835886, + }, + { + x: 1938, + y: 'Mass.', + value: 229.9885452, + }, + { + x: 1938, + y: 'Md.', + value: 159.0600227, + }, + { + x: 1938, + y: 'Maine', + value: 509.6678529, + }, + { + x: 1938, + y: 'Mich.', + value: 1505.528085, + }, + { + x: 1938, + y: 'Minn.', + value: 256.1932437, + }, + { + x: 1938, + y: 'Mo.', + value: 525.4033325, + }, + { + x: 1938, + y: 'Miss.', + value: 0, + }, + { + x: 1938, + y: 'Mont.', + value: 1119.746377, + }, + { + x: 1938, + y: 'N.C.', + value: 1383.343023, + }, + { + x: 1938, + y: 'N.D.', + value: 863.446677, + }, + { + x: 1938, + y: 'Neb.', + value: 209.0874811, + }, + { + x: 1938, + y: 'N.H.', + value: 341.3402062, + }, + { + x: 1938, + y: 'N.J.', + value: 716.9756098, + }, + { + x: 1938, + y: 'N.M', + value: 628.9473684, + }, + { + x: 1938, + y: 'Nev.', + value: null, + }, + { + x: 1938, + y: 'N.Y.', + value: 518.857312, + }, + { + x: 1938, + y: 'Ohio', + value: 694.2811174, + }, + { + x: 1938, + y: 'Okla.', + value: 116.630809, + }, + { + x: 1938, + y: 'Ore.', + value: 121.8837863, + }, + { + x: 1938, + y: 'Pa.', + value: 1329.77291, + }, + { + x: 1938, + y: 'R.I.', + value: 35.95100865, + }, + { + x: 1938, + y: 'S.C.', + value: 373.4187568, + }, + { + x: 1938, + y: 'S.D.', + value: 212.4807396, + }, + { + x: 1938, + y: 'Tenn.', + value: 403.6511875, + }, + { + x: 1938, + y: 'Texas', + value: 95.34994445, + }, + { + x: 1938, + y: 'Utah', + value: 1808.878505, + }, + { + x: 1938, + y: 'Va.', + value: 475.8150114, + }, + { + x: 1938, + y: 'Vt.', + value: 1652.668539, + }, + { + x: 1938, + y: 'Wash.', + value: 112.1908127, + }, + { + x: 1938, + y: 'Wis.', + value: 2348.047127, + }, + { + x: 1938, + y: 'W.Va.', + value: 595.1586433, + }, + { + x: 1938, + y: 'Wyo.', + value: 360.5691057, + }, + { + x: 1939, + y: 'Alaska', + value: null, + }, + { + x: 1939, + y: 'Ala.', + value: 182.6581379, + }, + { + x: 1939, + y: 'Ark.', + value: 123.536961, + }, + { + x: 1939, + y: 'Ariz.', + value: 144.0082645, + }, + { + x: 1939, + y: 'Calif.', + value: 939.4841562, + }, + { + x: 1939, + y: 'Colo.', + value: 525.2083333, + }, + { + x: 1939, + y: 'Conn.', + value: 937.5589623, + }, + { + x: 1939, + y: 'D.C.', + value: 497.4164134, + }, + { + x: 1939, + y: 'Del.', + value: 94.67680608, + }, + { + x: 1939, + y: 'Fla.', + value: 157.5344953, + }, + { + x: 1939, + y: 'Ga.', + value: 115.9615385, + }, + { + x: 1939, + y: 'Hawaii', + value: null, + }, + { + x: 1939, + y: 'Iowa', + value: 209.1071429, + }, + { + x: 1939, + y: 'Idaho', + value: 694.1778631, + }, + { + x: 1939, + y: 'Ill.', + value: 100.0887199, + }, + { + x: 1939, + y: 'Ind.', + value: 59.75609756, + }, + { + x: 1939, + y: 'Kan.', + value: 158.1962719, + }, + { + x: 1939, + y: 'Ky.', + value: 79.81120944, + }, + { + x: 1939, + y: 'La.', + value: 157.0479863, + }, + { + x: 1939, + y: 'Mass.', + value: 546.1697723, + }, + { + x: 1939, + y: 'Md.', + value: 852.8908719, + }, + { + x: 1939, + y: 'Maine', + value: 271.0992908, + }, + { + x: 1939, + y: 'Mich.', + value: 328.1613654, + }, + { + x: 1939, + y: 'Minn.', + value: 655.6297366, + }, + { + x: 1939, + y: 'Mo.', + value: 76.56621729, + }, + { + x: 1939, + y: 'Miss.', + value: 0, + }, + { + x: 1939, + y: 'Mont.', + value: 1973.333333, + }, + { + x: 1939, + y: 'N.C.', + value: 664.4991463, + }, + { + x: 1939, + y: 'N.D.', + value: 843.1677019, + }, + { + x: 1939, + y: 'Neb.', + value: 275.9484067, + }, + { + x: 1939, + y: 'N.H.', + value: 133.9795918, + }, + { + x: 1939, + y: 'N.J.', + value: 104.8680068, + }, + { + x: 1939, + y: 'N.M', + value: 316.1249203, + }, + { + x: 1939, + y: 'Nev.', + value: null, + }, + { + x: 1939, + y: 'N.Y.', + value: 331.3576869, + }, + { + x: 1939, + y: 'Ohio', + value: 74.01248911, + }, + { + x: 1939, + y: 'Okla.', + value: 194.3849121, + }, + { + x: 1939, + y: 'Ore.', + value: 219.7502313, + }, + { + x: 1939, + y: 'Pa.', + value: 186.6023634, + }, + { + x: 1939, + y: 'R.I.', + value: 416.8330956, + }, + { + x: 1939, + y: 'S.C.', + value: 60.36324786, + }, + { + x: 1939, + y: 'S.D.', + value: 1173.72093, + }, + { + x: 1939, + y: 'Tenn.', + value: 108.4261192, + }, + { + x: 1939, + y: 'Texas', + value: 115.9879455, + }, + { + x: 1939, + y: 'Utah', + value: 1002.209945, + }, + { + x: 1939, + y: 'Va.', + value: 394.2509363, + }, + { + x: 1939, + y: 'Vt.', + value: 1029.189944, + }, + { + x: 1939, + y: 'Wash.', + value: 1158.172983, + }, + { + x: 1939, + y: 'Wis.', + value: 768.03909, + }, + { + x: 1939, + y: 'W.Va.', + value: 99.09885796, + }, + { + x: 1939, + y: 'Wyo.', + value: 1392.33871, + }, + { + x: 1940, + y: 'Alaska', + value: null, + }, + { + x: 1940, + y: 'Ala.', + value: 115.1142355, + }, + { + x: 1940, + y: 'Ark.', + value: 72.02046036, + }, + { + x: 1940, + y: 'Ariz.', + value: 339.0781563, + }, + { + x: 1940, + y: 'Calif.', + value: 376.4460432, + }, + { + x: 1940, + y: 'Colo.', + value: 231.8141593, + }, + { + x: 1940, + y: 'Conn.', + value: 376.5222482, + }, + { + x: 1940, + y: 'D.C.', + value: 127.0289855, + }, + { + x: 1940, + y: 'Del.', + value: 36.05947955, + }, + { + x: 1940, + y: 'Fla.', + value: 114.229765, + }, + { + x: 1940, + y: 'Ga.', + value: 93.87624239, + }, + { + x: 1940, + y: 'Hawaii', + value: null, + }, + { + x: 1940, + y: 'Iowa', + value: 212.5936145, + }, + { + x: 1940, + y: 'Idaho', + value: 337.5478927, + }, + { + x: 1940, + y: 'Ill.', + value: 84.14927261, + }, + { + x: 1940, + y: 'Ind.', + value: 16.64724731, + }, + { + x: 1940, + y: 'Kan.', + value: 450.3076063, + }, + { + x: 1940, + y: 'Ky.', + value: 97.63903463, + }, + { + x: 1940, + y: 'La.', + value: 47.80590717, + }, + { + x: 1940, + y: 'Mass.', + value: 498.7262622, + }, + { + x: 1940, + y: 'Md.', + value: 233.8499184, + }, + { + x: 1940, + y: 'Maine', + value: 837.7502945, + }, + { + x: 1940, + y: 'Mich.', + value: 299.6895579, + }, + { + x: 1940, + y: 'Minn.', + value: 300.3046595, + }, + { + x: 1940, + y: 'Mo.', + value: 15.54410988, + }, + { + x: 1940, + y: 'Miss.', + value: 0, + }, + { + x: 1940, + y: 'Mont.', + value: 476.4336918, + }, + { + x: 1940, + y: 'N.C.', + value: 210.2825965, + }, + { + x: 1940, + y: 'N.D.', + value: 149.0625, + }, + { + x: 1940, + y: 'Neb.', + value: 129.0273556, + }, + { + x: 1940, + y: 'N.H.', + value: 147.6626016, + }, + { + x: 1940, + y: 'N.J.', + value: 302.011976, + }, + { + x: 1940, + y: 'N.M', + value: 216.6666667, + }, + { + x: 1940, + y: 'Nev.', + value: 0, + }, + { + x: 1940, + y: 'N.Y.', + value: 212.2213139, + }, + { + x: 1940, + y: 'Ohio', + value: 22.40583057, + }, + { + x: 1940, + y: 'Okla.', + value: 60.3655914, + }, + { + x: 1940, + y: 'Ore.', + value: 671.1325967, + }, + { + x: 1940, + y: 'Pa.', + value: 148.6156023, + }, + { + x: 1940, + y: 'R.I.', + value: 467.7329624, + }, + { + x: 1940, + y: 'S.C.', + value: 32.28180862, + }, + { + x: 1940, + y: 'S.D.', + value: 253.8221529, + }, + { + x: 1940, + y: 'Tenn.', + value: 95.14480409, + }, + { + x: 1940, + y: 'Texas', + value: 249.9066148, + }, + { + x: 1940, + y: 'Utah', + value: 1363.224638, + }, + { + x: 1940, + y: 'Va.', + value: 203.8419118, + }, + { + x: 1940, + y: 'Vt.', + value: 241.046832, + }, + { + x: 1940, + y: 'Wash.', + value: 919.6264368, + }, + { + x: 1940, + y: 'Wis.', + value: 636.4301623, + }, + { + x: 1940, + y: 'W.Va.', + value: 29.81122181, + }, + { + x: 1940, + y: 'Wyo.', + value: 393.6, + }, + { + x: 1941, + y: 'Alaska', + value: null, + }, + { + x: 1941, + y: 'Ala.', + value: 297.5017229, + }, + { + x: 1941, + y: 'Ark.', + value: 273.8953784, + }, + { + x: 1941, + y: 'Ariz.', + value: 615.3061224, + }, + { + x: 1941, + y: 'Calif.', + value: 174.4300124, + }, + { + x: 1941, + y: 'Colo.', + value: 661.6992883, + }, + { + x: 1941, + y: 'Conn.', + value: 364.5761741, + }, + { + x: 1941, + y: 'D.C.', + value: 488.2198953, + }, + { + x: 1941, + y: 'Del.', + value: 1268.363636, + }, + { + x: 1941, + y: 'Fla.', + value: 459.7174021, + }, + { + x: 1941, + y: 'Ga.', + value: 294.1176471, + }, + { + x: 1941, + y: 'Hawaii', + value: null, + }, + { + x: 1941, + y: 'Iowa', + value: 197.8924127, + }, + { + x: 1941, + y: 'Idaho', + value: 101.996008, + }, + { + x: 1941, + y: 'Ill.', + value: 613.1394622, + }, + { + x: 1941, + y: 'Ind.', + value: 381.6106804, + }, + { + x: 1941, + y: 'Kan.', + value: 764.4759207, + }, + { + x: 1941, + y: 'Ky.', + value: 610.5169972, + }, + { + x: 1941, + y: 'La.', + value: 35.04428341, + }, + { + x: 1941, + y: 'Mass.', + value: 474.0487583, + }, + { + x: 1941, + y: 'Md.', + value: 384.2916884, + }, + { + x: 1941, + y: 'Maine', + value: 557.6877934, + }, + { + x: 1941, + y: 'Mich.', + value: 1119.526681, + }, + { + x: 1941, + y: 'Minn.', + value: 35.33848418, + }, + { + x: 1941, + y: 'Mo.', + value: 175.163999, + }, + { + x: 1941, + y: 'Miss.', + value: 0, + }, + { + x: 1941, + y: 'Mont.', + value: 161.2338858, + }, + { + x: 1941, + y: 'N.C.', + value: 658.4285316, + }, + { + x: 1941, + y: 'N.D.', + value: 223.1707317, + }, + { + x: 1941, + y: 'Neb.', + value: 34.59119497, + }, + { + x: 1941, + y: 'N.H.', + value: 202.0408163, + }, + { + x: 1941, + y: 'N.J.', + value: 1044.569817, + }, + { + x: 1941, + y: 'N.M', + value: 778.0632411, + }, + { + x: 1941, + y: 'Nev.', + value: 275.8333333, + }, + { + x: 1941, + y: 'N.Y.', + value: 789.5304138, + }, + { + x: 1941, + y: 'Ohio', + value: 1132.789595, + }, + { + x: 1941, + y: 'Okla.', + value: 88.74889478, + }, + { + x: 1941, + y: 'Ore.', + value: 607.5163399, + }, + { + x: 1941, + y: 'Pa.', + value: 1011.29553, + }, + { + x: 1941, + y: 'R.I.', + value: 57.66073871, + }, + { + x: 1941, + y: 'S.C.', + value: 481.9571865, + }, + { + x: 1941, + y: 'S.D.', + value: 61.33768352, + }, + { + x: 1941, + y: 'Tenn.', + value: 278.1365624, + }, + { + x: 1941, + y: 'Texas', + value: 308.3447229, + }, + { + x: 1941, + y: 'Utah', + value: 281.1252269, + }, + { + x: 1941, + y: 'Va.', + value: 1035.288967, + }, + { + x: 1941, + y: 'Vt.', + value: 384.6264368, + }, + { + x: 1941, + y: 'Wash.', + value: 118.2224707, + }, + { + x: 1941, + y: 'Wis.', + value: 993.1050955, + }, + { + x: 1941, + y: 'W.Va.', + value: 592.2546419, + }, + { + x: 1941, + y: 'Wyo.', + value: 381.7813765, + }, + { + x: 1942, + y: 'Alaska', + value: null, + }, + { + x: 1942, + y: 'Ala.', + value: 126.1645699, + }, + { + x: 1942, + y: 'Ark.', + value: 232.7263531, + }, + { + x: 1942, + y: 'Ariz.', + value: 740.8396947, + }, + { + x: 1942, + y: 'Calif.', + value: 1222.029735, + }, + { + x: 1942, + y: 'Colo.', + value: 505.4806828, + }, + { + x: 1942, + y: 'Conn.', + value: 587.8627232, + }, + { + x: 1942, + y: 'D.C.', + value: 190.7168038, + }, + { + x: 1942, + y: 'Del.', + value: 90.14336918, + }, + { + x: 1942, + y: 'Fla.', + value: 189.632729, + }, + { + x: 1942, + y: 'Ga.', + value: 168.7597382, + }, + { + x: 1942, + y: 'Hawaii', + value: null, + }, + { + x: 1942, + y: 'Iowa', + value: 254.7765478, + }, + { + x: 1942, + y: 'Idaho', + value: 395.083682, + }, + { + x: 1942, + y: 'Ill.', + value: 132.6858632, + }, + { + x: 1942, + y: 'Ind.', + value: 94.98146564, + }, + { + x: 1942, + y: 'Kan.', + value: 535.2272727, + }, + { + x: 1942, + y: 'Ky.', + value: 84.07222024, + }, + { + x: 1942, + y: 'La.', + value: 123.7038492, + }, + { + x: 1942, + y: 'Mass.', + value: 564.9084668, + }, + { + x: 1942, + y: 'Md.', + value: 535.2102102, + }, + { + x: 1942, + y: 'Maine', + value: 540.5840286, + }, + { + x: 1942, + y: 'Mich.', + value: 168.3366372, + }, + { + x: 1942, + y: 'Minn.', + value: 567.6934636, + }, + { + x: 1942, + y: 'Mo.', + value: 178.6758945, + }, + { + x: 1942, + y: 'Miss.', + value: 0, + }, + { + x: 1942, + y: 'Mont.', + value: 588.5135135, + }, + { + x: 1942, + y: 'N.C.', + value: 564.8781171, + }, + { + x: 1942, + y: 'N.D.', + value: 274.0994854, + }, + { + x: 1942, + y: 'Neb.', + value: 428.5310734, + }, + { + x: 1942, + y: 'N.H.', + value: 167.1517672, + }, + { + x: 1942, + y: 'N.J.', + value: 322.0851757, + }, + { + x: 1942, + y: 'N.M', + value: 315.6374502, + }, + { + x: 1942, + y: 'Nev.', + value: 811.6788321, + }, + { + x: 1942, + y: 'N.Y.', + value: 191.2282726, + }, + { + x: 1942, + y: 'Ohio', + value: 127.0627063, + }, + { + x: 1942, + y: 'Okla.', + value: 260.8803612, + }, + { + x: 1942, + y: 'Ore.', + value: 499.0966576, + }, + { + x: 1942, + y: 'Pa.', + value: 380.3946826, + }, + { + x: 1942, + y: 'R.I.', + value: 609.2914439, + }, + { + x: 1942, + y: 'S.C.', + value: 218.2361734, + }, + { + x: 1942, + y: 'S.D.', + value: 143.0390492, + }, + { + x: 1942, + y: 'Tenn.', + value: 106.3456958, + }, + { + x: 1942, + y: 'Texas', + value: 517.2850544, + }, + { + x: 1942, + y: 'Utah', + value: 2589.043478, + }, + { + x: 1942, + y: 'Va.', + value: 177.6168532, + }, + { + x: 1942, + y: 'Vt.', + value: 1071.282799, + }, + { + x: 1942, + y: 'Wash.', + value: 645.6338769, + }, + { + x: 1942, + y: 'Wis.', + value: 781.8047822, + }, + { + x: 1942, + y: 'W.Va.', + value: 303.79574, + }, + { + x: 1942, + y: 'Wyo.', + value: 635.2589641, + }, + { + x: 1943, + y: 'Alaska', + value: null, + }, + { + x: 1943, + y: 'Ala.', + value: 130.82357, + }, + { + x: 1943, + y: 'Ark.', + value: 162.5881715, + }, + { + x: 1943, + y: 'Ariz.', + value: 172.4710983, + }, + { + x: 1943, + y: 'Calif.', + value: 340.0775923, + }, + { + x: 1943, + y: 'Colo.', + value: 976.9731136, + }, + { + x: 1943, + y: 'Conn.', + value: 550.390625, + }, + { + x: 1943, + y: 'D.C.', + value: 234.2777778, + }, + { + x: 1943, + y: 'Del.', + value: 564.5390071, + }, + { + x: 1943, + y: 'Fla.', + value: 68.60465116, + }, + { + x: 1943, + y: 'Ga.', + value: 126.4560863, + }, + { + x: 1943, + y: 'Hawaii', + value: null, + }, + { + x: 1943, + y: 'Iowa', + value: 242.7806341, + }, + { + x: 1943, + y: 'Idaho', + value: 650.9, + }, + { + x: 1943, + y: 'Ill.', + value: 328.4692694, + }, + { + x: 1943, + y: 'Ind.', + value: 263.0182662, + }, + { + x: 1943, + y: 'Kan.', + value: 547.8285078, + }, + { + x: 1943, + y: 'Ky.', + value: 383.7913108, + }, + { + x: 1943, + y: 'La.', + value: 106.4327485, + }, + { + x: 1943, + y: 'Mass.', + value: 752.1846371, + }, + { + x: 1943, + y: 'Md.', + value: 196.7687889, + }, + { + x: 1943, + y: 'Maine', + value: 298.0148883, + }, + { + x: 1943, + y: 'Mich.', + value: 765.1803885, + }, + { + x: 1943, + y: 'Minn.', + value: 398.0015522, + }, + { + x: 1943, + y: 'Mo.', + value: 196.099865, + }, + { + x: 1943, + y: 'Miss.', + value: null, + }, + { + x: 1943, + y: 'Mont.', + value: 1122.061856, + }, + { + x: 1943, + y: 'N.C.', + value: 165.9824849, + }, + { + x: 1943, + y: 'N.D.', + value: 798.5347985, + }, + { + x: 1943, + y: 'Neb.', + value: 401.0878324, + }, + { + x: 1943, + y: 'N.H.', + value: 211.1471861, + }, + { + x: 1943, + y: 'N.J.', + value: 927.141505, + }, + { + x: 1943, + y: 'N.M', + value: 105.7116105, + }, + { + x: 1943, + y: 'Nev.', + value: 397.3509934, + }, + { + x: 1943, + y: 'N.Y.', + value: 478.1877098, + }, + { + x: 1943, + y: 'Ohio', + value: 276.4269074, + }, + { + x: 1943, + y: 'Okla.', + value: 76.03174603, + }, + { + x: 1943, + y: 'Ore.', + value: 693.980344, + }, + { + x: 1943, + y: 'Pa.', + value: 563.1406184, + }, + { + x: 1943, + y: 'R.I.', + value: 296.3815789, + }, + { + x: 1943, + y: 'S.C.', + value: 153.7112354, + }, + { + x: 1943, + y: 'S.D.', + value: 507.3253833, + }, + { + x: 1943, + y: 'Tenn.', + value: 194.9697174, + }, + { + x: 1943, + y: 'Texas', + value: 233.4498003, + }, + { + x: 1943, + y: 'Utah', + value: 1211.251981, + }, + { + x: 1943, + y: 'Va.', + value: 341.3258786, + }, + { + x: 1943, + y: 'Vt.', + value: 2323.700306, + }, + { + x: 1943, + y: 'Wash.', + value: 765.0962013, + }, + { + x: 1943, + y: 'Wis.', + value: 1290.544127, + }, + { + x: 1943, + y: 'W.Va.', + value: 133.716255, + }, + { + x: 1943, + y: 'Wyo.', + value: 1088.663968, + }, + { + x: 1944, + y: 'Alaska', + value: null, + }, + { + x: 1944, + y: 'Ala.', + value: 252.8372591, + }, + { + x: 1944, + y: 'Ark.', + value: 207.4660633, + }, + { + x: 1944, + y: 'Ariz.', + value: 736.7213115, + }, + { + x: 1944, + y: 'Calif.', + value: 599.960872, + }, + { + x: 1944, + y: 'Colo.', + value: 556.4643799, + }, + { + x: 1944, + y: 'Conn.', + value: 493.503937, + }, + { + x: 1944, + y: 'D.C.', + value: 310.1021566, + }, + { + x: 1944, + y: 'Del.', + value: 138.4210526, + }, + { + x: 1944, + y: 'Fla.', + value: 189.7727273, + }, + { + x: 1944, + y: 'Ga.', + value: 171.5207809, + }, + { + x: 1944, + y: 'Hawaii', + value: null, + }, + { + x: 1944, + y: 'Iowa', + value: 201.3906997, + }, + { + x: 1944, + y: 'Idaho', + value: 182.3251418, + }, + { + x: 1944, + y: 'Ill.', + value: 239.8108563, + }, + { + x: 1944, + y: 'Ind.', + value: 149.0843023, + }, + { + x: 1944, + y: 'Kan.', + value: 551.6301293, + }, + { + x: 1944, + y: 'Ky.', + value: 86.48802737, + }, + { + x: 1944, + y: 'La.', + value: 103.9673046, + }, + { + x: 1944, + y: 'Mass.', + value: 433.3850191, + }, + { + x: 1944, + y: 'Md.', + value: 613.7865911, + }, + { + x: 1944, + y: 'Maine', + value: 611.1111111, + }, + { + x: 1944, + y: 'Mich.', + value: 466.9014085, + }, + { + x: 1944, + y: 'Minn.', + value: 770.50673, + }, + { + x: 1944, + y: 'Mo.', + value: 155.9550562, + }, + { + x: 1944, + y: 'Miss.', + value: 0, + }, + { + x: 1944, + y: 'Mont.', + value: 720.7889126, + }, + { + x: 1944, + y: 'N.C.', + value: 671.4747191, + }, + { + x: 1944, + y: 'N.D.', + value: 644.3820225, + }, + { + x: 1944, + y: 'Neb.', + value: 186.1430921, + }, + { + x: 1944, + y: 'N.H.', + value: 125.9868421, + }, + { + x: 1944, + y: 'N.J.', + value: 658.6339586, + }, + { + x: 1944, + y: 'N.M', + value: 303.7001898, + }, + { + x: 1944, + y: 'Nev.', + value: 244.4444444, + }, + { + x: 1944, + y: 'N.Y.', + value: 334.8630029, + }, + { + x: 1944, + y: 'Ohio', + value: 557.899682, + }, + { + x: 1944, + y: 'Okla.', + value: 166.7890357, + }, + { + x: 1944, + y: 'Ore.', + value: 239.8621249, + }, + { + x: 1944, + y: 'Pa.', + value: 256.5715216, + }, + { + x: 1944, + y: 'R.I.', + value: 535.9748428, + }, + { + x: 1944, + y: 'S.C.', + value: 363.6129696, + }, + { + x: 1944, + y: 'S.D.', + value: 258.7610619, + }, + { + x: 1944, + y: 'Tenn.', + value: 184.3967922, + }, + { + x: 1944, + y: 'Texas', + value: 542.1974985, + }, + { + x: 1944, + y: 'Utah', + value: 200.661157, + }, + { + x: 1944, + y: 'Va.', + value: 475.4618227, + }, + { + x: 1944, + y: 'Vt.', + value: 751.433121, + }, + { + x: 1944, + y: 'Wash.', + value: 264.0296367, + }, + { + x: 1944, + y: 'Wis.', + value: 1407.885906, + }, + { + x: 1944, + y: 'W.Va.', + value: 497.2450176, + }, + { + x: 1944, + y: 'Wyo.', + value: 728.0991736, + }, + { + x: 1945, + y: 'Alaska', + value: null, + }, + { + x: 1945, + y: 'Ala.', + value: 27.31531532, + }, + { + x: 1945, + y: 'Ark.', + value: 69.52326901, + }, + { + x: 1945, + y: 'Ariz.', + value: 93.68686869, + }, + { + x: 1945, + y: 'Calif.', + value: 339.4638271, + }, + { + x: 1945, + y: 'Colo.', + value: 95.92293907, + }, + { + x: 1945, + y: 'Conn.', + value: 170.2091577, + }, + { + x: 1945, + y: 'D.C.', + value: 39.61187215, + }, + { + x: 1945, + y: 'Del.', + value: 96.85314685, + }, + { + x: 1945, + y: 'Fla.', + value: 39.63488844, + }, + { + x: 1945, + y: 'Ga.', + value: 27.54087849, + }, + { + x: 1945, + y: 'Hawaii', + value: null, + }, + { + x: 1945, + y: 'Iowa', + value: 61.39514731, + }, + { + x: 1945, + y: 'Idaho', + value: 259.9605523, + }, + { + x: 1945, + y: 'Ill.', + value: 103.2561505, + }, + { + x: 1945, + y: 'Ind.', + value: 33.45491684, + }, + { + x: 1945, + y: 'Kan.', + value: 95.95609474, + }, + { + x: 1945, + y: 'Ky.', + value: 61.10897189, + }, + { + x: 1945, + y: 'La.', + value: 41.18979004, + }, + { + x: 1945, + y: 'Mass.', + value: 186.6341347, + }, + { + x: 1945, + y: 'Md.', + value: 87.42843511, + }, + { + x: 1945, + y: 'Maine', + value: 61.3125, + }, + { + x: 1945, + y: 'Mich.', + value: 121.2054795, + }, + { + x: 1945, + y: 'Minn.', + value: 62.92865589, + }, + { + x: 1945, + y: 'Mo.', + value: 30.20477816, + }, + { + x: 1945, + y: 'Miss.', + value: 0, + }, + { + x: 1945, + y: 'Mont.', + value: 175.2620545, + }, + { + x: 1945, + y: 'N.C.', + value: 72.51627512, + }, + { + x: 1945, + y: 'N.D.', + value: 64.1025641, + }, + { + x: 1945, + y: 'Neb.', + value: 71.552436, + }, + { + x: 1945, + y: 'N.H.', + value: 33.87799564, + }, + { + x: 1945, + y: 'N.J.', + value: 78.88266796, + }, + { + x: 1945, + y: 'N.M', + value: 67.87709497, + }, + { + x: 1945, + y: 'Nev.', + value: 71.81208054, + }, + { + x: 1945, + y: 'N.Y.', + value: 52.38895558, + }, + { + x: 1945, + y: 'Ohio', + value: 49.81203008, + }, + { + x: 1945, + y: 'Okla.', + value: 51.10946746, + }, + { + x: 1945, + y: 'Ore.', + value: 156.32, + }, + { + x: 1945, + y: 'Pa.', + value: 127.2995734, + }, + { + x: 1945, + y: 'R.I.', + value: 55.54123711, + }, + { + x: 1945, + y: 'S.C.', + value: 78.90382627, + }, + { + x: 1945, + y: 'S.D.', + value: 100.6044905, + }, + { + x: 1945, + y: 'Tenn.', + value: 65.86170952, + }, + { + x: 1945, + y: 'Texas', + value: 188.8514503, + }, + { + x: 1945, + y: 'Utah', + value: 746.108291, + }, + { + x: 1945, + y: 'Va.', + value: 64.43783276, + }, + { + x: 1945, + y: 'Vt.', + value: 180, + }, + { + x: 1945, + y: 'Wash.', + value: 291.7044424, + }, + { + x: 1945, + y: 'Wis.', + value: 165.5352921, + }, + { + x: 1945, + y: 'W.Va.', + value: 79.62529274, + }, + { + x: 1945, + y: 'Wyo.', + value: 157.5313808, + }, + { + x: 1946, + y: 'Alaska', + value: null, + }, + { + x: 1946, + y: 'Ala.', + value: 126.7605634, + }, + { + x: 1946, + y: 'Ark.', + value: 168.4474124, + }, + { + x: 1946, + y: 'Ariz.', + value: 498.7012987, + }, + { + x: 1946, + y: 'Calif.', + value: 575.1595355, + }, + { + x: 1946, + y: 'Colo.', + value: 992.726517, + }, + { + x: 1946, + y: 'Conn.', + value: 397.9013641, + }, + { + x: 1946, + y: 'D.C.', + value: 465.9621802, + }, + { + x: 1946, + y: 'Del.', + value: 198.9966555, + }, + { + x: 1946, + y: 'Fla.', + value: 116.9262295, + }, + { + x: 1946, + y: 'Ga.', + value: 117.1036397, + }, + { + x: 1946, + y: 'Hawaii', + value: null, + }, + { + x: 1946, + y: 'Iowa', + value: 160.4783137, + }, + { + x: 1946, + y: 'Idaho', + value: 433.5952849, + }, + { + x: 1946, + y: 'Ill.', + value: 298.1361128, + }, + { + x: 1946, + y: 'Ind.', + value: 293.017288, + }, + { + x: 1946, + y: 'Kan.', + value: 658.1717452, + }, + { + x: 1946, + y: 'Ky.', + value: 269.5943499, + }, + { + x: 1946, + y: 'La.', + value: 126.3106416, + }, + { + x: 1946, + y: 'Mass.', + value: 798.3867379, + }, + { + x: 1946, + y: 'Md.', + value: 488.4146341, + }, + { + x: 1946, + y: 'Maine', + value: 578.0048077, + }, + { + x: 1946, + y: 'Mich.', + value: 627.9196459, + }, + { + x: 1946, + y: 'Minn.', + value: 44.80614484, + }, + { + x: 1946, + y: 'Mo.', + value: 166.9247197, + }, + { + x: 1946, + y: 'Miss.', + value: null, + }, + { + x: 1946, + y: 'Mont.', + value: 422.6653696, + }, + { + x: 1946, + y: 'N.C.', + value: 225.1888829, + }, + { + x: 1946, + y: 'N.D.', + value: 40.78947368, + }, + { + x: 1946, + y: 'Neb.', + value: 395.6210191, + }, + { + x: 1946, + y: 'N.H.', + value: 226.7206478, + }, + { + x: 1946, + y: 'N.J.', + value: 1151.73642, + }, + { + x: 1946, + y: 'N.M', + value: 215.4188948, + }, + { + x: 1946, + y: 'Nev.', + value: 125.8741259, + }, + { + x: 1946, + y: 'N.Y.', + value: 600.8284819, + }, + { + x: 1946, + y: 'Ohio', + value: 200.4526092, + }, + { + x: 1946, + y: 'Okla.', + value: 188.9567669, + }, + { + x: 1946, + y: 'Ore.', + value: 453.4005979, + }, + { + x: 1946, + y: 'Pa.', + value: 611.488952, + }, + { + x: 1946, + y: 'R.I.', + value: 160.5844156, + }, + { + x: 1946, + y: 'S.C.', + value: 358.1869835, + }, + { + x: 1946, + y: 'S.D.', + value: 189.7108844, + }, + { + x: 1946, + y: 'Tenn.', + value: 150.4554327, + }, + { + x: 1946, + y: 'Texas', + value: 410.1709045, + }, + { + x: 1946, + y: 'Utah', + value: 1244.592476, + }, + { + x: 1946, + y: 'Va.', + value: 385.8188045, + }, + { + x: 1946, + y: 'Vt.', + value: 858.625731, + }, + { + x: 1946, + y: 'Wash.', + value: 513.6363636, + }, + { + x: 1946, + y: 'Wis.', + value: 1333.628039, + }, + { + x: 1946, + y: 'W.Va.', + value: 140.5805038, + }, + { + x: 1946, + y: 'Wyo.', + value: 397.6377953, + }, + { + x: 1947, + y: 'Alaska', + value: null, + }, + { + x: 1947, + y: 'Ala.', + value: 127.2603671, + }, + { + x: 1947, + y: 'Ark.', + value: 130.6372549, + }, + { + x: 1947, + y: 'Ariz.', + value: 224.5022971, + }, + { + x: 1947, + y: 'Calif.', + value: 74.97457282, + }, + { + x: 1947, + y: 'Colo.', + value: 142.9264349, + }, + { + x: 1947, + y: 'Conn.', + value: 814.8957804, + }, + { + x: 1947, + y: 'D.C.', + value: 60.13513514, + }, + { + x: 1947, + y: 'Del.', + value: 19.3442623, + }, + { + x: 1947, + y: 'Fla.', + value: 53.06566456, + }, + { + x: 1947, + y: 'Ga.', + value: 102.4297066, + }, + { + x: 1947, + y: 'Hawaii', + value: null, + }, + { + x: 1947, + y: 'Iowa', + value: 177.8597051, + }, + { + x: 1947, + y: 'Idaho', + value: 51.14942529, + }, + { + x: 1947, + y: 'Ill.', + value: 91.45785877, + }, + { + x: 1947, + y: 'Ind.', + value: 60.91558613, + }, + { + x: 1947, + y: 'Kan.', + value: 48.0841878, + }, + { + x: 1947, + y: 'Ky.', + value: 30.09275776, + }, + { + x: 1947, + y: 'La.', + value: 49.96122528, + }, + { + x: 1947, + y: 'Mass.', + value: 252.6637555, + }, + { + x: 1947, + y: 'Md.', + value: 50.88967972, + }, + { + x: 1947, + y: 'Maine', + value: 504.5667447, + }, + { + x: 1947, + y: 'Mich.', + value: 148.0250165, + }, + { + x: 1947, + y: 'Minn.', + value: 319.3669528, + }, + { + x: 1947, + y: 'Mo.', + value: 33.56306892, + }, + { + x: 1947, + y: 'Miss.', + value: 14.97389654, + }, + { + x: 1947, + y: 'Mont.', + value: 843.4086629, + }, + { + x: 1947, + y: 'N.C.', + value: 127.6067923, + }, + { + x: 1947, + y: 'N.D.', + value: 236.0726644, + }, + { + x: 1947, + y: 'Neb.', + value: 37.39130435, + }, + { + x: 1947, + y: 'N.H.', + value: 61.04536489, + }, + { + x: 1947, + y: 'N.J.', + value: 250.7037679, + }, + { + x: 1947, + y: 'N.M', + value: 226.8041237, + }, + { + x: 1947, + y: 'Nev.', + value: 18.45637584, + }, + { + x: 1947, + y: 'N.Y.', + value: 107.9709627, + }, + { + x: 1947, + y: 'Ohio', + value: 239.4484101, + }, + { + x: 1947, + y: 'Okla.', + value: 10.75949367, + }, + { + x: 1947, + y: 'Ore.', + value: 71.93240265, + }, + { + x: 1947, + y: 'Pa.', + value: 113.3728913, + }, + { + x: 1947, + y: 'R.I.', + value: 507.3453608, + }, + { + x: 1947, + y: 'S.C.', + value: 161.87249, + }, + { + x: 1947, + y: 'S.D.', + value: 218.3028286, + }, + { + x: 1947, + y: 'Tenn.', + value: 60.97599495, + }, + { + x: 1947, + y: 'Texas', + value: 109.4951272, + }, + { + x: 1947, + y: 'Utah', + value: 99.21383648, + }, + { + x: 1947, + y: 'Va.', + value: 242.1743205, + }, + { + x: 1947, + y: 'Vt.', + value: 1348.870056, + }, + { + x: 1947, + y: 'Wash.', + value: 63.81727725, + }, + { + x: 1947, + y: 'Wis.', + value: 383.1692308, + }, + { + x: 1947, + y: 'W.Va.', + value: 143.5740839, + }, + { + x: 1947, + y: 'Wyo.', + value: 170.1550388, + }, + { + x: 1948, + y: 'Alaska', + value: null, + }, + { + x: 1948, + y: 'Ala.', + value: 69.08049848, + }, + { + x: 1948, + y: 'Ark.', + value: 208.3287671, + }, + { + x: 1948, + y: 'Ariz.', + value: 623.4057971, + }, + { + x: 1948, + y: 'Calif.', + value: 487.8477742, + }, + { + x: 1948, + y: 'Colo.', + value: 723.2779097, + }, + { + x: 1948, + y: 'Conn.', + value: 140.590864, + }, + { + x: 1948, + y: 'D.C.', + value: 305.0595238, + }, + { + x: 1948, + y: 'Del.', + value: 333.1730769, + }, + { + x: 1948, + y: 'Fla.', + value: 152.3661753, + }, + { + x: 1948, + y: 'Ga.', + value: 37.81834919, + }, + { + x: 1948, + y: 'Hawaii', + value: null, + }, + { + x: 1948, + y: 'Iowa', + value: 352.2414471, + }, + { + x: 1948, + y: 'Idaho', + value: 275.2268603, + }, + { + x: 1948, + y: 'Ill.', + value: 426.9761459, + }, + { + x: 1948, + y: 'Ind.', + value: 366.5849884, + }, + { + x: 1948, + y: 'Kan.', + value: 58.29809725, + }, + { + x: 1948, + y: 'Ky.', + value: 127.9730209, + }, + { + x: 1948, + y: 'La.', + value: 57.62711864, + }, + { + x: 1948, + y: 'Mass.', + value: 674.9679076, + }, + { + x: 1948, + y: 'Md.', + value: 435.3808895, + }, + { + x: 1948, + y: 'Maine', + value: 335.022779, + }, + { + x: 1948, + y: 'Mich.', + value: 561.0735554, + }, + { + x: 1948, + y: 'Minn.', + value: 286.3319386, + }, + { + x: 1948, + y: 'Mo.', + value: 150.2211238, + }, + { + x: 1948, + y: 'Miss.', + value: 58.261079, + }, + { + x: 1948, + y: 'Mont.', + value: 341.6051661, + }, + { + x: 1948, + y: 'N.C.', + value: 26.96116758, + }, + { + x: 1948, + y: 'N.D.', + value: 214.4827586, + }, + { + x: 1948, + y: 'Neb.', + value: 263.2806324, + }, + { + x: 1948, + y: 'N.H.', + value: 77.59615385, + }, + { + x: 1948, + y: 'N.J.', + value: 715.4482614, + }, + { + x: 1948, + y: 'N.M', + value: 174.6688742, + }, + { + x: 1948, + y: 'Nev.', + value: 38.14102564, + }, + { + x: 1948, + y: 'N.Y.', + value: 330.9443333, + }, + { + x: 1948, + y: 'Ohio', + value: 282.3006602, + }, + { + x: 1948, + y: 'Okla.', + value: 66.01244615, + }, + { + x: 1948, + y: 'Ore.', + value: 367.6156584, + }, + { + x: 1948, + y: 'Pa.', + value: 306.6880529, + }, + { + x: 1948, + y: 'R.I.', + value: 48.41168996, + }, + { + x: 1948, + y: 'S.C.', + value: 120.6663327, + }, + { + x: 1948, + y: 'S.D.', + value: 140.2777778, + }, + { + x: 1948, + y: 'Tenn.', + value: 127.5497512, + }, + { + x: 1948, + y: 'Texas', + value: 583.8578547, + }, + { + x: 1948, + y: 'Utah', + value: 910.949464, + }, + { + x: 1948, + y: 'Va.', + value: 191.3002806, + }, + { + x: 1948, + y: 'Vt.', + value: 407.1030641, + }, + { + x: 1948, + y: 'Wash.', + value: 482.2838137, + }, + { + x: 1948, + y: 'Wis.', + value: 926.1466506, + }, + { + x: 1948, + y: 'W.Va.', + value: 295.4713007, + }, + { + x: 1948, + y: 'Wyo.', + value: 805.3903346, + }, + { + x: 1949, + y: 'Alaska', + value: null, + }, + { + x: 1949, + y: 'Ala.', + value: 368.8666667, + }, + { + x: 1949, + y: 'Ark.', + value: 667.7331887, + }, + { + x: 1949, + y: 'Ariz.', + value: 531.512605, + }, + { + x: 1949, + y: 'Calif.', + value: 320.7990713, + }, + { + x: 1949, + y: 'Colo.', + value: 557.6061776, + }, + { + x: 1949, + y: 'Conn.', + value: 935.6299213, + }, + { + x: 1949, + y: 'D.C.', + value: 278.5625774, + }, + { + x: 1949, + y: 'Del.', + value: 234.4936709, + }, + { + x: 1949, + y: 'Fla.', + value: 144.0404798, + }, + { + x: 1949, + y: 'Ga.', + value: 288.6917293, + }, + { + x: 1949, + y: 'Hawaii', + value: null, + }, + { + x: 1949, + y: 'Iowa', + value: 87.00543057, + }, + { + x: 1949, + y: 'Idaho', + value: 511.0526316, + }, + { + x: 1949, + y: 'Ill.', + value: 65.91695502, + }, + { + x: 1949, + y: 'Ind.', + value: 100.1515917, + }, + { + x: 1949, + y: 'Kan.', + value: 882.2857143, + }, + { + x: 1949, + y: 'Ky.', + value: 294.5945946, + }, + { + x: 1949, + y: 'La.', + value: 51.59453303, + }, + { + x: 1949, + y: 'Mass.', + value: 556.8656402, + }, + { + x: 1949, + y: 'Md.', + value: 740.2318592, + }, + { + x: 1949, + y: 'Maine', + value: 1108.859358, + }, + { + x: 1949, + y: 'Mich.', + value: 312.0814908, + }, + { + x: 1949, + y: 'Minn.', + value: 114.4463373, + }, + { + x: 1949, + y: 'Mo.', + value: 203.760948, + }, + { + x: 1949, + y: 'Miss.', + value: 106.7625899, + }, + { + x: 1949, + y: 'Mont.', + value: 676.0984183, + }, + { + x: 1949, + y: 'N.C.', + value: 442.4955254, + }, + { + x: 1949, + y: 'N.D.', + value: 245.8961474, + }, + { + x: 1949, + y: 'Neb.', + value: 207.9877112, + }, + { + x: 1949, + y: 'N.H.', + value: 230.5816135, + }, + { + x: 1949, + y: 'N.J.', + value: 705.1135201, + }, + { + x: 1949, + y: 'N.M', + value: 671.4285714, + }, + { + x: 1949, + y: 'Nev.', + value: 60.50955414, + }, + { + x: 1949, + y: 'N.Y.', + value: 353.0754768, + }, + { + x: 1949, + y: 'Ohio', + value: 268.2679042, + }, + { + x: 1949, + y: 'Okla.', + value: 354.0617577, + }, + { + x: 1949, + y: 'Ore.', + value: 684.3466108, + }, + { + x: 1949, + y: 'Pa.', + value: 483.9653513, + }, + { + x: 1949, + y: 'R.I.', + value: 561.6729089, + }, + { + x: 1949, + y: 'S.C.', + value: 453.0803351, + }, + { + x: 1949, + y: 'S.D.', + value: 157.3692552, + }, + { + x: 1949, + y: 'Tenn.', + value: 252.750309, + }, + { + x: 1949, + y: 'Texas', + value: 749.4818313, + }, + { + x: 1949, + y: 'Utah', + value: 526.5275708, + }, + { + x: 1949, + y: 'Va.', + value: 649.3620899, + }, + { + x: 1949, + y: 'Vt.', + value: 1711.382114, + }, + { + x: 1949, + y: 'Wash.', + value: 551.1769834, + }, + { + x: 1949, + y: 'Wis.', + value: 1171.099971, + }, + { + x: 1949, + y: 'W.Va.', + value: 188.4455959, + }, + { + x: 1949, + y: 'Wyo.', + value: 201.4440433, + }, + { + x: 1950, + y: 'Alaska', + value: null, + }, + { + x: 1950, + y: 'Ala.', + value: 50.88293002, + }, + { + x: 1950, + y: 'Ark.', + value: 91.14255765, + }, + { + x: 1950, + y: 'Ariz.', + value: 316.005291, + }, + { + x: 1950, + y: 'Calif.', + value: 137.9413693, + }, + { + x: 1950, + y: 'Colo.', + value: 395.3962264, + }, + { + x: 1950, + y: 'Conn.', + value: 197.4206349, + }, + { + x: 1950, + y: 'D.C.', + value: 213.5235732, + }, + { + x: 1950, + y: 'Del.', + value: 194.7040498, + }, + { + x: 1950, + y: 'Fla.', + value: 83.41637011, + }, + { + x: 1950, + y: 'Ga.', + value: 62.43493349, + }, + { + x: 1950, + y: 'Hawaii', + value: 13.25301205, + }, + { + x: 1950, + y: 'Iowa', + value: 399.4666667, + }, + { + x: 1950, + y: 'Idaho', + value: 324.0677966, + }, + { + x: 1950, + y: 'Ill.', + value: 200.3547723, + }, + { + x: 1950, + y: 'Ind.', + value: 169.4227376, + }, + { + x: 1950, + y: 'Kan.', + value: 93.16283925, + }, + { + x: 1950, + y: 'Ky.', + value: 162.6362398, + }, + { + x: 1950, + y: 'La.', + value: 28.55024101, + }, + { + x: 1950, + y: 'Mass.', + value: 264.7247119, + }, + { + x: 1950, + y: 'Md.', + value: 61.74097665, + }, + { + x: 1950, + y: 'Maine', + value: 106.1068702, + }, + { + x: 1950, + y: 'Mich.', + value: 575.2926487, + }, + { + x: 1950, + y: 'Minn.', + value: 125.1584918, + }, + { + x: 1950, + y: 'Mo.', + value: 58.04742684, + }, + { + x: 1950, + y: 'Miss.', + value: 99.49448529, + }, + { + x: 1950, + y: 'Mont.', + value: 300.1686341, + }, + { + x: 1950, + y: 'N.C.', + value: 118.879056, + }, + { + x: 1950, + y: 'N.D.', + value: 63.65105008, + }, + { + x: 1950, + y: 'Neb.', + value: 275.2825923, + }, + { + x: 1950, + y: 'N.H.', + value: 34.39849624, + }, + { + x: 1950, + y: 'N.J.', + value: 601.6625616, + }, + { + x: 1950, + y: 'N.M', + value: 135.9941945, + }, + { + x: 1950, + y: 'Nev.', + value: 67.90123457, + }, + { + x: 1950, + y: 'N.Y.', + value: 201.305079, + }, + { + x: 1950, + y: 'Ohio', + value: 161.7919799, + }, + { + x: 1950, + y: 'Okla.', + value: 27.50112158, + }, + { + x: 1950, + y: 'Ore.', + value: 49.41253264, + }, + { + x: 1950, + y: 'Pa.', + value: 165.4325688, + }, + { + x: 1950, + y: 'R.I.', + value: 30.66157761, + }, + { + x: 1950, + y: 'S.C.', + value: 90.62943682, + }, + { + x: 1950, + y: 'S.D.', + value: 102.5954198, + }, + { + x: 1950, + y: 'Tenn.', + value: 104.13273, + }, + { + x: 1950, + y: 'Texas', + value: 175.6430041, + }, + { + x: 1950, + y: 'Utah', + value: 879.1666667, + }, + { + x: 1950, + y: 'Va.', + value: 85.42986425, + }, + { + x: 1950, + y: 'Vt.', + value: 157.5197889, + }, + { + x: 1950, + y: 'Wash.', + value: 142.6057813, + }, + { + x: 1950, + y: 'Wis.', + value: 546.7132054, + }, + { + x: 1950, + y: 'W.Va.', + value: 293.1704885, + }, + { + x: 1950, + y: 'Wyo.', + value: 210, + }, + { + x: 1951, + y: 'Alaska', + value: null, + }, + { + x: 1951, + y: 'Ala.', + value: 103.2363517, + }, + { + x: 1951, + y: 'Ark.', + value: 401.1046817, + }, + { + x: 1951, + y: 'Ariz.', + value: 1351.464968, + }, + { + x: 1951, + y: 'Calif.', + value: 548.3653673, + }, + { + x: 1951, + y: 'Colo.', + value: 934.0120664, + }, + { + x: 1951, + y: 'Conn.', + value: 227.4161736, + }, + { + x: 1951, + y: 'D.C.', + value: 185.1485149, + }, + { + x: 1951, + y: 'Del.', + value: 208.4592145, + }, + { + x: 1951, + y: 'Fla.', + value: 76.17449664, + }, + { + x: 1951, + y: 'Ga.', + value: 213.0557916, + }, + { + x: 1951, + y: 'Hawaii', + value: 955.2529183, + }, + { + x: 1951, + y: 'Iowa', + value: 103.7829576, + }, + { + x: 1951, + y: 'Idaho', + value: 358.0645161, + }, + { + x: 1951, + y: 'Ill.', + value: 187.6450512, + }, + { + x: 1951, + y: 'Ind.', + value: 102.0019531, + }, + { + x: 1951, + y: 'Kan.', + value: 572.2051282, + }, + { + x: 1951, + y: 'Ky.', + value: 290.9894594, + }, + { + x: 1951, + y: 'La.', + value: 78.72878295, + }, + { + x: 1951, + y: 'Mass.', + value: 311.5384615, + }, + { + x: 1951, + y: 'Md.', + value: 269.0700533, + }, + { + x: 1951, + y: 'Maine', + value: 193.0131004, + }, + { + x: 1951, + y: 'Mich.', + value: 221.8562413, + }, + { + x: 1951, + y: 'Minn.', + value: 93.35548173, + }, + { + x: 1951, + y: 'Mo.', + value: 188.5678705, + }, + { + x: 1951, + y: 'Miss.', + value: 91.26213592, + }, + { + x: 1951, + y: 'Mont.', + value: 416.6107383, + }, + { + x: 1951, + y: 'N.C.', + value: 81.38349515, + }, + { + x: 1951, + y: 'N.D.', + value: 426.986755, + }, + { + x: 1951, + y: 'Neb.', + value: 41.71732523, + }, + { + x: 1951, + y: 'N.H.', + value: 196.4083176, + }, + { + x: 1951, + y: 'N.J.', + value: 394.9860168, + }, + { + x: 1951, + y: 'N.M', + value: 297.4895397, + }, + { + x: 1951, + y: 'Nev.', + value: 171.4285714, + }, + { + x: 1951, + y: 'N.Y.', + value: 240.6111484, + }, + { + x: 1951, + y: 'Ohio', + value: 295.782161, + }, + { + x: 1951, + y: 'Okla.', + value: 359.9095023, + }, + { + x: 1951, + y: 'Ore.', + value: 617.8020566, + }, + { + x: 1951, + y: 'Pa.', + value: 299.8661696, + }, + { + x: 1951, + y: 'R.I.', + value: 113.2653061, + }, + { + x: 1951, + y: 'S.C.', + value: 34.28703276, + }, + { + x: 1951, + y: 'S.D.', + value: 106.7175573, + }, + { + x: 1951, + y: 'Tenn.', + value: 80.6346382, + }, + { + x: 1951, + y: 'Texas', + value: 808.7905314, + }, + { + x: 1951, + y: 'Utah', + value: 331.4447592, + }, + { + x: 1951, + y: 'Va.', + value: 408.7070472, + }, + { + x: 1951, + y: 'Vt.', + value: 1130.952381, + }, + { + x: 1951, + y: 'Wash.', + value: 733.3333333, + }, + { + x: 1951, + y: 'Wis.', + value: 958.0692062, + }, + { + x: 1951, + y: 'W.Va.', + value: 227.2681452, + }, + { + x: 1951, + y: 'Wyo.', + value: 753.6082474, + }, + { + x: 1952, + y: 'Alaska', + value: null, + }, + { + x: 1952, + y: 'Ala.', + value: 351.7275098, + }, + { + x: 1952, + y: 'Ark.', + value: 188.5473341, + }, + { + x: 1952, + y: 'Ariz.', + value: 424.584323, + }, + { + x: 1952, + y: 'Calif.', + value: 335.2943704, + }, + { + x: 1952, + y: 'Colo.', + value: 386.9230769, + }, + { + x: 1952, + y: 'Conn.', + value: 1179.000481, + }, + { + x: 1952, + y: 'D.C.', + value: 286.2111801, + }, + { + x: 1952, + y: 'Del.', + value: 119.3548387, + }, + { + x: 1952, + y: 'Fla.', + value: 110.0095027, + }, + { + x: 1952, + y: 'Ga.', + value: 225.4324777, + }, + { + x: 1952, + y: 'Hawaii', + value: null, + }, + { + x: 1952, + y: 'Iowa', + value: 120.8111196, + }, + { + x: 1952, + y: 'Idaho', + value: 196.0817717, + }, + { + x: 1952, + y: 'Ill.', + value: 294.5399732, + }, + { + x: 1952, + y: 'Ind.', + value: 179.1224687, + }, + { + x: 1952, + y: 'Kan.', + value: 326.0748609, + }, + { + x: 1952, + y: 'Ky.', + value: 362.9794521, + }, + { + x: 1952, + y: 'La.', + value: 23.9268121, + }, + { + x: 1952, + y: 'Mass.', + value: 940.0645161, + }, + { + x: 1952, + y: 'Md.', + value: 348.04, + }, + { + x: 1952, + y: 'Maine', + value: 987.704918, + }, + { + x: 1952, + y: 'Mich.', + value: 407.4736842, + }, + { + x: 1952, + y: 'Minn.', + value: 96.96369637, + }, + { + x: 1952, + y: 'Mo.', + value: 60.93907351, + }, + { + x: 1952, + y: 'Miss.', + value: 64.59107807, + }, + { + x: 1952, + y: 'Mont.', + value: 643.9368771, + }, + { + x: 1952, + y: 'N.C.', + value: 93.50206863, + }, + { + x: 1952, + y: 'N.D.', + value: 432.1546053, + }, + { + x: 1952, + y: 'Neb.', + value: 214.0350877, + }, + { + x: 1952, + y: 'N.H.', + value: 447.2897196, + }, + { + x: 1952, + y: 'N.J.', + value: 1282.682927, + }, + { + x: 1952, + y: 'N.M', + value: 210.6122449, + }, + { + x: 1952, + y: 'Nev.', + value: 285.359116, + }, + { + x: 1952, + y: 'N.Y.', + value: 500.5891259, + }, + { + x: 1952, + y: 'Ohio', + value: 248.0181269, + }, + { + x: 1952, + y: 'Okla.', + value: 91.97836863, + }, + { + x: 1952, + y: 'Ore.', + value: 209.7661188, + }, + { + x: 1952, + y: 'Pa.', + value: 358.4737694, + }, + { + x: 1952, + y: 'R.I.', + value: 665.7730673, + }, + { + x: 1952, + y: 'S.C.', + value: 81.70339761, + }, + { + x: 1952, + y: 'S.D.', + value: 115.2841782, + }, + { + x: 1952, + y: 'Tenn.', + value: 200.477327, + }, + { + x: 1952, + y: 'Texas', + value: 283.2812124, + }, + { + x: 1952, + y: 'Utah', + value: 652.4861878, + }, + { + x: 1952, + y: 'Va.', + value: 376.5268265, + }, + { + x: 1952, + y: 'Vt.', + value: 1397.333333, + }, + { + x: 1952, + y: 'Wash.', + value: 243.7908497, + }, + { + x: 1952, + y: 'Wis.', + value: 1140.833093, + }, + { + x: 1952, + y: 'W.Va.', + value: 269.9795606, + }, + { + x: 1952, + y: 'Wyo.', + value: 231.7406143, + }, + { + x: 1953, + y: 'Alaska', + value: null, + }, + { + x: 1953, + y: 'Ala.', + value: 93.97314117, + }, + { + x: 1953, + y: 'Ark.', + value: 727.3876404, + }, + { + x: 1953, + y: 'Ariz.', + value: 557.885906, + }, + { + x: 1953, + y: 'Calif.', + value: 438.9111093, + }, + { + x: 1953, + y: 'Colo.', + value: 683.9622642, + }, + { + x: 1953, + y: 'Conn.', + value: 100, + }, + { + x: 1953, + y: 'D.C.', + value: 44.07407407, + }, + { + x: 1953, + y: 'Del.', + value: 115.954416, + }, + { + x: 1953, + y: 'Fla.', + value: 38.54984894, + }, + { + x: 1953, + y: 'Ga.', + value: 86.50927487, + }, + { + x: 1953, + y: 'Hawaii', + value: null, + }, + { + x: 1953, + y: 'Iowa', + value: 413.7694941, + }, + { + x: 1953, + y: 'Idaho', + value: 324.3288591, + }, + { + x: 1953, + y: 'Ill.', + value: 173.6955323, + }, + { + x: 1953, + y: 'Ind.', + value: 162.577714, + }, + { + x: 1953, + y: 'Kan.', + value: 750.8776329, + }, + { + x: 1953, + y: 'Ky.', + value: 134.550465, + }, + { + x: 1953, + y: 'La.', + value: 155.931612, + }, + { + x: 1953, + y: 'Mass.', + value: 68.26883063, + }, + { + x: 1953, + y: 'Md.', + value: 79.47019868, + }, + { + x: 1953, + y: 'Maine', + value: 181.5443593, + }, + { + x: 1953, + y: 'Mich.', + value: 323.0211082, + }, + { + x: 1953, + y: 'Minn.', + value: 136.2459016, + }, + { + x: 1953, + y: 'Mo.', + value: 218.880597, + }, + { + x: 1953, + y: 'Miss.', + value: 115.415677, + }, + { + x: 1953, + y: 'Mont.', + value: 505.275974, + }, + { + x: 1953, + y: 'N.C.', + value: 115.4490291, + }, + { + x: 1953, + y: 'N.D.', + value: 254.4334975, + }, + { + x: 1953, + y: 'Neb.', + value: 183.7253414, + }, + { + x: 1953, + y: 'N.H.', + value: 50.73126143, + }, + { + x: 1953, + y: 'N.J.', + value: 81.1914324, + }, + { + x: 1953, + y: 'N.M', + value: 662.8968254, + }, + { + x: 1953, + y: 'Nev.', + value: 102.3076923, + }, + { + x: 1953, + y: 'N.Y.', + value: 74.16435886, + }, + { + x: 1953, + y: 'Ohio', + value: 314.9575137, + }, + { + x: 1953, + y: 'Okla.', + value: 173.0980752, + }, + { + x: 1953, + y: 'Ore.', + value: 558.1511555, + }, + { + x: 1953, + y: 'Pa.', + value: 146.1827049, + }, + { + x: 1953, + y: 'R.I.', + value: 61.96319018, + }, + { + x: 1953, + y: 'S.C.', + value: 89.36267767, + }, + { + x: 1953, + y: 'S.D.', + value: 68.82716049, + }, + { + x: 1953, + y: 'Tenn.', + value: 84.76950889, + }, + { + x: 1953, + y: 'Texas', + value: 885.790547, + }, + { + x: 1953, + y: 'Utah', + value: 775.3721245, + }, + { + x: 1953, + y: 'Va.', + value: 138.9654203, + }, + { + x: 1953, + y: 'Vt.', + value: 148.944591, + }, + { + x: 1953, + y: 'Wash.', + value: 473.1143552, + }, + { + x: 1953, + y: 'Wis.', + value: 1166.871078, + }, + { + x: 1953, + y: 'W.Va.', + value: 309.5904614, + }, + { + x: 1953, + y: 'Wyo.', + value: 497.5862069, + }, + { + x: 1954, + y: 'Alaska', + value: 691.627907, + }, + { + x: 1954, + y: 'Ala.', + value: 280.3915063, + }, + { + x: 1954, + y: 'Ark.', + value: 151.0380623, + }, + { + x: 1954, + y: 'Ariz.', + value: 531.511254, + }, + { + x: 1954, + y: 'Calif.', + value: 473.0346775, + }, + { + x: 1954, + y: 'Colo.', + value: 127.6624246, + }, + { + x: 1954, + y: 'Conn.', + value: 223.4771009, + }, + { + x: 1954, + y: 'D.C.', + value: 383.312263, + }, + { + x: 1954, + y: 'Del.', + value: 527.7173913, + }, + { + x: 1954, + y: 'Fla.', + value: 312.2681883, + }, + { + x: 1954, + y: 'Ga.', + value: 188.0344253, + }, + { + x: 1954, + y: 'Hawaii', + value: 99.8019802, + }, + { + x: 1954, + y: 'Iowa', + value: 477.1515613, + }, + { + x: 1954, + y: 'Idaho', + value: 734.1666667, + }, + { + x: 1954, + y: 'Ill.', + value: 358.7332469, + }, + { + x: 1954, + y: 'Ind.', + value: 517.0966229, + }, + { + x: 1954, + y: 'Kan.', + value: 66.35651322, + }, + { + x: 1954, + y: 'Ky.', + value: 1025.982081, + }, + { + x: 1954, + y: 'La.', + value: 105.0294832, + }, + { + x: 1954, + y: 'Mass.', + value: 475.0509165, + }, + { + x: 1954, + y: 'Md.', + value: 433.8175047, + }, + { + x: 1954, + y: 'Maine', + value: 626.7529666, + }, + { + x: 1954, + y: 'Mich.', + value: 568.596094, + }, + { + x: 1954, + y: 'Minn.', + value: 92.93286219, + }, + { + x: 1954, + y: 'Mo.', + value: 37.89965568, + }, + { + x: 1954, + y: 'Miss.', + value: 145.9302326, + }, + { + x: 1954, + y: 'Mont.', + value: 750, + }, + { + x: 1954, + y: 'N.C.', + value: 229.2907286, + }, + { + x: 1954, + y: 'N.D.', + value: 454.1734861, + }, + { + x: 1954, + y: 'Neb.', + value: 191.641791, + }, + { + x: 1954, + y: 'N.H.', + value: 168.2310469, + }, + { + x: 1954, + y: 'N.J.', + value: 445.8208955, + }, + { + x: 1954, + y: 'N.M', + value: 355.9633028, + }, + { + x: 1954, + y: 'Nev.', + value: 182.1596244, + }, + { + x: 1954, + y: 'N.Y.', + value: 548.3622107, + }, + { + x: 1954, + y: 'Ohio', + value: 322.2923476, + }, + { + x: 1954, + y: 'Okla.', + value: 152.1502943, + }, + { + x: 1954, + y: 'Ore.', + value: 244.3419434, + }, + { + x: 1954, + y: 'Pa.', + value: 351.8258297, + }, + { + x: 1954, + y: 'R.I.', + value: 223.6519608, + }, + { + x: 1954, + y: 'S.C.', + value: 254.8713235, + }, + { + x: 1954, + y: 'S.D.', + value: 123.5114504, + }, + { + x: 1954, + y: 'Tenn.', + value: 416.4036916, + }, + { + x: 1954, + y: 'Texas', + value: 906.1441183, + }, + { + x: 1954, + y: 'Utah', + value: 1043.866667, + }, + { + x: 1954, + y: 'Va.', + value: 673.5583685, + }, + { + x: 1954, + y: 'Vt.', + value: 760.2122016, + }, + { + x: 1954, + y: 'Wash.', + value: 857.4721781, + }, + { + x: 1954, + y: 'Wis.', + value: 289.578714, + }, + { + x: 1954, + y: 'W.Va.', + value: 512.0734908, + }, + { + x: 1954, + y: 'Wyo.', + value: 391.8088737, + }, + { + x: 1955, + y: 'Alaska', + value: 241.8918919, + }, + { + x: 1955, + y: 'Ala.', + value: 69.67213115, + }, + { + x: 1955, + y: 'Ark.', + value: 173.5652174, + }, + { + x: 1955, + y: 'Ariz.', + value: 1024.012158, + }, + { + x: 1955, + y: 'Calif.', + value: 513.469885, + }, + { + x: 1955, + y: 'Colo.', + value: 317.076326, + }, + { + x: 1955, + y: 'Conn.', + value: 1256.608696, + }, + { + x: 1955, + y: 'D.C.', + value: 57.70700637, + }, + { + x: 1955, + y: 'Del.', + value: 26.99228792, + }, + { + x: 1955, + y: 'Fla.', + value: 38.08380037, + }, + { + x: 1955, + y: 'Ga.', + value: 68.15181518, + }, + { + x: 1955, + y: 'Hawaii', + value: 1186.456401, + }, + { + x: 1955, + y: 'Iowa', + value: 286.6368048, + }, + { + x: 1955, + y: 'Idaho', + value: 113.7540453, + }, + { + x: 1955, + y: 'Ill.', + value: 144.663487, + }, + { + x: 1955, + y: 'Ind.', + value: 86.38551455, + }, + { + x: 1955, + y: 'Kan.', + value: 145.5327281, + }, + { + x: 1955, + y: 'Ky.', + value: 76.04810997, + }, + { + x: 1955, + y: 'La.', + value: 5.668703327, + }, + { + x: 1955, + y: 'Mass.', + value: 957.4969275, + }, + { + x: 1955, + y: 'Md.', + value: 83.51568198, + }, + { + x: 1955, + y: 'Maine', + value: 710.4925054, + }, + { + x: 1955, + y: 'Mich.', + value: 309.1283459, + }, + { + x: 1955, + y: 'Minn.', + value: 225.2837327, + }, + { + x: 1955, + y: 'Mo.', + value: 96.5408805, + }, + { + x: 1955, + y: 'Miss.', + value: 72.76699029, + }, + { + x: 1955, + y: 'Mont.', + value: 449.8427673, + }, + { + x: 1955, + y: 'N.C.', + value: 29.67939651, + }, + { + x: 1955, + y: 'N.D.', + value: 407.804878, + }, + { + x: 1955, + y: 'Neb.', + value: 12.08151383, + }, + { + x: 1955, + y: 'N.H.', + value: 831.4183124, + }, + { + x: 1955, + y: 'N.J.', + value: 937.0956016, + }, + { + x: 1955, + y: 'N.M', + value: 621.7834395, + }, + { + x: 1955, + y: 'Nev.', + value: 165.4008439, + }, + { + x: 1955, + y: 'N.Y.', + value: 241.400476, + }, + { + x: 1955, + y: 'Ohio', + value: 170.3005434, + }, + { + x: 1955, + y: 'Okla.', + value: 132.2666667, + }, + { + x: 1955, + y: 'Ore.', + value: 295.177818, + }, + { + x: 1955, + y: 'Pa.', + value: 170.4634793, + }, + { + x: 1955, + y: 'R.I.', + value: 657.2296476, + }, + { + x: 1955, + y: 'S.C.', + value: 53.31818182, + }, + { + x: 1955, + y: 'S.D.', + value: 63.65007541, + }, + { + x: 1955, + y: 'Tenn.', + value: 172.0644217, + }, + { + x: 1955, + y: 'Texas', + value: 455.7274827, + }, + { + x: 1955, + y: 'Utah', + value: 101.0217114, + }, + { + x: 1955, + y: 'Va.', + value: 120.122631, + }, + { + x: 1955, + y: 'Vt.', + value: 1894.933333, + }, + { + x: 1955, + y: 'Wash.', + value: 425.0384025, + }, + { + x: 1955, + y: 'Wis.', + value: 1389.045936, + }, + { + x: 1955, + y: 'W.Va.', + value: 204.2021277, + }, + { + x: 1955, + y: 'Wyo.', + value: 180.781759, + }, + { + x: 1956, + y: 'Alaska', + value: 1120.982143, + }, + { + x: 1956, + y: 'Ala.', + value: 231.7486161, + }, + { + x: 1956, + y: 'Ark.', + value: 506.8661972, + }, + { + x: 1956, + y: 'Ariz.', + value: 644.3494777, + }, + { + x: 1956, + y: 'Calif.', + value: 235.2074674, + }, + { + x: 1956, + y: 'Colo.', + value: 873.2307692, + }, + { + x: 1956, + y: 'Conn.', + value: 116.4507772, + }, + { + x: 1956, + y: 'D.C.', + value: 210.2766798, + }, + { + x: 1956, + y: 'Del.', + value: 212.254902, + }, + { + x: 1956, + y: 'Fla.', + value: 127.2300469, + }, + { + x: 1956, + y: 'Ga.', + value: 128.8840854, + }, + { + x: 1956, + y: 'Hawaii', + value: 922.0035778, + }, + { + x: 1956, + y: 'Iowa', + value: 307.3991861, + }, + { + x: 1956, + y: 'Idaho', + value: 317.5159236, + }, + { + x: 1956, + y: 'Ill.', + value: 442.0146905, + }, + { + x: 1956, + y: 'Ind.', + value: 368.2144459, + }, + { + x: 1956, + y: 'Kan.', + value: 200.7550731, + }, + { + x: 1956, + y: 'Ky.', + value: 610.3174603, + }, + { + x: 1956, + y: 'La.', + value: 69.65699208, + }, + { + x: 1956, + y: 'Mass.', + value: 72.00981394, + }, + { + x: 1956, + y: 'Md.', + value: 310.7790822, + }, + { + x: 1956, + y: 'Maine', + value: 115.3518124, + }, + { + x: 1956, + y: 'Mich.', + value: 540.1499933, + }, + { + x: 1956, + y: 'Minn.', + value: 40.74074074, + }, + { + x: 1956, + y: 'Mo.', + value: 124.9099207, + }, + { + x: 1956, + y: 'Miss.', + value: 107.7660594, + }, + { + x: 1956, + y: 'Mont.', + value: 1016.615854, + }, + { + x: 1956, + y: 'N.C.', + value: 178.8117893, + }, + { + x: 1956, + y: 'N.D.', + value: 362.4796085, + }, + { + x: 1956, + y: 'Neb.', + value: 178.5969936, + }, + { + x: 1956, + y: 'N.H.', + value: 35.33568905, + }, + { + x: 1956, + y: 'N.J.', + value: 340.3383793, + }, + { + x: 1956, + y: 'N.M', + value: 495.2853598, + }, + { + x: 1956, + y: 'Nev.', + value: 55.2, + }, + { + x: 1956, + y: 'N.Y.', + value: 308.5650447, + }, + { + x: 1956, + y: 'Ohio', + value: 477.3107418, + }, + { + x: 1956, + y: 'Okla.', + value: 440.4311483, + }, + { + x: 1956, + y: 'Ore.', + value: 135.041225, + }, + { + x: 1956, + y: 'Pa.', + value: 397.9584397, + }, + { + x: 1956, + y: 'R.I.', + value: 22.38095238, + }, + { + x: 1956, + y: 'S.C.', + value: 384.7465231, + }, + { + x: 1956, + y: 'S.D.', + value: 86.71641791, + }, + { + x: 1956, + y: 'Tenn.', + value: 617.0131772, + }, + { + x: 1956, + y: 'Texas', + value: 755.209513, + }, + { + x: 1956, + y: 'Utah', + value: 284.1779975, + }, + { + x: 1956, + y: 'Va.', + value: 634.4975819, + }, + { + x: 1956, + y: 'Vt.', + value: 340.8488064, + }, + { + x: 1956, + y: 'Wash.', + value: 481.3343328, + }, + { + x: 1956, + y: 'Wis.', + value: 715.7135222, + }, + { + x: 1956, + y: 'W.Va.', + value: 587.1297792, + }, + { + x: 1956, + y: 'Wyo.', + value: 640.7051282, + }, + { + x: 1957, + y: 'Alaska', + value: 414.7186147, + }, + { + x: 1957, + y: 'Ala.', + value: 299.7748472, + }, + { + x: 1957, + y: 'Ark.', + value: 78.36122331, + }, + { + x: 1957, + y: 'Ariz.', + value: 700.9777778, + }, + { + x: 1957, + y: 'Calif.', + value: 353.3581043, + }, + { + x: 1957, + y: 'Colo.', + value: 173.4975962, + }, + { + x: 1957, + y: 'Conn.', + value: 410.0042391, + }, + { + x: 1957, + y: 'D.C.', + value: 114.8099607, + }, + { + x: 1957, + y: 'Del.', + value: 78.16901408, + }, + { + x: 1957, + y: 'Fla.', + value: 120.3568161, + }, + { + x: 1957, + y: 'Ga.', + value: 155.6027616, + }, + { + x: 1957, + y: 'Hawaii', + value: 866.2671233, + }, + { + x: 1957, + y: 'Iowa', + value: 330.7805596, + }, + { + x: 1957, + y: 'Idaho', + value: 486.9158879, + }, + { + x: 1957, + y: 'Ill.', + value: 100.2482416, + }, + { + x: 1957, + y: 'Ind.', + value: 180.326783, + }, + { + x: 1957, + y: 'Kan.', + value: 0.610902256, + }, + { + x: 1957, + y: 'Ky.', + value: 557.7527322, + }, + { + x: 1957, + y: 'La.', + value: 34.67094703, + }, + { + x: 1957, + y: 'Mass.', + value: 222.0531548, + }, + { + x: 1957, + y: 'Md.', + value: 79.67281587, + }, + { + x: 1957, + y: 'Maine', + value: 478.8971368, + }, + { + x: 1957, + y: 'Mich.', + value: 234.8659004, + }, + { + x: 1957, + y: 'Minn.', + value: 229.3219304, + }, + { + x: 1957, + y: 'Mo.', + value: 102.2439723, + }, + { + x: 1957, + y: 'Miss.', + value: 61.44636015, + }, + { + x: 1957, + y: 'Mont.', + value: 528.6356822, + }, + { + x: 1957, + y: 'N.C.', + value: 43.63553114, + }, + { + x: 1957, + y: 'N.D.', + value: 629.248366, + }, + { + x: 1957, + y: 'Neb.', + value: 16.78622669, + }, + { + x: 1957, + y: 'N.H.', + value: 69.05594406, + }, + { + x: 1957, + y: 'N.J.', + value: 458.0617047, + }, + { + x: 1957, + y: 'N.M', + value: 747.3435655, + }, + { + x: 1957, + y: 'Nev.', + value: 592.3076923, + }, + { + x: 1957, + y: 'N.Y.', + value: 233.6325882, + }, + { + x: 1957, + y: 'Ohio', + value: 86.93942614, + }, + { + x: 1957, + y: 'Okla.', + value: 66.08238387, + }, + { + x: 1957, + y: 'Ore.', + value: 879.2640187, + }, + { + x: 1957, + y: 'Pa.', + value: 117.0896476, + }, + { + x: 1957, + y: 'R.I.', + value: 72.62044653, + }, + { + x: 1957, + y: 'S.C.', + value: 248.1970097, + }, + { + x: 1957, + y: 'S.D.', + value: 81.53153153, + }, + { + x: 1957, + y: 'Tenn.', + value: 455.9988352, + }, + { + x: 1957, + y: 'Texas', + value: 471.8522602, + }, + { + x: 1957, + y: 'Utah', + value: 1749.878935, + }, + { + x: 1957, + y: 'Va.', + value: 128.6680541, + }, + { + x: 1957, + y: 'Vt.', + value: 761.4361702, + }, + { + x: 1957, + y: 'Wash.', + value: 614.3538913, + }, + { + x: 1957, + y: 'Wis.', + value: 980.7702453, + }, + { + x: 1957, + y: 'W.Va.', + value: 185.0786761, + }, + { + x: 1957, + y: 'Wyo.', + value: 69.42675159, + }, + { + x: 1958, + y: 'Alaska', + value: 562.0535714, + }, + { + x: 1958, + y: 'Ala.', + value: 242.3016124, + }, + { + x: 1958, + y: 'Ark.', + value: 173.9281576, + }, + { + x: 1958, + y: 'Ariz.', + value: 825.2305113, + }, + { + x: 1958, + y: 'Calif.', + value: 235.7123656, + }, + { + x: 1958, + y: 'Colo.', + value: 566.0467906, + }, + { + x: 1958, + y: 'Conn.', + value: 645.625511, + }, + { + x: 1958, + y: 'D.C.', + value: 187.5825627, + }, + { + x: 1958, + y: 'Del.', + value: 118.9376443, + }, + { + x: 1958, + y: 'Fla.', + value: 266.6738661, + }, + { + x: 1958, + y: 'Ga.', + value: 175.1840168, + }, + { + x: 1958, + y: 'Hawaii', + value: 95.04132231, + }, + { + x: 1958, + y: 'Iowa', + value: 463.8109306, + }, + { + x: 1958, + y: 'Idaho', + value: 591.9504644, + }, + { + x: 1958, + y: 'Ill.', + value: 233.1074246, + }, + { + x: 1958, + y: 'Ind.', + value: 396.5306568, + }, + { + x: 1958, + y: 'Kan.', + value: 3.314659197, + }, + { + x: 1958, + y: 'Ky.', + value: 619.6555218, + }, + { + x: 1958, + y: 'La.', + value: 9.033280507, + }, + { + x: 1958, + y: 'Mass.', + value: 714.9500998, + }, + { + x: 1958, + y: 'Md.', + value: 210.8316566, + }, + { + x: 1958, + y: 'Maine', + value: 462.6059322, + }, + { + x: 1958, + y: 'Mich.', + value: 530.4160689, + }, + { + x: 1958, + y: 'Minn.', + value: 37.85089043, + }, + { + x: 1958, + y: 'Mo.', + value: 82.41758242, + }, + { + x: 1958, + y: 'Miss.', + value: 67.49760307, + }, + { + x: 1958, + y: 'Mont.', + value: 1065.465465, + }, + { + x: 1958, + y: 'N.C.', + value: 93.76142596, + }, + { + x: 1958, + y: 'N.D.', + value: 714.5214521, + }, + { + x: 1958, + y: 'Neb.', + value: 108.8214027, + }, + { + x: 1958, + y: 'N.H.', + value: 367.9862306, + }, + { + x: 1958, + y: 'N.J.', + value: 429.1001698, + }, + { + x: 1958, + y: 'N.M', + value: 912.1896163, + }, + { + x: 1958, + y: 'Nev.', + value: 73.60594796, + }, + { + x: 1958, + y: 'N.Y.', + value: 364.1768568, + }, + { + x: 1958, + y: 'Ohio', + value: 312.7929993, + }, + { + x: 1958, + y: 'Okla.', + value: 317.8650199, + }, + { + x: 1958, + y: 'Ore.', + value: 528.9871944, + }, + { + x: 1958, + y: 'Pa.', + value: 307.1803219, + }, + { + x: 1958, + y: 'R.I.', + value: 496.8531469, + }, + { + x: 1958, + y: 'S.C.', + value: 472.1788194, + }, + { + x: 1958, + y: 'S.D.', + value: 18.44512195, + }, + { + x: 1958, + y: 'Tenn.', + value: 793.5465284, + }, + { + x: 1958, + y: 'Texas', + value: 889.5265888, + }, + { + x: 1958, + y: 'Utah', + value: 458.816568, + }, + { + x: 1958, + y: 'Va.', + value: 550.1532959, + }, + { + x: 1958, + y: 'Vt.', + value: 549.2105263, + }, + { + x: 1958, + y: 'Wash.', + value: 384.2048323, + }, + { + x: 1958, + y: 'Wis.', + value: 1665.3656, + }, + { + x: 1958, + y: 'W.Va.', + value: 657.1815718, + }, + { + x: 1958, + y: 'Wyo.', + value: 433.3333333, + }, + { + x: 1959, + y: 'Alaska', + value: 816.5178571, + }, + { + x: 1959, + y: 'Ala.', + value: 108.2084894, + }, + { + x: 1959, + y: 'Ark.', + value: 46.46924829, + }, + { + x: 1959, + y: 'Ariz.', + value: 719.0325139, + }, + { + x: 1959, + y: 'Calif.', + value: 251.8329346, + }, + { + x: 1959, + y: 'Colo.', + value: 411.5204678, + }, + { + x: 1959, + y: 'Conn.', + value: 516.4486722, + }, + { + x: 1959, + y: 'D.C.', + value: 52.16819974, + }, + { + x: 1959, + y: 'Del.', + value: 139.6825397, + }, + { + x: 1959, + y: 'Fla.', + value: 74.70881864, + }, + { + x: 1959, + y: 'Ga.', + value: 11.50465357, + }, + { + x: 1959, + y: 'Hawaii', + value: 592.6045016, + }, + { + x: 1959, + y: 'Iowa', + value: 420.2271894, + }, + { + x: 1959, + y: 'Idaho', + value: 247.1841705, + }, + { + x: 1959, + y: 'Ill.', + value: 96.24474264, + }, + { + x: 1959, + y: 'Ind.', + value: 99.6097984, + }, + { + x: 1959, + y: 'Kan.', + value: null, + }, + { + x: 1959, + y: 'Ky.', + value: 221.6405468, + }, + { + x: 1959, + y: 'La.', + value: 2.119700748, + }, + { + x: 1959, + y: 'Mass.', + value: 123.2167286, + }, + { + x: 1959, + y: 'Md.', + value: 76.09262883, + }, + { + x: 1959, + y: 'Maine', + value: 270.4284222, + }, + { + x: 1959, + y: 'Mich.', + value: 147.6631904, + }, + { + x: 1959, + y: 'Minn.', + value: 80.03565062, + }, + { + x: 1959, + y: 'Mo.', + value: 84.66416158, + }, + { + x: 1959, + y: 'Miss.', + value: 66.46398503, + }, + { + x: 1959, + y: 'Mont.', + value: 625.5605381, + }, + { + x: 1959, + y: 'N.C.', + value: 73.12696276, + }, + { + x: 1959, + y: 'N.D.', + value: 899.5145631, + }, + { + x: 1959, + y: 'Neb.', + value: 29.34860415, + }, + { + x: 1959, + y: 'N.H.', + value: 76.51006711, + }, + { + x: 1959, + y: 'N.J.', + value: 502.1945137, + }, + { + x: 1959, + y: 'N.M', + value: 484.0043526, + }, + { + x: 1959, + y: 'Nev.', + value: 220.0716846, + }, + { + x: 1959, + y: 'N.Y.', + value: 140.1977824, + }, + { + x: 1959, + y: 'Ohio', + value: 124.3821735, + }, + { + x: 1959, + y: 'Okla.', + value: 29.18304937, + }, + { + x: 1959, + y: 'Ore.', + value: 447.5945017, + }, + { + x: 1959, + y: 'Pa.', + value: 247.534271, + }, + { + x: 1959, + y: 'R.I.', + value: 35.93932322, + }, + { + x: 1959, + y: 'S.C.', + value: 82.879046, + }, + { + x: 1959, + y: 'S.D.', + value: 129.0854573, + }, + { + x: 1959, + y: 'Tenn.', + value: 275.9795571, + }, + { + x: 1959, + y: 'Texas', + value: 360.6273259, + }, + { + x: 1959, + y: 'Utah', + value: 670.9195402, + }, + { + x: 1959, + y: 'Va.', + value: 349.3039737, + }, + { + x: 1959, + y: 'Vt.', + value: 525.5813953, + }, + { + x: 1959, + y: 'Wash.', + value: 512.4778447, + }, + { + x: 1959, + y: 'Wis.', + value: 384.7854022, + }, + { + x: 1959, + y: 'W.Va.', + value: 406.361186, + }, + { + x: 1959, + y: 'Wyo.', + value: 281.25, + }, + { + x: 1960, + y: 'Alaska', + value: 635.8078603, + }, + { + x: 1960, + y: 'Ala.', + value: 63.37813073, + }, + { + x: 1960, + y: 'Ark.', + value: 89.2118502, + }, + { + x: 1960, + y: 'Ariz.', + value: 325.8894777, + }, + { + x: 1960, + y: 'Calif.', + value: 140.0252048, + }, + { + x: 1960, + y: 'Colo.', + value: 384.7371396, + }, + { + x: 1960, + y: 'Conn.', + value: 434.6305031, + }, + { + x: 1960, + y: 'D.C.', + value: 158.1699346, + }, + { + x: 1960, + y: 'Del.', + value: 212.9175947, + }, + { + x: 1960, + y: 'Fla.', + value: 74.40047962, + }, + { + x: 1960, + y: 'Ga.', + value: 5.485338726, + }, + { + x: 1960, + y: 'Hawaii', + value: 828.9719626, + }, + { + x: 1960, + y: 'Iowa', + value: 64.00580552, + }, + { + x: 1960, + y: 'Idaho', + value: 421.9076006, + }, + { + x: 1960, + y: 'Ill.', + value: 224.6281975, + }, + { + x: 1960, + y: 'Ind.', + value: 223.0851519, + }, + { + x: 1960, + y: 'Kan.', + value: null, + }, + { + x: 1960, + y: 'Ky.', + value: 352.9759947, + }, + { + x: 1960, + y: 'La.', + value: 7.484662577, + }, + { + x: 1960, + y: 'Mass.', + value: 420.6007752, + }, + { + x: 1960, + y: 'Md.', + value: 104.4330228, + }, + { + x: 1960, + y: 'Maine', + value: 413.025641, + }, + { + x: 1960, + y: 'Mich.', + value: 451.6083738, + }, + { + x: 1960, + y: 'Minn.', + value: 126.2773723, + }, + { + x: 1960, + y: 'Mo.', + value: 17.36014794, + }, + { + x: 1960, + y: 'Miss.', + value: 76.30614115, + }, + { + x: 1960, + y: 'Mont.', + value: 313.9911635, + }, + { + x: 1960, + y: 'N.C.', + value: 27.0938115, + }, + { + x: 1960, + y: 'N.D.', + value: 390.5362776, + }, + { + x: 1960, + y: 'Neb.', + value: 14.82004234, + }, + { + x: 1960, + y: 'N.H.', + value: 186.3711002, + }, + { + x: 1960, + y: 'N.J.', + value: 175.2744552, + }, + { + x: 1960, + y: 'N.M', + value: 6.813417191, + }, + { + x: 1960, + y: 'Nev.', + value: 262.8865979, + }, + { + x: 1960, + y: 'N.Y.', + value: 277.2597696, + }, + { + x: 1960, + y: 'Ohio', + value: 191.1341689, + }, + { + x: 1960, + y: 'Okla.', + value: 51.71232877, + }, + { + x: 1960, + y: 'Ore.', + value: 624.9435666, + }, + { + x: 1960, + y: 'Pa.', + value: 59.73166211, + }, + { + x: 1960, + y: 'R.I.', + value: 227.8362573, + }, + { + x: 1960, + y: 'S.C.', + value: 53.67892977, + }, + { + x: 1960, + y: 'S.D.', + value: 17.56954612, + }, + { + x: 1960, + y: 'Tenn.', + value: 535.8881119, + }, + { + x: 1960, + y: 'Texas', + value: 516.1886949, + }, + { + x: 1960, + y: 'Utah', + value: 551.7777778, + }, + { + x: 1960, + y: 'Va.', + value: 185.549423, + }, + { + x: 1960, + y: 'Vt.', + value: 893.3161954, + }, + { + x: 1960, + y: 'Wash.', + value: 456.1471103, + }, + { + x: 1960, + y: 'Wis.', + value: 1090.131247, + }, + { + x: 1960, + y: 'W.Va.', + value: 190.3939557, + }, + { + x: 1960, + y: 'Wyo.', + value: 209.6676737, + }, + { + x: 1961, + y: 'Alaska', + value: 421.0084034, + }, + { + x: 1961, + y: 'Ala.', + value: 78.04583836, + }, + { + x: 1961, + y: 'Ark.', + value: 93.24473976, + }, + { + x: 1961, + y: 'Ariz.', + value: 559.2039801, + }, + { + x: 1961, + y: 'Calif.', + value: 223.3921319, + }, + { + x: 1961, + y: 'Colo.', + value: 210.3579176, + }, + { + x: 1961, + y: 'Conn.', + value: 261.7169374, + }, + { + x: 1961, + y: 'D.C.', + value: 47.0437018, + }, + { + x: 1961, + y: 'Del.', + value: 368.329718, + }, + { + x: 1961, + y: 'Fla.', + value: 127.6940683, + }, + { + x: 1961, + y: 'Ga.', + value: 10.2864259, + }, + { + x: 1961, + y: 'Hawaii', + value: 29.59028832, + }, + { + x: 1961, + y: 'Iowa', + value: 192.5253991, + }, + { + x: 1961, + y: 'Idaho', + value: 281.7251462, + }, + { + x: 1961, + y: 'Ill.', + value: 159.0128332, + }, + { + x: 1961, + y: 'Ind.', + value: 124.6934461, + }, + { + x: 1961, + y: 'Kan.', + value: null, + }, + { + x: 1961, + y: 'Ky.', + value: 368.6640472, + }, + { + x: 1961, + y: 'La.', + value: 1.247337998, + }, + { + x: 1961, + y: 'Mass.', + value: 416.4590918, + }, + { + x: 1961, + y: 'Md.', + value: 130.2581864, + }, + { + x: 1961, + y: 'Maine', + value: 279.0954774, + }, + { + x: 1961, + y: 'Mich.', + value: 349.4235398, + }, + { + x: 1961, + y: 'Minn.', + value: 20.57636888, + }, + { + x: 1961, + y: 'Mo.', + value: 102.1154288, + }, + { + x: 1961, + y: 'Miss.', + value: 68.90299184, + }, + { + x: 1961, + y: 'Mont.', + value: 326.1494253, + }, + { + x: 1961, + y: 'N.C.', + value: 110.7012653, + }, + { + x: 1961, + y: 'N.D.', + value: 439.0015601, + }, + { + x: 1961, + y: 'Neb.', + value: 44.19087137, + }, + { + x: 1961, + y: 'N.H.', + value: 234.6278317, + }, + { + x: 1961, + y: 'N.J.', + value: 293.5514765, + }, + { + x: 1961, + y: 'N.M', + value: 2.07253886, + }, + { + x: 1961, + y: 'Nev.', + value: 197.7777778, + }, + { + x: 1961, + y: 'N.Y.', + value: 207.2973448, + }, + { + x: 1961, + y: 'Ohio', + value: 208.7375685, + }, + { + x: 1961, + y: 'Okla.', + value: 25.12605042, + }, + { + x: 1961, + y: 'Ore.', + value: 322.0481253, + }, + { + x: 1961, + y: 'Pa.', + value: 226.1060393, + }, + { + x: 1961, + y: 'R.I.', + value: 766.0839161, + }, + { + x: 1961, + y: 'S.C.', + value: 136.6542134, + }, + { + x: 1961, + y: 'S.D.', + value: 21.78932179, + }, + { + x: 1961, + y: 'Tenn.', + value: 403.0922142, + }, + { + x: 1961, + y: 'Texas', + value: 164.0631365, + }, + { + x: 1961, + y: 'Utah', + value: 179.5940171, + }, + { + x: 1961, + y: 'Va.', + value: 285.9340659, + }, + { + x: 1961, + y: 'Vt.', + value: 295.8974359, + }, + { + x: 1961, + y: 'Wash.', + value: 301.3532269, + }, + { + x: 1961, + y: 'Wis.', + value: 932.9259167, + }, + { + x: 1961, + y: 'W.Va.', + value: 428.9934354, + }, + { + x: 1961, + y: 'Wyo.', + value: 143.620178, + }, + { + x: 1962, + y: 'Alaska', + value: 571.5447154, + }, + { + x: 1962, + y: 'Ala.', + value: 71.591935, + }, + { + x: 1962, + y: 'Ark.', + value: 77.60388559, + }, + { + x: 1962, + y: 'Ariz.', + value: 431.6791298, + }, + { + x: 1962, + y: 'Calif.', + value: 164.8313027, + }, + { + x: 1962, + y: 'Colo.', + value: 473.9863086, + }, + { + x: 1962, + y: 'Conn.', + value: 672.0816018, + }, + { + x: 1962, + y: 'D.C.', + value: 89.21319797, + }, + { + x: 1962, + y: 'Del.', + value: 129.424307, + }, + { + x: 1962, + y: 'Fla.', + value: 76.10846464, + }, + { + x: 1962, + y: 'Ga.', + value: 10.23005384, + }, + { + x: 1962, + y: 'Hawaii', + value: 387.2807018, + }, + { + x: 1962, + y: 'Iowa', + value: 393.6363636, + }, + { + x: 1962, + y: 'Idaho', + value: 234.1040462, + }, + { + x: 1962, + y: 'Ill.', + value: 163.3754864, + }, + { + x: 1962, + y: 'Ind.', + value: 161.7609797, + }, + { + x: 1962, + y: 'Kan.', + value: null, + }, + { + x: 1962, + y: 'Ky.', + value: 202.3059435, + }, + { + x: 1962, + y: 'La.', + value: 6.87593423, + }, + { + x: 1962, + y: 'Mass.', + value: 511.3053392, + }, + { + x: 1962, + y: 'Md.', + value: 96.65951578, + }, + { + x: 1962, + y: 'Maine', + value: 718.0080483, + }, + { + x: 1962, + y: 'Mich.', + value: 318.9587798, + }, + { + x: 1962, + y: 'Minn.', + value: 47.45231995, + }, + { + x: 1962, + y: 'Mo.', + value: 31.71907276, + }, + { + x: 1962, + y: 'Miss.', + value: 119.037004, + }, + { + x: 1962, + y: 'Mont.', + value: 1181.375358, + }, + { + x: 1962, + y: 'N.C.', + value: 19.26917357, + }, + { + x: 1962, + y: 'N.D.', + value: 583.2025118, + }, + { + x: 1962, + y: 'Neb.', + value: 8.128415301, + }, + { + x: 1962, + y: 'N.H.', + value: 163.6075949, + }, + { + x: 1962, + y: 'N.J.', + value: 510.1631117, + }, + { + x: 1962, + y: 'N.M', + value: null, + }, + { + x: 1962, + y: 'Nev.', + value: 191.4772727, + }, + { + x: 1962, + y: 'N.Y.', + value: 272.9553205, + }, + { + x: 1962, + y: 'Ohio', + value: 118.4711451, + }, + { + x: 1962, + y: 'Okla.', + value: 86.48537289, + }, + { + x: 1962, + y: 'Ore.', + value: 766.1716172, + }, + { + x: 1962, + y: 'Pa.', + value: 83.10876266, + }, + { + x: 1962, + y: 'R.I.', + value: 378.989667, + }, + { + x: 1962, + y: 'S.C.', + value: 38.38217086, + }, + { + x: 1962, + y: 'S.D.', + value: 64.25531915, + }, + { + x: 1962, + y: 'Tenn.', + value: 666.3218078, + }, + { + x: 1962, + y: 'Texas', + value: 665.6222023, + }, + { + x: 1962, + y: 'Utah', + value: 430.5845511, + }, + { + x: 1962, + y: 'Va.', + value: 231.1004785, + }, + { + x: 1962, + y: 'Vt.', + value: 518.3206107, + }, + { + x: 1962, + y: 'Wash.', + value: 704.0788579, + }, + { + x: 1962, + y: 'Wis.', + value: 365.349469, + }, + { + x: 1962, + y: 'W.Va.', + value: 551.1332228, + }, + { + x: 1962, + y: 'Wyo.', + value: 142.9429429, + }, + { + x: 1963, + y: 'Alaska', + value: 722.265625, + }, + { + x: 1963, + y: 'Ala.', + value: 34.6932698, + }, + { + x: 1963, + y: 'Ark.', + value: 77.49333333, + }, + { + x: 1963, + y: 'Ariz.', + value: 583.6949375, + }, + { + x: 1963, + y: 'Calif.', + value: 113.3574825, + }, + { + x: 1963, + y: 'Colo.', + value: 325.3099174, + }, + { + x: 1963, + y: 'Conn.', + value: 214.8514851, + }, + { + x: 1963, + y: 'D.C.', + value: 27.69423559, + }, + { + x: 1963, + y: 'Del.', + value: 248.6542443, + }, + { + x: 1963, + y: 'Fla.', + value: 66.70220327, + }, + { + x: 1963, + y: 'Ga.', + value: 4.793863854, + }, + { + x: 1963, + y: 'Hawaii', + value: 521.8475073, + }, + { + x: 1963, + y: 'Iowa', + value: 280.0509647, + }, + { + x: 1963, + y: 'Idaho', + value: 572.4743777, + }, + { + x: 1963, + y: 'Ill.', + value: 98.50990194, + }, + { + x: 1963, + y: 'Ind.', + value: 122.3379871, + }, + { + x: 1963, + y: 'Kan.', + value: null, + }, + { + x: 1963, + y: 'Ky.', + value: 284.8514212, + }, + { + x: 1963, + y: 'La.', + value: 4.234527687, + }, + { + x: 1963, + y: 'Mass.', + value: 84.11302395, + }, + { + x: 1963, + y: 'Md.', + value: 60.07088009, + }, + { + x: 1963, + y: 'Maine', + value: 48.53977845, + }, + { + x: 1963, + y: 'Mich.', + value: 516.6542566, + }, + { + x: 1963, + y: 'Minn.', + value: 76.74879637, + }, + { + x: 1963, + y: 'Mo.', + value: 64.02550091, + }, + { + x: 1963, + y: 'Miss.', + value: 29.90196078, + }, + { + x: 1963, + y: 'Mont.', + value: 482.3613087, + }, + { + x: 1963, + y: 'N.C.', + value: 30.55672712, + }, + { + x: 1963, + y: 'N.D.', + value: 677.9503106, + }, + { + x: 1963, + y: 'Neb.', + value: 15.85365854, + }, + { + x: 1963, + y: 'N.H.', + value: 6.471494607, + }, + { + x: 1963, + y: 'N.J.', + value: 160.6185883, + }, + { + x: 1963, + y: 'N.M', + value: null, + }, + { + x: 1963, + y: 'Nev.', + value: 67.7581864, + }, + { + x: 1963, + y: 'N.Y.', + value: 107.6627914, + }, + { + x: 1963, + y: 'Ohio', + value: 146.6653315, + }, + { + x: 1963, + y: 'Okla.', + value: 14.18614186, + }, + { + x: 1963, + y: 'Ore.', + value: 258.3378305, + }, + { + x: 1963, + y: 'Pa.', + value: 106.109944, + }, + { + x: 1963, + y: 'R.I.', + value: 139.6118721, + }, + { + x: 1963, + y: 'S.C.', + value: 95.77235772, + }, + { + x: 1963, + y: 'S.D.', + value: 12.57062147, + }, + { + x: 1963, + y: 'Tenn.', + value: 183.5664336, + }, + { + x: 1963, + y: 'Texas', + value: 164.356728, + }, + { + x: 1963, + y: 'Utah', + value: 316.2217659, + }, + { + x: 1963, + y: 'Va.', + value: 172.5210477, + }, + { + x: 1963, + y: 'Vt.', + value: 405.7934509, + }, + { + x: 1963, + y: 'Wash.', + value: 166.9373942, + }, + { + x: 1963, + y: 'Wis.', + value: 1413.107977, + }, + { + x: 1963, + y: 'W.Va.', + value: 696.2694878, + }, + { + x: 1963, + y: 'Wyo.', + value: 97.91666667, + }, + { + x: 1964, + y: 'Alaska', + value: 439.9239544, + }, + { + x: 1964, + y: 'Ala.', + value: 533.6671576, + }, + { + x: 1964, + y: 'Ark.', + value: 58.30258303, + }, + { + x: 1964, + y: 'Ariz.', + value: 405.5269923, + }, + { + x: 1964, + y: 'Calif.', + value: 179.8798964, + }, + { + x: 1964, + y: 'Colo.', + value: 164.4670051, + }, + { + x: 1964, + y: 'Conn.', + value: 189.0278771, + }, + { + x: 1964, + y: 'D.C.', + value: 43.10776942, + }, + { + x: 1964, + y: 'Del.', + value: 79.27565392, + }, + { + x: 1964, + y: 'Fla.', + value: 121.5706625, + }, + { + x: 1964, + y: 'Ga.', + value: 4.955378112, + }, + { + x: 1964, + y: 'Hawaii', + value: 123.1428571, + }, + { + x: 1964, + y: 'Iowa', + value: 819.8106336, + }, + { + x: 1964, + y: 'Idaho', + value: 336.1764706, + }, + { + x: 1964, + y: 'Ill.', + value: 149.3478261, + }, + { + x: 1964, + y: 'Ind.', + value: 458.8344316, + }, + { + x: 1964, + y: 'Kan.', + value: null, + }, + { + x: 1964, + y: 'Ky.', + value: 481.8152764, + }, + { + x: 1964, + y: 'La.', + value: 3.395240859, + }, + { + x: 1964, + y: 'Mass.', + value: 135.9581498, + }, + { + x: 1964, + y: 'Md.', + value: 89.49026346, + }, + { + x: 1964, + y: 'Maine', + value: 373.917422, + }, + { + x: 1964, + y: 'Mich.', + value: 354.5010382, + }, + { + x: 1964, + y: 'Minn.', + value: 9.696458685, + }, + { + x: 1964, + y: 'Mo.', + value: 24.17829806, + }, + { + x: 1964, + y: 'Miss.', + value: 261.4457831, + }, + { + x: 1964, + y: 'Mont.', + value: 579.6033994, + }, + { + x: 1964, + y: 'N.C.', + value: 26.34319034, + }, + { + x: 1964, + y: 'N.D.', + value: 813.2511556, + }, + { + x: 1964, + y: 'Neb.', + value: 54.65587045, + }, + { + x: 1964, + y: 'N.H.', + value: 134.6907994, + }, + { + x: 1964, + y: 'N.J.', + value: 176.3363363, + }, + { + x: 1964, + y: 'N.M', + value: 111.1332008, + }, + { + x: 1964, + y: 'Nev.', + value: 233.8028169, + }, + { + x: 1964, + y: 'N.Y.', + value: 156.9105691, + }, + { + x: 1964, + y: 'Ohio', + value: 191.1309524, + }, + { + x: 1964, + y: 'Okla.', + value: 42.43663123, + }, + { + x: 1964, + y: 'Ore.', + value: 453.0190678, + }, + { + x: 1964, + y: 'Pa.', + value: 101.8838441, + }, + { + x: 1964, + y: 'R.I.', + value: 279.3220339, + }, + { + x: 1964, + y: 'S.C.', + value: 161.6565657, + }, + { + x: 1964, + y: 'S.D.', + value: 9.843081312, + }, + { + x: 1964, + y: 'Tenn.', + value: 629.3821268, + }, + { + x: 1964, + y: 'Texas', + value: 383.1840312, + }, + { + x: 1964, + y: 'Utah', + value: 260.7361963, + }, + { + x: 1964, + y: 'Va.', + value: 274.7991737, + }, + { + x: 1964, + y: 'Vt.', + value: 596.7418546, + }, + { + x: 1964, + y: 'Wash.', + value: 674.7044917, + }, + { + x: 1964, + y: 'Wis.', + value: 370.3481393, + }, + { + x: 1964, + y: 'W.Va.', + value: 518.6978297, + }, + { + x: 1964, + y: 'Wyo.', + value: 84.36578171, + }, + { + x: 1965, + y: 'Alaska', + value: 79.33579336, + }, + { + x: 1965, + y: 'Ala.', + value: 68.13825152, + }, + { + x: 1965, + y: 'Ark.', + value: 63.09398099, + }, + { + x: 1965, + y: 'Ariz.', + value: 100.5681818, + }, + { + x: 1965, + y: 'Calif.', + value: 74.59779392, + }, + { + x: 1965, + y: 'Colo.', + value: 302.720403, + }, + { + x: 1965, + y: 'Conn.', + value: 322.7861393, + }, + { + x: 1965, + y: 'D.C.', + value: 19.69887077, + }, + { + x: 1965, + y: 'Del.', + value: 102.3668639, + }, + { + x: 1965, + y: 'Fla.', + value: 62.27746053, + }, + { + x: 1965, + y: 'Ga.', + value: 15.12003693, + }, + { + x: 1965, + y: 'Hawaii', + value: 575.8522727, + }, + { + x: 1965, + y: 'Iowa', + value: 339.4967177, + }, + { + x: 1965, + y: 'Idaho', + value: 454.664723, + }, + { + x: 1965, + y: 'Ill.', + value: 42.69148041, + }, + { + x: 1965, + y: 'Ind.', + value: 48.06989029, + }, + { + x: 1965, + y: 'Kan.', + value: null, + }, + { + x: 1965, + y: 'Ky.', + value: 121.0828025, + }, + { + x: 1965, + y: 'La.', + value: 3.832951945, + }, + { + x: 1965, + y: 'Mass.', + value: 354.5074518, + }, + { + x: 1965, + y: 'Md.', + value: 35.52777778, + }, + { + x: 1965, + y: 'Maine', + value: 295.7873621, + }, + { + x: 1965, + y: 'Mich.', + value: 336.974991, + }, + { + x: 1965, + y: 'Minn.', + value: 26.44766147, + }, + { + x: 1965, + y: 'Mo.', + value: 60.17461383, + }, + { + x: 1965, + y: 'Miss.', + value: 51.20213713, + }, + { + x: 1965, + y: 'Mont.', + value: 556.3739377, + }, + { + x: 1965, + y: 'N.C.', + value: 8.616080609, + }, + { + x: 1965, + y: 'N.D.', + value: 623.2665639, + }, + { + x: 1965, + y: 'Neb.', + value: 31.9510537, + }, + { + x: 1965, + y: 'N.H.', + value: 55.0295858, + }, + { + x: 1965, + y: 'N.J.', + value: 61.17925225, + }, + { + x: 1965, + y: 'N.M', + value: 68.5770751, + }, + { + x: 1965, + y: 'Nev.', + value: 50.67567568, + }, + { + x: 1965, + y: 'N.Y.', + value: 52.41908199, + }, + { + x: 1965, + y: 'Ohio', + value: 90.9420645, + }, + { + x: 1965, + y: 'Okla.', + value: 10, + }, + { + x: 1965, + y: 'Ore.', + value: 181.724316, + }, + { + x: 1965, + y: 'Pa.', + value: 57.17728055, + }, + { + x: 1965, + y: 'R.I.', + value: 444.7928331, + }, + { + x: 1965, + y: 'S.C.', + value: 50.60144346, + }, + { + x: 1965, + y: 'S.D.', + value: 16.76300578, + }, + { + x: 1965, + y: 'Tenn.', + value: 238.0989995, + }, + { + x: 1965, + y: 'Texas', + value: 284.341877, + }, + { + x: 1965, + y: 'Utah', + value: 444.8692153, + }, + { + x: 1965, + y: 'Va.', + value: 93.33484471, + }, + { + x: 1965, + y: 'Vt.', + value: 360.6435644, + }, + { + x: 1965, + y: 'Wash.', + value: 255.7128413, + }, + { + x: 1965, + y: 'Wis.', + value: 482.2069943, + }, + { + x: 1965, + y: 'W.Va.', + value: 832.6987682, + }, + { + x: 1965, + y: 'Wyo.', + value: 226.2048193, + }, + { + x: 1966, + y: 'Alaska', + value: 236.5313653, + }, + { + x: 1966, + y: 'Ala.', + value: 52.33833718, + }, + { + x: 1966, + y: 'Ark.', + value: 72.51184834, + }, + { + x: 1966, + y: 'Ariz.', + value: 336.9268897, + }, + { + x: 1966, + y: 'Calif.', + value: 80.58648849, + }, + { + x: 1966, + y: 'Colo.', + value: 71.99800698, + }, + { + x: 1966, + y: 'Conn.', + value: 32.51808474, + }, + { + x: 1966, + y: 'D.C.', + value: 49.30467762, + }, + { + x: 1966, + y: 'Del.', + value: 51.1627907, + }, + { + x: 1966, + y: 'Fla.', + value: 64.40039318, + }, + { + x: 1966, + y: 'Ga.', + value: 5.572048413, + }, + { + x: 1966, + y: 'Hawaii', + value: 20.42253521, + }, + { + x: 1966, + y: 'Iowa', + value: 197.429399, + }, + { + x: 1966, + y: 'Idaho', + value: 246.8795356, + }, + { + x: 1966, + y: 'Ill.', + value: 106.3215209, + }, + { + x: 1966, + y: 'Ind.', + value: 116.3632727, + }, + { + x: 1966, + y: 'Kan.', + value: null, + }, + { + x: 1966, + y: 'Ky.', + value: 154.1785828, + }, + { + x: 1966, + y: 'La.', + value: 3.014084507, + }, + { + x: 1966, + y: 'Mass.', + value: 15.01355014, + }, + { + x: 1966, + y: 'Md.', + value: 57.72665765, + }, + { + x: 1966, + y: 'Maine', + value: 29.72972973, + }, + { + x: 1966, + y: 'Mich.', + value: 176.0338346, + }, + { + x: 1966, + y: 'Minn.', + value: 46.53027371, + }, + { + x: 1966, + y: 'Mo.', + value: 12.5580367, + }, + { + x: 1966, + y: 'Miss.', + value: 57.0155902, + }, + { + x: 1966, + y: 'Mont.', + value: 272.7015559, + }, + { + x: 1966, + y: 'N.C.', + value: 15.89052288, + }, + { + x: 1966, + y: 'N.D.', + value: 212.6738794, + }, + { + x: 1966, + y: 'Neb.', + value: 11.60714286, + }, + { + x: 1966, + y: 'N.H.', + value: 11.60058737, + }, + { + x: 1966, + y: 'N.J.', + value: 29.41176471, + }, + { + x: 1966, + y: 'N.M', + value: 126.3157895, + }, + { + x: 1966, + y: 'Nev.', + value: 14.34977578, + }, + { + x: 1966, + y: 'N.Y.', + value: 61.05475537, + }, + { + x: 1966, + y: 'Ohio', + value: 62.95256534, + }, + { + x: 1966, + y: 'Okla.', + value: 25.26487368, + }, + { + x: 1966, + y: 'Ore.', + value: 126.9172169, + }, + { + x: 1966, + y: 'Pa.', + value: 47.14506173, + }, + { + x: 1966, + y: 'R.I.', + value: 9.78865406, + }, + { + x: 1966, + y: 'S.C.', + value: 26.30952381, + }, + { + x: 1966, + y: 'S.D.', + value: 5.856515373, + }, + { + x: 1966, + y: 'Tenn.', + value: 332.7577185, + }, + { + x: 1966, + y: 'Texas', + value: 239.973313, + }, + { + x: 1966, + y: 'Utah', + value: 68.18632309, + }, + { + x: 1966, + y: 'Va.', + value: 50.62836625, + }, + { + x: 1966, + y: 'Vt.', + value: 79.17675545, + }, + { + x: 1966, + y: 'Wash.', + value: 166.6993785, + }, + { + x: 1966, + y: 'Wis.', + value: 736.0552176, + }, + { + x: 1966, + y: 'W.Va.', + value: 313.4647887, + }, + { + x: 1966, + y: 'Wyo.', + value: 72.75541796, + }, + { + x: 1967, + y: 'Alaska', + value: 53.23741007, + }, + { + x: 1967, + y: 'Ala.', + value: 38.92423366, + }, + { + x: 1967, + y: 'Ark.', + value: 66.75433982, + }, + { + x: 1967, + y: 'Ariz.', + value: 62.08991495, + }, + { + x: 1967, + y: 'Calif.', + value: 27.43012098, + }, + { + x: 1967, + y: 'Colo.', + value: 79.63955188, + }, + { + x: 1967, + y: 'Conn.', + value: 3.611584327, + }, + { + x: 1967, + y: 'D.C.', + value: 3.413400759, + }, + { + x: 1967, + y: 'Del.', + value: 10.66666667, + }, + { + x: 1967, + y: 'Fla.', + value: 28.93303428, + }, + { + x: 1967, + y: 'Ga.', + value: 0.952813067, + }, + { + x: 1967, + y: 'Hawaii', + value: 24.4813278, + }, + { + x: 1967, + y: 'Iowa', + value: 29.57393484, + }, + { + x: 1967, + y: 'Idaho', + value: 60.02906977, + }, + { + x: 1967, + y: 'Ill.', + value: 11.93020919, + }, + { + x: 1967, + y: 'Ind.', + value: 13.41777162, + }, + { + x: 1967, + y: 'Kan.', + value: 4.415111516, + }, + { + x: 1967, + y: 'Ky.', + value: 46.84741488, + }, + { + x: 1967, + y: 'La.', + value: 4.440100531, + }, + { + x: 1967, + y: 'Mass.', + value: 7.436539149, + }, + { + x: 1967, + y: 'Md.', + value: 4.844290657, + }, + { + x: 1967, + y: 'Maine', + value: 24.60159363, + }, + { + x: 1967, + y: 'Mich.', + value: 13.33719583, + }, + { + x: 1967, + y: 'Minn.', + value: 3.744192402, + }, + { + x: 1967, + y: 'Mo.', + value: 7.490636704, + }, + { + x: 1967, + y: 'Miss.', + value: 30.43087971, + }, + { + x: 1967, + y: 'Mont.', + value: 48.93009986, + }, + { + x: 1967, + y: 'N.C.', + value: 19.04281099, + }, + { + x: 1967, + y: 'N.D.', + value: 143.1309904, + }, + { + x: 1967, + y: 'Neb.', + value: 36.51338367, + }, + { + x: 1967, + y: 'N.H.', + value: 3.87374462, + }, + { + x: 1967, + y: 'N.J.', + value: 8.833718245, + }, + { + x: 1967, + y: 'N.M', + value: 61.2, + }, + { + x: 1967, + y: 'Nev.', + value: 59.91091314, + }, + { + x: 1967, + y: 'N.Y.', + value: 6.71870644, + }, + { + x: 1967, + y: 'Ohio', + value: 11.71499904, + }, + { + x: 1967, + y: 'Okla.', + value: 32.38248292, + }, + { + x: 1967, + y: 'Ore.', + value: 86.7609904, + }, + { + x: 1967, + y: 'Pa.', + value: 6.780241418, + }, + { + x: 1967, + y: 'R.I.', + value: 6.820682068, + }, + { + x: 1967, + y: 'S.C.', + value: 20.41058034, + }, + { + x: 1967, + y: 'S.D.', + value: 8.643815201, + }, + { + x: 1967, + y: 'Tenn.', + value: 53.5890127, + }, + { + x: 1967, + y: 'Texas', + value: 125.3231437, + }, + { + x: 1967, + y: 'Utah', + value: 37.78213935, + }, + { + x: 1967, + y: 'Va.', + value: 52.04081633, + }, + { + x: 1967, + y: 'Vt.', + value: 9.929078014, + }, + { + x: 1967, + y: 'Wash.', + value: 178.9224953, + }, + { + x: 1967, + y: 'Wis.', + value: 49.52358819, + }, + { + x: 1967, + y: 'W.Va.', + value: 84.56755229, + }, + { + x: 1967, + y: 'Wyo.', + value: 64.28571429, + }, + { + x: 1968, + y: 'Alaska', + value: 3.859649123, + }, + { + x: 1968, + y: 'Ala.', + value: 4.61404527, + }, + { + x: 1968, + y: 'Ark.', + value: 0.157728707, + }, + { + x: 1968, + y: 'Ariz.', + value: 14.56599287, + }, + { + x: 1968, + y: 'Calif.', + value: 8.497473445, + }, + { + x: 1968, + y: 'Colo.', + value: 23.53773585, + }, + { + x: 1968, + y: 'Conn.', + value: 23.85290148, + }, + { + x: 1968, + y: 'D.C.', + value: 0.771208226, + }, + { + x: 1968, + y: 'Del.', + value: 4.494382022, + }, + { + x: 1968, + y: 'Fla.', + value: 8.907197264, + }, + { + x: 1968, + y: 'Ga.', + value: 0.089245872, + }, + { + x: 1968, + y: 'Hawaii', + value: 5.040871935, + }, + { + x: 1968, + y: 'Iowa', + value: 6.528719229, + }, + { + x: 1968, + y: 'Idaho', + value: 3.021582734, + }, + { + x: 1968, + y: 'Ill.', + value: 13.48794907, + }, + { + x: 1968, + y: 'Ind.', + value: 15.49185156, + }, + { + x: 1968, + y: 'Kan.', + value: 0.94765343, + }, + { + x: 1968, + y: 'Ky.', + value: 4.41314554, + }, + { + x: 1968, + y: 'La.', + value: 0.777130169, + }, + { + x: 1968, + y: 'Mass.', + value: 9.825560698, + }, + { + x: 1968, + y: 'Md.', + value: 2.726081258, + }, + { + x: 1968, + y: 'Maine', + value: 3.521126761, + }, + { + x: 1968, + y: 'Mich.', + value: 4.036338546, + }, + { + x: 1968, + y: 'Minn.', + value: 0.513097489, + }, + { + x: 1968, + y: 'Mo.', + value: 0.700525394, + }, + { + x: 1968, + y: 'Miss.', + value: 10.86074808, + }, + { + x: 1968, + y: 'Mont.', + value: 9.714285714, + }, + { + x: 1968, + y: 'N.C.', + value: 6.474820144, + }, + { + x: 1968, + y: 'N.D.', + value: 22.86634461, + }, + { + x: 1968, + y: 'Neb.', + value: 4.567143831, + }, + { + x: 1968, + y: 'N.H.', + value: 21.01551481, + }, + { + x: 1968, + y: 'N.J.', + value: 9.735902926, + }, + { + x: 1968, + y: 'N.M', + value: 17.70623742, + }, + { + x: 1968, + y: 'Nev.', + value: 1.724137931, + }, + { + x: 1968, + y: 'N.Y.', + value: 21.04592543, + }, + { + x: 1968, + y: 'Ohio', + value: 3.17611259, + }, + { + x: 1968, + y: 'Okla.', + value: 4.954055134, + }, + { + x: 1968, + y: 'Ore.', + value: 30.63872255, + }, + { + x: 1968, + y: 'Pa.', + value: 2.512562814, + }, + { + x: 1968, + y: 'R.I.', + value: 7.26681128, + }, + { + x: 1968, + y: 'S.C.', + value: 1.484955061, + }, + { + x: 1968, + y: 'S.D.', + value: 0.597907324, + }, + { + x: 1968, + y: 'Tenn.', + value: 1.676121712, + }, + { + x: 1968, + y: 'Texas', + value: 47.56446991, + }, + { + x: 1968, + y: 'Utah', + value: 2.040816327, + }, + { + x: 1968, + y: 'Va.', + value: 9.499780606, + }, + { + x: 1968, + y: 'Vt.', + value: 1.860465116, + }, + { + x: 1968, + y: 'Wash.', + value: 18.28746177, + }, + { + x: 1968, + y: 'Wis.', + value: 31.85270426, + }, + { + x: 1968, + y: 'W.Va.', + value: 20.53318208, + }, + { + x: 1968, + y: 'Wyo.', + value: 16.97530864, + }, + { + x: 1969, + y: 'Alaska', + value: 6.756756757, + }, + { + x: 1969, + y: 'Ala.', + value: 0.348837209, + }, + { + x: 1969, + y: 'Ark.', + value: 1.515943544, + }, + { + x: 1969, + y: 'Ariz.', + value: 31.20322395, + }, + { + x: 1969, + y: 'Calif.', + value: 4.555831769, + }, + { + x: 1969, + y: 'Colo.', + value: 6.417359187, + }, + { + x: 1969, + y: 'Conn.', + value: 21.4, + }, + { + x: 1969, + y: 'D.C.', + value: 5.905511811, + }, + { + x: 1969, + y: 'Del.', + value: 93.7037037, + }, + { + x: 1969, + y: 'Fla.', + value: 9.200421623, + }, + { + x: 1969, + y: 'Ga.', + value: 0.043946385, + }, + { + x: 1969, + y: 'Hawaii', + value: 7.066666667, + }, + { + x: 1969, + y: 'Iowa', + value: 9.946524064, + }, + { + x: 1969, + y: 'Idaho', + value: 12.72984441, + }, + { + x: 1969, + y: 'Ill.', + value: 10.14584654, + }, + { + x: 1969, + y: 'Ind.', + value: 10.49970834, + }, + { + x: 1969, + y: 'Kan.', + value: 0.402504472, + }, + { + x: 1969, + y: 'Ky.', + value: 2.220137586, + }, + { + x: 1969, + y: 'La.', + value: 3.426360873, + }, + { + x: 1969, + y: 'Mass.', + value: 6.566371681, + }, + { + x: 1969, + y: 'Md.', + value: 2.559462254, + }, + { + x: 1969, + y: 'Maine', + value: 0.806451613, + }, + { + x: 1969, + y: 'Mich.', + value: 4.43001936, + }, + { + x: 1969, + y: 'Minn.', + value: 0.71846727, + }, + { + x: 1969, + y: 'Mo.', + value: 1.594827586, + }, + { + x: 1969, + y: 'Miss.', + value: 1.036036036, + }, + { + x: 1969, + y: 'Mont.', + value: 17.14697406, + }, + { + x: 1969, + y: 'N.C.', + value: 7.414032995, + }, + { + x: 1969, + y: 'N.D.', + value: 13.04347826, + }, + { + x: 1969, + y: 'Neb.', + value: 44.84396201, + }, + { + x: 1969, + y: 'N.H.', + value: 27.0718232, + }, + { + x: 1969, + y: 'N.J.', + value: 13.46018323, + }, + { + x: 1969, + y: 'N.M', + value: 28.28882295, + }, + { + x: 1969, + y: 'Nev.', + value: 0.208333333, + }, + { + x: 1969, + y: 'N.Y.', + value: 30.48881524, + }, + { + x: 1969, + y: 'Ohio', + value: 5.348859226, + }, + { + x: 1969, + y: 'Okla.', + value: 5.601577909, + }, + { + x: 1969, + y: 'Ore.', + value: 9.796314258, + }, + { + x: 1969, + y: 'Pa.', + value: 10.65496976, + }, + { + x: 1969, + y: 'R.I.', + value: 2.896995708, + }, + { + x: 1969, + y: 'S.C.', + value: 5.291828794, + }, + { + x: 1969, + y: 'S.D.', + value: 7.634730539, + }, + { + x: 1969, + y: 'Tenn.', + value: 0.487554529, + }, + { + x: 1969, + y: 'Texas', + value: 44.88003622, + }, + { + x: 1969, + y: 'Utah', + value: 1.050620821, + }, + { + x: 1969, + y: 'Va.', + value: 20.24273949, + }, + { + x: 1969, + y: 'Vt.', + value: 0.686498856, + }, + { + x: 1969, + y: 'Wash.', + value: 1.675142088, + }, + { + x: 1969, + y: 'Wis.', + value: 15.32663317, + }, + { + x: 1969, + y: 'W.Va.', + value: 13.860252, + }, + { + x: 1969, + y: 'Wyo.', + value: 2.431610942, + }, + { + x: 1970, + y: 'Alaska', + value: 33.59639948, + }, + { + x: 1970, + y: 'Ala.', + value: 13.92591983, + }, + { + x: 1970, + y: 'Ark.', + value: 1.673163272, + }, + { + x: 1970, + y: 'Ariz.', + value: 53.0642774, + }, + { + x: 1970, + y: 'Calif.', + value: 9.579307202, + }, + { + x: 1970, + y: 'Colo.', + value: 10.41881917, + }, + { + x: 1970, + y: 'Conn.', + value: 3.789687998, + }, + { + x: 1970, + y: 'D.C.', + value: 46.01343592, + }, + { + x: 1970, + y: 'Del.', + value: 47.45815537, + }, + { + x: 1970, + y: 'Fla.', + value: 20.18634582, + }, + { + x: 1970, + y: 'Ga.', + value: 0.382039881, + }, + { + x: 1970, + y: 'Hawaii', + value: 23.95078114, + }, + { + x: 1970, + y: 'Iowa', + value: 31.34966625, + }, + { + x: 1970, + y: 'Idaho', + value: 13.26559757, + }, + { + x: 1970, + y: 'Ill.', + value: 29.39549455, + }, + { + x: 1970, + y: 'Ind.', + value: 5.4631328, + }, + { + x: 1970, + y: 'Kan.', + value: 3.3828897, + }, + { + x: 1970, + y: 'Ky.', + value: 32.44338402, + }, + { + x: 1970, + y: 'La.', + value: 8.327747813, + }, + { + x: 1970, + y: 'Mass.', + value: 15.77320055, + }, + { + x: 1970, + y: 'Md.', + value: 34.64130817, + }, + { + x: 1970, + y: 'Maine', + value: 41.46190134, + }, + { + x: 1970, + y: 'Mich.', + value: 20.26924782, + }, + { + x: 1970, + y: 'Minn.', + value: 1.271575919, + }, + { + x: 1970, + y: 'Mo.', + value: 16.48410712, + }, + { + x: 1970, + y: 'Miss.', + value: 6.091553399, + }, + { + x: 1970, + y: 'Mont.', + value: 16.03795086, + }, + { + x: 1970, + y: 'N.C.', + value: 19.46755002, + }, + { + x: 1970, + y: 'N.D.', + value: 51.21577637, + }, + { + x: 1970, + y: 'Neb.', + value: 52.30612174, + }, + { + x: 1970, + y: 'N.H.', + value: 8.400592767, + }, + { + x: 1970, + y: 'N.J.', + value: 23.48543978, + }, + { + x: 1970, + y: 'N.M', + value: 28.6599028, + }, + { + x: 1970, + y: 'Nev.', + value: 4.03832175, + }, + { + x: 1970, + y: 'N.Y.', + value: 8.541243803, + }, + { + x: 1970, + y: 'Ohio', + value: 37.67180776, + }, + { + x: 1970, + y: 'Okla.', + value: 30.62704093, + }, + { + x: 1970, + y: 'Ore.', + value: 21.15273577, + }, + { + x: 1970, + y: 'Pa.', + value: 17.65042401, + }, + { + x: 1970, + y: 'R.I.', + value: 11.42136855, + }, + { + x: 1970, + y: 'S.C.', + value: 23.96452049, + }, + { + x: 1970, + y: 'S.D.', + value: 15.79032827, + }, + { + x: 1970, + y: 'Tenn.', + value: 13.60372014, + }, + { + x: 1970, + y: 'Texas', + value: 72.34674168, + }, + { + x: 1970, + y: 'Utah', + value: 3.541616721, + }, + { + x: 1970, + y: 'Va.', + value: 51.90663205, + }, + { + x: 1970, + y: 'Vt.', + value: 1.980991288, + }, + { + x: 1970, + y: 'Wash.', + value: 19.66612261, + }, + { + x: 1970, + y: 'Wis.', + value: 31.01640351, + }, + { + x: 1970, + y: 'W.Va.', + value: 19.71019797, + }, + { + x: 1970, + y: 'Wyo.', + value: 3.232584451, + }, + { + x: 1971, + y: 'Alaska', + value: 19.4166379, + }, + { + x: 1971, + y: 'Ala.', + value: 55.23535062, + }, + { + x: 1971, + y: 'Ark.', + value: 21.89595163, + }, + { + x: 1971, + y: 'Ariz.', + value: 25.34493258, + }, + { + x: 1971, + y: 'Calif.', + value: 13.9127265, + }, + { + x: 1971, + y: 'Colo.', + value: 37.17844698, + }, + { + x: 1971, + y: 'Conn.', + value: 38.90899694, + }, + { + x: 1971, + y: 'D.C.', + value: 2.155634087, + }, + { + x: 1971, + y: 'Del.', + value: 7.330956009, + }, + { + x: 1971, + y: 'Fla.', + value: 30.83287503, + }, + { + x: 1971, + y: 'Ga.', + value: 23.5991758, + }, + { + x: 1971, + y: 'Hawaii', + value: 59.03437153, + }, + { + x: 1971, + y: 'Iowa', + value: 94.81566011, + }, + { + x: 1971, + y: 'Idaho', + value: 35.89972708, + }, + { + x: 1971, + y: 'Ill.', + value: 29.04385978, + }, + { + x: 1971, + y: 'Ind.', + value: 58.19967619, + }, + { + x: 1971, + y: 'Kan.', + value: 62.44529389, + }, + { + x: 1971, + y: 'Ky.', + value: 111.4299487, + }, + { + x: 1971, + y: 'La.', + value: 42.18897791, + }, + { + x: 1971, + y: 'Mass.', + value: 8.089853622, + }, + { + x: 1971, + y: 'Md.', + value: 13.64919937, + }, + { + x: 1971, + y: 'Maine', + value: 120.2755121, + }, + { + x: 1971, + y: 'Mich.', + value: 28.85165751, + }, + { + x: 1971, + y: 'Minn.', + value: 2.04147713, + }, + { + x: 1971, + y: 'Mo.', + value: 42.82610249, + }, + { + x: 1971, + y: 'Miss.', + value: 66.83666238, + }, + { + x: 1971, + y: 'Mont.', + value: 112.9767424, + }, + { + x: 1971, + y: 'N.C.', + value: 35.84127972, + }, + { + x: 1971, + y: 'N.D.', + value: 36.12630898, + }, + { + x: 1971, + y: 'Neb.', + value: 4.871584377, + }, + { + x: 1971, + y: 'N.H.', + value: 26.62887415, + }, + { + x: 1971, + y: 'N.J.', + value: 17.39594674, + }, + { + x: 1971, + y: 'N.M', + value: 37.26718439, + }, + { + x: 1971, + y: 'Nev.', + value: 1.280201321, + }, + { + x: 1971, + y: 'N.Y.', + value: 23.90481695, + }, + { + x: 1971, + y: 'Ohio', + value: 37.0708346, + }, + { + x: 1971, + y: 'Okla.', + value: 25.05034518, + }, + { + x: 1971, + y: 'Ore.', + value: 15.92866144, + }, + { + x: 1971, + y: 'Pa.', + value: 15.57745805, + }, + { + x: 1971, + y: 'R.I.', + value: 24.72327373, + }, + { + x: 1971, + y: 'S.C.', + value: 32.803802, + }, + { + x: 1971, + y: 'S.D.', + value: 31.30380341, + }, + { + x: 1971, + y: 'Tenn.', + value: 24.73983487, + }, + { + x: 1971, + y: 'Texas', + value: 77.39506298, + }, + { + x: 1971, + y: 'Utah', + value: 30.03217229, + }, + { + x: 1971, + y: 'Va.', + value: 32.39732762, + }, + { + x: 1971, + y: 'Vt.', + value: 26.55767225, + }, + { + x: 1971, + y: 'Wash.', + value: 33.12175435, + }, + { + x: 1971, + y: 'Wis.', + value: 87.55307155, + }, + { + x: 1971, + y: 'W.Va.', + value: 31.9862398, + }, + { + x: 1971, + y: 'Wyo.', + value: 24.47134693, + }, + { + x: 1972, + y: 'Alaska', + value: 3.932922494, + }, + { + x: 1972, + y: 'Ala.', + value: 3.99465889, + }, + { + x: 1972, + y: 'Ark.', + value: 0.631295963, + }, + { + x: 1972, + y: 'Ariz.', + value: 40.85786453, + }, + { + x: 1972, + y: 'Calif.', + value: 15.43936938, + }, + { + x: 1972, + y: 'Colo.', + value: 20.9145676, + }, + { + x: 1972, + y: 'Conn.', + value: 50.06822448, + }, + { + x: 1972, + y: 'D.C.', + value: 0.273415285, + }, + { + x: 1972, + y: 'Del.', + value: 9.692622703, + }, + { + x: 1972, + y: 'Fla.', + value: 17.6403036, + }, + { + x: 1972, + y: 'Ga.', + value: 3.584248369, + }, + { + x: 1972, + y: 'Hawaii', + value: 11.27296426, + }, + { + x: 1972, + y: 'Iowa', + value: 33.34829059, + }, + { + x: 1972, + y: 'Idaho', + value: 14.06516519, + }, + { + x: 1972, + y: 'Ill.', + value: 40.20844756, + }, + { + x: 1972, + y: 'Ind.', + value: 23.80918038, + }, + { + x: 1972, + y: 'Kan.', + value: 1.721396026, + }, + { + x: 1972, + y: 'Ky.', + value: 14.3873197, + }, + { + x: 1972, + y: 'La.', + value: 3.246774673, + }, + { + x: 1972, + y: 'Mass.', + value: 21.96786396, + }, + { + x: 1972, + y: 'Md.', + value: 0.317229929, + }, + { + x: 1972, + y: 'Maine', + value: 20.94381034, + }, + { + x: 1972, + y: 'Mich.', + value: 25.74368063, + }, + { + x: 1972, + y: 'Minn.', + value: 0.668495258, + }, + { + x: 1972, + y: 'Mo.', + value: 3.742698862, + }, + { + x: 1972, + y: 'Miss.', + value: 9.023019766, + }, + { + x: 1972, + y: 'Mont.', + value: 2.3390268, + }, + { + x: 1972, + y: 'N.C.', + value: 0.68647525, + }, + { + x: 1972, + y: 'N.D.', + value: 9.483542103, + }, + { + x: 1972, + y: 'Neb.', + value: 1.569071508, + }, + { + x: 1972, + y: 'N.H.', + value: 99.00730507, + }, + { + x: 1972, + y: 'N.J.', + value: 5.659284096, + }, + { + x: 1972, + y: 'N.M', + value: 12.12089416, + }, + { + x: 1972, + y: 'Nev.', + value: 0.175749704, + }, + { + x: 1972, + y: 'N.Y.', + value: 3.603442426, + }, + { + x: 1972, + y: 'Ohio', + value: 2.767635457, + }, + { + x: 1972, + y: 'Okla.', + value: 0.482208187, + }, + { + x: 1972, + y: 'Ore.', + value: 9.010085944, + }, + { + x: 1972, + y: 'Pa.', + value: 0.563473764, + }, + { + x: 1972, + y: 'R.I.', + value: 52.26812935, + }, + { + x: 1972, + y: 'S.C.', + value: 7.599208386, + }, + { + x: 1972, + y: 'S.D.', + value: 1.768046971, + }, + { + x: 1972, + y: 'Tenn.', + value: 4.701739716, + }, + { + x: 1972, + y: 'Texas', + value: 13.16189809, + }, + { + x: 1972, + y: 'Utah', + value: 13.67474616, + }, + { + x: 1972, + y: 'Va.', + value: 1.571014337, + }, + { + x: 1972, + y: 'Vt.', + value: 17.07832547, + }, + { + x: 1972, + y: 'Wash.', + value: 28.37199917, + }, + { + x: 1972, + y: 'Wis.', + value: 76.36634983, + }, + { + x: 1972, + y: 'W.Va.', + value: 15.44542616, + }, + { + x: 1972, + y: 'Wyo.', + value: 14.40429756, + }, + { + x: 1973, + y: 'Alaska', + value: 1.466004814, + }, + { + x: 1973, + y: 'Ala.', + value: 0.413622064, + }, + { + x: 1973, + y: 'Ark.', + value: 3.66421862, + }, + { + x: 1973, + y: 'Ariz.', + value: 1.169487531, + }, + { + x: 1973, + y: 'Calif.', + value: 3.797133872, + }, + { + x: 1973, + y: 'Colo.', + value: 6.531817427, + }, + { + x: 1973, + y: 'Conn.', + value: 59.17281031, + }, + { + x: 1973, + y: 'D.C.', + value: 1.392860476, + }, + { + x: 1973, + y: 'Del.', + value: 1.719932991, + }, + { + x: 1973, + y: 'Fla.', + value: 4.735646112, + }, + { + x: 1973, + y: 'Ga.', + value: 1.020118538, + }, + { + x: 1973, + y: 'Hawaii', + value: 3.4563088, + }, + { + x: 1973, + y: 'Iowa', + value: 10.18297978, + }, + { + x: 1973, + y: 'Idaho', + value: 31.68356044, + }, + { + x: 1973, + y: 'Ill.', + value: 19.4900705, + }, + { + x: 1973, + y: 'Ind.', + value: 13.27889979, + }, + { + x: 1973, + y: 'Kan.', + value: 1.189689883, + }, + { + x: 1973, + y: 'Ky.', + value: 12.35249091, + }, + { + x: 1973, + y: 'La.', + value: 2.355953718, + }, + { + x: 1973, + y: 'Mass.', + value: 69.160246, + }, + { + x: 1973, + y: 'Md.', + value: 0.339903589, + }, + { + x: 1973, + y: 'Maine', + value: 5.382232966, + }, + { + x: 1973, + y: 'Mich.', + value: 46.65749091, + }, + { + x: 1973, + y: 'Minn.', + value: 0.614765909, + }, + { + x: 1973, + y: 'Mo.', + value: 1.167656742, + }, + { + x: 1973, + y: 'Miss.', + value: 2.733081385, + }, + { + x: 1973, + y: 'Mont.', + value: 48.61362893, + }, + { + x: 1973, + y: 'N.C.', + value: 0.109670949, + }, + { + x: 1973, + y: 'N.D.', + value: 11.1888729, + }, + { + x: 1973, + y: 'Neb.', + value: 0.389815169, + }, + { + x: 1973, + y: 'N.H.', + value: 90.32814733, + }, + { + x: 1973, + y: 'N.J.', + value: 10.09217841, + }, + { + x: 1973, + y: 'N.M', + value: 13.96612243, + }, + { + x: 1973, + y: 'Nev.', + value: 0.167554145, + }, + { + x: 1973, + y: 'N.Y.', + value: 9.817296892, + }, + { + x: 1973, + y: 'Ohio', + value: 3.743349633, + }, + { + x: 1973, + y: 'Okla.', + value: 2.413367423, + }, + { + x: 1973, + y: 'Ore.', + value: 19.51848852, + }, + { + x: 1973, + y: 'Pa.', + value: 3.403284878, + }, + { + x: 1973, + y: 'R.I.', + value: 68.06120248, + }, + { + x: 1973, + y: 'S.C.', + value: 2.777046411, + }, + { + x: 1973, + y: 'S.D.', + value: 0.441445882, + }, + { + x: 1973, + y: 'Tenn.', + value: 3.915975972, + }, + { + x: 1973, + y: 'Texas', + value: 4.075434998, + }, + { + x: 1973, + y: 'Utah', + value: 10.74578228, + }, + { + x: 1973, + y: 'Va.', + value: 8.750632912, + }, + { + x: 1973, + y: 'Vt.', + value: 25.58128718, + }, + { + x: 1973, + y: 'Wash.', + value: 25.01446501, + }, + { + x: 1973, + y: 'Wis.', + value: 29.93984313, + }, + { + x: 1973, + y: 'W.Va.', + value: 12.44872475, + }, + { + x: 1973, + y: 'Wyo.', + value: 19.69898851, + }, + { + x: 1974, + y: 'Alaska', + value: 0.265837254, + }, + { + x: 1974, + y: 'Ala.', + value: 0.570836144, + }, + { + x: 1974, + y: 'Ark.', + value: 0.648290412, + }, + { + x: 1974, + y: 'Ariz.', + value: 0.919098741, + }, + { + x: 1974, + y: 'Calif.', + value: 5.121217072, + }, + { + x: 1974, + y: 'Colo.', + value: 6.109368523, + }, + { + x: 1974, + y: 'Conn.', + value: 5.644768856, + }, + { + x: 1974, + y: 'D.C.', + value: 0.141468528, + }, + { + x: 1974, + y: 'Del.', + value: 2.727633829, + }, + { + x: 1974, + y: 'Fla.', + value: 2.676552066, + }, + { + x: 1974, + y: 'Ga.', + value: 0.059240829, + }, + { + x: 1974, + y: 'Hawaii', + value: 7.10932563, + }, + { + x: 1974, + y: 'Iowa', + value: 4.616697798, + }, + { + x: 1974, + y: 'Idaho', + value: 6.490525035, + }, + { + x: 1974, + y: 'Ill.', + value: 18.75706877, + }, + { + x: 1974, + y: 'Ind.', + value: 4.808260368, + }, + { + x: 1974, + y: 'Kan.', + value: 8.243524229, + }, + { + x: 1974, + y: 'Ky.', + value: 5.479027006, + }, + { + x: 1974, + y: 'La.', + value: 0.360257986, + }, + { + x: 1974, + y: 'Mass.', + value: 7.103461835, + }, + { + x: 1974, + y: 'Md.', + value: 0.579836757, + }, + { + x: 1974, + y: 'Maine', + value: 3.451508636, + }, + { + x: 1974, + y: 'Mich.', + value: 25.09413591, + }, + { + x: 1974, + y: 'Minn.', + value: 2.161466644, + }, + { + x: 1974, + y: 'Mo.', + value: 5.511294202, + }, + { + x: 1974, + y: 'Miss.', + value: 0.625143523, + }, + { + x: 1974, + y: 'Mont.', + value: 46.24382525, + }, + { + x: 1974, + y: 'N.C.', + value: 0.108162911, + }, + { + x: 1974, + y: 'N.D.', + value: 5.791330535, + }, + { + x: 1974, + y: 'Neb.', + value: 6.091566615, + }, + { + x: 1974, + y: 'N.H.', + value: 20.2762641, + }, + { + x: 1974, + y: 'N.J.', + value: 75.02284415, + }, + { + x: 1974, + y: 'N.M', + value: 5.345085625, + }, + { + x: 1974, + y: 'Nev.', + value: 26.77540276, + }, + { + x: 1974, + y: 'N.Y.', + value: 7.865143887, + }, + { + x: 1974, + y: 'Ohio', + value: 27.40838918, + }, + { + x: 1974, + y: 'Okla.', + value: 1.045164439, + }, + { + x: 1974, + y: 'Ore.', + value: 1.030192805, + }, + { + x: 1974, + y: 'Pa.', + value: 7.735533775, + }, + { + x: 1974, + y: 'R.I.', + value: 6.576239833, + }, + { + x: 1974, + y: 'S.C.', + value: 1.998602357, + }, + { + x: 1974, + y: 'S.D.', + value: 4.111347024, + }, + { + x: 1974, + y: 'Tenn.', + value: 1.30976811, + }, + { + x: 1974, + y: 'Texas', + value: 1.424156543, + }, + { + x: 1974, + y: 'Utah', + value: 1.213562778, + }, + { + x: 1974, + y: 'Va.', + value: 0.851924607, + }, + { + x: 1974, + y: 'Vt.', + value: 11.88210451, + }, + { + x: 1974, + y: 'Wash.', + value: 2.181513523, + }, + { + x: 1974, + y: 'Wis.', + value: 13.91137689, + }, + { + x: 1974, + y: 'W.Va.', + value: 12.70185914, + }, + { + x: 1974, + y: 'Wyo.', + value: 4.453817839, + }, + { + x: 1975, + y: 'Alaska', + value: null, + }, + { + x: 1975, + y: 'Ala.', + value: 0.133863827, + }, + { + x: 1975, + y: 'Ark.', + value: 0.092159061, + }, + { + x: 1975, + y: 'Ariz.', + value: 3.537700162, + }, + { + x: 1975, + y: 'Calif.', + value: 23.78292142, + }, + { + x: 1975, + y: 'Colo.', + value: 44.44771998, + }, + { + x: 1975, + y: 'Conn.', + value: 4.183781522, + }, + { + x: 1975, + y: 'D.C.', + value: 0.288894185, + }, + { + x: 1975, + y: 'Del.', + value: 5.930534799, + }, + { + x: 1975, + y: 'Fla.', + value: 0.946076086, + }, + { + x: 1975, + y: 'Ga.', + value: 0.779299924, + }, + { + x: 1975, + y: 'Hawaii', + value: 7.188746625, + }, + { + x: 1975, + y: 'Iowa', + value: 24.11230547, + }, + { + x: 1975, + y: 'Idaho', + value: 2.333768581, + }, + { + x: 1975, + y: 'Ill.', + value: 16.45970374, + }, + { + x: 1975, + y: 'Ind.', + value: 9.630572, + }, + { + x: 1975, + y: 'Kan.', + value: 93.30721716, + }, + { + x: 1975, + y: 'Ky.', + value: 4.476862977, + }, + { + x: 1975, + y: 'La.', + value: 0.075937736, + }, + { + x: 1975, + y: 'Mass.', + value: 2.733442996, + }, + { + x: 1975, + y: 'Md.', + value: 1.541968405, + }, + { + x: 1975, + y: 'Maine', + value: 1.470031569, + }, + { + x: 1975, + y: 'Mich.', + value: 35.26046353, + }, + { + x: 1975, + y: 'Minn.', + value: 5.826447532, + }, + { + x: 1975, + y: 'Mo.', + value: 5.434974661, + }, + { + x: 1975, + y: 'Miss.', + value: 1.481630254, + }, + { + x: 1975, + y: 'Mont.', + value: 6.99839037, + }, + { + x: 1975, + y: 'N.C.', + value: 0.053495351, + }, + { + x: 1975, + y: 'N.D.', + value: 131.9300028, + }, + { + x: 1975, + y: 'Neb.', + value: 25.53338006, + }, + { + x: 1975, + y: 'N.H.', + value: 2.366169456, + }, + { + x: 1975, + y: 'N.J.', + value: 6.539736735, + }, + { + x: 1975, + y: 'N.M', + value: 9.081010178, + }, + { + x: 1975, + y: 'Nev.', + value: 4.327833378, + }, + { + x: 1975, + y: 'N.Y.', + value: 6.80581483, + }, + { + x: 1975, + y: 'Ohio', + value: 1.060202581, + }, + { + x: 1975, + y: 'Okla.', + value: 9.586761072, + }, + { + x: 1975, + y: 'Ore.', + value: 8.451549913, + }, + { + x: 1975, + y: 'Pa.', + value: 4.740540311, + }, + { + x: 1975, + y: 'R.I.', + value: 0.528491506, + }, + { + x: 1975, + y: 'S.C.', + value: 0.577512937, + }, + { + x: 1975, + y: 'S.D.', + value: 51.86555748, + }, + { + x: 1975, + y: 'Tenn.', + value: 4.094845831, + }, + { + x: 1975, + y: 'Texas', + value: 2.177604324, + }, + { + x: 1975, + y: 'Utah', + value: 27.84470966, + }, + { + x: 1975, + y: 'Va.', + value: 0.83953827, + }, + { + x: 1975, + y: 'Vt.', + value: 15.25999736, + }, + { + x: 1975, + y: 'Wash.', + value: 8.122135255, + }, + { + x: 1975, + y: 'Wis.', + value: 32.02851931, + }, + { + x: 1975, + y: 'W.Va.', + value: 11.70522207, + }, + { + x: 1975, + y: 'Wyo.', + value: 0.755758883, + }, + { + x: 1976, + y: 'Alaska', + value: 2.726578689, + }, + { + x: 1976, + y: 'Ala.', + value: null, + }, + { + x: 1976, + y: 'Ark.', + value: 0.905382954, + }, + { + x: 1976, + y: 'Ariz.', + value: 10.01980458, + }, + { + x: 1976, + y: 'Calif.', + value: 10.39709568, + }, + { + x: 1976, + y: 'Colo.', + value: 16.69052794, + }, + { + x: 1976, + y: 'Conn.', + value: 7.680536354, + }, + { + x: 1976, + y: 'D.C.', + value: 1.919589857, + }, + { + x: 1976, + y: 'Del.', + value: 18.75541753, + }, + { + x: 1976, + y: 'Fla.', + value: 3.805251088, + }, + { + x: 1976, + y: 'Ga.', + value: 0.095791001, + }, + { + x: 1976, + y: 'Hawaii', + value: 1.197919106, + }, + { + x: 1976, + y: 'Iowa', + value: 1.441529009, + }, + { + x: 1976, + y: 'Idaho', + value: 224.3429028, + }, + { + x: 1976, + y: 'Ill.', + value: 17.84598284, + }, + { + x: 1976, + y: 'Ind.', + value: 79.93529977, + }, + { + x: 1976, + y: 'Kan.', + value: 32.18929893, + }, + { + x: 1976, + y: 'Ky.', + value: 21.88212586, + }, + { + x: 1976, + y: 'La.', + value: 7.821726414, + }, + { + x: 1976, + y: 'Mass.', + value: 0.749364043, + }, + { + x: 1976, + y: 'Md.', + value: 19.88202691, + }, + { + x: 1976, + y: 'Maine', + value: 0.906143472, + }, + { + x: 1976, + y: 'Mich.', + value: 65.65181314, + }, + { + x: 1976, + y: 'Minn.', + value: 10.77866046, + }, + { + x: 1976, + y: 'Mo.', + value: 4.811673366, + }, + { + x: 1976, + y: 'Miss.', + value: 0.73194505, + }, + { + x: 1976, + y: 'Mont.', + value: 65.84817515, + }, + { + x: 1976, + y: 'N.C.', + value: 0.33417716, + }, + { + x: 1976, + y: 'N.D.', + value: 0.461702544, + }, + { + x: 1976, + y: 'Neb.', + value: 3.532792666, + }, + { + x: 1976, + y: 'N.H.', + value: 1.149738492, + }, + { + x: 1976, + y: 'N.J.', + value: 8.531901064, + }, + { + x: 1976, + y: 'N.M', + value: 1.316092521, + }, + { + x: 1976, + y: 'Nev.', + value: 12.38329847, + }, + { + x: 1976, + y: 'N.Y.', + value: 17.36411109, + }, + { + x: 1976, + y: 'Ohio', + value: 6.740074683, + }, + { + x: 1976, + y: 'Okla.', + value: 10.06963729, + }, + { + x: 1976, + y: 'Ore.', + value: 7.152570041, + }, + { + x: 1976, + y: 'Pa.', + value: 28.49433783, + }, + { + x: 1976, + y: 'R.I.', + value: 2.209991265, + }, + { + x: 1976, + y: 'S.C.', + value: 0.167130118, + }, + { + x: 1976, + y: 'S.D.', + value: 0.726237509, + }, + { + x: 1976, + y: 'Tenn.', + value: 4.793212449, + }, + { + x: 1976, + y: 'Texas', + value: 1.985894088, + }, + { + x: 1976, + y: 'Utah', + value: 166.5009488, + }, + { + x: 1976, + y: 'Va.', + value: 16.48337259, + }, + { + x: 1976, + y: 'Vt.', + value: 34.35441149, + }, + { + x: 1976, + y: 'Wash.', + value: 10.24880497, + }, + { + x: 1976, + y: 'Wis.', + value: 88.53318071, + }, + { + x: 1976, + y: 'W.Va.', + value: 11.11059867, + }, + { + x: 1976, + y: 'Wyo.', + value: 0.967693551, + }, + { + x: 1977, + y: 'Alaska', + value: 15.07043576, + }, + { + x: 1977, + y: 'Ala.', + value: 2.061674873, + }, + { + x: 1977, + y: 'Ark.', + value: 2.050708676, + }, + { + x: 1977, + y: 'Ariz.', + value: 8.666903085, + }, + { + x: 1977, + y: 'Calif.', + value: 34.76096777, + }, + { + x: 1977, + y: 'Colo.', + value: 15.68628585, + }, + { + x: 1977, + y: 'Conn.', + value: 25.03536164, + }, + { + x: 1977, + y: 'D.C.', + value: 2.105098549, + }, + { + x: 1977, + y: 'Del.', + value: 1.176913662, + }, + { + x: 1977, + y: 'Fla.', + value: 3.306953876, + }, + { + x: 1977, + y: 'Ga.', + value: 14.38889404, + }, + { + x: 1977, + y: 'Hawaii', + value: 4.723138225, + }, + { + x: 1977, + y: 'Iowa', + value: 123.7462171, + }, + { + x: 1977, + y: 'Idaho', + value: 18.55735761, + }, + { + x: 1977, + y: 'Ill.', + value: 16.55193782, + }, + { + x: 1977, + y: 'Ind.', + value: 71.18551486, + }, + { + x: 1977, + y: 'Kan.', + value: 61.22474319, + }, + { + x: 1977, + y: 'Ky.', + value: 33.0196101, + }, + { + x: 1977, + y: 'La.', + value: 2.236653141, + }, + { + x: 1977, + y: 'Mass.', + value: 12.28979011, + }, + { + x: 1977, + y: 'Md.', + value: 8.485508783, + }, + { + x: 1977, + y: 'Maine', + value: 15.89488185, + }, + { + x: 1977, + y: 'Mich.', + value: 13.4848365, + }, + { + x: 1977, + y: 'Minn.', + value: 68.08886219, + }, + { + x: 1977, + y: 'Mo.', + value: 18.59124199, + }, + { + x: 1977, + y: 'Miss.', + value: 2.090186734, + }, + { + x: 1977, + y: 'Mont.', + value: 119.6445942, + }, + { + x: 1977, + y: 'N.C.', + value: 0.902857405, + }, + { + x: 1977, + y: 'N.D.', + value: 4.759704039, + }, + { + x: 1977, + y: 'Neb.', + value: 13.68387937, + }, + { + x: 1977, + y: 'N.H.', + value: 29.05150754, + }, + { + x: 1977, + y: 'N.J.', + value: 2.666374998, + }, + { + x: 1977, + y: 'N.M', + value: 1.938557422, + }, + { + x: 1977, + y: 'Nev.', + value: 10.8418261, + }, + { + x: 1977, + y: 'N.Y.', + value: 26.1869104, + }, + { + x: 1977, + y: 'Ohio', + value: 17.29411321, + }, + { + x: 1977, + y: 'Okla.', + value: 1.782448096, + }, + { + x: 1977, + y: 'Ore.', + value: 12.74670432, + }, + { + x: 1977, + y: 'Pa.', + value: 27.07208346, + }, + { + x: 1977, + y: 'R.I.', + value: 6.72398867, + }, + { + x: 1977, + y: 'S.C.', + value: 3.31760591, + }, + { + x: 1977, + y: 'S.D.', + value: 10.60152778, + }, + { + x: 1977, + y: 'Tenn.', + value: 15.7590396, + }, + { + x: 1977, + y: 'Texas', + value: 13.99214795, + }, + { + x: 1977, + y: 'Utah', + value: 1.755014589, + }, + { + x: 1977, + y: 'Va.', + value: 50.77567625, + }, + { + x: 1977, + y: 'Vt.', + value: 47.17842882, + }, + { + x: 1977, + y: 'Wash.', + value: 12.36798589, + }, + { + x: 1977, + y: 'Wis.', + value: 45.34978524, + }, + { + x: 1977, + y: 'W.Va.', + value: 13.88170397, + }, + { + x: 1977, + y: 'Wyo.', + value: 5.775272593, + }, + { + x: 1978, + y: 'Alaska', + value: 0.496582273, + }, + { + x: 1978, + y: 'Ala.', + value: 3.414162775, + }, + { + x: 1978, + y: 'Ark.', + value: 0.968594213, + }, + { + x: 1978, + y: 'Ariz.', + value: 2.504201177, + }, + { + x: 1978, + y: 'Calif.', + value: 2.777672671, + }, + { + x: 1978, + y: 'Colo.', + value: 1.754857621, + }, + { + x: 1978, + y: 'Conn.', + value: 17.05472078, + }, + { + x: 1978, + y: 'D.C.', + value: 0.307684734, + }, + { + x: 1978, + y: 'Del.', + value: 1.848789211, + }, + { + x: 1978, + y: 'Fla.', + value: 11.60599986, + }, + { + x: 1978, + y: 'Ga.', + value: 1.036771316, + }, + { + x: 1978, + y: 'Hawaii', + value: 2.202860362, + }, + { + x: 1978, + y: 'Iowa', + value: 2.983806164, + }, + { + x: 1978, + y: 'Idaho', + value: 0.428896011, + }, + { + x: 1978, + y: 'Ill.', + value: 6.949296546, + }, + { + x: 1978, + y: 'Ind.', + value: 3.980968426, + }, + { + x: 1978, + y: 'Kan.', + value: 4.466363181, + }, + { + x: 1978, + y: 'Ky.', + value: 3.349988083, + }, + { + x: 1978, + y: 'La.', + value: 21.21969758, + }, + { + x: 1978, + y: 'Mass.', + value: 5.48933118, + }, + { + x: 1978, + y: 'Md.', + value: 1.216846887, + }, + { + x: 1978, + y: 'Maine', + value: 117.7662189, + }, + { + x: 1978, + y: 'Mich.', + value: 82.21216999, + }, + { + x: 1978, + y: 'Minn.', + value: 2.123291121, + }, + { + x: 1978, + y: 'Mo.', + value: 3.542035205, + }, + { + x: 1978, + y: 'Miss.', + value: 31.19180206, + }, + { + x: 1978, + y: 'Mont.', + value: 13.84469805, + }, + { + x: 1978, + y: 'N.C.', + value: 2.146478805, + }, + { + x: 1978, + y: 'N.D.', + value: 27.41631133, + }, + { + x: 1978, + y: 'Neb.', + value: 0.510417624, + }, + { + x: 1978, + y: 'N.H.', + value: 7.150132992, + }, + { + x: 1978, + y: 'N.J.', + value: 1.031695869, + }, + { + x: 1978, + y: 'N.M', + value: null, + }, + { + x: 1978, + y: 'Nev.', + value: 2.613125468, + }, + { + x: 1978, + y: 'N.Y.', + value: 10.46415464, + }, + { + x: 1978, + y: 'Ohio', + value: 4.639620059, + }, + { + x: 1978, + y: 'Okla.', + value: 0.941078409, + }, + { + x: 1978, + y: 'Ore.', + value: 20.5563189, + }, + { + x: 1978, + y: 'Pa.', + value: 2.750678732, + }, + { + x: 1978, + y: 'R.I.', + value: 0.841766784, + }, + { + x: 1978, + y: 'S.C.', + value: 6.471932684, + }, + { + x: 1978, + y: 'S.D.', + value: null, + }, + { + x: 1978, + y: 'Tenn.', + value: 22.27839086, + }, + { + x: 1978, + y: 'Texas', + value: 7.538681102, + }, + { + x: 1978, + y: 'Utah', + value: 3.238893763, + }, + { + x: 1978, + y: 'Va.', + value: 49.88747999, + }, + { + x: 1978, + y: 'Vt.', + value: 10.48732419, + }, + { + x: 1978, + y: 'Wash.', + value: 10.67793168, + }, + { + x: 1978, + y: 'Wis.', + value: 33.2492599, + }, + { + x: 1978, + y: 'W.Va.', + value: 45.56814987, + }, + { + x: 1978, + y: 'Wyo.', + value: null, + }, + { + x: 1979, + y: 'Alaska', + value: 4.479272168, + }, + { + x: 1979, + y: 'Ala.', + value: 3.312884192, + }, + { + x: 1979, + y: 'Ark.', + value: 0.481098304, + }, + { + x: 1979, + y: 'Ariz.', + value: 3.237418674, + }, + { + x: 1979, + y: 'Calif.', + value: 4.115278152, + }, + { + x: 1979, + y: 'Colo.', + value: 2.525983023, + }, + { + x: 1979, + y: 'Conn.', + value: 0.128717689, + }, + { + x: 1979, + y: 'D.C.', + value: 0.156658045, + }, + { + x: 1979, + y: 'Del.', + value: 0.168254428, + }, + { + x: 1979, + y: 'Fla.', + value: 6.227989137, + }, + { + x: 1979, + y: 'Ga.', + value: 10.1590579, + }, + { + x: 1979, + y: 'Hawaii', + value: 7.981830451, + }, + { + x: 1979, + y: 'Iowa', + value: 0.549109619, + }, + { + x: 1979, + y: 'Idaho', + value: 2.330668955, + }, + { + x: 1979, + y: 'Ill.', + value: 11.5258209, + }, + { + x: 1979, + y: 'Ind.', + value: 3.642838616, + }, + { + x: 1979, + y: 'Kan.', + value: 3.173019687, + }, + { + x: 1979, + y: 'Ky.', + value: 1.638996311, + }, + { + x: 1979, + y: 'La.', + value: 6.181792244, + }, + { + x: 1979, + y: 'Mass.', + value: 0.470626213, + }, + { + x: 1979, + y: 'Md.', + value: 0.403132577, + }, + { + x: 1979, + y: 'Maine', + value: 1.867230985, + }, + { + x: 1979, + y: 'Mich.', + value: 9.447124069, + }, + { + x: 1979, + y: 'Minn.', + value: 29.88245743, + }, + { + x: 1979, + y: 'Mo.', + value: 9.742334573, + }, + { + x: 1979, + y: 'Miss.', + value: 1.071157382, + }, + { + x: 1979, + y: 'Mont.', + value: 7.88112217, + }, + { + x: 1979, + y: 'N.C.', + value: 1.955195089, + }, + { + x: 1979, + y: 'N.D.', + value: 2.604497815, + }, + { + x: 1979, + y: 'Neb.', + value: 4.267991655, + }, + { + x: 1979, + y: 'N.H.', + value: 3.15008527, + }, + { + x: 1979, + y: 'N.J.', + value: 0.678902942, + }, + { + x: 1979, + y: 'N.M', + value: 3.146840802, + }, + { + x: 1979, + y: 'Nev.', + value: 2.62338334, + }, + { + x: 1979, + y: 'N.Y.', + value: 8.901888544, + }, + { + x: 1979, + y: 'Ohio', + value: 3.019181061, + }, + { + x: 1979, + y: 'Okla.', + value: 0.859421741, + }, + { + x: 1979, + y: 'Ore.', + value: 2.77239229, + }, + { + x: 1979, + y: 'Pa.', + value: 0.531022906, + }, + { + x: 1979, + y: 'R.I.', + value: 10.87468353, + }, + { + x: 1979, + y: 'S.C.', + value: 3.363422619, + }, + { + x: 1979, + y: 'S.D.', + value: 0.28953281, + }, + { + x: 1979, + y: 'Tenn.', + value: 1.742494206, + }, + { + x: 1979, + y: 'Texas', + value: 4.554018566, + }, + { + x: 1979, + y: 'Utah', + value: 1.505779799, + }, + { + x: 1979, + y: 'Va.', + value: 5.984868009, + }, + { + x: 1979, + y: 'Vt.', + value: 23.26690859, + }, + { + x: 1979, + y: 'Wash.', + value: 25.14425883, + }, + { + x: 1979, + y: 'Wis.', + value: 13.74908702, + }, + { + x: 1979, + y: 'W.Va.', + value: 4.564935958, + }, + { + x: 1979, + y: 'Wyo.', + value: 0.42593338, + }, + { + x: 1980, + y: 'Alaska', + value: 1.433722589, + }, + { + x: 1980, + y: 'Ala.', + value: 0.561434885, + }, + { + x: 1980, + y: 'Ark.', + value: 0.784929014, + }, + { + x: 1980, + y: 'Ariz.', + value: 11.60098174, + }, + { + x: 1980, + y: 'Calif.', + value: 3.648202439, + }, + { + x: 1980, + y: 'Colo.', + value: 0.805937611, + }, + { + x: 1980, + y: 'Conn.', + value: 0.862940723, + }, + { + x: 1980, + y: 'D.C.', + value: 0.785061227, + }, + { + x: 1980, + y: 'Del.', + value: 0.671169093, + }, + { + x: 1980, + y: 'Fla.', + value: 3.993024863, + }, + { + x: 1980, + y: 'Ga.', + value: 15.2109828, + }, + { + x: 1980, + y: 'Hawaii', + value: 0.920061951, + }, + { + x: 1980, + y: 'Iowa', + value: 0.068776193, + }, + { + x: 1980, + y: 'Idaho', + value: null, + }, + { + x: 1980, + y: 'Ill.', + value: 2.962391263, + }, + { + x: 1980, + y: 'Ind.', + value: 2.007139944, + }, + { + x: 1980, + y: 'Kan.', + value: 3.10292182, + }, + { + x: 1980, + y: 'Ky.', + value: 1.716436982, + }, + { + x: 1980, + y: 'La.', + value: 0.443582908, + }, + { + x: 1980, + y: 'Mass.', + value: 1.005428447, + }, + { + x: 1980, + y: 'Md.', + value: 1.994413296, + }, + { + x: 1980, + y: 'Maine', + value: 4.236416768, + }, + { + x: 1980, + y: 'Mich.', + value: 3.0404091, + }, + { + x: 1980, + y: 'Minn.', + value: 26.89866645, + }, + { + x: 1980, + y: 'Mo.', + value: 1.013774355, + }, + { + x: 1980, + y: 'Miss.', + value: 3.899117618, + }, + { + x: 1980, + y: 'Mont.', + value: 0.251468576, + }, + { + x: 1980, + y: 'N.C.', + value: 2.19922161, + }, + { + x: 1980, + y: 'N.D.', + value: 0, + }, + { + x: 1980, + y: 'Neb.', + value: 4.941353107, + }, + { + x: 1980, + y: 'N.H.', + value: 26.6916928, + }, + { + x: 1980, + y: 'N.J.', + value: 8.93692207, + }, + { + x: 1980, + y: 'N.M', + value: 0.975428213, + }, + { + x: 1980, + y: 'Nev.', + value: 1.41567029, + }, + { + x: 1980, + y: 'N.Y.', + value: 10.98604977, + }, + { + x: 1980, + y: 'Ohio', + value: 3.522324586, + }, + { + x: 1980, + y: 'Okla.', + value: 22.67321757, + }, + { + x: 1980, + y: 'Ore.', + value: 0.074963024, + }, + { + x: 1980, + y: 'Pa.', + value: 9.503677805, + }, + { + x: 1980, + y: 'R.I.', + value: 0.209860726, + }, + { + x: 1980, + y: 'S.C.', + value: 5.032625568, + }, + { + x: 1980, + y: 'S.D.', + value: null, + }, + { + x: 1980, + y: 'Tenn.', + value: 3.868047293, + }, + { + x: 1980, + y: 'Texas', + value: 1.335926704, + }, + { + x: 1980, + y: 'Utah', + value: 2.969373878, + }, + { + x: 1980, + y: 'Va.', + value: 6.575929856, + }, + { + x: 1980, + y: 'Vt.', + value: 41.89342777, + }, + { + x: 1980, + y: 'Wash.', + value: 4.084300915, + }, + { + x: 1980, + y: 'Wis.', + value: 31.29269289, + }, + { + x: 1980, + y: 'W.Va.', + value: 1.791083882, + }, + { + x: 1980, + y: 'Wyo.', + value: null, + }, + { + x: 1981, + y: 'Alaska', + value: null, + }, + { + x: 1981, + y: 'Ala.', + value: 0, + }, + { + x: 1981, + y: 'Ark.', + value: 0.610219343, + }, + { + x: 1981, + y: 'Ariz.', + value: 0.380641145, + }, + { + x: 1981, + y: 'Calif.', + value: 1.398065569, + }, + { + x: 1981, + y: 'Colo.', + value: 0.261304353, + }, + { + x: 1981, + y: 'Conn.', + value: 0.286714327, + }, + { + x: 1981, + y: 'D.C.', + value: 0.31537086, + }, + { + x: 1981, + y: 'Del.', + value: null, + }, + { + x: 1981, + y: 'Fla.', + value: 2.86494451, + }, + { + x: 1981, + y: 'Ga.', + value: 1.946974331, + }, + { + x: 1981, + y: 'Hawaii', + value: 0.805007144, + }, + { + x: 1981, + y: 'Iowa', + value: 0.034623773, + }, + { + x: 1981, + y: 'Idaho', + value: 0.205397645, + }, + { + x: 1981, + y: 'Ill.', + value: 0.245110655, + }, + { + x: 1981, + y: 'Ind.', + value: 0.329192699, + }, + { + x: 1981, + y: 'Kan.', + value: 0.041645809, + }, + { + x: 1981, + y: 'Ky.', + value: 0.027148498, + }, + { + x: 1981, + y: 'La.', + value: 0.091898926, + }, + { + x: 1981, + y: 'Mass.', + value: 1.056968524, + }, + { + x: 1981, + y: 'Md.', + value: 0.116742701, + }, + { + x: 1981, + y: 'Maine', + value: 0.43987599, + }, + { + x: 1981, + y: 'Mich.', + value: 0.383974106, + }, + { + x: 1981, + y: 'Minn.', + value: 0.193636617, + }, + { + x: 1981, + y: 'Mo.', + value: 0.020286235, + }, + { + x: 1981, + y: 'Miss.', + value: null, + }, + { + x: 1981, + y: 'Mont.', + value: null, + }, + { + x: 1981, + y: 'N.C.', + value: 0.09968266, + }, + { + x: 1981, + y: 'N.D.', + value: null, + }, + { + x: 1981, + y: 'Neb.', + value: 0.252879667, + }, + { + x: 1981, + y: 'N.H.', + value: 0.949648577, + }, + { + x: 1981, + y: 'N.J.', + value: 0.793974621, + }, + { + x: 1981, + y: 'N.M', + value: 1.099849467, + }, + { + x: 1981, + y: 'Nev.', + value: 1.588135268, + }, + { + x: 1981, + y: 'N.Y.', + value: 1.984111418, + }, + { + x: 1981, + y: 'Ohio', + value: 0.18592394, + }, + { + x: 1981, + y: 'Okla.', + value: 0.249522554, + }, + { + x: 1981, + y: 'Ore.', + value: 0.187622752, + }, + { + x: 1981, + y: 'Pa.', + value: 4.330887943, + }, + { + x: 1981, + y: 'R.I.', + value: null, + }, + { + x: 1981, + y: 'S.C.', + value: 0, + }, + { + x: 1981, + y: 'S.D.', + value: null, + }, + { + x: 1981, + y: 'Tenn.', + value: 0.086094806, + }, + { + x: 1981, + y: 'Texas', + value: 6.026840967, + }, + { + x: 1981, + y: 'Utah', + value: null, + }, + { + x: 1981, + y: 'Va.', + value: 0.236674196, + }, + { + x: 1981, + y: 'Vt.', + value: 0.385275539, + }, + { + x: 1981, + y: 'Wash.', + value: 0.093533295, + }, + { + x: 1981, + y: 'Wis.', + value: 0.126880206, + }, + { + x: 1981, + y: 'W.Va.', + value: 0.615509611, + }, + { + x: 1981, + y: 'Wyo.', + value: 0.197472354, + }, + { + x: 1982, + y: 'Alaska', + value: 0.204743078, + }, + { + x: 1982, + y: 'Ala.', + value: 0.050837523, + }, + { + x: 1982, + y: 'Ark.', + value: null, + }, + { + x: 1982, + y: 'Ariz.', + value: 0.538915601, + }, + { + x: 1982, + y: 'Calif.', + value: 3.154570898, + }, + { + x: 1982, + y: 'Colo.', + value: 0.223383105, + }, + { + x: 1982, + y: 'Conn.', + value: 0.252976106, + }, + { + x: 1982, + y: 'D.C.', + value: 0.158119516, + }, + { + x: 1982, + y: 'Del.', + value: null, + }, + { + x: 1982, + y: 'Fla.', + value: 1.990725267, + }, + { + x: 1982, + y: 'Ga.', + value: null, + }, + { + x: 1982, + y: 'Hawaii', + value: 0.493721346, + }, + { + x: 1982, + y: 'Iowa', + value: null, + }, + { + x: 1982, + y: 'Idaho', + value: null, + }, + { + x: 1982, + y: 'Ill.', + value: 0.219128748, + }, + { + x: 1982, + y: 'Ind.', + value: 0.055041882, + }, + { + x: 1982, + y: 'Kan.', + value: 1.821545656, + }, + { + x: 1982, + y: 'Ky.', + value: 0.054134759, + }, + { + x: 1982, + y: 'La.', + value: 0.341272391, + }, + { + x: 1982, + y: 'Mass.', + value: 0.086215711, + }, + { + x: 1982, + y: 'Md.', + value: 0.115919799, + }, + { + x: 1982, + y: 'Maine', + value: null, + }, + { + x: 1982, + y: 'Mich.', + value: 0.618938136, + }, + { + x: 1982, + y: 'Minn.', + value: null, + }, + { + x: 1982, + y: 'Mo.', + value: 0.040455259, + }, + { + x: 1982, + y: 'Miss.', + value: 0.155780407, + }, + { + x: 1982, + y: 'Mont.', + value: null, + }, + { + x: 1982, + y: 'N.C.', + value: 0.032910673, + }, + { + x: 1982, + y: 'N.D.', + value: null, + }, + { + x: 1982, + y: 'Neb.', + value: 0.189358913, + }, + { + x: 1982, + y: 'N.H.', + value: 0.521847675, + }, + { + x: 1982, + y: 'N.J.', + value: 0.080345109, + }, + { + x: 1982, + y: 'N.M', + value: null, + }, + { + x: 1982, + y: 'Nev.', + value: null, + }, + { + x: 1982, + y: 'N.Y.', + value: 1.02900988, + }, + { + x: 1982, + y: 'Ohio', + value: 0.027939121, + }, + { + x: 1982, + y: 'Okla.', + value: 1.002916969, + }, + { + x: 1982, + y: 'Ore.', + value: 0.716152557, + }, + { + x: 1982, + y: 'Pa.', + value: 0.059132994, + }, + { + x: 1982, + y: 'R.I.', + value: null, + }, + { + x: 1982, + y: 'S.C.', + value: null, + }, + { + x: 1982, + y: 'S.D.', + value: null, + }, + { + x: 1982, + y: 'Tenn.', + value: 0.1287623, + }, + { + x: 1982, + y: 'Texas', + value: 1.110992887, + }, + { + x: 1982, + y: 'Utah', + value: 0.188094496, + }, + { + x: 1982, + y: 'Va.', + value: 0.143764476, + }, + { + x: 1982, + y: 'Vt.', + value: 0.382188488, + }, + { + x: 1982, + y: 'Wash.', + value: 0.860411891, + }, + { + x: 1982, + y: 'Wis.', + value: 0.021179988, + }, + { + x: 1982, + y: 'W.Va.', + value: 0.102824539, + }, + { + x: 1982, + y: 'Wyo.', + value: 0, + }, + { + x: 1983, + y: 'Alaska', + value: null, + }, + { + x: 1983, + y: 'Ala.', + value: 0.025304796, + }, + { + x: 1983, + y: 'Ark.', + value: 0.043107759, + }, + { + x: 1983, + y: 'Ariz.', + value: null, + }, + { + x: 1983, + y: 'Calif.', + value: 0.603612551, + }, + { + x: 1983, + y: 'Colo.', + value: null, + }, + { + x: 1983, + y: 'Conn.', + value: 0, + }, + { + x: 1983, + y: 'D.C.', + value: null, + }, + { + x: 1983, + y: 'Del.', + value: null, + }, + { + x: 1983, + y: 'Fla.', + value: 1.458343241, + }, + { + x: 1983, + y: 'Ga.', + value: 0.137104766, + }, + { + x: 1983, + y: 'Hawaii', + value: 0.097283646, + }, + { + x: 1983, + y: 'Iowa', + value: null, + }, + { + x: 1983, + y: 'Idaho', + value: 0.10092457, + }, + { + x: 1983, + y: 'Ill.', + value: 1.708707891, + }, + { + x: 1983, + y: 'Ind.', + value: 6.796960678, + }, + { + x: 1983, + y: 'Kan.', + value: null, + }, + { + x: 1983, + y: 'Ky.', + value: null, + }, + { + x: 1983, + y: 'La.', + value: 0.090899237, + }, + { + x: 1983, + y: 'Mass.', + value: 0.136968172, + }, + { + x: 1983, + y: 'Md.', + value: 0.183265857, + }, + { + x: 1983, + y: 'Maine', + value: null, + }, + { + x: 1983, + y: 'Mich.', + value: 0.033151179, + }, + { + x: 1983, + y: 'Minn.', + value: 0, + }, + { + x: 1983, + y: 'Mo.', + value: 0.040198759, + }, + { + x: 1983, + y: 'Miss.', + value: 0.077577984, + }, + { + x: 1983, + y: 'Mont.', + value: null, + }, + { + x: 1983, + y: 'N.C.', + value: null, + }, + { + x: 1983, + y: 'N.D.', + value: null, + }, + { + x: 1983, + y: 'Neb.', + value: null, + }, + { + x: 1983, + y: 'N.H.', + value: null, + }, + { + x: 1983, + y: 'N.J.', + value: 0.359258825, + }, + { + x: 1983, + y: 'N.M', + value: null, + }, + { + x: 1983, + y: 'Nev.', + value: 0.21623445, + }, + { + x: 1983, + y: 'N.Y.', + value: 0.174690364, + }, + { + x: 1983, + y: 'Ohio', + value: 0.819538849, + }, + { + x: 1983, + y: 'Okla.', + value: 0.030436462, + }, + { + x: 1983, + y: 'Ore.', + value: 0.375011063, + }, + { + x: 1983, + y: 'Pa.', + value: null, + }, + { + x: 1983, + y: 'R.I.', + value: null, + }, + { + x: 1983, + y: 'S.C.', + value: null, + }, + { + x: 1983, + y: 'S.D.', + value: null, + }, + { + x: 1983, + y: 'Tenn.', + value: 0.021336806, + }, + { + x: 1983, + y: 'Texas', + value: 0.23114763, + }, + { + x: 1983, + y: 'Utah', + value: 0.616392844, + }, + { + x: 1983, + y: 'Va.', + value: 0.372085112, + }, + { + x: 1983, + y: 'Vt.', + value: null, + }, + { + x: 1983, + y: 'Wash.', + value: 0.713684509, + }, + { + x: 1983, + y: 'Wis.', + value: null, + }, + { + x: 1983, + y: 'W.Va.', + value: 0.051875373, + }, + { + x: 1983, + y: 'Wyo.', + value: null, + }, + { + x: 1984, + y: 'Alaska', + value: null, + }, + { + x: 1984, + y: 'Ala.', + value: 0, + }, + { + x: 1984, + y: 'Ark.', + value: 0.386756429, + }, + { + x: 1984, + y: 'Ariz.', + value: null, + }, + { + x: 1984, + y: 'Calif.', + value: 1.179980764, + }, + { + x: 1984, + y: 'Colo.', + value: null, + }, + { + x: 1984, + y: 'Conn.', + value: 0.31238959, + }, + { + x: 1984, + y: 'D.C.', + value: null, + }, + { + x: 1984, + y: 'Del.', + value: null, + }, + { + x: 1984, + y: 'Fla.', + value: 0.140955279, + }, + { + x: 1984, + y: 'Ga.', + value: 0.050313107, + }, + { + x: 1984, + y: 'Hawaii', + value: 16.63944722, + }, + { + x: 1984, + y: 'Iowa', + value: null, + }, + { + x: 1984, + y: 'Idaho', + value: null, + }, + { + x: 1984, + y: 'Ill.', + value: 1.342128103, + }, + { + x: 1984, + y: 'Ind.', + value: 0.036635331, + }, + { + x: 1984, + y: 'Kan.', + value: null, + }, + { + x: 1984, + y: 'Ky.', + value: 0.027064874, + }, + { + x: 1984, + y: 'La.', + value: 0.181483345, + }, + { + x: 1984, + y: 'Mass.', + value: 1.445398048, + }, + { + x: 1984, + y: 'Md.', + value: 0.294579444, + }, + { + x: 1984, + y: 'Maine', + value: null, + }, + { + x: 1984, + y: 'Mich.', + value: 3.294296471, + }, + { + x: 1984, + y: 'Minn.', + value: 1.075448187, + }, + { + x: 1984, + y: 'Mo.', + value: 0.119993568, + }, + { + x: 1984, + y: 'Miss.', + value: null, + }, + { + x: 1984, + y: 'Mont.', + value: null, + }, + { + x: 1984, + y: 'N.C.', + value: null, + }, + { + x: 1984, + y: 'N.D.', + value: null, + }, + { + x: 1984, + y: 'Neb.', + value: null, + }, + { + x: 1984, + y: 'N.H.', + value: 3.310750005, + }, + { + x: 1984, + y: 'N.J.', + value: 0.079307089, + }, + { + x: 1984, + y: 'N.M', + value: 5.075221033, + }, + { + x: 1984, + y: 'Nev.', + value: null, + }, + { + x: 1984, + y: 'N.Y.', + value: 0.820608653, + }, + { + x: 1984, + y: 'Ohio', + value: 0.093153879, + }, + { + x: 1984, + y: 'Okla.', + value: 0.275117292, + }, + { + x: 1984, + y: 'Ore.', + value: null, + }, + { + x: 1984, + y: 'Pa.', + value: 0.042477773, + }, + { + x: 1984, + y: 'R.I.', + value: null, + }, + { + x: 1984, + y: 'S.C.', + value: null, + }, + { + x: 1984, + y: 'S.D.', + value: null, + }, + { + x: 1984, + y: 'Tenn.', + value: null, + }, + { + x: 1984, + y: 'Texas', + value: 3.336870129, + }, + { + x: 1984, + y: 'Utah', + value: 1.704292992, + }, + { + x: 1984, + y: 'Va.', + value: 0.069989377, + }, + { + x: 1984, + y: 'Vt.', + value: 0.754667145, + }, + { + x: 1984, + y: 'Wash.', + value: 3.909003845, + }, + { + x: 1984, + y: 'Wis.', + value: 0.674001062, + }, + { + x: 1984, + y: 'W.Va.', + value: null, + }, + { + x: 1984, + y: 'Wyo.', + value: null, + }, + { + x: 1985, + y: 'Alaska', + value: null, + }, + { + x: 1985, + y: 'Ala.', + value: null, + }, + { + x: 1985, + y: 'Ark.', + value: null, + }, + { + x: 1985, + y: 'Ariz.', + value: 7.496383297, + }, + { + x: 1985, + y: 'Calif.', + value: 0.955640673, + }, + { + x: 1985, + y: 'Colo.', + value: 0.277996571, + }, + { + x: 1985, + y: 'Conn.', + value: 0.186119228, + }, + { + x: 1985, + y: 'D.C.', + value: 4.386865099, + }, + { + x: 1985, + y: 'Del.', + value: null, + }, + { + x: 1985, + y: 'Fla.', + value: 0.968501835, + }, + { + x: 1985, + y: 'Ga.', + value: 0.131478047, + }, + { + x: 1985, + y: 'Hawaii', + value: 2.281885065, + }, + { + x: 1985, + y: 'Iowa', + value: null, + }, + { + x: 1985, + y: 'Idaho', + value: 6.261209585, + }, + { + x: 1985, + y: 'Ill.', + value: 2.406198437, + }, + { + x: 1985, + y: 'Ind.', + value: 0.055004411, + }, + { + x: 1985, + y: 'Kan.', + value: 0.041107958, + }, + { + x: 1985, + y: 'Ky.', + value: 0.054232744, + }, + { + x: 1985, + y: 'La.', + value: 0.953046788, + }, + { + x: 1985, + y: 'Mass.', + value: 1.37225849, + }, + { + x: 1985, + y: 'Md.', + value: 2.562984223, + }, + { + x: 1985, + y: 'Maine', + value: null, + }, + { + x: 1985, + y: 'Mich.', + value: 0.766890069, + }, + { + x: 1985, + y: 'Minn.', + value: null, + }, + { + x: 1985, + y: 'Mo.', + value: 0.019908152, + }, + { + x: 1985, + y: 'Miss.', + value: 0.038556491, + }, + { + x: 1985, + y: 'Mont.', + value: 20.52255084, + }, + { + x: 1985, + y: 'N.C.', + value: 0.142369516, + }, + { + x: 1985, + y: 'N.D.', + value: 0.149362521, + }, + { + x: 1985, + y: 'Neb.', + value: null, + }, + { + x: 1985, + y: 'N.H.', + value: null, + }, + { + x: 1985, + y: 'N.J.', + value: 0.327991059, + }, + { + x: 1985, + y: 'N.M', + value: 0.273461455, + }, + { + x: 1985, + y: 'Nev.', + value: null, + }, + { + x: 1985, + y: 'N.Y.', + value: 0.93083665, + }, + { + x: 1985, + y: 'Ohio', + value: 0, + }, + { + x: 1985, + y: 'Okla.', + value: null, + }, + { + x: 1985, + y: 'Ore.', + value: 0.186321887, + }, + { + x: 1985, + y: 'Pa.', + value: 0.339479266, + }, + { + x: 1985, + y: 'R.I.', + value: null, + }, + { + x: 1985, + y: 'S.C.', + value: 0.029915417, + }, + { + x: 1985, + y: 'S.D.', + value: null, + }, + { + x: 1985, + y: 'Tenn.', + value: null, + }, + { + x: 1985, + y: 'Texas', + value: 2.55417616, + }, + { + x: 1985, + y: 'Utah', + value: null, + }, + { + x: 1985, + y: 'Va.', + value: 0.481786741, + }, + { + x: 1985, + y: 'Vt.', + value: null, + }, + { + x: 1985, + y: 'Wash.', + value: 1.998778275, + }, + { + x: 1985, + y: 'Wis.', + value: 1.219610154, + }, + { + x: 1985, + y: 'W.Va.', + value: 2.496878901, + }, + { + x: 1985, + y: 'Wyo.', + value: 1.008810955, + }, + { + x: 1986, + y: 'Alaska', + value: null, + }, + { + x: 1986, + y: 'Ala.', + value: 0.024904963, + }, + { + x: 1986, + y: 'Ark.', + value: 12.20993402, + }, + { + x: 1986, + y: 'Ariz.', + value: 7.448132919, + }, + { + x: 1986, + y: 'Calif.', + value: 1.544434459, + }, + { + x: 1986, + y: 'Colo.', + value: 0.153351654, + }, + { + x: 1986, + y: 'Conn.', + value: 0.277154096, + }, + { + x: 1986, + y: 'D.C.', + value: null, + }, + { + x: 1986, + y: 'Del.', + value: 0.156998934, + }, + { + x: 1986, + y: 'Fla.', + value: 3.334088226, + }, + { + x: 1986, + y: 'Ga.', + value: 1.497954326, + }, + { + x: 1986, + y: 'Hawaii', + value: 2.809204452, + }, + { + x: 1986, + y: 'Iowa', + value: 5.095751336, + }, + { + x: 1986, + y: 'Idaho', + value: 0.101523152, + }, + { + x: 1986, + y: 'Ill.', + value: 3.634391456, + }, + { + x: 1986, + y: 'Ind.', + value: 0.694316037, + }, + { + x: 1986, + y: 'Kan.', + value: 4.04847207, + }, + { + x: 1986, + y: 'Ky.', + value: 0.08144806, + }, + { + x: 1986, + y: 'La.', + value: 0.092077894, + }, + { + x: 1986, + y: 'Mass.', + value: 0.62339896, + }, + { + x: 1986, + y: 'Md.', + value: 0.766609638, + }, + { + x: 1986, + y: 'Maine', + value: 1.266278004, + }, + { + x: 1986, + y: 'Mich.', + value: 1.164628259, + }, + { + x: 1986, + y: 'Minn.', + value: 0.850031735, + }, + { + x: 1986, + y: 'Mo.', + value: 0.61304852, + }, + { + x: 1986, + y: 'Miss.', + value: 0.38631741, + }, + { + x: 1986, + y: 'Mont.', + value: 0.248427763, + }, + { + x: 1986, + y: 'N.C.', + value: 0.062463888, + }, + { + x: 1986, + y: 'N.D.', + value: 3.176351008, + }, + { + x: 1986, + y: 'Neb.', + value: 0, + }, + { + x: 1986, + y: 'N.H.', + value: 2.655818281, + }, + { + x: 1986, + y: 'N.J.', + value: 11.6155647, + }, + { + x: 1986, + y: 'N.M', + value: 2.570137705, + }, + { + x: 1986, + y: 'Nev.', + value: 0.293147387, + }, + { + x: 1986, + y: 'N.Y.', + value: 5.28853343, + }, + { + x: 1986, + y: 'Ohio', + value: null, + }, + { + x: 1986, + y: 'Okla.', + value: 0.996846849, + }, + { + x: 1986, + y: 'Ore.', + value: 0.259164136, + }, + { + x: 1986, + y: 'Pa.', + value: 0.228603051, + }, + { + x: 1986, + y: 'R.I.', + value: 0.202101042, + }, + { + x: 1986, + y: 'S.C.', + value: 7.543249443, + }, + { + x: 1986, + y: 'S.D.', + value: null, + }, + { + x: 1986, + y: 'Tenn.', + value: 1.212646566, + }, + { + x: 1986, + y: 'Texas', + value: 2.238025974, + }, + { + x: 1986, + y: 'Utah', + value: 0.774676885, + }, + { + x: 1986, + y: 'Va.', + value: 0.859704922, + }, + { + x: 1986, + y: 'Vt.', + value: null, + }, + { + x: 1986, + y: 'Wash.', + value: 4.722080204, + }, + { + x: 1986, + y: 'Wis.', + value: 5.839362283, + }, + { + x: 1986, + y: 'W.Va.', + value: 0.107666675, + }, + { + x: 1986, + y: 'Wyo.', + value: null, + }, + { + x: 1987, + y: 'Alaska', + value: null, + }, + { + x: 1987, + y: 'Ala.', + value: 0.099407432, + }, + { + x: 1987, + y: 'Ark.', + value: null, + }, + { + x: 1987, + y: 'Ariz.', + value: 0.990047757, + }, + { + x: 1987, + y: 'Calif.', + value: 2.719200496, + }, + { + x: 1987, + y: 'Colo.', + value: 0.275880588, + }, + { + x: 1987, + y: 'Conn.', + value: 0.672381296, + }, + { + x: 1987, + y: 'D.C.', + value: null, + }, + { + x: 1987, + y: 'Del.', + value: 3.088221215, + }, + { + x: 1987, + y: 'Fla.', + value: 0.690697804, + }, + { + x: 1987, + y: 'Ga.', + value: 0.142492047, + }, + { + x: 1987, + y: 'Hawaii', + value: 0.185214682, + }, + { + x: 1987, + y: 'Iowa', + value: null, + }, + { + x: 1987, + y: 'Idaho', + value: null, + }, + { + x: 1987, + y: 'Ill.', + value: 1.641764667, + }, + { + x: 1987, + y: 'Ind.', + value: null, + }, + { + x: 1987, + y: 'Kan.', + value: null, + }, + { + x: 1987, + y: 'Ky.', + value: null, + }, + { + x: 1987, + y: 'La.', + value: null, + }, + { + x: 1987, + y: 'Mass.', + value: 1.086959794, + }, + { + x: 1987, + y: 'Md.', + value: 0.236157722, + }, + { + x: 1987, + y: 'Maine', + value: 0.249202552, + }, + { + x: 1987, + y: 'Mich.', + value: 0.303753592, + }, + { + x: 1987, + y: 'Minn.', + value: 0.651743904, + }, + { + x: 1987, + y: 'Mo.', + value: 3.738879784, + }, + { + x: 1987, + y: 'Miss.', + value: 0.15501761, + }, + { + x: 1987, + y: 'Mont.', + value: 17.12067703, + }, + { + x: 1987, + y: 'N.C.', + value: 0.21602958, + }, + { + x: 1987, + y: 'N.D.', + value: 0, + }, + { + x: 1987, + y: 'Neb.', + value: null, + }, + { + x: 1987, + y: 'N.H.', + value: 16.25750409, + }, + { + x: 1987, + y: 'N.J.', + value: 0.505683559, + }, + { + x: 1987, + y: 'N.M', + value: 10.53453011, + }, + { + x: 1987, + y: 'Nev.', + value: 0.186042704, + }, + { + x: 1987, + y: 'N.Y.', + value: 2.430145983, + }, + { + x: 1987, + y: 'Ohio', + value: 0.009260501, + }, + { + x: 1987, + y: 'Okla.', + value: 0.126300221, + }, + { + x: 1987, + y: 'Ore.', + value: 2.991284782, + }, + { + x: 1987, + y: 'Pa.', + value: 0.253255344, + }, + { + x: 1987, + y: 'R.I.', + value: 0.20072099, + }, + { + x: 1987, + y: 'S.C.', + value: 0.058614998, + }, + { + x: 1987, + y: 'S.D.', + value: null, + }, + { + x: 1987, + y: 'Tenn.', + value: null, + }, + { + x: 1987, + y: 'Texas', + value: 2.501946658, + }, + { + x: 1987, + y: 'Utah', + value: null, + }, + { + x: 1987, + y: 'Va.', + value: 0.016564768, + }, + { + x: 1987, + y: 'Vt.', + value: 4.001724379, + }, + { + x: 1987, + y: 'Wash.', + value: 1.034506615, + }, + { + x: 1987, + y: 'Wis.', + value: 3.027545689, + }, + { + x: 1987, + y: 'W.Va.', + value: null, + }, + { + x: 1987, + y: 'Wyo.', + value: null, + }, + { + x: 1988, + y: 'Alaska', + value: 0.182762232, + }, + { + x: 1988, + y: 'Ala.', + value: 0.024812529, + }, + { + x: 1988, + y: 'Ark.', + value: null, + }, + { + x: 1988, + y: 'Ariz.', + value: 0.082822937, + }, + { + x: 1988, + y: 'Calif.', + value: 2.515558472, + }, + { + x: 1988, + y: 'Colo.', + value: 3.541100269, + }, + { + x: 1988, + y: 'Conn.', + value: 0.517755512, + }, + { + x: 1988, + y: 'D.C.', + value: null, + }, + { + x: 1988, + y: 'Del.', + value: null, + }, + { + x: 1988, + y: 'Fla.', + value: 1.321441416, + }, + { + x: 1988, + y: 'Ga.', + value: null, + }, + { + x: 1988, + y: 'Hawaii', + value: 1.827171502, + }, + { + x: 1988, + y: 'Iowa', + value: null, + }, + { + x: 1988, + y: 'Idaho', + value: null, + }, + { + x: 1988, + y: 'Ill.', + value: 0.446984877, + }, + { + x: 1988, + y: 'Ind.', + value: 1.03191832, + }, + { + x: 1988, + y: 'Kan.', + value: 0.040439186, + }, + { + x: 1988, + y: 'Ky.', + value: 0.951783724, + }, + { + x: 1988, + y: 'La.', + value: null, + }, + { + x: 1988, + y: 'Mass.', + value: 0.083118914, + }, + { + x: 1988, + y: 'Md.', + value: 0.317305795, + }, + { + x: 1988, + y: 'Maine', + value: 0.655758668, + }, + { + x: 1988, + y: 'Mich.', + value: 0.335015797, + }, + { + x: 1988, + y: 'Minn.', + value: 0.484087692, + }, + { + x: 1988, + y: 'Mo.', + value: 0.41210166, + }, + { + x: 1988, + y: 'Miss.', + value: 1.243071334, + }, + { + x: 1988, + y: 'Mont.', + value: 9.629381369, + }, + { + x: 1988, + y: 'N.C.', + value: 0.030462455, + }, + { + x: 1988, + y: 'N.D.', + value: null, + }, + { + x: 1988, + y: 'Neb.', + value: null, + }, + { + x: 1988, + y: 'N.H.', + value: 10.23066992, + }, + { + x: 1988, + y: 'N.J.', + value: 4.25829938, + }, + { + x: 1988, + y: 'N.M', + value: null, + }, + { + x: 1988, + y: 'Nev.', + value: null, + }, + { + x: 1988, + y: 'N.Y.', + value: 0.511591837, + }, + { + x: 1988, + y: 'Ohio', + value: 0.886490685, + }, + { + x: 1988, + y: 'Okla.', + value: 0.253943505, + }, + { + x: 1988, + y: 'Ore.', + value: 1.290056709, + }, + { + x: 1988, + y: 'Pa.', + value: 4.390697587, + }, + { + x: 1988, + y: 'R.I.', + value: null, + }, + { + x: 1988, + y: 'S.C.', + value: null, + }, + { + x: 1988, + y: 'S.D.', + value: null, + }, + { + x: 1988, + y: 'Tenn.', + value: 0.020599681, + }, + { + x: 1988, + y: 'Texas', + value: 0.083299939, + }, + { + x: 1988, + y: 'Utah', + value: null, + }, + { + x: 1988, + y: 'Va.', + value: 3.463913052, + }, + { + x: 1988, + y: 'Vt.', + value: null, + }, + { + x: 1988, + y: 'Wash.', + value: 0.147482806, + }, + { + x: 1988, + y: 'Wis.', + value: null, + }, + { + x: 1988, + y: 'W.Va.', + value: 0.332121459, + }, + { + x: 1988, + y: 'Wyo.', + value: null, + }, + { + x: 1989, + y: 'Alaska', + value: 0, + }, + { + x: 1989, + y: 'Ala.', + value: 1.509681638, + }, + { + x: 1989, + y: 'Ark.', + value: 0.212700337, + }, + { + x: 1989, + y: 'Ariz.', + value: 3.956097683, + }, + { + x: 1989, + y: 'Calif.', + value: 7.3655862, + }, + { + x: 1989, + y: 'Colo.', + value: 3.035459632, + }, + { + x: 1989, + y: 'Conn.', + value: 6.540687947, + }, + { + x: 1989, + y: 'D.C.', + value: 6.755643434, + }, + { + x: 1989, + y: 'Del.', + value: 5.404042224, + }, + { + x: 1989, + y: 'Fla.', + value: 1.569030461, + }, + { + x: 1989, + y: 'Ga.', + value: 0.262417925, + }, + { + x: 1989, + y: 'Hawaii', + value: 2.797255802, + }, + { + x: 1989, + y: 'Iowa', + value: 0.432159121, + }, + { + x: 1989, + y: 'Idaho', + value: 0.794636995, + }, + { + x: 1989, + y: 'Ill.', + value: 22.31728478, + }, + { + x: 1989, + y: 'Ind.', + value: 2.020144083, + }, + { + x: 1989, + y: 'Kan.', + value: 4.762723535, + }, + { + x: 1989, + y: 'Ky.', + value: 1.166799085, + }, + { + x: 1989, + y: 'La.', + value: 2.796226421, + }, + { + x: 1989, + y: 'Mass.', + value: 1.795085952, + }, + { + x: 1989, + y: 'Md.', + value: 2.509689493, + }, + { + x: 1989, + y: 'Maine', + value: null, + }, + { + x: 1989, + y: 'Mich.', + value: 4.227944519, + }, + { + x: 1989, + y: 'Minn.', + value: 0.15999638, + }, + { + x: 1989, + y: 'Mo.', + value: 9.947092801, + }, + { + x: 1989, + y: 'Miss.', + value: 0.038861876, + }, + { + x: 1989, + y: 'Mont.', + value: 1.626901441, + }, + { + x: 1989, + y: 'N.C.', + value: 2.941781244, + }, + { + x: 1989, + y: 'N.D.', + value: null, + }, + { + x: 1989, + y: 'Neb.', + value: 6.652369352, + }, + { + x: 1989, + y: 'N.H.', + value: 1.442413446, + }, + { + x: 1989, + y: 'N.J.', + value: 5.31681765, + }, + { + x: 1989, + y: 'N.M', + value: 1.386075486, + }, + { + x: 1989, + y: 'Nev.', + value: 0.99847483, + }, + { + x: 1989, + y: 'N.Y.', + value: 1.617524404, + }, + { + x: 1989, + y: 'Ohio', + value: 25.09423012, + }, + { + x: 1989, + y: 'Okla.', + value: 4.037404807, + }, + { + x: 1989, + y: 'Ore.', + value: 1.442483097, + }, + { + x: 1989, + y: 'Pa.', + value: 1.986257288, + }, + { + x: 1989, + y: 'R.I.', + value: 3.886537036, + }, + { + x: 1989, + y: 'S.C.', + value: 0.51624701, + }, + { + x: 1989, + y: 'S.D.', + value: null, + }, + { + x: 1989, + y: 'Tenn.', + value: 2.850004665, + }, + { + x: 1989, + y: 'Texas', + value: 18.42049956, + }, + { + x: 1989, + y: 'Utah', + value: 6.907159648, + }, + { + x: 1989, + y: 'Va.', + value: 0.404049677, + }, + { + x: 1989, + y: 'Vt.', + value: 0.177696274, + }, + { + x: 1989, + y: 'Wash.', + value: 1.068487589, + }, + { + x: 1989, + y: 'Wis.', + value: 6.459830789, + }, + { + x: 1989, + y: 'W.Va.', + value: 2.955153593, + }, + { + x: 1989, + y: 'Wyo.', + value: null, + }, + { + x: 1990, + y: 'Alaska', + value: 4.879900233, + }, + { + x: 1990, + y: 'Ala.', + value: 0.691348636, + }, + { + x: 1990, + y: 'Ark.', + value: 1.739804955, + }, + { + x: 1990, + y: 'Ariz.', + value: 7.735952664, + }, + { + x: 1990, + y: 'Calif.', + value: 32.03656668, + }, + { + x: 1990, + y: 'Colo.', + value: 4.202419989, + }, + { + x: 1990, + y: 'Conn.', + value: 5.710871342, + }, + { + x: 1990, + y: 'D.C.', + value: 3.634435283, + }, + { + x: 1990, + y: 'Del.', + value: 1.344152266, + }, + { + x: 1990, + y: 'Fla.', + value: 2.846553066, + }, + { + x: 1990, + y: 'Ga.', + value: 5.497034826, + }, + { + x: 1990, + y: 'Hawaii', + value: 3.682113282, + }, + { + x: 1990, + y: 'Iowa', + value: 0.934909447, + }, + { + x: 1990, + y: 'Idaho', + value: 2.173088472, + }, + { + x: 1990, + y: 'Ill.', + value: 9.054146415, + }, + { + x: 1990, + y: 'Ind.', + value: 4.480191615, + }, + { + x: 1990, + y: 'Kan.', + value: 9.470654874, + }, + { + x: 1990, + y: 'Ky.', + value: 1.136964111, + }, + { + x: 1990, + y: 'La.', + value: 0, + }, + { + x: 1990, + y: 'Mass.', + value: 0.531328542, + }, + { + x: 1990, + y: 'Md.', + value: 4.291872319, + }, + { + x: 1990, + y: 'Maine', + value: 0.324749395, + }, + { + x: 1990, + y: 'Mich.', + value: 4.048835616, + }, + { + x: 1990, + y: 'Minn.', + value: 9.203033265, + }, + { + x: 1990, + y: 'Mo.', + value: 1.033364009, + }, + { + x: 1990, + y: 'Miss.', + value: 0.504091478, + }, + { + x: 1990, + y: 'Mont.', + value: null, + }, + { + x: 1990, + y: 'N.C.', + value: 0.675268487, + }, + { + x: 1990, + y: 'N.D.', + value: null, + }, + { + x: 1990, + y: 'Neb.', + value: 4.994752349, + }, + { + x: 1990, + y: 'N.H.', + value: null, + }, + { + x: 1990, + y: 'N.J.', + value: 2.460400752, + }, + { + x: 1990, + y: 'N.M', + value: 6.63786316, + }, + { + x: 1990, + y: 'Nev.', + value: 17.69483778, + }, + { + x: 1990, + y: 'N.Y.', + value: 4.4726134, + }, + { + x: 1990, + y: 'Ohio', + value: 5.218994341, + }, + { + x: 1990, + y: 'Okla.', + value: 5.621144395, + }, + { + x: 1990, + y: 'Ore.', + value: 1.363457589, + }, + { + x: 1990, + y: 'Pa.', + value: 3.763662494, + }, + { + x: 1990, + y: 'R.I.', + value: 2.982122178, + }, + { + x: 1990, + y: 'S.C.', + value: 0.114248012, + }, + { + x: 1990, + y: 'S.D.', + value: 2.295219774, + }, + { + x: 1990, + y: 'Tenn.', + value: 1.961388434, + }, + { + x: 1990, + y: 'Texas', + value: 22.85311596, + }, + { + x: 1990, + y: 'Utah', + value: 8.491107154, + }, + { + x: 1990, + y: 'Va.', + value: 1.206392141, + }, + { + x: 1990, + y: 'Vt.', + value: null, + }, + { + x: 1990, + y: 'Wash.', + value: 6.710118594, + }, + { + x: 1990, + y: 'Wis.', + value: 13.3956916, + }, + { + x: 1990, + y: 'W.Va.', + value: 0.33471907, + }, + { + x: 1990, + y: 'Wyo.', + value: null, + }, + { + x: 1991, + y: 'Alaska', + value: 0.175379214, + }, + { + x: 1991, + y: 'Ala.', + value: 0.024395266, + }, + { + x: 1991, + y: 'Ark.', + value: null, + }, + { + x: 1991, + y: 'Ariz.', + value: 9.027138429, + }, + { + x: 1991, + y: 'Calif.', + value: 6.442246751, + }, + { + x: 1991, + y: 'Colo.', + value: 0.324759774, + }, + { + x: 1991, + y: 'Conn.', + value: 0.6963588, + }, + { + x: 1991, + y: 'D.C.', + value: null, + }, + { + x: 1991, + y: 'Del.', + value: 2.781519002, + }, + { + x: 1991, + y: 'Fla.', + value: 2.221424737, + }, + { + x: 1991, + y: 'Ga.', + value: 0.225462028, + }, + { + x: 1991, + y: 'Hawaii', + value: 1.935335174, + }, + { + x: 1991, + y: 'Iowa', + value: 0.57191613, + }, + { + x: 1991, + y: 'Idaho', + value: 42.15819213, + }, + { + x: 1991, + y: 'Ill.', + value: 0.051862898, + }, + { + x: 1991, + y: 'Ind.', + value: 0.089025188, + }, + { + x: 1991, + y: 'Kan.', + value: 0.360184126, + }, + { + x: 1991, + y: 'Ky.', + value: 0.698487613, + }, + { + x: 1991, + y: 'La.', + value: null, + }, + { + x: 1991, + y: 'Mass.', + value: 0.714467298, + }, + { + x: 1991, + y: 'Md.', + value: 3.677345967, + }, + { + x: 1991, + y: 'Maine', + value: 0.565848154, + }, + { + x: 1991, + y: 'Mich.', + value: 0.37232276, + }, + { + x: 1991, + y: 'Minn.', + value: 0.607990481, + }, + { + x: 1991, + y: 'Mo.', + value: null, + }, + { + x: 1991, + y: 'Miss.', + value: null, + }, + { + x: 1991, + y: 'Mont.', + value: null, + }, + { + x: 1991, + y: 'N.C.', + value: 0.663298095, + }, + { + x: 1991, + y: 'N.D.', + value: null, + }, + { + x: 1991, + y: 'Neb.', + value: 0, + }, + { + x: 1991, + y: 'N.H.', + value: null, + }, + { + x: 1991, + y: 'N.J.', + value: 13.03956812, + }, + { + x: 1991, + y: 'N.M', + value: 4.950797432, + }, + { + x: 1991, + y: 'Nev.', + value: 1.465855971, + }, + { + x: 1991, + y: 'N.Y.', + value: 7.76382521, + }, + { + x: 1991, + y: 'Ohio', + value: 0.109631472, + }, + { + x: 1991, + y: 'Okla.', + value: null, + }, + { + x: 1991, + y: 'Ore.', + value: 2.800061601, + }, + { + x: 1991, + y: 'Pa.', + value: 11.70072451, + }, + { + x: 1991, + y: 'R.I.', + value: 0.395785283, + }, + { + x: 1991, + y: 'S.C.', + value: 0.364104454, + }, + { + x: 1991, + y: 'S.D.', + value: null, + }, + { + x: 1991, + y: 'Tenn.', + value: 0.201345512, + }, + { + x: 1991, + y: 'Texas', + value: 1.230026086, + }, + { + x: 1991, + y: 'Utah', + value: 12.36107834, + }, + { + x: 1991, + y: 'Va.', + value: 0.333268954, + }, + { + x: 1991, + y: 'Vt.', + value: 0.703474814, + }, + { + x: 1991, + y: 'Wash.', + value: 1.532148048, + }, + { + x: 1991, + y: 'Wis.', + value: 0.141005567, + }, + { + x: 1991, + y: 'W.Va.', + value: null, + }, + { + x: 1991, + y: 'Wyo.', + value: 0.653224753, + }, + { + x: 1992, + y: 'Alaska', + value: 0.679421676, + }, + { + x: 1992, + y: 'Ala.', + value: null, + }, + { + x: 1992, + y: 'Ark.', + value: null, + }, + { + x: 1992, + y: 'Ariz.', + value: 0, + }, + { + x: 1992, + y: 'Calif.', + value: 0.196935179, + }, + { + x: 1992, + y: 'Colo.', + value: 0.629301598, + }, + { + x: 1992, + y: 'Conn.', + value: 0.060592987, + }, + { + x: 1992, + y: 'D.C.', + value: 0.334691624, + }, + { + x: 1992, + y: 'Del.', + value: 0.431701263, + }, + { + x: 1992, + y: 'Fla.', + value: 0.300354132, + }, + { + x: 1992, + y: 'Ga.', + value: 0.044006318, + }, + { + x: 1992, + y: 'Hawaii', + value: 4.229194735, + }, + { + x: 1992, + y: 'Iowa', + value: null, + }, + { + x: 1992, + y: 'Idaho', + value: null, + }, + { + x: 1992, + y: 'Ill.', + value: 0.076961334, + }, + { + x: 1992, + y: 'Ind.', + value: 0.211470625, + }, + { + x: 1992, + y: 'Kan.', + value: 0.078976652, + }, + { + x: 1992, + y: 'Ky.', + value: 7.435992701, + }, + { + x: 1992, + y: 'La.', + value: null, + }, + { + x: 1992, + y: 'Mass.', + value: 0.348333283, + }, + { + x: 1992, + y: 'Md.', + value: 0.22342429, + }, + { + x: 1992, + y: 'Maine', + value: 0.242226938, + }, + { + x: 1992, + y: 'Mich.', + value: 0.147693892, + }, + { + x: 1992, + y: 'Minn.', + value: 0.222441104, + }, + { + x: 1992, + y: 'Mo.', + value: 0.019167733, + }, + { + x: 1992, + y: 'Miss.', + value: 0.03811362, + }, + { + x: 1992, + y: 'Mont.', + value: null, + }, + { + x: 1992, + y: 'N.C.', + value: 0.362465192, + }, + { + x: 1992, + y: 'N.D.', + value: null, + }, + { + x: 1992, + y: 'Neb.', + value: null, + }, + { + x: 1992, + y: 'N.H.', + value: 1.431403563, + }, + { + x: 1992, + y: 'N.J.', + value: 0.406065193, + }, + { + x: 1992, + y: 'N.M', + value: 0.062678556, + }, + { + x: 1992, + y: 'Nev.', + value: 0.073999143, + }, + { + x: 1992, + y: 'N.Y.', + value: 0.613811201, + }, + { + x: 1992, + y: 'Ohio', + value: 0.045333254, + }, + { + x: 1992, + y: 'Okla.', + value: 0.248407321, + }, + { + x: 1992, + y: 'Ore.', + value: 0.300826772, + }, + { + x: 1992, + y: 'Pa.', + value: 0.08299134, + }, + { + x: 1992, + y: 'R.I.', + value: 2.271423224, + }, + { + x: 1992, + y: 'S.C.', + value: 0.801002302, + }, + { + x: 1992, + y: 'S.D.', + value: null, + }, + { + x: 1992, + y: 'Tenn.', + value: null, + }, + { + x: 1992, + y: 'Texas', + value: 5.641975124, + }, + { + x: 1992, + y: 'Utah', + value: null, + }, + { + x: 1992, + y: 'Va.', + value: 0.233852231, + }, + { + x: 1992, + y: 'Vt.', + value: null, + }, + { + x: 1992, + y: 'Wash.', + value: null, + }, + { + x: 1992, + y: 'Wis.', + value: null, + }, + { + x: 1992, + y: 'W.Va.', + value: null, + }, + { + x: 1992, + y: 'Wyo.', + value: 0.214476752, + }, + { + x: 1993, + y: 'Alaska', + value: null, + }, + { + x: 1993, + y: 'Ala.', + value: 0.023729285, + }, + { + x: 1993, + y: 'Ark.', + value: null, + }, + { + x: 1993, + y: 'Ariz.', + value: 0.073792751, + }, + { + x: 1993, + y: 'Calif.', + value: 0.201439313, + }, + { + x: 1993, + y: 'Colo.', + value: 0, + }, + { + x: 1993, + y: 'Conn.', + value: 0.181314074, + }, + { + x: 1993, + y: 'D.C.', + value: null, + }, + { + x: 1993, + y: 'Del.', + value: 0.283134526, + }, + { + x: 1993, + y: 'Fla.', + value: 0.193865451, + }, + { + x: 1993, + y: 'Ga.', + value: 0.014330261, + }, + { + x: 1993, + y: 'Hawaii', + value: 1.278949011, + }, + { + x: 1993, + y: 'Iowa', + value: null, + }, + { + x: 1993, + y: 'Idaho', + value: null, + }, + { + x: 1993, + y: 'Ill.', + value: 0.033870809, + }, + { + x: 1993, + y: 'Ind.', + value: 0.017424581, + }, + { + x: 1993, + y: 'Kan.', + value: null, + }, + { + x: 1993, + y: 'Ky.', + value: null, + }, + { + x: 1993, + y: 'La.', + value: 0.023167304, + }, + { + x: 1993, + y: 'Mass.', + value: 0.297001816, + }, + { + x: 1993, + y: 'Md.', + value: 0.02011308, + }, + { + x: 1993, + y: 'Maine', + value: 0.16099145, + }, + { + x: 1993, + y: 'Mich.', + value: 0.073374385, + }, + { + x: 1993, + y: 'Minn.', + value: null, + }, + { + x: 1993, + y: 'Mo.', + value: 0, + }, + { + x: 1993, + y: 'Miss.', + value: null, + }, + { + x: 1993, + y: 'Mont.', + value: null, + }, + { + x: 1993, + y: 'N.C.', + value: null, + }, + { + x: 1993, + y: 'N.D.', + value: null, + }, + { + x: 1993, + y: 'Neb.', + value: null, + }, + { + x: 1993, + y: 'N.H.', + value: 0.177076084, + }, + { + x: 1993, + y: 'N.J.', + value: 0.062901666, + }, + { + x: 1993, + y: 'N.M', + value: null, + }, + { + x: 1993, + y: 'Nev.', + value: 0.070860925, + }, + { + x: 1993, + y: 'N.Y.', + value: 0, + }, + { + x: 1993, + y: 'Ohio', + value: 0.099088922, + }, + { + x: 1993, + y: 'Okla.', + value: null, + }, + { + x: 1993, + y: 'Ore.', + value: null, + }, + { + x: 1993, + y: 'Pa.', + value: null, + }, + { + x: 1993, + y: 'R.I.', + value: 0.098511297, + }, + { + x: 1993, + y: 'S.C.', + value: null, + }, + { + x: 1993, + y: 'S.D.', + value: null, + }, + { + x: 1993, + y: 'Tenn.', + value: 0, + }, + { + x: 1993, + y: 'Texas', + value: 0.055061192, + }, + { + x: 1993, + y: 'Utah', + value: null, + }, + { + x: 1993, + y: 'Va.', + value: null, + }, + { + x: 1993, + y: 'Vt.', + value: 5.365661153, + }, + { + x: 1993, + y: 'Wash.', + value: null, + }, + { + x: 1993, + y: 'Wis.', + value: 0, + }, + { + x: 1993, + y: 'W.Va.', + value: null, + }, + { + x: 1993, + y: 'Wyo.', + value: null, + }, + { + x: 1994, + y: 'Alaska', + value: 2.652045058, + }, + { + x: 1994, + y: 'Ala.', + value: null, + }, + { + x: 1994, + y: 'Ark.', + value: null, + }, + { + x: 1994, + y: 'Ariz.', + value: 0.212009689, + }, + { + x: 1994, + y: 'Calif.', + value: 0.203275047, + }, + { + x: 1994, + y: 'Colo.', + value: 0.537032701, + }, + { + x: 1994, + y: 'Conn.', + value: 0.12062286, + }, + { + x: 1994, + y: 'D.C.', + value: null, + }, + { + x: 1994, + y: 'Del.', + value: null, + }, + { + x: 1994, + y: 'Fla.', + value: 0.147477668, + }, + { + x: 1994, + y: 'Ga.', + value: 0.041916038, + }, + { + x: 1994, + y: 'Hawaii', + value: null, + }, + { + x: 1994, + y: 'Iowa', + value: 0.245549761, + }, + { + x: 1994, + y: 'Idaho', + value: 0.174651134, + }, + { + x: 1994, + y: 'Ill.', + value: 0.151100706, + }, + { + x: 1994, + y: 'Ind.', + value: 0.017260646, + }, + { + x: 1994, + y: 'Kan.', + value: 0.038751985, + }, + { + x: 1994, + y: 'Ky.', + value: null, + }, + { + x: 1994, + y: 'La.', + value: 0.023001826, + }, + { + x: 1994, + y: 'Mass.', + value: 0.098437453, + }, + { + x: 1994, + y: 'Md.', + value: 0.099540917, + }, + { + x: 1994, + y: 'Maine', + value: 0.241417216, + }, + { + x: 1994, + y: 'Mich.', + value: 0.156286841, + }, + { + x: 1994, + y: 'Minn.', + value: null, + }, + { + x: 1994, + y: 'Mo.', + value: 0.807588022, + }, + { + x: 1994, + y: 'Miss.', + value: null, + }, + { + x: 1994, + y: 'Mont.', + value: null, + }, + { + x: 1994, + y: 'N.C.', + value: 0.041739723, + }, + { + x: 1994, + y: 'N.D.', + value: null, + }, + { + x: 1994, + y: 'Neb.', + value: 0, + }, + { + x: 1994, + y: 'N.H.', + value: 0, + }, + { + x: 1994, + y: 'N.J.', + value: 1.684487715, + }, + { + x: 1994, + y: 'N.M', + value: null, + }, + { + x: 1994, + y: 'Nev.', + value: null, + }, + { + x: 1994, + y: 'N.Y.', + value: 0.303367323, + }, + { + x: 1994, + y: 'Ohio', + value: 0.044833182, + }, + { + x: 1994, + y: 'Okla.', + value: null, + }, + { + x: 1994, + y: 'Ore.', + value: null, + }, + { + x: 1994, + y: 'Pa.', + value: 0.057537163, + }, + { + x: 1994, + y: 'R.I.', + value: 0.689003504, + }, + { + x: 1994, + y: 'S.C.', + value: null, + }, + { + x: 1994, + y: 'S.D.', + value: null, + }, + { + x: 1994, + y: 'Tenn.', + value: 0.516110484, + }, + { + x: 1994, + y: 'Texas', + value: 0.086188034, + }, + { + x: 1994, + y: 'Utah', + value: 7.804346562, + }, + { + x: 1994, + y: 'Va.', + value: 0.030334564, + }, + { + x: 1994, + y: 'Vt.', + value: 0.171280976, + }, + { + x: 1994, + y: 'Wash.', + value: null, + }, + { + x: 1994, + y: 'Wis.', + value: 0.038958423, + }, + { + x: 1994, + y: 'W.Va.', + value: 1.97756453, + }, + { + x: 1994, + y: 'Wyo.', + value: null, + }, + { + x: 1995, + y: 'Alaska', + value: null, + }, + { + x: 1995, + y: 'Ala.', + value: null, + }, + { + x: 1995, + y: 'Ark.', + value: 0.078883048, + }, + { + x: 1995, + y: 'Ariz.', + value: 0.270727641, + }, + { + x: 1995, + y: 'Calif.', + value: 0.119886744, + }, + { + x: 1995, + y: 'Colo.', + value: 0.679444935, + }, + { + x: 1995, + y: 'Conn.', + value: 0.030082933, + }, + { + x: 1995, + y: 'D.C.', + value: null, + }, + { + x: 1995, + y: 'Del.', + value: null, + }, + { + x: 1995, + y: 'Fla.', + value: 0.061907259, + }, + { + x: 1995, + y: 'Ga.', + value: 0.068227596, + }, + { + x: 1995, + y: 'Hawaii', + value: 0, + }, + { + x: 1995, + y: 'Iowa', + value: null, + }, + { + x: 1995, + y: 'Idaho', + value: 0.33975412, + }, + { + x: 1995, + y: 'Ill.', + value: 0.041637392, + }, + { + x: 1995, + y: 'Ind.', + value: null, + }, + { + x: 1995, + y: 'Kan.', + value: 0.038446648, + }, + { + x: 1995, + y: 'Ky.', + value: null, + }, + { + x: 1995, + y: 'La.', + value: 0.411073498, + }, + { + x: 1995, + y: 'Mass.', + value: 0.081414065, + }, + { + x: 1995, + y: 'Md.', + value: 0, + }, + { + x: 1995, + y: 'Maine', + value: null, + }, + { + x: 1995, + y: 'Mich.', + value: 0.041338495, + }, + { + x: 1995, + y: 'Minn.', + value: null, + }, + { + x: 1995, + y: 'Mo.', + value: 0, + }, + { + x: 1995, + y: 'Miss.', + value: null, + }, + { + x: 1995, + y: 'Mont.', + value: null, + }, + { + x: 1995, + y: 'N.C.', + value: null, + }, + { + x: 1995, + y: 'N.D.', + value: null, + }, + { + x: 1995, + y: 'Neb.', + value: null, + }, + { + x: 1995, + y: 'N.H.', + value: null, + }, + { + x: 1995, + y: 'N.J.', + value: 0.049485095, + }, + { + x: 1995, + y: 'N.M', + value: 1.801912818, + }, + { + x: 1995, + y: 'Nev.', + value: 0.063227991, + }, + { + x: 1995, + y: 'N.Y.', + value: 0.010796744, + }, + { + x: 1995, + y: 'Ohio', + value: 0.017852758, + }, + { + x: 1995, + y: 'Okla.', + value: null, + }, + { + x: 1995, + y: 'Ore.', + value: 0.094210187, + }, + { + x: 1995, + y: 'Pa.', + value: 0.008197794, + }, + { + x: 1995, + y: 'R.I.', + value: 0.491641118, + }, + { + x: 1995, + y: 'S.C.', + value: null, + }, + { + x: 1995, + y: 'S.D.', + value: null, + }, + { + x: 1995, + y: 'Tenn.', + value: null, + }, + { + x: 1995, + y: 'Texas', + value: 0.068569918, + }, + { + x: 1995, + y: 'Utah', + value: 0, + }, + { + x: 1995, + y: 'Va.', + value: null, + }, + { + x: 1995, + y: 'Vt.', + value: null, + }, + { + x: 1995, + y: 'Wash.', + value: 0.401384631, + }, + { + x: 1995, + y: 'Wis.', + value: 0, + }, + { + x: 1995, + y: 'W.Va.', + value: null, + }, + { + x: 1995, + y: 'Wyo.', + value: null, + }, + { + x: 1996, + y: 'Alaska', + value: 11.17375351, + }, + { + x: 1996, + y: 'Ala.', + value: null, + }, + { + x: 1996, + y: 'Ark.', + value: null, + }, + { + x: 1996, + y: 'Ariz.', + value: 0.174408211, + }, + { + x: 1996, + y: 'Calif.', + value: 0.140542282, + }, + { + x: 1996, + y: 'Colo.', + value: 0.178572704, + }, + { + x: 1996, + y: 'Conn.', + value: 0.029969865, + }, + { + x: 1996, + y: 'D.C.', + value: 0, + }, + { + x: 1996, + y: 'Del.', + value: 0.134956955, + }, + { + x: 1996, + y: 'Fla.', + value: 0, + }, + { + x: 1996, + y: 'Ga.', + value: 0.013331433, + }, + { + x: 1996, + y: 'Hawaii', + value: 2.824495018, + }, + { + x: 1996, + y: 'Iowa', + value: 0, + }, + { + x: 1996, + y: 'Idaho', + value: 0.16623957, + }, + { + x: 1996, + y: 'Ill.', + value: 0.016526198, + }, + { + x: 1996, + y: 'Ind.', + value: null, + }, + { + x: 1996, + y: 'Kan.', + value: 0.038247441, + }, + { + x: 1996, + y: 'Ky.', + value: null, + }, + { + x: 1996, + y: 'La.', + value: null, + }, + { + x: 1996, + y: 'Mass.', + value: 0.194182424, + }, + { + x: 1996, + y: 'Md.', + value: 0.078247476, + }, + { + x: 1996, + y: 'Maine', + value: 0, + }, + { + x: 1996, + y: 'Mich.', + value: 0.020494649, + }, + { + x: 1996, + y: 'Minn.', + value: 0.381936362, + }, + { + x: 1996, + y: 'Mo.', + value: 0.036821881, + }, + { + x: 1996, + y: 'Miss.', + value: null, + }, + { + x: 1996, + y: 'Mont.', + value: null, + }, + { + x: 1996, + y: 'N.C.', + value: 0.053328569, + }, + { + x: 1996, + y: 'N.D.', + value: null, + }, + { + x: 1996, + y: 'Neb.', + value: null, + }, + { + x: 1996, + y: 'N.H.', + value: null, + }, + { + x: 1996, + y: 'N.J.', + value: 0, + }, + { + x: 1996, + y: 'N.M', + value: 0.970139118, + }, + { + x: 1996, + y: 'Nev.', + value: 0.24004993, + }, + { + x: 1996, + y: 'N.Y.', + value: null, + }, + { + x: 1996, + y: 'Ohio', + value: 0.05336736, + }, + { + x: 1996, + y: 'Okla.', + value: null, + }, + { + x: 1996, + y: 'Ore.', + value: 0.338762672, + }, + { + x: 1996, + y: 'Pa.', + value: 0.098195944, + }, + { + x: 1996, + y: 'R.I.', + value: null, + }, + { + x: 1996, + y: 'S.C.', + value: null, + }, + { + x: 1996, + y: 'S.D.', + value: null, + }, + { + x: 1996, + y: 'Tenn.', + value: 0.036923238, + }, + { + x: 1996, + y: 'Texas', + value: 0.139604563, + }, + { + x: 1996, + y: 'Utah', + value: 5.754418813, + }, + { + x: 1996, + y: 'Va.', + value: 0.014812875, + }, + { + x: 1996, + y: 'Vt.', + value: 0.168434953, + }, + { + x: 1996, + y: 'Wash.', + value: 0.915659994, + }, + { + x: 1996, + y: 'Wis.', + value: 0.01912051, + }, + { + x: 1996, + y: 'W.Va.', + value: null, + }, + { + x: 1996, + y: 'Wyo.', + value: 0.204847931, + }, + { + x: 1997, + y: 'Alaska', + value: 0.163140653, + }, + { + x: 1997, + y: 'Ala.', + value: 0.137364681, + }, + { + x: 1997, + y: 'Ark.', + value: 0.115336263, + }, + { + x: 1997, + y: 'Ariz.', + value: 0.189994068, + }, + { + x: 1997, + y: 'Calif.', + value: 0.107738685, + }, + { + x: 1997, + y: 'Colo.', + value: 0.721699488, + }, + { + x: 1997, + y: 'Conn.', + value: 0, + }, + { + x: 1997, + y: 'D.C.', + value: 0.35227641, + }, + { + x: 1997, + y: 'Del.', + value: null, + }, + { + x: 1997, + y: 'Fla.', + value: 0.052679046, + }, + { + x: 1997, + y: 'Ga.', + value: 0, + }, + { + x: 1997, + y: 'Hawaii', + value: 0.495196593, + }, + { + x: 1997, + y: 'Iowa', + value: 0.276709468, + }, + { + x: 1997, + y: 'Idaho', + value: 6.593299254, + }, + { + x: 1997, + y: 'Ill.', + value: 0.073856971, + }, + { + x: 1997, + y: 'Ind.', + value: null, + }, + { + x: 1997, + y: 'Kan.', + value: null, + }, + { + x: 1997, + y: 'Ky.', + value: null, + }, + { + x: 1997, + y: 'La.', + value: null, + }, + { + x: 1997, + y: 'Mass.', + value: 0.86732247, + }, + { + x: 1997, + y: 'Md.', + value: 0.504137026, + }, + { + x: 1997, + y: 'Maine', + value: 0.318782506, + }, + { + x: 1997, + y: 'Mich.', + value: 0.081557329, + }, + { + x: 1997, + y: 'Minn.', + value: 0.356888686, + }, + { + x: 1997, + y: 'Mo.', + value: 0.05473261, + }, + { + x: 1997, + y: 'Miss.', + value: 0.144040124, + }, + { + x: 1997, + y: 'Mont.', + value: null, + }, + { + x: 1997, + y: 'N.C.', + value: 0.026120487, + }, + { + x: 1997, + y: 'N.D.', + value: 0.153913402, + }, + { + x: 1997, + y: 'Neb.', + value: 0.05929728, + }, + { + x: 1997, + y: 'N.H.', + value: 1.933707464, + }, + { + x: 1997, + y: 'N.J.', + value: 0.024334429, + }, + { + x: 1997, + y: 'N.M', + value: 0.394401971, + }, + { + x: 1997, + y: 'Nev.', + value: 0.056686, + }, + { + x: 1997, + y: 'N.Y.', + value: 0.117921077, + }, + { + x: 1997, + y: 'Ohio', + value: 0.301489081, + }, + { + x: 1997, + y: 'Okla.', + value: 0, + }, + { + x: 1997, + y: 'Ore.', + value: 0.090790513, + }, + { + x: 1997, + y: 'Pa.', + value: 0.12267115, + }, + { + x: 1997, + y: 'R.I.', + value: 0.487636941, + }, + { + x: 1997, + y: 'S.C.', + value: 0.051817552, + }, + { + x: 1997, + y: 'S.D.', + value: 1.20931495, + }, + { + x: 1997, + y: 'Tenn.', + value: 0.054553062, + }, + { + x: 1997, + y: 'Texas', + value: 0.045591973, + }, + { + x: 1997, + y: 'Utah', + value: 0.047174618, + }, + { + x: 1997, + y: 'Va.', + value: 0.02928608, + }, + { + x: 1997, + y: 'Vt.', + value: 9.878792242, + }, + { + x: 1997, + y: 'Wash.', + value: 0.264328965, + }, + { + x: 1997, + y: 'Wis.', + value: 0, + }, + { + x: 1997, + y: 'W.Va.', + value: 0.054971846, + }, + { + x: 1997, + y: 'Wyo.', + value: 0.612931632, + }, + { + x: 1998, + y: 'Alaska', + value: 2.580928231, + }, + { + x: 1998, + y: 'Ala.', + value: 0, + }, + { + x: 1998, + y: 'Ark.', + value: null, + }, + { + x: 1998, + y: 'Ariz.', + value: 0.204777794, + }, + { + x: 1998, + y: 'Calif.', + value: 0.012125741, + }, + { + x: 1998, + y: 'Colo.', + value: null, + }, + { + x: 1998, + y: 'Conn.', + value: null, + }, + { + x: 1998, + y: 'D.C.', + value: null, + }, + { + x: 1998, + y: 'Del.', + value: 0, + }, + { + x: 1998, + y: 'Fla.', + value: 0.006457212, + }, + { + x: 1998, + y: 'Ga.', + value: 0.012716925, + }, + { + x: 1998, + y: 'Hawaii', + value: null, + }, + { + x: 1998, + y: 'Iowa', + value: 0.034448643, + }, + { + x: 1998, + y: 'Idaho', + value: 0.079851157, + }, + { + x: 1998, + y: 'Ill.', + value: 0.008148733, + }, + { + x: 1998, + y: 'Ind.', + value: 0.033339557, + }, + { + x: 1998, + y: 'Kan.', + value: null, + }, + { + x: 1998, + y: 'Ky.', + value: null, + }, + { + x: 1998, + y: 'La.', + value: 0.022520778, + }, + { + x: 1998, + y: 'Mass.', + value: 0.015944289, + }, + { + x: 1998, + y: 'Md.', + value: 0, + }, + { + x: 1998, + y: 'Maine', + value: null, + }, + { + x: 1998, + y: 'Mich.', + value: 0.091389653, + }, + { + x: 1998, + y: 'Minn.', + value: null, + }, + { + x: 1998, + y: 'Mo.', + value: null, + }, + { + x: 1998, + y: 'Miss.', + value: null, + }, + { + x: 1998, + y: 'Mont.', + value: null, + }, + { + x: 1998, + y: 'N.C.', + value: null, + }, + { + x: 1998, + y: 'N.D.', + value: null, + }, + { + x: 1998, + y: 'Neb.', + value: null, + }, + { + x: 1998, + y: 'N.H.', + value: null, + }, + { + x: 1998, + y: 'N.J.', + value: 0.084465391, + }, + { + x: 1998, + y: 'N.M', + value: null, + }, + { + x: 1998, + y: 'Nev.', + value: null, + }, + { + x: 1998, + y: 'N.Y.', + value: null, + }, + { + x: 1998, + y: 'Ohio', + value: 0, + }, + { + x: 1998, + y: 'Okla.', + value: null, + }, + { + x: 1998, + y: 'Ore.', + value: null, + }, + { + x: 1998, + y: 'Pa.', + value: 0.024498451, + }, + { + x: 1998, + y: 'R.I.', + value: null, + }, + { + x: 1998, + y: 'S.C.', + value: null, + }, + { + x: 1998, + y: 'S.D.', + value: null, + }, + { + x: 1998, + y: 'Tenn.', + value: 0, + }, + { + x: 1998, + y: 'Texas', + value: null, + }, + { + x: 1998, + y: 'Utah', + value: null, + }, + { + x: 1998, + y: 'Va.', + value: 0, + }, + { + x: 1998, + y: 'Vt.', + value: 0, + }, + { + x: 1998, + y: 'Wash.', + value: 0, + }, + { + x: 1998, + y: 'Wis.', + value: 0, + }, + { + x: 1998, + y: 'W.Va.', + value: null, + }, + { + x: 1998, + y: 'Wyo.', + value: null, + }, + { + x: 1999, + y: 'Alaska', + value: null, + }, + { + x: 1999, + y: 'Ala.', + value: null, + }, + { + x: 1999, + y: 'Ark.', + value: 0.150837525, + }, + { + x: 1999, + y: 'Ariz.', + value: 0.01990516, + }, + { + x: 1999, + y: 'Calif.', + value: 0.05373262, + }, + { + x: 1999, + y: 'Colo.', + value: 0, + }, + { + x: 1999, + y: 'Conn.', + value: 0, + }, + { + x: 1999, + y: 'D.C.', + value: null, + }, + { + x: 1999, + y: 'Del.', + value: null, + }, + { + x: 1999, + y: 'Fla.', + value: 0.006345411, + }, + { + x: 1999, + y: 'Ga.', + value: null, + }, + { + x: 1999, + y: 'Hawaii', + value: 0.082624143, + }, + { + x: 1999, + y: 'Iowa', + value: null, + }, + { + x: 1999, + y: 'Idaho', + value: null, + }, + { + x: 1999, + y: 'Ill.', + value: null, + }, + { + x: 1999, + y: 'Ind.', + value: 0.016542682, + }, + { + x: 1999, + y: 'Kan.', + value: null, + }, + { + x: 1999, + y: 'Ky.', + value: 0, + }, + { + x: 1999, + y: 'La.', + value: null, + }, + { + x: 1999, + y: 'Mass.', + value: 0.031658869, + }, + { + x: 1999, + y: 'Md.', + value: null, + }, + { + x: 1999, + y: 'Maine', + value: null, + }, + { + x: 1999, + y: 'Mich.', + value: 0, + }, + { + x: 1999, + y: 'Minn.', + value: 0, + }, + { + x: 1999, + y: 'Mo.', + value: 0.017979312, + }, + { + x: 1999, + y: 'Miss.', + value: null, + }, + { + x: 1999, + y: 'Mont.', + value: null, + }, + { + x: 1999, + y: 'N.C.', + value: 0, + }, + { + x: 1999, + y: 'N.D.', + value: null, + }, + { + x: 1999, + y: 'Neb.', + value: null, + }, + { + x: 1999, + y: 'N.H.', + value: 0, + }, + { + x: 1999, + y: 'N.J.', + value: null, + }, + { + x: 1999, + y: 'N.M', + value: null, + }, + { + x: 1999, + y: 'Nev.', + value: 0, + }, + { + x: 1999, + y: 'N.Y.', + value: null, + }, + { + x: 1999, + y: 'Ohio', + value: null, + }, + { + x: 1999, + y: 'Okla.', + value: null, + }, + { + x: 1999, + y: 'Ore.', + value: 0.147321359, + }, + { + x: 1999, + y: 'Pa.', + value: null, + }, + { + x: 1999, + y: 'R.I.', + value: null, + }, + { + x: 1999, + y: 'S.C.', + value: null, + }, + { + x: 1999, + y: 'S.D.', + value: null, + }, + { + x: 1999, + y: 'Tenn.', + value: null, + }, + { + x: 1999, + y: 'Texas', + value: 0.03404964, + }, + { + x: 1999, + y: 'Utah', + value: 0.090765434, + }, + { + x: 1999, + y: 'Va.', + value: 0.257136465, + }, + { + x: 1999, + y: 'Vt.', + value: null, + }, + { + x: 1999, + y: 'Wash.', + value: null, + }, + { + x: 1999, + y: 'Wis.', + value: null, + }, + { + x: 1999, + y: 'W.Va.', + value: null, + }, + { + x: 1999, + y: 'Wyo.', + value: null, + }, + { + x: 2000, + y: 'Alaska', + value: 0.159362804, + }, + { + x: 2000, + y: 'Ala.', + value: null, + }, + { + x: 2000, + y: 'Ark.', + value: 0.037337284, + }, + { + x: 2000, + y: 'Ariz.', + value: null, + }, + { + x: 2000, + y: 'Calif.', + value: 0.044124693, + }, + { + x: 2000, + y: 'Colo.', + value: 0.06931496, + }, + { + x: 2000, + y: 'Conn.', + value: null, + }, + { + x: 2000, + y: 'D.C.', + value: null, + }, + { + x: 2000, + y: 'Del.', + value: null, + }, + { + x: 2000, + y: 'Fla.', + value: 0.012463297, + }, + { + x: 2000, + y: 'Ga.', + value: null, + }, + { + x: 2000, + y: 'Hawaii', + value: 0.165075613, + }, + { + x: 2000, + y: 'Iowa', + value: 0.068301719, + }, + { + x: 2000, + y: 'Idaho', + value: null, + }, + { + x: 2000, + y: 'Ill.', + value: 0.032160429, + }, + { + x: 2000, + y: 'Ind.', + value: null, + }, + { + x: 2000, + y: 'Kan.', + value: 0.074271857, + }, + { + x: 2000, + y: 'Ky.', + value: null, + }, + { + x: 2000, + y: 'La.', + value: null, + }, + { + x: 2000, + y: 'Mass.', + value: 0, + }, + { + x: 2000, + y: 'Md.', + value: null, + }, + { + x: 2000, + y: 'Maine', + value: null, + }, + { + x: 2000, + y: 'Mich.', + value: 0.020089785, + }, + { + x: 2000, + y: 'Minn.', + value: 0.020267704, + }, + { + x: 2000, + y: 'Mo.', + value: null, + }, + { + x: 2000, + y: 'Miss.', + value: null, + }, + { + x: 2000, + y: 'Mont.', + value: null, + }, + { + x: 2000, + y: 'N.C.', + value: null, + }, + { + x: 2000, + y: 'N.D.', + value: null, + }, + { + x: 2000, + y: 'Neb.', + value: null, + }, + { + x: 2000, + y: 'N.H.', + value: 0.241848496, + }, + { + x: 2000, + y: 'N.J.', + value: null, + }, + { + x: 2000, + y: 'N.M', + value: null, + }, + { + x: 2000, + y: 'Nev.', + value: 0.346841832, + }, + { + x: 2000, + y: 'N.Y.', + value: 0.0105274, + }, + { + x: 2000, + y: 'Ohio', + value: 0.026399518, + }, + { + x: 2000, + y: 'Okla.', + value: null, + }, + { + x: 2000, + y: 'Ore.', + value: null, + }, + { + x: 2000, + y: 'Pa.', + value: 0, + }, + { + x: 2000, + y: 'R.I.', + value: null, + }, + { + x: 2000, + y: 'S.C.', + value: null, + }, + { + x: 2000, + y: 'S.D.', + value: null, + }, + { + x: 2000, + y: 'Tenn.', + value: null, + }, + { + x: 2000, + y: 'Texas', + value: null, + }, + { + x: 2000, + y: 'Utah', + value: 0.133671135, + }, + { + x: 2000, + y: 'Va.', + value: 0.028151041, + }, + { + x: 2000, + y: 'Vt.', + value: 0.163960499, + }, + { + x: 2000, + y: 'Wash.', + value: 0, + }, + { + x: 2000, + y: 'Wis.', + value: null, + }, + { + x: 2000, + y: 'W.Va.', + value: null, + }, + { + x: 2000, + y: 'Wyo.', + value: null, + }, + { + x: 2001, + y: 'Alaska', + value: null, + }, + { + x: 2001, + y: 'Ala.', + value: null, + }, + { + x: 2001, + y: 'Ark.', + value: null, + }, + { + x: 2001, + y: 'Ariz.', + value: 0.018852213, + }, + { + x: 2001, + y: 'Calif.', + value: 0.09859181, + }, + { + x: 2001, + y: 'Colo.', + value: null, + }, + { + x: 2001, + y: 'Conn.', + value: 0, + }, + { + x: 2001, + y: 'D.C.', + value: null, + }, + { + x: 2001, + y: 'Del.', + value: null, + }, + { + x: 2001, + y: 'Fla.', + value: null, + }, + { + x: 2001, + y: 'Ga.', + value: 0.011877057, + }, + { + x: 2001, + y: 'Hawaii', + value: 0.574568766, + }, + { + x: 2001, + y: 'Iowa', + value: null, + }, + { + x: 2001, + y: 'Idaho', + value: 0.151380973, + }, + { + x: 2001, + y: 'Ill.', + value: 0.00799499, + }, + { + x: 2001, + y: 'Ind.', + value: 0.032653237, + }, + { + x: 2001, + y: 'Kan.', + value: 0.037017075, + }, + { + x: 2001, + y: 'Ky.', + value: 0.049149819, + }, + { + x: 2001, + y: 'La.', + value: null, + }, + { + x: 2001, + y: 'Mass.', + value: 0, + }, + { + x: 2001, + y: 'Md.', + value: 0.055813611, + }, + { + x: 2001, + y: 'Maine', + value: null, + }, + { + x: 2001, + y: 'Mich.', + value: null, + }, + { + x: 2001, + y: 'Minn.', + value: 0.04013797, + }, + { + x: 2001, + y: 'Mo.', + value: 0.017717974, + }, + { + x: 2001, + y: 'Miss.', + value: null, + }, + { + x: 2001, + y: 'Mont.', + value: null, + }, + { + x: 2001, + y: 'N.C.', + value: null, + }, + { + x: 2001, + y: 'N.D.', + value: null, + }, + { + x: 2001, + y: 'Neb.', + value: null, + }, + { + x: 2001, + y: 'N.H.', + value: null, + }, + { + x: 2001, + y: 'N.J.', + value: 0.0117793, + }, + { + x: 2001, + y: 'N.M', + value: null, + }, + { + x: 2001, + y: 'Nev.', + value: null, + }, + { + x: 2001, + y: 'N.Y.', + value: 0, + }, + { + x: 2001, + y: 'Ohio', + value: 0.008774336, + }, + { + x: 2001, + y: 'Okla.', + value: null, + }, + { + x: 2001, + y: 'Ore.', + value: 0.17289163, + }, + { + x: 2001, + y: 'Pa.', + value: 0.04878234, + }, + { + x: 2001, + y: 'R.I.', + value: null, + }, + { + x: 2001, + y: 'S.C.', + value: null, + }, + { + x: 2001, + y: 'S.D.', + value: null, + }, + { + x: 2001, + y: 'Tenn.', + value: null, + }, + { + x: 2001, + y: 'Texas', + value: 0, + }, + { + x: 2001, + y: 'Utah', + value: null, + }, + { + x: 2001, + y: 'Va.', + value: 0.013905684, + }, + { + x: 2001, + y: 'Vt.', + value: 0.163357853, + }, + { + x: 2001, + y: 'Wash.', + value: 0, + }, + { + x: 2001, + y: 'Wis.', + value: null, + }, + { + x: 2001, + y: 'W.Va.', + value: null, + }, + { + x: 2001, + y: 'Wyo.', + value: null, + }, + { + x: 2002, + y: 'Alaska', + value: null, + }, + { + x: 2002, + y: 'Ala.', + value: 0.156514817, + }, + { + x: 2002, + y: 'Ark.', + value: null, + }, + { + x: 2002, + y: 'Ariz.', + value: null, + }, + { + x: 2002, + y: 'Calif.', + value: 0, + }, + { + x: 2002, + y: 'Colo.', + value: null, + }, + { + x: 2002, + y: 'Conn.', + value: null, + }, + { + x: 2002, + y: 'D.C.', + value: null, + }, + { + x: 2002, + y: 'Del.', + value: null, + }, + { + x: 2002, + y: 'Fla.', + value: 0.005995093, + }, + { + x: 2002, + y: 'Ga.', + value: 0.011647498, + }, + { + x: 2002, + y: 'Hawaii', + value: 0.081428649, + }, + { + x: 2002, + y: 'Iowa', + value: null, + }, + { + x: 2002, + y: 'Idaho', + value: 0, + }, + { + x: 2002, + y: 'Ill.', + value: null, + }, + { + x: 2002, + y: 'Ind.', + value: 0.016262788, + }, + { + x: 2002, + y: 'Kan.', + value: null, + }, + { + x: 2002, + y: 'Ky.', + value: null, + }, + { + x: 2002, + y: 'La.', + value: null, + }, + { + x: 2002, + y: 'Mass.', + value: null, + }, + { + x: 2002, + y: 'Md.', + value: null, + }, + { + x: 2002, + y: 'Maine', + value: null, + }, + { + x: 2002, + y: 'Mich.', + value: null, + }, + { + x: 2002, + y: 'Minn.', + value: 0, + }, + { + x: 2002, + y: 'Mo.', + value: 0.017602993, + }, + { + x: 2002, + y: 'Miss.', + value: null, + }, + { + x: 2002, + y: 'Mont.', + value: null, + }, + { + x: 2002, + y: 'N.C.', + value: null, + }, + { + x: 2002, + y: 'N.D.', + value: null, + }, + { + x: 2002, + y: 'Neb.', + value: null, + }, + { + x: 2002, + y: 'N.H.', + value: null, + }, + { + x: 2002, + y: 'N.J.', + value: null, + }, + { + x: 2002, + y: 'N.M', + value: null, + }, + { + x: 2002, + y: 'Nev.', + value: 0, + }, + { + x: 2002, + y: 'N.Y.', + value: 0.005218697, + }, + { + x: 2002, + y: 'Ohio', + value: 0, + }, + { + x: 2002, + y: 'Okla.', + value: null, + }, + { + x: 2002, + y: 'Ore.', + value: null, + }, + { + x: 2002, + y: 'Pa.', + value: null, + }, + { + x: 2002, + y: 'R.I.', + value: null, + }, + { + x: 2002, + y: 'S.C.', + value: null, + }, + { + x: 2002, + y: 'S.D.', + value: null, + }, + { + x: 2002, + y: 'Tenn.', + value: null, + }, + { + x: 2002, + y: 'Texas', + value: 0.004606005, + }, + { + x: 2002, + y: 'Utah', + value: 0, + }, + { + x: 2002, + y: 'Va.', + value: null, + }, + { + x: 2002, + y: 'Vt.', + value: null, + }, + { + x: 2002, + y: 'Wash.', + value: null, + }, + { + x: 2002, + y: 'Wis.', + value: null, + }, + { + x: 2002, + y: 'W.Va.', + value: null, + }, + { + x: 2002, + y: 'Wyo.', + value: null, + }, + { + x: 2003, + y: 'Ala.', + value: 0, + }, + { + x: 2003, + y: 'Ark.', + value: 0, + }, + { + x: 2003, + y: 'Ariz.', + value: 0.02, + }, + { + x: 2003, + y: 'Calif.', + value: 0.01, + }, + { + x: 2003, + y: 'Colo.', + value: 0, + }, + { + x: 2003, + y: 'Conn.', + value: 0, + }, + { + x: 2003, + y: 'D.C.', + value: 0, + }, + { + x: 2003, + y: 'Del.', + value: 0, + }, + { + x: 2003, + y: 'Fla.', + value: 0, + }, + { + x: 2003, + y: 'Ga.', + value: 0.01, + }, + { + x: 2003, + y: 'Hawaii', + value: 1.52, + }, + { + x: 2003, + y: 'Iowa', + value: 0, + }, + { + x: 2003, + y: 'Idaho', + value: 0, + }, + { + x: 2003, + y: 'Ill.', + value: 0.01, + }, + { + x: 2003, + y: 'Ind.', + value: 0, + }, + { + x: 2003, + y: 'Kan.', + value: 0, + }, + { + x: 2003, + y: 'Ky.', + value: 0, + }, + { + x: 2003, + y: 'La.', + value: 0, + }, + { + x: 2003, + y: 'Mass.', + value: 0, + }, + { + x: 2003, + y: 'Md.', + value: 0.02, + }, + { + x: 2003, + y: 'Maine', + value: 0, + }, + { + x: 2003, + y: 'Mich.', + value: 0.02, + }, + { + x: 2003, + y: 'Minn.', + value: 0, + }, + { + x: 2003, + y: 'Mo.', + value: 0, + }, + { + x: 2003, + y: 'Miss.', + value: 0, + }, + { + x: 2003, + y: 'Mont.', + value: 0, + }, + { + x: 2003, + y: 'N.C.', + value: 0.01, + }, + { + x: 2003, + y: 'N.D.', + value: 0, + }, + { + x: 2003, + y: 'Neb.', + value: 0, + }, + { + x: 2003, + y: 'N.H.', + value: 0.08, + }, + { + x: 2003, + y: 'N.J.', + value: 0.02, + }, + { + x: 2003, + y: 'N.M', + value: 0, + }, + { + x: 2003, + y: 'Nev.', + value: 0, + }, + { + x: 2003, + y: 'N.Y.', + value: 0.04, + }, + { + x: 2003, + y: 'Ohio', + value: 0.02, + }, + { + x: 2003, + y: 'Okla.', + value: 0, + }, + { + x: 2003, + y: 'Ore.', + value: 0.08, + }, + { + x: 2003, + y: 'Pa.', + value: 0.07, + }, + { + x: 2003, + y: 'R.I.', + value: 0, + }, + { + x: 2003, + y: 'S.C.', + value: 0, + }, + { + x: 2003, + y: 'S.D.', + value: 0, + }, + { + x: 2003, + y: 'Tenn.', + value: 0, + }, + { + x: 2003, + y: 'Texas', + value: 0, + }, + { + x: 2003, + y: 'Utah', + value: 0, + }, + { + x: 2003, + y: 'Va.', + value: 0, + }, + { + x: 2003, + y: 'Vt.', + value: 0, + }, + { + x: 2003, + y: 'Wash.', + value: 0, + }, + { + x: 2003, + y: 'Wis.', + value: 0, + }, + { + x: 2003, + y: 'W.Va.', + value: 0.02, + }, + { + x: 2003, + y: 'Wyo.', + value: 0, + }, + { + x: 2004, + y: 'Alaska', + value: 0, + }, + { + x: 2004, + y: 'Ala.', + value: 0, + }, + { + x: 2004, + y: 'Ark.', + value: 0, + }, + { + x: 2004, + y: 'Ariz.', + value: 0, + }, + { + x: 2004, + y: 'Calif.', + value: 0.02, + }, + { + x: 2004, + y: 'Colo.', + value: 0.02, + }, + { + x: 2004, + y: 'Conn.', + value: 0, + }, + { + x: 2004, + y: 'D.C.', + value: 0, + }, + { + x: 2004, + y: 'Del.', + value: 0, + }, + { + x: 2004, + y: 'Fla.', + value: 0.01, + }, + { + x: 2004, + y: 'Ga.', + value: 0.01, + }, + { + x: 2004, + y: 'Hawaii', + value: 0.24, + }, + { + x: 2004, + y: 'Iowa', + value: 0.1, + }, + { + x: 2004, + y: 'Idaho', + value: 0, + }, + { + x: 2004, + y: 'Ill.', + value: 0.01, + }, + { + x: 2004, + y: 'Ind.', + value: 0, + }, + { + x: 2004, + y: 'Kan.', + value: 0, + }, + { + x: 2004, + y: 'Ky.', + value: 0, + }, + { + x: 2004, + y: 'La.', + value: 0, + }, + { + x: 2004, + y: 'Mass.', + value: 0.03, + }, + { + x: 2004, + y: 'Md.', + value: 0.02, + }, + { + x: 2004, + y: 'Maine', + value: 0, + }, + { + x: 2004, + y: 'Mich.', + value: 0, + }, + { + x: 2004, + y: 'Minn.', + value: 0, + }, + { + x: 2004, + y: 'Mo.', + value: 0.03, + }, + { + x: 2004, + y: 'Miss.', + value: 0, + }, + { + x: 2004, + y: 'Mont.', + value: 0, + }, + { + x: 2004, + y: 'N.C.', + value: 0.02, + }, + { + x: 2004, + y: 'N.D.', + value: 0, + }, + { + x: 2004, + y: 'Neb.', + value: 0, + }, + { + x: 2004, + y: 'N.H.', + value: 0, + }, + { + x: 2004, + y: 'N.J.', + value: 0.02, + }, + { + x: 2004, + y: 'N.M', + value: 0, + }, + { + x: 2004, + y: 'Nev.', + value: 0, + }, + { + x: 2004, + y: 'N.Y.', + value: 0.03, + }, + { + x: 2004, + y: 'Ohio', + value: 0, + }, + { + x: 2004, + y: 'Okla.', + value: 0, + }, + { + x: 2004, + y: 'Ore.', + value: 0, + }, + { + x: 2004, + y: 'Pa.', + value: 0, + }, + { + x: 2004, + y: 'R.I.', + value: 0, + }, + { + x: 2004, + y: 'S.C.', + value: 0, + }, + { + x: 2004, + y: 'S.D.', + value: 0, + }, + { + x: 2004, + y: 'Tenn.', + value: 0, + }, + { + x: 2004, + y: 'Texas', + value: 0, + }, + { + x: 2004, + y: 'Utah', + value: 0, + }, + { + x: 2004, + y: 'Va.', + value: 0, + }, + { + x: 2004, + y: 'Vt.', + value: 0, + }, + { + x: 2004, + y: 'Wash.', + value: 0.11, + }, + { + x: 2004, + y: 'Wis.', + value: 0, + }, + { + x: 2004, + y: 'W.Va.', + value: 0, + }, + { + x: 2004, + y: 'Wyo.', + value: 0, + }, + { + x: 2005, + y: 'Alaska', + value: 0, + }, + { + x: 2005, + y: 'Ala.', + value: 0, + }, + { + x: 2005, + y: 'Ark.', + value: 0, + }, + { + x: 2005, + y: 'Ariz.', + value: 0.02, + }, + { + x: 2005, + y: 'Calif.', + value: 0.01, + }, + { + x: 2005, + y: 'Colo.', + value: 0, + }, + { + x: 2005, + y: 'Conn.', + value: 0, + }, + { + x: 2005, + y: 'D.C.', + value: 0, + }, + { + x: 2005, + y: 'Del.', + value: 0.12, + }, + { + x: 2005, + y: 'Fla.', + value: 0, + }, + { + x: 2005, + y: 'Ga.', + value: 0, + }, + { + x: 2005, + y: 'Hawaii', + value: 0.08, + }, + { + x: 2005, + y: 'Iowa', + value: 0, + }, + { + x: 2005, + y: 'Idaho', + value: 0, + }, + { + x: 2005, + y: 'Ill.', + value: 0.02, + }, + { + x: 2005, + y: 'Ind.', + value: 0.53, + }, + { + x: 2005, + y: 'Kan.', + value: 0, + }, + { + x: 2005, + y: 'Ky.', + value: 0, + }, + { + x: 2005, + y: 'La.', + value: 0, + }, + { + x: 2005, + y: 'Mass.', + value: 0, + }, + { + x: 2005, + y: 'Md.', + value: 0, + }, + { + x: 2005, + y: 'Maine', + value: 0, + }, + { + x: 2005, + y: 'Mich.', + value: 0.01, + }, + { + x: 2005, + y: 'Minn.', + value: 0, + }, + { + x: 2005, + y: 'Mo.', + value: 0, + }, + { + x: 2005, + y: 'Miss.', + value: 0, + }, + { + x: 2005, + y: 'Mont.', + value: 0, + }, + { + x: 2005, + y: 'N.C.', + value: 0, + }, + { + x: 2005, + y: 'N.D.', + value: 0, + }, + { + x: 2005, + y: 'Neb.', + value: 0, + }, + { + x: 2005, + y: 'N.H.', + value: 0.08, + }, + { + x: 2005, + y: 'N.J.', + value: 0.02, + }, + { + x: 2005, + y: 'N.M', + value: 0, + }, + { + x: 2005, + y: 'Nev.', + value: 0, + }, + { + x: 2005, + y: 'N.Y.', + value: 0.04, + }, + { + x: 2005, + y: 'Ohio', + value: 0.03, + }, + { + x: 2005, + y: 'Okla.', + value: 0, + }, + { + x: 2005, + y: 'Ore.', + value: 0.06, + }, + { + x: 2005, + y: 'Pa.', + value: 0, + }, + { + x: 2005, + y: 'R.I.', + value: 0, + }, + { + x: 2005, + y: 'S.C.', + value: 0, + }, + { + x: 2005, + y: 'S.D.', + value: 0, + }, + { + x: 2005, + y: 'Tenn.', + value: 0.02, + }, + { + x: 2005, + y: 'Texas', + value: 0.01, + }, + { + x: 2005, + y: 'Utah', + value: 0, + }, + { + x: 2005, + y: 'Va.', + value: 0, + }, + { + x: 2005, + y: 'Vt.', + value: 0, + }, + { + x: 2005, + y: 'Wash.', + value: 0.03, + }, + { + x: 2005, + y: 'Wis.', + value: 0, + }, + { + x: 2005, + y: 'W.Va.', + value: 0.04, + }, + { + x: 2005, + y: 'Wyo.', + value: 0, + }, + { + x: 2006, + y: 'Alaska', + value: 0, + }, + { + x: 2006, + y: 'Ala.', + value: 0, + }, + { + x: 2006, + y: 'Ark.', + value: 0, + }, + { + x: 2006, + y: 'Ariz.', + value: 0, + }, + { + x: 2006, + y: 'Calif.', + value: 0.02, + }, + { + x: 2006, + y: 'Colo.', + value: 0.02, + }, + { + x: 2006, + y: 'Conn.', + value: 0, + }, + { + x: 2006, + y: 'D.C.', + value: 0, + }, + { + x: 2006, + y: 'Del.', + value: 0, + }, + { + x: 2006, + y: 'Fla.', + value: 0.02, + }, + { + x: 2006, + y: 'Ga.', + value: 0, + }, + { + x: 2006, + y: 'Hawaii', + value: 0, + }, + { + x: 2006, + y: 'Iowa', + value: 0, + }, + { + x: 2006, + y: 'Idaho', + value: 0, + }, + { + x: 2006, + y: 'Ill.', + value: 0, + }, + { + x: 2006, + y: 'Ind.', + value: 0.02, + }, + { + x: 2006, + y: 'Kan.', + value: 0.04, + }, + { + x: 2006, + y: 'Ky.', + value: 0, + }, + { + x: 2006, + y: 'La.', + value: 0, + }, + { + x: 2006, + y: 'Mass.', + value: 0.3, + }, + { + x: 2006, + y: 'Md.', + value: 0.04, + }, + { + x: 2006, + y: 'Maine', + value: 0, + }, + { + x: 2006, + y: 'Mich.', + value: 0.01, + }, + { + x: 2006, + y: 'Minn.', + value: 0.02, + }, + { + x: 2006, + y: 'Mo.', + value: 0.02, + }, + { + x: 2006, + y: 'Miss.', + value: 0, + }, + { + x: 2006, + y: 'Mont.', + value: 0, + }, + { + x: 2006, + y: 'N.C.', + value: 0, + }, + { + x: 2006, + y: 'N.D.', + value: 0, + }, + { + x: 2006, + y: 'Neb.', + value: 0, + }, + { + x: 2006, + y: 'N.H.', + value: 0.08, + }, + { + x: 2006, + y: 'N.J.', + value: 0.01, + }, + { + x: 2006, + y: 'N.M', + value: 0, + }, + { + x: 2006, + y: 'Nev.', + value: 0, + }, + { + x: 2006, + y: 'N.Y.', + value: 0.05, + }, + { + x: 2006, + y: 'Ohio', + value: 0, + }, + { + x: 2006, + y: 'Okla.', + value: 0, + }, + { + x: 2006, + y: 'Ore.', + value: 0.05, + }, + { + x: 2006, + y: 'Pa.', + value: 0.02, + }, + { + x: 2006, + y: 'R.I.', + value: 0, + }, + { + x: 2006, + y: 'S.C.', + value: 0, + }, + { + x: 2006, + y: 'S.D.', + value: 0, + }, + { + x: 2006, + y: 'Tenn.', + value: 0, + }, + { + x: 2006, + y: 'Texas', + value: 0, + }, + { + x: 2006, + y: 'Utah', + value: 0, + }, + { + x: 2006, + y: 'Va.', + value: 0, + }, + { + x: 2006, + y: 'Vt.', + value: 0, + }, + { + x: 2006, + y: 'Wash.', + value: 0.03, + }, + { + x: 2006, + y: 'Wis.', + value: 0, + }, + { + x: 2006, + y: 'W.Va.', + value: 0, + }, + { + x: 2006, + y: 'Wyo.', + value: 0, + }, + { + x: 2007, + y: 'Alaska', + value: 0, + }, + { + x: 2007, + y: 'Ala.', + value: 0, + }, + { + x: 2007, + y: 'Ark.', + value: 0, + }, + { + x: 2007, + y: 'Ariz.', + value: 0, + }, + { + x: 2007, + y: 'Calif.', + value: 0.01, + }, + { + x: 2007, + y: 'Colo.', + value: 0, + }, + { + x: 2007, + y: 'Conn.', + value: 0, + }, + { + x: 2007, + y: 'D.C.', + value: 0, + }, + { + x: 2007, + y: 'Del.', + value: 0, + }, + { + x: 2007, + y: 'Fla.', + value: 0.03, + }, + { + x: 2007, + y: 'Ga.', + value: 0, + }, + { + x: 2007, + y: 'Hawaii', + value: 0.15, + }, + { + x: 2007, + y: 'Iowa', + value: 0, + }, + { + x: 2007, + y: 'Idaho', + value: 0, + }, + { + x: 2007, + y: 'Ill.', + value: 0.01, + }, + { + x: 2007, + y: 'Ind.', + value: 0, + }, + { + x: 2007, + y: 'Kan.', + value: 0, + }, + { + x: 2007, + y: 'Ky.', + value: 0, + }, + { + x: 2007, + y: 'La.', + value: 0, + }, + { + x: 2007, + y: 'Mass.', + value: 0.02, + }, + { + x: 2007, + y: 'Md.', + value: 0, + }, + { + x: 2007, + y: 'Maine', + value: 0, + }, + { + x: 2007, + y: 'Mich.', + value: 0.03, + }, + { + x: 2007, + y: 'Minn.', + value: 0.02, + }, + { + x: 2007, + y: 'Mo.', + value: 0, + }, + { + x: 2007, + y: 'Miss.', + value: 0, + }, + { + x: 2007, + y: 'Mont.', + value: 0, + }, + { + x: 2007, + y: 'N.C.', + value: 0.03, + }, + { + x: 2007, + y: 'N.D.', + value: 0, + }, + { + x: 2007, + y: 'Neb.', + value: 0, + }, + { + x: 2007, + y: 'N.H.', + value: 0, + }, + { + x: 2007, + y: 'N.J.', + value: 0.01, + }, + { + x: 2007, + y: 'N.M', + value: 0.05, + }, + { + x: 2007, + y: 'Nev.', + value: 0, + }, + { + x: 2007, + y: 'N.Y.', + value: 0.04, + }, + { + x: 2007, + y: 'Ohio', + value: 0, + }, + { + x: 2007, + y: 'Okla.', + value: 0, + }, + { + x: 2007, + y: 'Ore.', + value: 0.03, + }, + { + x: 2007, + y: 'Pa.', + value: 0.02, + }, + { + x: 2007, + y: 'R.I.', + value: 0, + }, + { + x: 2007, + y: 'S.C.', + value: 0, + }, + { + x: 2007, + y: 'S.D.', + value: 0, + }, + { + x: 2007, + y: 'Tenn.', + value: 0, + }, + { + x: 2007, + y: 'Texas', + value: 0.03, + }, + { + x: 2007, + y: 'Utah', + value: 0, + }, + { + x: 2007, + y: 'Va.', + value: 0, + }, + { + x: 2007, + y: 'Vt.', + value: 0, + }, + { + x: 2007, + y: 'Wash.', + value: 0.05, + }, + { + x: 2007, + y: 'Wis.', + value: 0, + }, + { + x: 2007, + y: 'W.Va.', + value: 0, + }, + { + x: 2007, + y: 'Wyo.', + value: 0, + }, + { + x: 2008, + y: 'Alaska', + value: 0, + }, + { + x: 2008, + y: 'Ala.', + value: 0, + }, + { + x: 2008, + y: 'Ark.', + value: 0.07, + }, + { + x: 2008, + y: 'Ariz.', + value: 0.22, + }, + { + x: 2008, + y: 'Calif.', + value: 0.05, + }, + { + x: 2008, + y: 'Colo.', + value: 0, + }, + { + x: 2008, + y: 'Conn.', + value: 0, + }, + { + x: 2008, + y: 'D.C.', + value: 0.17, + }, + { + x: 2008, + y: 'Del.', + value: 0, + }, + { + x: 2008, + y: 'Fla.', + value: 0.01, + }, + { + x: 2008, + y: 'Ga.', + value: 0.01, + }, + { + x: 2008, + y: 'Hawaii', + value: 0.3, + }, + { + x: 2008, + y: 'Iowa', + value: 0, + }, + { + x: 2008, + y: 'Idaho', + value: 0, + }, + { + x: 2008, + y: 'Ill.', + value: 0.25, + }, + { + x: 2008, + y: 'Ind.', + value: 0, + }, + { + x: 2008, + y: 'Kan.', + value: 0, + }, + { + x: 2008, + y: 'Ky.', + value: 0, + }, + { + x: 2008, + y: 'La.', + value: 0.02, + }, + { + x: 2008, + y: 'Mass.', + value: 0.03, + }, + { + x: 2008, + y: 'Md.', + value: 0, + }, + { + x: 2008, + y: 'Maine', + value: 0, + }, + { + x: 2008, + y: 'Mich.', + value: 0.04, + }, + { + x: 2008, + y: 'Minn.', + value: 0, + }, + { + x: 2008, + y: 'Mo.', + value: 0.02, + }, + { + x: 2008, + y: 'Miss.', + value: 0, + }, + { + x: 2008, + y: 'Mont.', + value: 0, + }, + { + x: 2008, + y: 'N.C.', + value: 0, + }, + { + x: 2008, + y: 'N.D.', + value: 0, + }, + { + x: 2008, + y: 'Neb.', + value: 0, + }, + { + x: 2008, + y: 'N.H.', + value: 0, + }, + { + x: 2008, + y: 'N.J.', + value: 0.01, + }, + { + x: 2008, + y: 'N.M', + value: 0.05, + }, + { + x: 2008, + y: 'Nev.', + value: 0, + }, + { + x: 2008, + y: 'N.Y.', + value: 0.16, + }, + { + x: 2008, + y: 'Ohio', + value: 0, + }, + { + x: 2008, + y: 'Okla.', + value: 0, + }, + { + x: 2008, + y: 'Ore.', + value: 0.03, + }, + { + x: 2008, + y: 'Pa.', + value: 0.01, + }, + { + x: 2008, + y: 'R.I.', + value: 0, + }, + { + x: 2008, + y: 'S.C.', + value: 0, + }, + { + x: 2008, + y: 'S.D.', + value: 0, + }, + { + x: 2008, + y: 'Tenn.', + value: 0, + }, + { + x: 2008, + y: 'Texas', + value: 0, + }, + { + x: 2008, + y: 'Utah', + value: 0, + }, + { + x: 2008, + y: 'Va.', + value: 0.01, + }, + { + x: 2008, + y: 'Vt.', + value: 0, + }, + { + x: 2008, + y: 'Wash.', + value: 0.29, + }, + { + x: 2008, + y: 'Wis.', + value: 0, + }, + { + x: 2008, + y: 'W.Va.', + value: 0.11, + }, + { + x: 2008, + y: 'Wyo.', + value: 0, + }, + { + x: 2009, + y: 'Alaska', + value: 0, + }, + { + x: 2009, + y: 'Ala.', + value: 0, + }, + { + x: 2009, + y: 'Ark.', + value: 0, + }, + { + x: 2009, + y: 'Ariz.', + value: 0, + }, + { + x: 2009, + y: 'Calif.', + value: 0.02, + }, + { + x: 2009, + y: 'Colo.', + value: 0, + }, + { + x: 2009, + y: 'Conn.', + value: 0, + }, + { + x: 2009, + y: 'D.C.', + value: 0.34, + }, + { + x: 2009, + y: 'Del.', + value: 0, + }, + { + x: 2009, + y: 'Fla.', + value: 0.03, + }, + { + x: 2009, + y: 'Ga.', + value: 0.01, + }, + { + x: 2009, + y: 'Hawaii', + value: 0, + }, + { + x: 2009, + y: 'Iowa', + value: 0.03, + }, + { + x: 2009, + y: 'Idaho', + value: 0, + }, + { + x: 2009, + y: 'Ill.', + value: 0, + }, + { + x: 2009, + y: 'Ind.', + value: 0, + }, + { + x: 2009, + y: 'Kan.', + value: 0, + }, + { + x: 2009, + y: 'Ky.', + value: 0, + }, + { + x: 2009, + y: 'La.', + value: 0, + }, + { + x: 2009, + y: 'Mass.', + value: 0.03, + }, + { + x: 2009, + y: 'Md.', + value: 0.07, + }, + { + x: 2009, + y: 'Maine', + value: 0, + }, + { + x: 2009, + y: 'Mich.', + value: 0, + }, + { + x: 2009, + y: 'Minn.', + value: 0.02, + }, + { + x: 2009, + y: 'Mo.', + value: 0.1, + }, + { + x: 2009, + y: 'Miss.', + value: 0, + }, + { + x: 2009, + y: 'Mont.', + value: 0, + }, + { + x: 2009, + y: 'N.C.', + value: 0, + }, + { + x: 2009, + y: 'N.D.', + value: 0, + }, + { + x: 2009, + y: 'Neb.', + value: 0, + }, + { + x: 2009, + y: 'N.H.', + value: 0, + }, + { + x: 2009, + y: 'N.J.', + value: 0.02, + }, + { + x: 2009, + y: 'N.M', + value: 0, + }, + { + x: 2009, + y: 'Nev.', + value: 0, + }, + { + x: 2009, + y: 'N.Y.', + value: 0.09, + }, + { + x: 2009, + y: 'Ohio', + value: 0.01, + }, + { + x: 2009, + y: 'Okla.', + value: 0, + }, + { + x: 2009, + y: 'Ore.', + value: 0, + }, + { + x: 2009, + y: 'Pa.', + value: 0.11, + }, + { + x: 2009, + y: 'R.I.', + value: 0, + }, + { + x: 2009, + y: 'S.C.', + value: 0, + }, + { + x: 2009, + y: 'S.D.', + value: 0, + }, + { + x: 2009, + y: 'Tenn.', + value: 0.02, + }, + { + x: 2009, + y: 'Texas', + value: 0, + }, + { + x: 2009, + y: 'Utah', + value: 0, + }, + { + x: 2009, + y: 'Va.', + value: 0.01, + }, + { + x: 2009, + y: 'Vt.', + value: 0, + }, + { + x: 2009, + y: 'Wash.', + value: 0.01, + }, + { + x: 2009, + y: 'Wis.', + value: 0.05, + }, + { + x: 2009, + y: 'W.Va.', + value: 0, + }, + { + x: 2009, + y: 'Wyo.', + value: 0, + }, + { + x: 2010, + y: 'Alaska', + value: 0, + }, + { + x: 2010, + y: 'Ala.', + value: 0, + }, + { + x: 2010, + y: 'Ark.', + value: 0, + }, + { + x: 2010, + y: 'Ariz.', + value: 0.02, + }, + { + x: 2010, + y: 'Calif.', + value: 0.07, + }, + { + x: 2010, + y: 'Colo.', + value: 0, + }, + { + x: 2010, + y: 'Conn.', + value: 0.03, + }, + { + x: 2010, + y: 'D.C.', + value: 0, + }, + { + x: 2010, + y: 'Del.', + value: 0, + }, + { + x: 2010, + y: 'Fla.', + value: 0.01, + }, + { + x: 2010, + y: 'Ga.', + value: 0.01, + }, + { + x: 2010, + y: 'Hawaii', + value: 0.29, + }, + { + x: 2010, + y: 'Iowa', + value: 0, + }, + { + x: 2010, + y: 'Idaho', + value: 0, + }, + { + x: 2010, + y: 'Ill.', + value: 0, + }, + { + x: 2010, + y: 'Ind.', + value: 0, + }, + { + x: 2010, + y: 'Kan.', + value: 0, + }, + { + x: 2010, + y: 'Ky.', + value: 0.02, + }, + { + x: 2010, + y: 'La.', + value: 0, + }, + { + x: 2010, + y: 'Mass.', + value: 0.05, + }, + { + x: 2010, + y: 'Md.', + value: 0, + }, + { + x: 2010, + y: 'Maine', + value: 0, + }, + { + x: 2010, + y: 'Mich.', + value: 0, + }, + { + x: 2010, + y: 'Minn.', + value: 0.06, + }, + { + x: 2010, + y: 'Mo.', + value: 0.05, + }, + { + x: 2010, + y: 'Miss.', + value: 0, + }, + { + x: 2010, + y: 'Mont.', + value: 0, + }, + { + x: 2010, + y: 'N.C.', + value: 0, + }, + { + x: 2010, + y: 'N.D.', + value: 0, + }, + { + x: 2010, + y: 'Neb.', + value: 0, + }, + { + x: 2010, + y: 'N.H.', + value: 0, + }, + { + x: 2010, + y: 'N.J.', + value: 0, + }, + { + x: 2010, + y: 'N.M', + value: 0, + }, + { + x: 2010, + y: 'Nev.', + value: 0.04, + }, + { + x: 2010, + y: 'N.Y.', + value: 0.04, + }, + { + x: 2010, + y: 'Ohio', + value: 0.02, + }, + { + x: 2010, + y: 'Okla.', + value: 0, + }, + { + x: 2010, + y: 'Ore.', + value: 0, + }, + { + x: 2010, + y: 'Pa.', + value: 0.02, + }, + { + x: 2010, + y: 'R.I.', + value: 0, + }, + { + x: 2010, + y: 'S.C.', + value: 0, + }, + { + x: 2010, + y: 'S.D.', + value: 0, + }, + { + x: 2010, + y: 'Tenn.', + value: 0, + }, + { + x: 2010, + y: 'Texas', + value: 0, + }, + { + x: 2010, + y: 'Utah', + value: 0, + }, + { + x: 2010, + y: 'Va.', + value: 0.04, + }, + { + x: 2010, + y: 'Vt.', + value: 0, + }, + { + x: 2010, + y: 'Wash.', + value: 0.01, + }, + { + x: 2010, + y: 'Wis.', + value: 0, + }, + { + x: 2010, + y: 'W.Va.', + value: 0, + }, + { + x: 2010, + y: 'Wyo.', + value: 0.18, + }, + { + x: 2011, + y: 'Alaska', + value: 0, + }, + { + x: 2011, + y: 'Ala.', + value: 0, + }, + { + x: 2011, + y: 'Ark.', + value: 0, + }, + { + x: 2011, + y: 'Ariz.', + value: 0.03, + }, + { + x: 2011, + y: 'Calif.', + value: 0.08, + }, + { + x: 2011, + y: 'Colo.', + value: 0, + }, + { + x: 2011, + y: 'Conn.', + value: 0.03, + }, + { + x: 2011, + y: 'D.C.', + value: null, + }, + { + x: 2011, + y: 'Del.', + value: 0.11, + }, + { + x: 2011, + y: 'Fla.', + value: 0.04, + }, + { + x: 2011, + y: 'Ga.', + value: 0, + }, + { + x: 2011, + y: 'Hawaii', + value: 0, + }, + { + x: 2011, + y: 'Iowa', + value: 0.03, + }, + { + x: 2011, + y: 'Idaho', + value: 0, + }, + { + x: 2011, + y: 'Ill.', + value: 0.02, + }, + { + x: 2011, + y: 'Ind.', + value: 0.21, + }, + { + x: 2011, + y: 'Kan.', + value: 0.21, + }, + { + x: 2011, + y: 'Ky.', + value: 0.02, + }, + { + x: 2011, + y: 'La.', + value: 0, + }, + { + x: 2011, + y: 'Mass.', + value: 0.36, + }, + { + x: 2011, + y: 'Md.', + value: 0.03, + }, + { + x: 2011, + y: 'Maine', + value: 0, + }, + { + x: 2011, + y: 'Mich.', + value: 0.02, + }, + { + x: 2011, + y: 'Minn.', + value: 0.49, + }, + { + x: 2011, + y: 'Mo.', + value: 0, + }, + { + x: 2011, + y: 'Miss.', + value: 0, + }, + { + x: 2011, + y: 'Mont.', + value: 0, + }, + { + x: 2011, + y: 'N.C.', + value: 0.02, + }, + { + x: 2011, + y: 'N.D.', + value: 0.15, + }, + { + x: 2011, + y: 'Neb.', + value: 0, + }, + { + x: 2011, + y: 'N.H.', + value: 0.08, + }, + { + x: 2011, + y: 'N.J.', + value: 0.05, + }, + { + x: 2011, + y: 'N.M', + value: 0.19, + }, + { + x: 2011, + y: 'Nev.', + value: 0.04, + }, + { + x: 2011, + y: 'N.Y.', + value: 0.16, + }, + { + x: 2011, + y: 'Ohio', + value: 0, + }, + { + x: 2011, + y: 'Okla.', + value: 0, + }, + { + x: 2011, + y: 'Ore.', + value: 0.08, + }, + { + x: 2011, + y: 'Pa.', + value: 0.1, + }, + { + x: 2011, + y: 'R.I.', + value: 0.1, + }, + { + x: 2011, + y: 'S.C.', + value: 0, + }, + { + x: 2011, + y: 'S.D.', + value: 0, + }, + { + x: 2011, + y: 'Tenn.', + value: 0.05, + }, + { + x: 2011, + y: 'Texas', + value: 0.02, + }, + { + x: 2011, + y: 'Utah', + value: 0.46, + }, + { + x: 2011, + y: 'Va.', + value: 0.09, + }, + { + x: 2011, + y: 'Vt.', + value: 0.16, + }, + { + x: 2011, + y: 'Wash.', + value: 0.06, + }, + { + x: 2011, + y: 'Wis.', + value: 0, + }, + { + x: 2011, + y: 'W.Va.', + value: 0.04, + }, + { + x: 2011, + y: 'Wyo.', + value: 0, + }, + { + x: 2012, + y: 'Alaska', + value: 0, + }, + { + x: 2012, + y: 'Ala.', + value: 0, + }, + { + x: 2012, + y: 'Ark.', + value: 0.14, + }, + { + x: 2012, + y: 'Ariz.', + value: 0.03, + }, + { + x: 2012, + y: 'Calif.', + value: 0.02, + }, + { + x: 2012, + y: 'Colo.', + value: 0, + }, + { + x: 2012, + y: 'Conn.', + value: 0.03, + }, + { + x: 2012, + y: 'D.C.', + value: 0.16, + }, + { + x: 2012, + y: 'Del.', + value: 0.11, + }, + { + x: 2012, + y: 'Fla.', + value: 0, + }, + { + x: 2012, + y: 'Ga.', + value: 0.02, + }, + { + x: 2012, + y: 'Hawaii', + value: 0, + }, + { + x: 2012, + y: 'Iowa', + value: 0, + }, + { + x: 2012, + y: 'Idaho', + value: 0, + }, + { + x: 2012, + y: 'Ill.', + value: 0, + }, + { + x: 2012, + y: 'Ind.', + value: 0.23, + }, + { + x: 2012, + y: 'Kan.', + value: 0.21, + }, + { + x: 2012, + y: 'Ky.', + value: 0, + }, + { + x: 2012, + y: 'La.', + value: 0, + }, + { + x: 2012, + y: 'Mass.', + value: 0, + }, + { + x: 2012, + y: 'Md.', + value: 0, + }, + { + x: 2012, + y: 'Maine', + value: 0, + }, + { + x: 2012, + y: 'Mich.', + value: 0.01, + }, + { + x: 2012, + y: 'Minn.', + value: 0, + }, + { + x: 2012, + y: 'Mo.', + value: 0, + }, + { + x: 2012, + y: 'Miss.', + value: 0, + }, + { + x: 2012, + y: 'Mont.', + value: 0, + }, + { + x: 2012, + y: 'N.C.', + value: 0, + }, + { + x: 2012, + y: 'N.D.', + value: 0, + }, + { + x: 2012, + y: 'Neb.', + value: 0, + }, + { + x: 2012, + y: 'N.H.', + value: 0, + }, + { + x: 2012, + y: 'N.J.', + value: 0.02, + }, + { + x: 2012, + y: 'N.M', + value: 0.1, + }, + { + x: 2012, + y: 'Nev.', + value: 0, + }, + { + x: 2012, + y: 'N.Y.', + value: 0.03, + }, + { + x: 2012, + y: 'Ohio', + value: 0.01, + }, + { + x: 2012, + y: 'Okla.', + value: 0, + }, + { + x: 2012, + y: 'Ore.', + value: 0.03, + }, + { + x: 2012, + y: 'Pa.', + value: 0.02, + }, + { + x: 2012, + y: 'R.I.', + value: 0, + }, + { + x: 2012, + y: 'S.C.', + value: 0, + }, + { + x: 2012, + y: 'S.D.', + value: 0, + }, + { + x: 2012, + y: 'Tenn.', + value: 0, + }, + { + x: 2012, + y: 'Texas', + value: 0, + }, + { + x: 2012, + y: 'Utah', + value: 0.04, + }, + { + x: 2012, + y: 'Va.', + value: 0, + }, + { + x: 2012, + y: 'Vt.', + value: 0, + }, + { + x: 2012, + y: 'Wash.', + value: 0, + }, + { + x: 2012, + y: 'Wis.', + value: 0, + }, + { + x: 2012, + y: 'W.Va.', + value: 0, + }, + { + x: 2012, + y: 'Wyo.', + value: 0, + }, +]; From 904125f287025fcbf205ac094860313a9877c402 Mon Sep 17 00:00:00 2001 From: Moritz Heckmann Date: Mon, 19 Jun 2023 14:36:25 +0200 Subject: [PATCH 070/241] 0% --- package.json | 1 + src/demo/MainApp.tsx | 2 - src/vis/Vis.tsx | 2 +- src/vis/correlation/CorrelationMatrix.tsx | 145 +++++++++++++++++- src/vis/correlation/CorrelationVisSidebar.tsx | 109 +++++++++++++ src/vis/correlation/utils.ts | 29 +++- src/vis/scatter/ScatterVis.tsx | 1 - src/vis/stories/Iris.stories.tsx | 30 ++++ 8 files changed, 309 insertions(+), 10 deletions(-) create mode 100644 src/vis/correlation/CorrelationVisSidebar.tsx diff --git a/package.json b/package.json index 20bba166d..6116a62ca 100644 --- a/package.json +++ b/package.json @@ -150,6 +150,7 @@ "@types/react": "^18.2.0", "@types/react-dom": "^18.2.0", "@types/react-plotly.js": "^2.5.0", + "calculate-correlation": "^1.2.3", "d3-hexbin": "^0.2.2", "d3v7": "npm:d3@^7.4.0", "i18next": "^22.4.15", diff --git a/src/demo/MainApp.tsx b/src/demo/MainApp.tsx index 4b81a55d0..608fdf1c6 100644 --- a/src/demo/MainApp.tsx +++ b/src/demo/MainApp.tsx @@ -54,8 +54,6 @@ export function MainApp() { /> } > - - ); } diff --git a/src/vis/Vis.tsx b/src/vis/Vis.tsx index a98b35010..8e571b3fb 100644 --- a/src/vis/Vis.tsx +++ b/src/vis/Vis.tsx @@ -286,7 +286,7 @@ export function EagerVis({ /> ) : null} - {isCorrelation(visConfig) ? : null} + {isCorrelation(visConfig) ? : null} ); } diff --git a/src/vis/correlation/CorrelationMatrix.tsx b/src/vis/correlation/CorrelationMatrix.tsx index c544f66ed..f6da8acc6 100644 --- a/src/vis/correlation/CorrelationMatrix.tsx +++ b/src/vis/correlation/CorrelationMatrix.tsx @@ -1,18 +1,155 @@ import * as React from 'react'; +import { scaleBand, scaleLinear, scalePoint } from 'd3v7'; +import { Group, Stack, useMantineColorScheme, useMantineTheme } from '@mantine/core'; +import { useResizeObserver } from '@mantine/hooks'; +import * as calculateCorrelation from 'calculate-correlation'; import { ICorrelationConfig, IVisConfig, VisColumn } from '../interfaces'; +import { VisSidebarWrapper } from '../VisSidebarWrapper'; +import { InvalidCols } from '../general/InvalidCols'; +import { VisSidebarOpenButton } from '../VisSidebarOpenButton'; +import { CorrelationVisSidebar } from './CorrelationVisSidebar'; +import { useAsync } from '../../hooks/useAsync'; +import { getScatterData } from './utils'; export function CorrelationMatrix({ config, columns, setConfig, + enableSidebar, + showSidebar, + setShowSidebar, + extensions, }: { config: ICorrelationConfig; columns: VisColumn[]; - setConfig: (config: IVisConfig) => void; + setConfig?: (config: IVisConfig) => void; + enableSidebar?: boolean; + showSidebar?: boolean; + setShowSidebar?(show: boolean): void; + extensions?: { + prePlot?: React.ReactNode; + postPlot?: React.ReactNode; + preSidebar?: React.ReactNode; + postSidebar?: React.ReactNode; + }; }) { + const color = scaleLinear().domain([-1, 0, 1]).range(['#B22222', '#fff', '#000080']); + const data = useAsync(getScatterData, [columns, config.numColumnsSelected]); + + const theme = useMantineTheme(); + const borderColor = theme.colors.gray[7]; + + const [ref, { width, height }] = useResizeObserver(); + + const xScale = React.useMemo(() => { + if (!data?.value?.numericalColumns) return null; + + return scaleBand() + .range([0, width]) + .domain(data.value.numericalColumns.map((column) => column.info.name)); + }, [width, data]); + + const yScale = React.useMemo(() => { + if (!data?.value?.numericalColumns) return null; + + return scaleBand() + .range([0, height]) + .domain(data.value.numericalColumns.map((column) => column.info.name)); + }, [height, data]); + + const memoized = React.useMemo(() => { + if (!data?.value?.numericalColumns) return null; + + const circles = [] as { cx: number; cy: number; correlation: number }[]; + const texts = [] as { cx: number; cy: number; correlation: number }[]; + + data.value.numericalColumns.forEach((column, i) => { + const xname = column.info.name; + + data.value.numericalColumns.forEach((column2, j) => { + const yname = column2.info.name; + + const correlation = calculateCorrelation( + column.resolvedValues.map((resolved) => resolved.val as number), + column2.resolvedValues.map((resolved) => resolved.val as number), + ); + + if (i > j) { + circles.push({ cx: xScale(xname) + xScale.bandwidth() / 2, cy: yScale(yname) + yScale.bandwidth() / 2, correlation }); + } + if (j > i) { + texts.push({ cx: xScale(xname) + xScale.bandwidth() / 2, cy: yScale(yname) + yScale.bandwidth() / 2, correlation }); + } + }); + }); + + return { circle: circles, text: texts }; + }, [xScale, yScale, data]); + + const colorScale = scaleLinear().domain([-1, 0, 1]).range(['#B22222', '#fff', '#000080']); + return ( -
-

Correlation Matrix

-
+ + {enableSidebar ? setShowSidebar(!showSidebar)} isOpen={showSidebar} /> : null} + + + + {data.value?.numericalColumns.map((column) => { + return ( + <> + + + + ); + })} + + + + + {memoized?.circle.map((value) => { + return ; + })} + + {memoized?.text.map((value) => { + return ( + + {value.correlation.toFixed(2)} + + ); + })} + + + {showSidebar ? ( + + + + ) : null} + ); } diff --git a/src/vis/correlation/CorrelationVisSidebar.tsx b/src/vis/correlation/CorrelationVisSidebar.tsx new file mode 100644 index 000000000..88a53b2aa --- /dev/null +++ b/src/vis/correlation/CorrelationVisSidebar.tsx @@ -0,0 +1,109 @@ +import * as React from 'react'; +import { useMemo } from 'react'; +import merge from 'lodash/merge'; +import { Container, Divider } from '@mantine/core'; +import { ColumnInfo, ESupportedPlotlyVis, IVisConfig, VisColumn, ICommonVisSideBarProps, EFilterOptions, ICorrelationConfig } from '../interfaces'; +import { VisTypeSelect } from '../sidebar/VisTypeSelect'; +import { NumericalColumnSelect } from '../sidebar/NumericalColumnSelect'; + +const defaultConfig = { + group: { + enable: true, + customComponent: null, + }, + multiples: { + enable: true, + customComponent: null, + }, + direction: { + enable: true, + customComponent: null, + }, + filter: { + enable: true, + customComponent: null, + }, + groupType: { + enable: true, + customComponent: null, + }, + display: { + enable: true, + customComponent: null, + }, +}; + +const defaultExtensions = { + prePlot: null, + postPlot: null, + preSidebar: null, + postSidebar: null, +}; + +export function CorrelationVisSidebar({ + config, + optionsConfig, + extensions, + columns, + filterCallback = () => null, + setConfig, + className = '', + style: { width = '20em', ...style } = {}, +}: { + config: ICorrelationConfig; + optionsConfig?: { + group?: { + enable?: boolean; + customComponent?: React.ReactNode; + }; + multiples?: { + enable?: boolean; + customComponent?: React.ReactNode; + }; + direction?: { + enable?: boolean; + customComponent?: React.ReactNode; + }; + groupingType?: { + enable?: boolean; + customComponent?: React.ReactNode; + }; + filter?: { + enable?: boolean; + customComponent?: React.ReactNode; + }; + display?: { + enable?: boolean; + customComponent?: React.ReactNode; + }; + }; + extensions?: { + prePlot?: React.ReactNode; + postPlot?: React.ReactNode; + preSidebar?: React.ReactNode; + postSidebar?: React.ReactNode; + }; + filterCallback?: (s: EFilterOptions) => void; + columns: VisColumn[]; + setConfig: (config: IVisConfig) => void; +} & ICommonVisSideBarProps) { + const mergedOptionsConfig = useMemo(() => { + return merge({}, defaultConfig, optionsConfig); + }, [optionsConfig]); + + const mergedExtensions = useMemo(() => { + return merge({}, defaultExtensions, extensions); + }, [extensions]); + + return ( + + setConfig({ ...(config as any), type })} currentSelected={config.type} /> + + setConfig({ ...config, numColumnsSelected })} + columns={columns} + currentSelected={config.numColumnsSelected || []} + /> + + ); +} diff --git a/src/vis/correlation/utils.ts b/src/vis/correlation/utils.ts index 69d319a56..a8783cede 100644 --- a/src/vis/correlation/utils.ts +++ b/src/vis/correlation/utils.ts @@ -1,8 +1,18 @@ import merge from 'lodash/merge'; -import { ESupportedPlotlyVis, ICorrelationConfig, IVisConfig, VisColumn } from '../interfaces'; +import { + ColumnInfo, + EColumnTypes, + ESupportedPlotlyVis, + ICorrelationConfig, + IVisConfig, + VisCategoricalValue, + VisColumn, + VisNumericalValue, +} from '../interfaces'; +import { resolveColumnValues, resolveSingleColumn } from '../general/layoutUtils'; export function isCorrelation(s: IVisConfig): s is ICorrelationConfig { - return s.type === ESupportedPlotlyVis.BAR; + return s.type === ESupportedPlotlyVis.CORRELATION; } const defaultConfig: ICorrelationConfig = { @@ -15,3 +25,18 @@ export function correlationMergeDefaultConfig(columns: VisColumn[], config: ICor return merged; } + +export async function getScatterData( + columns: VisColumn[], + numericalColumnDescs: ColumnInfo[], +): Promise<{ + numericalColumns: { + resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; + type: EColumnTypes.NUMERICAL | EColumnTypes.CATEGORICAL; + info: ColumnInfo; + }[]; +}> { + const numericalColumns = await resolveColumnValues(columns.filter((col) => numericalColumnDescs.find((numCol) => numCol.id === col.info.id))); + + return { numericalColumns }; +} diff --git a/src/vis/scatter/ScatterVis.tsx b/src/vis/scatter/ScatterVis.tsx index e1f80370f..c01a23a00 100644 --- a/src/vis/scatter/ScatterVis.tsx +++ b/src/vis/scatter/ScatterVis.tsx @@ -18,7 +18,6 @@ import { Plotly } from '../../plotly/full'; import { useAsync } from '../../hooks'; import { VisSidebarWrapper } from '../VisSidebarWrapper'; import { CloseButton } from '../sidebar/CloseButton'; -import { i18n } from '../../i18n'; import { VisSidebarOpenButton } from '../VisSidebarOpenButton'; const defaultExtensions = { diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index 288fe7e79..bde7fb997 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -175,3 +175,33 @@ ViolinPlot.args = { violinOverlay: EViolinOverlay.NONE, }, }; + +export const CorrelationPlot: typeof Template = Template.bind({}); +CorrelationPlot.args = { + externalConfig: { + type: ESupportedPlotlyVis.CORRELATION, + numColumnsSelected: [ + { + description: '', + id: 'sepalLength', + name: 'Sepal Length', + }, + { + description: '', + id: 'sepalWidth', + name: 'Sepal Width', + }, + { + description: '', + id: 'petalWidth', + name: 'Sepal Width', + }, + { + description: '', + id: 'petalLength', + name: 'Sepal Width', + }, + ], + }, + enableSidebar: true, +}; From e459ebfe02d69a4c7fcc5923f7eb6dc0b9e30b30 Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Mon, 19 Jun 2023 14:42:23 +0200 Subject: [PATCH 071/241] making work --- src/vis/stories/Iris.stories.tsx | 61 ++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index 3779d8d9b..586e99e96 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -24,23 +24,43 @@ export function fetchIrisData(): VisColumn[] { let counter = 0; heatmapData.forEach((state) => { - for (let i = 0; i < Math.round(state.value / 100); i++) { + for (let i = 0; i < Math.round(state.value / 100) + 1; i++) { + if (!state.x || !state.y) { + console.log('danger'); + } myData[counter] = { year: state.x.toString(), state: state.y }; counter += 1; } }); - console.log(myData); - return [ + { + info: { + description: 'data from description', + id: 'sepalLength', + name: 'Sepal Length', + }, + type: EColumnTypes.NUMERICAL, + values: () => dataPromise.then((data) => data.map((r) => r.sepalLength).map((val, i) => ({ id: i.toString(), val }))), + }, + { + info: { + description: 'data from description', + id: 'sepalWidth', + name: 'Sepal Width', + }, + type: EColumnTypes.NUMERICAL, + values: () => dataPromise.then((data) => data.map((r) => r.sepalWidth).map((val, i) => ({ id: i.toString(), val }))), + }, { info: { description: '', - id: 'state', - name: 'US States', + id: 'randomThing', + name: 'Random Thing', }, type: EColumnTypes.CATEGORICAL, - values: () => Object.keys(myData).map((d) => ({ val: myData[d].state, id: d })), + color: { 1: 'cornflowerblue' }, + values: () => dataPromise.then((data) => data.map((r) => Math.round(Math.random() * 4)).map((val, i) => ({ id: i.toString(), val: val.toString() }))), }, { info: { @@ -49,7 +69,34 @@ export function fetchIrisData(): VisColumn[] { name: 'Petal Length PEtal length petal length', }, type: EColumnTypes.NUMERICAL, - values: () => dataPromise.then((d) => d.map((r) => r.petalLength).map((val, i) => ({ id: i.toString(), val }))), + values: () => dataPromise.then((data) => data.map((r) => r.petalLength).map((val, i) => ({ id: i.toString(), val }))), + }, + { + info: { + description: 'data from description', + id: 'petalWidth', + name: 'Petal Width', + }, + type: EColumnTypes.NUMERICAL, + values: () => dataPromise.then((data) => data.map((r) => r.petalWidth).map((val, i) => ({ id: i.toString(), val }))), + }, + { + info: { + description: 'data from description', + id: 'species', + name: 'Species', + }, + type: EColumnTypes.CATEGORICAL, + values: () => dataPromise.then((data) => data.map((r) => r.species).map((val, i) => ({ id: i.toString(), val }))), + }, + { + info: { + description: '', + id: 'state', + name: 'US States', + }, + type: EColumnTypes.CATEGORICAL, + values: () => Object.keys(myData).map((d) => ({ val: myData[d].state, id: d })), }, { info: { From 9ced7a7f1aa5b7253c7a25ff3c2911d66ec46a89 Mon Sep 17 00:00:00 2001 From: oltionchampari Date: Mon, 19 Jun 2023 14:49:34 +0200 Subject: [PATCH 072/241] Get data --- src/vis/parallelCoordinates/ParallelPlot.tsx | 54 +++++++++++++------- src/vis/parallelCoordinates/ParallelVis.tsx | 31 +++++------ src/vis/parallelCoordinates/utils.ts | 2 +- tsconfig.json | 1 + 4 files changed, 51 insertions(+), 37 deletions(-) diff --git a/src/vis/parallelCoordinates/ParallelPlot.tsx b/src/vis/parallelCoordinates/ParallelPlot.tsx index 4aec45b76..484375e48 100644 --- a/src/vis/parallelCoordinates/ParallelPlot.tsx +++ b/src/vis/parallelCoordinates/ParallelPlot.tsx @@ -1,22 +1,11 @@ import * as React from 'react'; -import merge from 'lodash/merge'; -import uniqueId from 'lodash/uniqueId'; -import { useEffect, useState } from 'react'; -import { Center, Group, Stack } from '@mantine/core'; -import * as d3 from 'd3v7'; -import { EFilterOptions, IVisConfig, Scales, IScatterConfig, VisColumn, EScatterSelectSettings, IParallelCoordinatesConfig } from '../interfaces'; -import { InvalidCols } from '../general/InvalidCols'; -import { beautifyLayout } from '../general/layoutUtils'; -import { BrushOptionButtons } from '../sidebar/BrushOptionButtons'; -import { PlotlyComponent } from '../../plotly'; -import { Plotly } from '../../plotly/full'; +import * as d3v7 from 'd3v7'; +import { useResizeObserver } from '@mantine/hooks'; +import { Group, Stack } from '@mantine/core'; +import { IParallelCoordinatesConfig, VisColumn } from '../interfaces'; + import { useAsync } from '../../hooks'; -import { VisSidebarWrapper } from '../VisSidebarWrapper'; -import { CloseButton } from '../sidebar/CloseButton'; -import { i18n } from '../../i18n'; -import { VisSidebarOpenButton } from '../VisSidebarOpenButton'; -import { ScatterVisSidebar } from '../scatter/ScatterVisSidebar'; -import { ParallelVisSidebar } from './ParallelVisSidebar'; +import { getParallelData } from './utils'; const defaultExtensions = { prePlot: null, @@ -32,9 +21,36 @@ const margin = { left: 10, }; -export function ParallelPlot() { +export function ParallelPlot({ columns, config }: { config: IParallelCoordinatesConfig; columns: VisColumn[] }) { + const [ref, { width, height }] = useResizeObserver(); + const { value: allColumns, status: colsStatus } = useAsync(getParallelData, [columns, config?.numColumnsSelected, config?.catColumnsSelected]); + + // // create y scale + // const yScales = React.useMemo(() => { + // if (!allColumns?.numColValues?.length) return; + // allColumns?.numColVals.map((c) => { + // console.log( + // 'inside', + // c.resolvedValues.map((v) => v.val), + // ); + // return d3v7 + // .scaleLinear() + // .domain(c.resolvedValues.map((v) => v.val)) + // .range([height - margin.bottom, margin.top]); + // }); + // }, [allColumns, height]); + const yScale = React.useMemo(() => { + if (!allColumns?.numColVals?.length) return () => null; + console.log('inside'); + return d3v7 + .scaleLinear() + .domain(allColumns.numColVals[0].resolvedValues.map((v) => v.val)) + .range([height - margin.bottom, margin.top]); + }, [allColumns, height]); + + console.log('HERE', allColumns, yScale(allColumns?.numColValues?.[0]?.resolvedValues?.[0]?.id)); return ( - + ); diff --git a/src/vis/parallelCoordinates/ParallelVis.tsx b/src/vis/parallelCoordinates/ParallelVis.tsx index ffdf9a8aa..9e44c522a 100644 --- a/src/vis/parallelCoordinates/ParallelVis.tsx +++ b/src/vis/parallelCoordinates/ParallelVis.tsx @@ -1,23 +1,22 @@ import * as React from 'react'; -import merge from 'lodash/merge'; -import uniqueId from 'lodash/uniqueId'; -import { useEffect, useState } from 'react'; -import { Center, Group, Stack } from '@mantine/core'; -import * as d3 from 'd3v7'; -import { EFilterOptions, IVisConfig, Scales, IScatterConfig, VisColumn, EScatterSelectSettings, IParallelCoordinatesConfig } from '../interfaces'; -import { InvalidCols } from '../general/InvalidCols'; -import { beautifyLayout } from '../general/layoutUtils'; -import { BrushOptionButtons } from '../sidebar/BrushOptionButtons'; -import { PlotlyComponent } from '../../plotly'; -import { Plotly } from '../../plotly/full'; + +import * as d3v7 from 'd3v7'; +import { Group, Stack } from '@mantine/core'; +import { useResizeObserver } from '@mantine/hooks'; +import { IVisConfig, VisColumn, IParallelCoordinatesConfig } from '../interfaces'; import { useAsync } from '../../hooks'; import { VisSidebarWrapper } from '../VisSidebarWrapper'; -import { CloseButton } from '../sidebar/CloseButton'; -import { i18n } from '../../i18n'; import { VisSidebarOpenButton } from '../VisSidebarOpenButton'; -import { ScatterVisSidebar } from '../scatter/ScatterVisSidebar'; import { ParallelVisSidebar } from './ParallelVisSidebar'; import { ParallelPlot } from './ParallelPlot'; +import { getParallelData } from './utils'; + +const margin = { + top: 30, + right: 10, + bottom: 10, + left: 10, +}; const defaultExtensions = { prePlot: null, @@ -63,8 +62,6 @@ export function ParallelVis({ setShowSidebar?(show: boolean): void; enableSidebar?: boolean; }) { - const { value: allColumns, status: colsStatus } = useAsync(getParallelData, [columns, config.numColumnsSelected, config.color]); - return ( setShowSidebar(!showSidebar)} isOpen={showSidebar} /> : null} - {config.numColumnsSelected.length > 1 ? : null} + {config?.numColumnsSelected?.length > 1 ? : null} {showSidebar ? ( diff --git a/src/vis/parallelCoordinates/utils.ts b/src/vis/parallelCoordinates/utils.ts index 774ae2f3b..43c8924c6 100644 --- a/src/vis/parallelCoordinates/utils.ts +++ b/src/vis/parallelCoordinates/utils.ts @@ -54,7 +54,7 @@ export async function getParallelData( const numColVals = await resolveColumnValues(numCols); const catColVals = await resolveColumnValues(catCols); - + console.log(numColVals); // const colorColVals = await resolveSingleColumn(colorColumn ? columns.find((col) => col.info.id === colorColumn.id) : null); return { numColVals, catColVals }; diff --git a/tsconfig.json b/tsconfig.json index 213cc4d2e..801c29aa0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,7 @@ { "extends": "visyn_scripts/config/tsconfig.template.json", "compilerOptions": { + "jsx": "react", "outDir": "./dist", }, "include": [ From fa5a6b8868c460335818dc44850f940a554c2565 Mon Sep 17 00:00:00 2001 From: Moritz Heckmann Date: Mon, 19 Jun 2023 15:09:41 +0200 Subject: [PATCH 073/241] working version --- src/vis/correlation/CorrelationMatrix.tsx | 80 ++++++++++++++++++----- 1 file changed, 65 insertions(+), 15 deletions(-) diff --git a/src/vis/correlation/CorrelationMatrix.tsx b/src/vis/correlation/CorrelationMatrix.tsx index f6da8acc6..783df6414 100644 --- a/src/vis/correlation/CorrelationMatrix.tsx +++ b/src/vis/correlation/CorrelationMatrix.tsx @@ -11,6 +11,41 @@ import { CorrelationVisSidebar } from './CorrelationVisSidebar'; import { useAsync } from '../../hooks/useAsync'; import { getScatterData } from './utils'; +interface CircleProps { + cx: number; + cy: number; + correlation: number; + xname: string; + yname: string; +} + +function SCircle({ value, fill, xScale, yScale, hover }: { value: CircleProps; fill: string; xScale; yScale; hover: boolean }) { + const cx = xScale(value.xname) + xScale.bandwidth() / 2; + const cy = yScale(value.yname) + yScale.bandwidth() / 2; + + return ( + <> + + + {value.correlation.toFixed(2)} + + + ); +} + export function CorrelationMatrix({ config, columns, @@ -37,7 +72,9 @@ export function CorrelationMatrix({ const data = useAsync(getScatterData, [columns, config.numColumnsSelected]); const theme = useMantineTheme(); - const borderColor = theme.colors.gray[7]; + const borderColor = theme.colors.gray[4]; + + const [hover, setHover] = React.useState<{ xi: number; yi: number }>(undefined); const [ref, { width, height }] = useResizeObserver(); @@ -60,7 +97,7 @@ export function CorrelationMatrix({ const memoized = React.useMemo(() => { if (!data?.value?.numericalColumns) return null; - const circles = [] as { cx: number; cy: number; correlation: number }[]; + const circles = [] as CircleProps[]; const texts = [] as { cx: number; cy: number; correlation: number }[]; data.value.numericalColumns.forEach((column, i) => { @@ -75,7 +112,7 @@ export function CorrelationMatrix({ ); if (i > j) { - circles.push({ cx: xScale(xname) + xScale.bandwidth() / 2, cy: yScale(yname) + yScale.bandwidth() / 2, correlation }); + circles.push({ cx: i, cy: j, correlation, xname: column.info.name, yname: column2.info.name }); } if (j > i) { texts.push({ cx: xScale(xname) + xScale.bandwidth() / 2, cy: yScale(yname) + yScale.bandwidth() / 2, correlation }); @@ -119,28 +156,41 @@ export function CorrelationMatrix({ position: 'relative', }} > - + { + console.log(event.nativeEvent.offsetX, event.nativeEvent.offsetY); + + const xi = Math.floor(event.nativeEvent.offsetX / (width / data.value.numericalColumns.length)); + const yi = Math.floor(event.nativeEvent.offsetY / (height / data.value.numericalColumns.length)); + + setHover({ xi, yi }); + }} + onMouseLeave={() => { + setHover(undefined); + }} + > {data.value?.numericalColumns.map((column) => { return ( <> - - + + ); })} - - + + {memoized?.circle.map((value) => { - return ; - })} - - {memoized?.text.map((value) => { return ( - - {value.correlation.toFixed(2)} - + ); })} From c5d24ace89804d9cc161de85a94ce2fba43fb86d Mon Sep 17 00:00:00 2001 From: Daniela Date: Mon, 19 Jun 2023 15:24:44 +0200 Subject: [PATCH 074/241] working on scales --- src/vis/parallelCoordinates/ParallelPlot.tsx | 57 +++++++++++--------- src/vis/parallelCoordinates/YAxis.tsx | 6 +-- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/vis/parallelCoordinates/ParallelPlot.tsx b/src/vis/parallelCoordinates/ParallelPlot.tsx index 484375e48..fa3cefc65 100644 --- a/src/vis/parallelCoordinates/ParallelPlot.tsx +++ b/src/vis/parallelCoordinates/ParallelPlot.tsx @@ -3,6 +3,7 @@ import * as d3v7 from 'd3v7'; import { useResizeObserver } from '@mantine/hooks'; import { Group, Stack } from '@mantine/core'; import { IParallelCoordinatesConfig, VisColumn } from '../interfaces'; +import { ParallelYAxis } from './YAxis'; import { useAsync } from '../../hooks'; import { getParallelData } from './utils'; @@ -18,40 +19,46 @@ const margin = { top: 30, right: 10, bottom: 10, - left: 10, + left: 30, }; export function ParallelPlot({ columns, config }: { config: IParallelCoordinatesConfig; columns: VisColumn[] }) { const [ref, { width, height }] = useResizeObserver(); const { value: allColumns, status: colsStatus } = useAsync(getParallelData, [columns, config?.numColumnsSelected, config?.catColumnsSelected]); - // // create y scale - // const yScales = React.useMemo(() => { - // if (!allColumns?.numColValues?.length) return; - // allColumns?.numColVals.map((c) => { - // console.log( - // 'inside', - // c.resolvedValues.map((v) => v.val), - // ); - // return d3v7 - // .scaleLinear() - // .domain(c.resolvedValues.map((v) => v.val)) - // .range([height - margin.bottom, margin.top]); - // }); - // }, [allColumns, height]); - const yScale = React.useMemo(() => { - if (!allColumns?.numColVals?.length) return () => null; - console.log('inside'); - return d3v7 - .scaleLinear() - .domain(allColumns.numColVals[0].resolvedValues.map((v) => v.val)) - .range([height - margin.bottom, margin.top]); - }, [allColumns, height]); + const oneNumCol = allColumns?.numColVals?.[0]; + const yScales = React.useMemo(() => { + if (allColumns?.numColVals.length === 0) return null; + const allNuimericalScales = allColumns?.numColVals?.map((col) => { + const scale = d3v7 + .scaleLinear() + .domain(d3v7.extent(col.resolvedValues.map((v) => v.val as number))) + .range([height, margin.top]); + return { + id: col.info.name, + scale, + }; + }); + }, [allColumns?.numColVals, height]); - console.log('HERE', allColumns, yScale(allColumns?.numColValues?.[0]?.resolvedValues?.[0]?.id)); + const xScale = React.useMemo(() => { + return d3v7 + .scaleBand() + .domain(allColumns?.numColVals.map((col) => col.info.name as string)) + .range([margin.left, width - margin.right]); + }, [allColumns?.numColVals, width]); + // const yScale = React.useMemo(() => { + // if (!oneNumCol) return null; + // return d3v7 + // .scaleLinear() + // .domain(d3v7.extent(oneNumCol.resolvedValues.map((v) => v.val as number))) + // .range([height, margin.top]); + // }, [height, oneNumCol]); return ( - + {xScale ? xScale() : null} + {yScales ? yScales.map((yScale, index) => ) : null} + {/* */} ); } diff --git a/src/vis/parallelCoordinates/YAxis.tsx b/src/vis/parallelCoordinates/YAxis.tsx index 5837e6e67..34b91ee90 100644 --- a/src/vis/parallelCoordinates/YAxis.tsx +++ b/src/vis/parallelCoordinates/YAxis.tsx @@ -2,14 +2,14 @@ import * as React from 'react'; import { useMemo } from 'react'; // code taken from https://wattenberger.com/blog/react-and-d3 -export function YAxis({ yScale, xRange, horizontalPosition }) { +export function ParallelYAxis({ yScale, xRange, horizontalPosition }) { const ticks = useMemo(() => { return yScale.ticks(5).map((value) => ({ value, yOffset: yScale(value), })); }, [yScale]); - + console.log('ticks: ', ticks); return ( <> ( - + {/* */} Date: Mon, 19 Jun 2023 16:08:01 +0200 Subject: [PATCH 075/241] first draft --- package.json | 3 +- src/vis/Vis.tsx | 19 ++++++ src/vis/heatmap/Heatmap.tsx | 91 +++++++++++++++++++++++++++ src/vis/heatmap/HeatmapRect.tsx | 23 +++++++ src/vis/heatmap/HeatmapVis.tsx | 41 ++++++++++++ src/vis/heatmap/HeatmapVisSidebar.tsx | 20 ++++++ src/vis/heatmap/utils.ts | 33 ++++++++++ src/vis/interfaces.ts | 10 ++- src/vis/stories/Iris.stories.tsx | 27 +++++++- 9 files changed, 264 insertions(+), 3 deletions(-) create mode 100644 src/vis/heatmap/Heatmap.tsx create mode 100644 src/vis/heatmap/HeatmapRect.tsx create mode 100644 src/vis/heatmap/HeatmapVis.tsx create mode 100644 src/vis/heatmap/HeatmapVisSidebar.tsx create mode 100644 src/vis/heatmap/utils.ts diff --git a/package.json b/package.json index 1dd93fb9d..47446c1bb 100644 --- a/package.json +++ b/package.json @@ -150,6 +150,7 @@ "@types/react": "^18.2.0", "@types/react-dom": "^18.2.0", "@types/react-plotly.js": "^2.5.0", + "arquero": "^5.0.0", "d3-hexbin": "^0.2.2", "d3v7": "npm:d3@^7.4.0", "i18next": "^22.4.15", @@ -160,7 +161,7 @@ "react-dom": "^18.2.0", "react-highlight-words": "^0.17.0", "react-plotly.js": "^2.5.1", - "react-spring": "^9.7.1", + "react-spring": "^9.3.0", "use-deep-compare-effect": "^1.8.0", "visyn_scripts": "git+ssh://git@github.com/datavisyn/visyn_scripts#develop" }, diff --git a/src/vis/Vis.tsx b/src/vis/Vis.tsx index 3f996e8bd..8d03dbeb9 100644 --- a/src/vis/Vis.tsx +++ b/src/vis/Vis.tsx @@ -23,6 +23,8 @@ import { getCssValue } from '../utils'; import { useSyncedRef } from '../hooks/useSyncedRef'; import { hexinbMergeDefaultConfig, isHexbin } from './hexbin/utils'; import { HexbinVis } from './hexbin/HexbinVis'; +import { HeatmapVis } from './heatmap/HeatmapVis'; +import { heatmapMergeDefaultConfig, isHeatmap } from './heatmap/utils'; const DEFAULT_SHAPES = ['circle', 'square', 'triangle-up', 'star']; @@ -157,6 +159,10 @@ export function EagerVis({ const newConfig = hexinbMergeDefaultConfig(columns, inconsistentVisConfig); _setVisConfig({ current: newConfig, consistent: newConfig }); } + if (isHeatmap(inconsistentVisConfig)) { + const newConfig = heatmapMergeDefaultConfig(columns, inconsistentVisConfig); + _setVisConfig({ current: newConfig, consistent: newConfig }); + } // DANGER:: this useEffect should only occur when the visConfig.type changes. adding visconfig into the dep array will cause an infinite loop. // eslint-disable-next-line react-hooks/exhaustive-deps }, [inconsistentVisConfig.type]); @@ -284,6 +290,19 @@ export function EagerVis({ {...commonProps} /> ) : null} + + {isHeatmap(visConfig) ? ( + + ) : null} ); } diff --git a/src/vis/heatmap/Heatmap.tsx b/src/vis/heatmap/Heatmap.tsx new file mode 100644 index 000000000..7034dce9a --- /dev/null +++ b/src/vis/heatmap/Heatmap.tsx @@ -0,0 +1,91 @@ +import { Group, Stack, Text, Tooltip } from '@mantine/core'; +import { useResizeObserver } from '@mantine/hooks'; +import { table } from 'arquero'; +import * as d3 from 'd3v7'; +import * as React from 'react'; + +import { useAsync } from '../../hooks'; +import { IHeatmapConfig, VisColumn } from '../interfaces'; +import { HeatmapRect } from './HeatmapRect'; +import { getHeatmapData } from './utils'; + +const interRectDistance = 1; +const margin = { + top: 20, + right: 20, + bottom: 10, + left: 20, +}; + +export function Heatmap({ config, columns }: { config: IHeatmapConfig; columns: VisColumn[] }) { + const { value: allColumns } = useAsync(getHeatmapData, [columns, config?.catColumnsSelected]); + const [ref, { width, height }] = useResizeObserver(); + const [tooltipText, setTooltipText] = React.useState(null); + + const hasEnoughCatCols = allColumns?.catColumn && allColumns?.catColumn?.length > 1; + + const { xValues, yValues, groupedValues } = React.useMemo(() => { + if (!hasEnoughCatCols) return { xValues: [], yValues: [], groupedValues: [] }; + const myTable = table({ + x: allColumns.catColumn[0]?.resolvedValues.map(({ val }) => val), + y: allColumns.catColumn[1]?.resolvedValues.map(({ val }) => val), + }); + const xVals = [...new Set(allColumns.catColumn[0]?.resolvedValues.map(({ val }) => val))]; + const yVals = [...new Set(allColumns.catColumn[1]?.resolvedValues.map(({ val }) => val))]; + return { + xValues: xVals as string[], + yValues: yVals as string[], + groupedValues: myTable.groupby('x', 'y').count().objects() as { x: string; y: string; count: number }[], + }; + }, [allColumns?.catColumn, hasEnoughCatCols]); + + const rectWidth = React.useMemo( + () => (xValues.length && width ? (width - margin.left - margin.right - interRectDistance * xValues.length) / xValues.length : 0), + [width, xValues.length], + ); + const rectHeight = React.useMemo( + () => (yValues.length && height ? (height - margin.bottom - margin.top - interRectDistance * yValues.length) / yValues.length : 0), + [height, yValues.length], + ); + + const colorScale = React.useMemo(() => { + if (!hasEnoughCatCols) return d3.scaleSequential(d3.interpolateReds); + return d3.scaleSequential(d3.interpolateBlues).domain(d3.extent(groupedValues, (d) => d.count as number)); + }, [hasEnoughCatCols, groupedValues]); + + return !hasEnoughCatCols ? ( + Select at least 2 categorical columns to display heatmap + ) : ( + + + + {allColumns.catColumn[1].info.name} + + + + {xValues.map((x: string, iX: number) => + yValues.map((y: string, iY: number) => { + const count = groupedValues?.find((d) => d.x === x && d.y === y)?.count ?? 0; + return ( + setTooltipText(`${x} - ${y} (${count})`)} + unsetTooltipText={() => setTooltipText(null)} + /> + ); + }), + )} + + + + + {allColumns.catColumn[0].info.name ?? ''} + + + ); +} diff --git a/src/vis/heatmap/HeatmapRect.tsx b/src/vis/heatmap/HeatmapRect.tsx new file mode 100644 index 000000000..bdd4c9544 --- /dev/null +++ b/src/vis/heatmap/HeatmapRect.tsx @@ -0,0 +1,23 @@ +import * as React from 'react'; +import { useSpring, animated } from 'react-spring'; + +export function HeatmapRect({ + x, + y, + width, + height, + color, + setTooltipText, + unsetTooltipText, +}: { + x: number; + y: number; + width: number; + height: number; + color: string; + setTooltipText(): void; + unsetTooltipText(): void; +}) { + const spring = useSpring({ from: { opacity: 0, width: 0, height: 0 }, to: { opacity: 1, width, height }, duration: 50 }); + return ; +} diff --git a/src/vis/heatmap/HeatmapVis.tsx b/src/vis/heatmap/HeatmapVis.tsx new file mode 100644 index 000000000..d40e9f3a3 --- /dev/null +++ b/src/vis/heatmap/HeatmapVis.tsx @@ -0,0 +1,41 @@ +import { Group, Text } from '@mantine/core'; +import * as React from 'react'; +import { VisSidebarWrapper } from '../VisSidebarWrapper'; +import { IHeatmapConfig, IVisConfig, VisColumn } from '../interfaces'; +import { HeatmapVisSidebar } from './HeatmapVisSidebar'; +import { VisSidebarOpenButton } from '../VisSidebarOpenButton'; +import { Heatmap } from './Heatmap'; + +export function HeatmapVis({ + config, + columns, + setConfig, + selectionCallback = () => null, + selected = {}, + enableSidebar, + setShowSidebar, + showSidebar, + showDragModeOptions = true, +}: { + config: IHeatmapConfig; + columns: VisColumn[]; + setConfig: (config: IVisConfig) => void; + selectionCallback?: (ids: string[]) => void; + selected?: { [key: string]: boolean }; + showSidebar?: boolean; + setShowSidebar?(show: boolean): void; + showDragModeOptions?: boolean; + enableSidebar?: boolean; +}) { + return ( + + {enableSidebar ? setShowSidebar(!showSidebar)} isOpen={showSidebar} /> : null} + + {showSidebar ? ( + + + + ) : null} + + ); +} diff --git a/src/vis/heatmap/HeatmapVisSidebar.tsx b/src/vis/heatmap/HeatmapVisSidebar.tsx new file mode 100644 index 000000000..17eb94715 --- /dev/null +++ b/src/vis/heatmap/HeatmapVisSidebar.tsx @@ -0,0 +1,20 @@ +import { Container, Stack } from '@mantine/core'; +import * as React from 'react'; +import { ColumnInfo, ESupportedPlotlyVis, IHeatmapConfig, IVisConfig, VisColumn } from '../interfaces'; +import { VisTypeSelect } from '../sidebar/VisTypeSelect'; +import { CategoricalColumnSelect } from '../sidebar/CategoricalColumnSelect'; + +export function HeatmapVisSidebar({ config, columns, setConfig }: { config: IHeatmapConfig; columns: VisColumn[]; setConfig: (config: IVisConfig) => void }) { + return ( + + + setConfig({ ...config, catColumnsSelected })} + columns={columns} + currentSelected={config.catColumnsSelected || []} + /> + setConfig({ ...(config as any), type })} currentSelected={config.type} /> + + + ); +} diff --git a/src/vis/heatmap/utils.ts b/src/vis/heatmap/utils.ts new file mode 100644 index 000000000..cc3b0749e --- /dev/null +++ b/src/vis/heatmap/utils.ts @@ -0,0 +1,33 @@ +import merge from 'lodash/merge'; +import { IVisConfig, IHeatmapConfig, ESupportedPlotlyVis, VisColumn, EColumnTypes, ColumnInfo, VisNumericalValue, VisCategoricalValue } from '../interfaces'; +import { resolveColumnValues, resolveSingleColumn } from '../general/layoutUtils'; + +export function isHeatmap(vis: IVisConfig): vis is IHeatmapConfig { + return vis.type === ESupportedPlotlyVis.HEATMAP; +} + +const defaultConfig: IHeatmapConfig = { + type: ESupportedPlotlyVis.HEATMAP, + colorScale: null, + catColumnsSelected: [], +}; + +export function heatmapMergeDefaultConfig(columns: VisColumn[], config: IHeatmapConfig): IVisConfig { + const merged = merge({}, defaultConfig, config); + return merged; +} + +export async function getHeatmapData( + columns: VisColumn[], + catColumnDesc: ColumnInfo[], +): Promise<{ + catColumn: { + resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; + type: EColumnTypes.NUMERICAL | EColumnTypes.CATEGORICAL; + info: ColumnInfo; + }[]; +}> { + const catColumn = await resolveColumnValues(columns.filter((col) => catColumnDesc.find((catCol) => catCol.id === col.info.id))); + + return { catColumn }; +} diff --git a/src/vis/interfaces.ts b/src/vis/interfaces.ts index 45e99396a..97f0ad170 100644 --- a/src/vis/interfaces.ts +++ b/src/vis/interfaces.ts @@ -5,6 +5,7 @@ export enum ESupportedPlotlyVis { VIOLIN = 'Violin plot', BAR = 'Bar chart', HEXBIN = 'Hexbin plot', + HEATMAP = 'Heatmap plot', } export const allVisTypes: ESupportedPlotlyVis[] = [ @@ -12,9 +13,10 @@ export const allVisTypes: ESupportedPlotlyVis[] = [ ESupportedPlotlyVis.BAR, ESupportedPlotlyVis.VIOLIN, ESupportedPlotlyVis.HEXBIN, + ESupportedPlotlyVis.HEATMAP, ]; -export type IVisConfig = IScatterConfig | IViolinConfig | IBarConfig | IHexbinConfig; +export type IVisConfig = IScatterConfig | IViolinConfig | IBarConfig | IHexbinConfig | IHeatmapConfig; export enum EBarDisplayType { ABSOLUTE = 'Absolute', @@ -120,6 +122,12 @@ export interface IHexbinConfig { hexbinOptions: EHexbinOptions; } +export interface IHeatmapConfig { + type: ESupportedPlotlyVis.HEATMAP; + colorScale: Scales; + catColumnsSelected: ColumnInfo[]; +} + type ValueGetter = () => T | Promise; export interface IVisCommonValue { diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index 586e99e96..7bbe05cf8 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -24,7 +24,7 @@ export function fetchIrisData(): VisColumn[] { let counter = 0; heatmapData.forEach((state) => { - for (let i = 0; i < Math.round(state.value / 100) + 1; i++) { + for (let i = 0; i < Math.round(state.value / 10) + 1; i++) { if (!state.x || !state.y) { console.log('danger'); } @@ -198,3 +198,28 @@ ViolinPlot.args = { violinOverlay: EViolinOverlay.NONE, }, }; + +export const Heatmap: typeof Template = Template.bind({}); +Heatmap.args = { + externalConfig: { + type: ESupportedPlotlyVis.HEATMAP, + colorScale: null, + catColumnsSelected: [ + { + description: '', + id: 'state', + name: 'US States', + }, + { + description: '', + id: 'randomThing', + name: 'Random Thing', + }, + { + description: '', + id: 'year', + name: 'Years', + }, + ], + }, +}; From cb9e7356cca11baa38ca03ed62c47a3abdee990a Mon Sep 17 00:00:00 2001 From: tschachinger Date: Mon, 19 Jun 2023 16:12:26 +0200 Subject: [PATCH 076/241] trying stuff --- src/vis/heatmap/Heatmap.tsx | 68 ++++++++++++++++++---------------- src/vis/heatmap/HeatmapVis.tsx | 2 +- 2 files changed, 38 insertions(+), 32 deletions(-) diff --git a/src/vis/heatmap/Heatmap.tsx b/src/vis/heatmap/Heatmap.tsx index 7034dce9a..a8fbb4462 100644 --- a/src/vis/heatmap/Heatmap.tsx +++ b/src/vis/heatmap/Heatmap.tsx @@ -53,39 +53,45 @@ export function Heatmap({ config, columns }: { config: IHeatmapConfig; columns: return d3.scaleSequential(d3.interpolateBlues).domain(d3.extent(groupedValues, (d) => d.count as number)); }, [hasEnoughCatCols, groupedValues]); - return !hasEnoughCatCols ? ( - Select at least 2 categorical columns to display heatmap - ) : ( + return ( - - - {allColumns.catColumn[1].info.name} + {!hasEnoughCatCols ? ( + + Select at least 2 categorical columns to display heatmap - - - {xValues.map((x: string, iX: number) => - yValues.map((y: string, iY: number) => { - const count = groupedValues?.find((d) => d.x === x && d.y === y)?.count ?? 0; - return ( - setTooltipText(`${x} - ${y} (${count})`)} - unsetTooltipText={() => setTooltipText(null)} - /> - ); - }), - )} - - - - - {allColumns.catColumn[0].info.name ?? ''} - + ) : ( + <> + + + {allColumns.catColumn[1].info.name} + + + + {xValues.map((x: string, iX: number) => + yValues.map((y: string, iY: number) => { + const count = groupedValues?.find((d) => d.x === x && d.y === y)?.count ?? 0; + return ( + setTooltipText(`${x} - ${y} (${count})`)} + unsetTooltipText={() => setTooltipText(null)} + /> + ); + }), + )} + + + + + {allColumns.catColumn[0].info.name ?? ''} + + + )} ); } diff --git a/src/vis/heatmap/HeatmapVis.tsx b/src/vis/heatmap/HeatmapVis.tsx index d40e9f3a3..6c7878683 100644 --- a/src/vis/heatmap/HeatmapVis.tsx +++ b/src/vis/heatmap/HeatmapVis.tsx @@ -28,7 +28,7 @@ export function HeatmapVis({ enableSidebar?: boolean; }) { return ( - + {enableSidebar ? setShowSidebar(!showSidebar)} isOpen={showSidebar} /> : null} {showSidebar ? ( From 12d189665f6dc22faf950fb7366efb20e518af9d Mon Sep 17 00:00:00 2001 From: oltionchampari Date: Mon, 19 Jun 2023 16:27:18 +0200 Subject: [PATCH 077/241] Add axis --- src/vis/parallelCoordinates/ParallelPlot.tsx | 65 +++++++++++++------- src/vis/parallelCoordinates/YAxis.tsx | 18 ++++-- src/vis/parallelCoordinates/utils.ts | 3 +- 3 files changed, 57 insertions(+), 29 deletions(-) diff --git a/src/vis/parallelCoordinates/ParallelPlot.tsx b/src/vis/parallelCoordinates/ParallelPlot.tsx index fa3cefc65..6b02ef78f 100644 --- a/src/vis/parallelCoordinates/ParallelPlot.tsx +++ b/src/vis/parallelCoordinates/ParallelPlot.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import * as d3v7 from 'd3v7'; import { useResizeObserver } from '@mantine/hooks'; import { Group, Stack } from '@mantine/core'; -import { IParallelCoordinatesConfig, VisColumn } from '../interfaces'; +import { EColumnTypes, IParallelCoordinatesConfig, VisColumn } from '../interfaces'; import { ParallelYAxis } from './YAxis'; import { useAsync } from '../../hooks'; @@ -22,42 +22,63 @@ const margin = { left: 30, }; +const removeSpace = (col: string) => col.replace(' ', ''); + export function ParallelPlot({ columns, config }: { config: IParallelCoordinatesConfig; columns: VisColumn[] }) { const [ref, { width, height }] = useResizeObserver(); - const { value: allColumns, status: colsStatus } = useAsync(getParallelData, [columns, config?.numColumnsSelected, config?.catColumnsSelected]); + const { value: allColumns, status: colsStatus, error } = useAsync(getParallelData, [columns, config?.numColumnsSelected, config?.catColumnsSelected]); - const oneNumCol = allColumns?.numColVals?.[0]; const yScales = React.useMemo(() => { - if (allColumns?.numColVals.length === 0) return null; - const allNuimericalScales = allColumns?.numColVals?.map((col) => { - const scale = d3v7 - .scaleLinear() - .domain(d3v7.extent(col.resolvedValues.map((v) => v.val as number))) - .range([height, margin.top]); + const all = [...(allColumns?.numColVals || []), ...(allColumns?.catColVals || [])]; + if (all.length === 0) return null; + return all?.map((col) => { + let scale; + if (col.type === EColumnTypes.NUMERICAL) { + scale = d3v7 + .scaleLinear() + .domain(d3v7.extent(col.resolvedValues.map((v) => v.val as number))) + .range([height, margin.top]); + } else { + scale = d3v7 + .scaleBand() + .domain(col.resolvedValues.map((c) => c.val as string)) + .range([height, margin.top]); + } + return { - id: col.info.name, + id: removeSpace(col.info.name), + type: col.type, scale, }; }); - }, [allColumns?.numColVals, height]); + }, [allColumns, height]); + console.log(yScales); const xScale = React.useMemo(() => { + const all = [...(allColumns?.numColVals || []), ...(allColumns?.catColVals || [])]; + if (all.length === 0) return null; + return d3v7 .scaleBand() - .domain(allColumns?.numColVals.map((col) => col.info.name as string)) + .domain(all.map((c) => removeSpace(c.info.name))) .range([margin.left, width - margin.right]); - }, [allColumns?.numColVals, width]); - // const yScale = React.useMemo(() => { - // if (!oneNumCol) return null; - // return d3v7 - // .scaleLinear() - // .domain(d3v7.extent(oneNumCol.resolvedValues.map((v) => v.val as number))) - // .range([height, margin.top]); - // }, [height, oneNumCol]); + }, [allColumns?.catColVals, allColumns?.numColVals, width]); + return ( - {xScale ? xScale() : null} - {yScales ? yScales.map((yScale, index) => ) : null} + {allColumns && yScales && xScale + ? yScales.map((yScale) => { + return ( + + ); + }) + : null} {/* */} ); diff --git a/src/vis/parallelCoordinates/YAxis.tsx b/src/vis/parallelCoordinates/YAxis.tsx index 34b91ee90..c0ae7bfe8 100644 --- a/src/vis/parallelCoordinates/YAxis.tsx +++ b/src/vis/parallelCoordinates/YAxis.tsx @@ -1,15 +1,22 @@ import * as React from 'react'; import { useMemo } from 'react'; - +import { EColumnTypes, IParallelCoordinatesConfig, VisColumn } from '../interfaces'; // code taken from https://wattenberger.com/blog/react-and-d3 -export function ParallelYAxis({ yScale, xRange, horizontalPosition }) { +export function ParallelYAxis({ yScale, xRange, horizontalPosition, type }) { + console.log(yScale); const ticks = useMemo(() => { - return yScale.ticks(5).map((value) => ({ + if (type === EColumnTypes.NUMERICAL) { + return yScale.ticks(5).map((value) => ({ + value, + yOffset: yScale(value), + })); + } + return yScale.domain().map((value) => ({ value, yOffset: yScale(value), })); - }, [yScale]); - console.log('ticks: ', ticks); + }, [type, yScale]); + return ( <> ( - {/* */} { + console.log('num'); const numCols: VisNumericalColumn[] = numColumnsSelected.map((col) => columns.find((c) => c.info.id === col.id)) as VisNumericalColumn[]; const catCols: VisCategoricalColumn[] = catColumnsSelected.map((col) => columns.find((c) => c.info.id === col.id)) as VisCategoricalColumn[]; const numColVals = await resolveColumnValues(numCols); const catColVals = await resolveColumnValues(catCols); - console.log(numColVals); + console.log('num', numColVals); // const colorColVals = await resolveSingleColumn(colorColumn ? columns.find((col) => col.info.id === colorColumn.id) : null); return { numColVals, catColVals }; From 303314b503e5a54eeecaa70c86269aba1bd51a4a Mon Sep 17 00:00:00 2001 From: Daniela Date: Mon, 19 Jun 2023 17:12:29 +0200 Subject: [PATCH 078/241] calculate path --- package.json | 1 + src/vis/parallelCoordinates/ParallelPlot.tsx | 30 ++++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 20bba166d..0fffdc784 100644 --- a/package.json +++ b/package.json @@ -150,6 +150,7 @@ "@types/react": "^18.2.0", "@types/react-dom": "^18.2.0", "@types/react-plotly.js": "^2.5.0", + "arquero": "^5.2.0", "d3-hexbin": "^0.2.2", "d3v7": "npm:d3@^7.4.0", "i18next": "^22.4.15", diff --git a/src/vis/parallelCoordinates/ParallelPlot.tsx b/src/vis/parallelCoordinates/ParallelPlot.tsx index 6b02ef78f..6e4cdf334 100644 --- a/src/vis/parallelCoordinates/ParallelPlot.tsx +++ b/src/vis/parallelCoordinates/ParallelPlot.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import * as d3v7 from 'd3v7'; import { useResizeObserver } from '@mantine/hooks'; -import { Group, Stack } from '@mantine/core'; +import { table } from 'arquero'; import { EColumnTypes, IParallelCoordinatesConfig, VisColumn } from '../interfaces'; import { ParallelYAxis } from './YAxis'; @@ -28,6 +28,15 @@ export function ParallelPlot({ columns, config }: { config: IParallelCoordinates const [ref, { width, height }] = useResizeObserver(); const { value: allColumns, status: colsStatus, error } = useAsync(getParallelData, [columns, config?.numColumnsSelected, config?.catColumnsSelected]); + const rows = React.useMemo(() => { + const all = [...(allColumns?.numColVals || []), ...(allColumns?.catColVals || [])]; + if (all.length === 0) return null; + const dt = table(all.reduce((acc, col) => ({ ...acc, [removeSpace(col.info.name)]: col.resolvedValues.map((v) => v.val) }), {})); + console.log('table: ', dt); + console.log(dt.objects()); + return dt.objects(); + }, [allColumns]); + const yScales = React.useMemo(() => { const all = [...(allColumns?.numColVals || []), ...(allColumns?.catColVals || [])]; if (all.length === 0) return null; @@ -52,7 +61,6 @@ export function ParallelPlot({ columns, config }: { config: IParallelCoordinates }; }); }, [allColumns, height]); - console.log(yScales); const xScale = React.useMemo(() => { const all = [...(allColumns?.numColVals || []), ...(allColumns?.catColVals || [])]; @@ -64,6 +72,23 @@ export function ParallelPlot({ columns, config }: { config: IParallelCoordinates .range([margin.left, width - margin.right]); }, [allColumns?.catColVals, allColumns?.numColVals, width]); + const paths = React.useMemo(() => { + const r = rows?.[0]; + if (!r) return null; + const yPositions = Object.keys(r).map((col) => { + const xPos = xScale(col); + const yPos = yScales?.find((yScale) => yScale.id === col)?.scale(r[col]) || 0; + return [xPos, yPos]; + }); + // yScales?.map((yScale) => { + // return r[yScale.id]; + // }); + console.log('yPositions: ', yPositions); + return yPositions; + // const xPos = xScale(col) || 0; + }, [rows, xScale, yScales]); + console.log('paths: ', paths); + return ( {allColumns && yScales && xScale @@ -79,6 +104,7 @@ export function ParallelPlot({ columns, config }: { config: IParallelCoordinates ); }) : null} + {rows ? : null} {/* */} ); From cb2ac8b29f8e51d617a0da187da3c817094e5b69 Mon Sep 17 00:00:00 2001 From: Daniela Date: Mon, 19 Jun 2023 18:45:03 +0200 Subject: [PATCH 079/241] draw paths --- src/vis/parallelCoordinates/ParallelPlot.tsx | 42 +++++++++----------- src/vis/parallelCoordinates/ParallelVis.tsx | 9 +---- 2 files changed, 21 insertions(+), 30 deletions(-) diff --git a/src/vis/parallelCoordinates/ParallelPlot.tsx b/src/vis/parallelCoordinates/ParallelPlot.tsx index 6e4cdf334..1a8610185 100644 --- a/src/vis/parallelCoordinates/ParallelPlot.tsx +++ b/src/vis/parallelCoordinates/ParallelPlot.tsx @@ -8,13 +8,6 @@ import { ParallelYAxis } from './YAxis'; import { useAsync } from '../../hooks'; import { getParallelData } from './utils'; -const defaultExtensions = { - prePlot: null, - postPlot: null, - preSidebar: null, - postSidebar: null, -}; - const margin = { top: 30, right: 10, @@ -32,8 +25,6 @@ export function ParallelPlot({ columns, config }: { config: IParallelCoordinates const all = [...(allColumns?.numColVals || []), ...(allColumns?.catColVals || [])]; if (all.length === 0) return null; const dt = table(all.reduce((acc, col) => ({ ...acc, [removeSpace(col.info.name)]: col.resolvedValues.map((v) => v.val) }), {})); - console.log('table: ', dt); - console.log(dt.objects()); return dt.objects(); }, [allColumns]); @@ -73,24 +64,30 @@ export function ParallelPlot({ columns, config }: { config: IParallelCoordinates }, [allColumns?.catColVals, allColumns?.numColVals, width]); const paths = React.useMemo(() => { - const r = rows?.[0]; - if (!r) return null; - const yPositions = Object.keys(r).map((col) => { - const xPos = xScale(col); - const yPos = yScales?.find((yScale) => yScale.id === col)?.scale(r[col]) || 0; - return [xPos, yPos]; + return rows?.map((r) => { + if (!r) return null; + const yPositions = Object.keys(r).map((col) => { + const xPos = xScale(col); + const yPos = yScales?.find((yScale) => yScale.id === col)?.scale(r[col]) || 0; + return [xPos, yPos]; + }); + + let svgPath = ''; + yPositions.forEach((yPos, i) => { + if (i === 0) { + svgPath += `M ${yPos[0]},${yPos[1]}`; + } else { + svgPath += `L ${yPos[0]},${yPos[1]}`; + } + }); + return svgPath; }); - // yScales?.map((yScale) => { - // return r[yScale.id]; - // }); - console.log('yPositions: ', yPositions); - return yPositions; - // const xPos = xScale(col) || 0; }, [rows, xScale, yScales]); - console.log('paths: ', paths); return ( + {paths ? paths?.map((path, i) => ) : null} + {allColumns && yScales && xScale ? yScales.map((yScale) => { return ( @@ -104,7 +101,6 @@ export function ParallelPlot({ columns, config }: { config: IParallelCoordinates ); }) : null} - {rows ? : null} {/* */} ); diff --git a/src/vis/parallelCoordinates/ParallelVis.tsx b/src/vis/parallelCoordinates/ParallelVis.tsx index 9e44c522a..a7ebeabee 100644 --- a/src/vis/parallelCoordinates/ParallelVis.tsx +++ b/src/vis/parallelCoordinates/ParallelVis.tsx @@ -3,6 +3,7 @@ import * as React from 'react'; import * as d3v7 from 'd3v7'; import { Group, Stack } from '@mantine/core'; import { useResizeObserver } from '@mantine/hooks'; +import { Text } from '@mantine/core'; import { IVisConfig, VisColumn, IParallelCoordinatesConfig } from '../interfaces'; import { useAsync } from '../../hooks'; import { VisSidebarWrapper } from '../VisSidebarWrapper'; @@ -11,13 +12,6 @@ import { ParallelVisSidebar } from './ParallelVisSidebar'; import { ParallelPlot } from './ParallelPlot'; import { getParallelData } from './utils'; -const margin = { - top: 30, - right: 10, - bottom: 10, - left: 10, -}; - const defaultExtensions = { prePlot: null, postPlot: null, @@ -83,6 +77,7 @@ export function ParallelVis({ {config?.numColumnsSelected?.length > 1 ? : null} + test {showSidebar ? ( From 66509e223612988c05950e75527f720ba33ddba3 Mon Sep 17 00:00:00 2001 From: Daniela Date: Mon, 19 Jun 2023 18:52:44 +0200 Subject: [PATCH 080/241] add mantine tooltip --- src/vis/parallelCoordinates/ParallelPlot.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/vis/parallelCoordinates/ParallelPlot.tsx b/src/vis/parallelCoordinates/ParallelPlot.tsx index 1a8610185..586f5068d 100644 --- a/src/vis/parallelCoordinates/ParallelPlot.tsx +++ b/src/vis/parallelCoordinates/ParallelPlot.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import * as d3v7 from 'd3v7'; import { useResizeObserver } from '@mantine/hooks'; import { table } from 'arquero'; +import { Tooltip } from '@mantine/core'; import { EColumnTypes, IParallelCoordinatesConfig, VisColumn } from '../interfaces'; import { ParallelYAxis } from './YAxis'; @@ -86,7 +87,13 @@ export function ParallelPlot({ columns, config }: { config: IParallelCoordinates return ( - {paths ? paths?.map((path, i) => ) : null} + {paths + ? paths.slice(0, 2)?.map((path, i) => ( + + + + )) + : null} {allColumns && yScales && xScale ? yScales.map((yScale) => { From 2649c09277d781b9b6cdf1d4014a4d3ad4b8d17c Mon Sep 17 00:00:00 2001 From: dvmartinweigl Date: Mon, 19 Jun 2023 19:17:11 +0200 Subject: [PATCH 081/241] refactor --- src/demo/MainApp.tsx | 4 +- src/vis/Vis.tsx | 5 +- src/vis/correlation/CorrelationMatrix.tsx | 267 +++++++----------- src/vis/correlation/CorrelationVis.tsx | 70 +++++ .../components/CircleCorrelationPair.tsx | 40 +++ .../components/CorrelationPlotAxis.tsx | 32 +++ src/vis/correlation/utils.ts | 2 +- src/vis/stories/Iris.stories.tsx | 4 +- 8 files changed, 246 insertions(+), 178 deletions(-) create mode 100644 src/vis/correlation/CorrelationVis.tsx create mode 100644 src/vis/correlation/components/CircleCorrelationPair.tsx create mode 100644 src/vis/correlation/components/CorrelationPlotAxis.tsx diff --git a/src/demo/MainApp.tsx b/src/demo/MainApp.tsx index 608fdf1c6..2777d5ea9 100644 --- a/src/demo/MainApp.tsx +++ b/src/demo/MainApp.tsx @@ -7,7 +7,6 @@ import { useVisynAppContext, VisynApp, VisynHeader } from '../app'; import { VisynRanking } from '../ranking'; import { IBuiltVisynRanking } from '../ranking/EagerVisynRanking'; import { MyNumberScore, MyStringScore } from './scoresUtils'; -import { CorrelationMatrix } from '../vis/correlation/CorrelationMatrix'; export function MainApp() { const { user } = useVisynAppContext(); @@ -53,7 +52,6 @@ export function MainApp() { }} /> } - > - + /> ); } diff --git a/src/vis/Vis.tsx b/src/vis/Vis.tsx index 8e571b3fb..fa3af68e4 100644 --- a/src/vis/Vis.tsx +++ b/src/vis/Vis.tsx @@ -23,7 +23,8 @@ import { getCssValue } from '../utils'; import { useSyncedRef } from '../hooks/useSyncedRef'; import { hexinbMergeDefaultConfig, isHexbin } from './hexbin/utils'; import { HexbinVis } from './hexbin/HexbinVis'; -import { CorrelationMatrix, isCorrelation } from './correlation'; +import { isCorrelation } from './correlation'; +import { CorrelationVis } from './correlation/CorrelationVis'; const DEFAULT_SHAPES = ['circle', 'square', 'triangle-up', 'star']; @@ -286,7 +287,7 @@ export function EagerVis({ /> ) : null} - {isCorrelation(visConfig) ? : null} + {isCorrelation(visConfig) ? : null} ); } diff --git a/src/vis/correlation/CorrelationMatrix.tsx b/src/vis/correlation/CorrelationMatrix.tsx index 783df6414..56556de81 100644 --- a/src/vis/correlation/CorrelationMatrix.tsx +++ b/src/vis/correlation/CorrelationMatrix.tsx @@ -1,86 +1,27 @@ import * as React from 'react'; -import { scaleBand, scaleLinear, scalePoint } from 'd3v7'; -import { Group, Stack, useMantineColorScheme, useMantineTheme } from '@mantine/core'; +import { scaleBand, scaleLinear } from 'd3v7'; +import { useMantineTheme } from '@mantine/core'; import { useResizeObserver } from '@mantine/hooks'; import * as calculateCorrelation from 'calculate-correlation'; -import { ICorrelationConfig, IVisConfig, VisColumn } from '../interfaces'; -import { VisSidebarWrapper } from '../VisSidebarWrapper'; -import { InvalidCols } from '../general/InvalidCols'; -import { VisSidebarOpenButton } from '../VisSidebarOpenButton'; -import { CorrelationVisSidebar } from './CorrelationVisSidebar'; +import { ICorrelationConfig, VisColumn } from '../interfaces'; import { useAsync } from '../../hooks/useAsync'; -import { getScatterData } from './utils'; - -interface CircleProps { - cx: number; - cy: number; - correlation: number; - xname: string; - yname: string; -} - -function SCircle({ value, fill, xScale, yScale, hover }: { value: CircleProps; fill: string; xScale; yScale; hover: boolean }) { - const cx = xScale(value.xname) + xScale.bandwidth() / 2; - const cy = yScale(value.yname) + yScale.bandwidth() / 2; - - return ( - <> - - - {value.correlation.toFixed(2)} - - - ); -} +import { getCorrelationMatrixData } from './utils'; +import { CircleCorrelationPair, CircleCorrelationPairProps } from './components/CircleCorrelationPair'; +import { CorrelationPlotXAxis } from './components/CorrelationPlotAxis'; -export function CorrelationMatrix({ - config, - columns, - setConfig, - enableSidebar, - showSidebar, - setShowSidebar, - extensions, -}: { - config: ICorrelationConfig; - columns: VisColumn[]; - setConfig?: (config: IVisConfig) => void; - enableSidebar?: boolean; - showSidebar?: boolean; - setShowSidebar?(show: boolean): void; - extensions?: { - prePlot?: React.ReactNode; - postPlot?: React.ReactNode; - preSidebar?: React.ReactNode; - postSidebar?: React.ReactNode; - }; -}) { +export function CorrelationMatrix({ config, columns }: { config: ICorrelationConfig; columns: VisColumn[] }) { const color = scaleLinear().domain([-1, 0, 1]).range(['#B22222', '#fff', '#000080']); - const data = useAsync(getScatterData, [columns, config.numColumnsSelected]); + const data = useAsync(getCorrelationMatrixData, [columns, config.numColumnsSelected]); const theme = useMantineTheme(); const borderColor = theme.colors.gray[4]; const [hover, setHover] = React.useState<{ xi: number; yi: number }>(undefined); - const [ref, { width, height }] = useResizeObserver(); + const [ref, { width, height }] = useResizeObserver(); const xScale = React.useMemo(() => { if (!data?.value?.numericalColumns) return null; - return scaleBand() .range([0, width]) .domain(data.value.numericalColumns.map((column) => column.info.name)); @@ -88,7 +29,6 @@ export function CorrelationMatrix({ const yScale = React.useMemo(() => { if (!data?.value?.numericalColumns) return null; - return scaleBand() .range([0, height]) .domain(data.value.numericalColumns.map((column) => column.info.name)); @@ -97,109 +37,96 @@ export function CorrelationMatrix({ const memoized = React.useMemo(() => { if (!data?.value?.numericalColumns) return null; - const circles = [] as CircleProps[]; - const texts = [] as { cx: number; cy: number; correlation: number }[]; - - data.value.numericalColumns.forEach((column, i) => { - const xname = column.info.name; - - data.value.numericalColumns.forEach((column2, j) => { - const yname = column2.info.name; + const cols = data.value.numericalColumns; + for (let y = 1; y < cols.length; y++) { + for (let x = 0; x < y; x++) { const correlation = calculateCorrelation( - column.resolvedValues.map((resolved) => resolved.val as number), - column2.resolvedValues.map((resolved) => resolved.val as number), + cols[x].resolvedValues.map((resolved) => resolved.val as number), + cols[y].resolvedValues.map((resolved) => resolved.val as number), ); - if (i > j) { - circles.push({ cx: i, cy: j, correlation, xname: column.info.name, yname: column2.info.name }); - } - if (j > i) { - texts.push({ cx: xScale(xname) + xScale.bandwidth() / 2, cy: yScale(yname) + yScale.bandwidth() / 2, correlation }); - } - }); - }); - - return { circle: circles, text: texts }; - }, [xScale, yScale, data]); - - const colorScale = scaleLinear().domain([-1, 0, 1]).range(['#B22222', '#fff', '#000080']); - - return ( - - {enableSidebar ? setShowSidebar(!showSidebar)} isOpen={showSidebar} /> : null} - - - { - console.log(event.nativeEvent.offsetX, event.nativeEvent.offsetY); - - const xi = Math.floor(event.nativeEvent.offsetX / (width / data.value.numericalColumns.length)); - const yi = Math.floor(event.nativeEvent.offsetY / (height / data.value.numericalColumns.length)); - - setHover({ xi, yi }); - }} - onMouseLeave={() => { - setHover(undefined); - }} - > - {data.value?.numericalColumns.map((column) => { - return ( - <> - - - - ); - })} - - - - - {memoized?.circle.map((value) => { - return ( - - ); - })} - - - {showSidebar ? ( - - - - ) : null} - - ); + console.log(x, y, correlation); + } + } + + return null; + }, [data]); + + return null; + + // const memoized = React.useMemo(() => { + // if (!data?.value?.numericalColumns) return null; + + // const circles = [] as CircleCorrelationPairProps[]; + // const texts = [] as { cx: number; cy: number; correlation: number }[]; + + // data.value.numericalColumns.forEach((column, i) => { + // const xname = column.info.name; + + // data.value.numericalColumns.forEach((column2, j) => { + // const yname = column2.info.name; + + // const correlation = calculateCorrelation( + // column.resolvedValues.map((resolved) => resolved.val as number), + // column2.resolvedValues.map((resolved) => resolved.val as number), + // ); + + // if (i > j) { + // circles.push({ cx: i, cy: j, correlation, xname: column.info.name, yname: column2.info.name }); + // } + // if (j > i) { + // texts.push({ cx: xScale(xname) + xScale.bandwidth() / 2, cy: yScale(yname) + yScale.bandwidth() / 2, correlation }); + // } + // }); + // }); + + // return { circle: circles, text: texts }; + // }, [xScale, yScale, data]); + + // const colorScale = scaleLinear().domain([-1, 0, 1]).range(['#B22222', '#fff', '#000080']); + + // return ( + // { + // const xi = Math.floor(event.nativeEvent.offsetX / (width / data.value.numericalColumns.length)); + // const yi = Math.floor(event.nativeEvent.offsetY / (height / data.value.numericalColumns.length)); + // setHover({ xi, yi }); + // }} + // onMouseLeave={() => { + // setHover(undefined); + // }} + // > + // {data.value?.numericalColumns.map((column) => { + // return ( + // <> + // + // + // + // ); + // })} + + // + // + + // {data.value?.numericalColumns ? ( + // ({ value: c.info.name, offset: 20 }))} /> + // ) : null} + + // {memoized?.circle.map((value) => { + // return ( + // + // ); + // })} + // + // ); } diff --git a/src/vis/correlation/CorrelationVis.tsx b/src/vis/correlation/CorrelationVis.tsx new file mode 100644 index 000000000..6be7f5cba --- /dev/null +++ b/src/vis/correlation/CorrelationVis.tsx @@ -0,0 +1,70 @@ +import * as React from 'react'; +import { Group, Stack } from '@mantine/core'; +import { ICorrelationConfig, IVisConfig, VisColumn } from '../interfaces'; +import { VisSidebarWrapper } from '../VisSidebarWrapper'; +import { VisSidebarOpenButton } from '../VisSidebarOpenButton'; +import { CorrelationVisSidebar } from './CorrelationVisSidebar'; +import { CorrelationMatrix } from './CorrelationMatrix'; + +export function CorrelationVis({ + config, + columns, + setConfig, + enableSidebar, + showSidebar, + setShowSidebar, + extensions, +}: { + config: ICorrelationConfig; + columns: VisColumn[]; + setConfig?: (config: IVisConfig) => void; + enableSidebar?: boolean; + showSidebar?: boolean; + setShowSidebar?(show: boolean): void; + extensions?: { + prePlot?: React.ReactNode; + postPlot?: React.ReactNode; + preSidebar?: React.ReactNode; + postSidebar?: React.ReactNode; + }; +}) { + return ( + + {enableSidebar ? setShowSidebar(!showSidebar)} isOpen={showSidebar} /> : null} + + + {config.numColumnsSelected.length > 1 ? : null} + + {showSidebar ? ( + + + + ) : null} + + ); +} diff --git a/src/vis/correlation/components/CircleCorrelationPair.tsx b/src/vis/correlation/components/CircleCorrelationPair.tsx new file mode 100644 index 000000000..87f14090e --- /dev/null +++ b/src/vis/correlation/components/CircleCorrelationPair.tsx @@ -0,0 +1,40 @@ +import * as React from 'react'; + +const padding = { top: 16, right: 16, bottom: 16, left: 16 }; + +export interface CorrelationPairProps { + cx: number; + cy: number; + correlation: number; + pValue: number; + xName: string; + yName: string; +} + +export function CircleCorrelationPair({ value, fill, hover }: { value: CorrelationPairProps; fill: string; hover: boolean }) { + return null; + // const cx = xScale(value.xname) + xScale.bandwidth() / 2; + // const cy = yScale(value.yname) + yScale.bandwidth() / 2; + + // return ( + // <> + // + // + // {value.correlation.toFixed(2)} + // + // + // ); +} diff --git a/src/vis/correlation/components/CorrelationPlotAxis.tsx b/src/vis/correlation/components/CorrelationPlotAxis.tsx new file mode 100644 index 000000000..c7dee6f47 --- /dev/null +++ b/src/vis/correlation/components/CorrelationPlotAxis.tsx @@ -0,0 +1,32 @@ +import * as React from 'react'; +import * as d3 from 'd3v7'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faCaretLeft, faCaretRight } from '@fortawesome/free-solid-svg-icons'; +import { Center, Group } from '@mantine/core'; + +// code taken from https://wattenberger.com/blog/react-and-d3 +export function CorrelationPlotXAxis({ xScale, ticks }: { xScale: d3.ScaleBand; ticks: { value: string; offset: number }[] }) { + console.log(ticks); + return ( + <> + {ticks.map(({ value, offset }) => ( + + {/* */} + + {value} + + + ))} + + ); +} diff --git a/src/vis/correlation/utils.ts b/src/vis/correlation/utils.ts index a8783cede..c3b9d7124 100644 --- a/src/vis/correlation/utils.ts +++ b/src/vis/correlation/utils.ts @@ -26,7 +26,7 @@ export function correlationMergeDefaultConfig(columns: VisColumn[], config: ICor return merged; } -export async function getScatterData( +export async function getCorrelationMatrixData( columns: VisColumn[], numericalColumnDescs: ColumnInfo[], ): Promise<{ diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index bde7fb997..8432d3fc2 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -194,12 +194,12 @@ CorrelationPlot.args = { { description: '', id: 'petalWidth', - name: 'Sepal Width', + name: 'Petal Width', }, { description: '', id: 'petalLength', - name: 'Sepal Width', + name: 'Petal Length', }, ], }, From b757064e57f9beec2c6ff4e3de0b8892a0879207 Mon Sep 17 00:00:00 2001 From: Daniela Date: Mon, 19 Jun 2023 19:32:40 +0200 Subject: [PATCH 082/241] add statically positioned mantine tooltip --- src/vis/parallelCoordinates/ParallelPath.tsx | 15 +++++ src/vis/parallelCoordinates/ParallelPlot.tsx | 64 ++++++++++++-------- 2 files changed, 55 insertions(+), 24 deletions(-) create mode 100644 src/vis/parallelCoordinates/ParallelPath.tsx diff --git a/src/vis/parallelCoordinates/ParallelPath.tsx b/src/vis/parallelCoordinates/ParallelPath.tsx new file mode 100644 index 000000000..d6aa63e7f --- /dev/null +++ b/src/vis/parallelCoordinates/ParallelPath.tsx @@ -0,0 +1,15 @@ +import * as React from 'react'; + +export function ParallelPath({ + path, + index, + onHover, + onLeave, +}: { + path: string; + index: number; + onLeave: (e: React.MouseEvent) => void; + onHover: (e: React.MouseEvent) => void; +}) { + return ; +} diff --git a/src/vis/parallelCoordinates/ParallelPlot.tsx b/src/vis/parallelCoordinates/ParallelPlot.tsx index 586f5068d..d5026f813 100644 --- a/src/vis/parallelCoordinates/ParallelPlot.tsx +++ b/src/vis/parallelCoordinates/ParallelPlot.tsx @@ -8,6 +8,7 @@ import { ParallelYAxis } from './YAxis'; import { useAsync } from '../../hooks'; import { getParallelData } from './utils'; +import { ParallelPath } from './ParallelPath'; const margin = { top: 30, @@ -22,6 +23,9 @@ export function ParallelPlot({ columns, config }: { config: IParallelCoordinates const [ref, { width, height }] = useResizeObserver(); const { value: allColumns, status: colsStatus, error } = useAsync(getParallelData, [columns, config?.numColumnsSelected, config?.catColumnsSelected]); + const [showTooltip, setShowTooltip] = React.useState(false); + const [tooltipContent, setTooltipContent] = React.useState(''); + const rows = React.useMemo(() => { const all = [...(allColumns?.numColVals || []), ...(allColumns?.catColVals || [])]; if (all.length === 0) return null; @@ -29,6 +33,23 @@ export function ParallelPlot({ columns, config }: { config: IParallelCoordinates return dt.objects(); }, [allColumns]); + const onPathHover = React.useCallback( + (e: React.MouseEvent) => { + const { index } = e.currentTarget.dataset; + setShowTooltip(true); + setTooltipContent( + Object.keys(rows[index]) + .map((label) => `${label}: ${rows[index][label]}`) + .join('; '), + ); + }, + [rows], + ); + + const onPathLeave = React.useCallback((e: React.MouseEvent) => { + setShowTooltip(false); + }, []); + const yScales = React.useMemo(() => { const all = [...(allColumns?.numColVals || []), ...(allColumns?.catColVals || [])]; if (all.length === 0) return null; @@ -86,29 +107,24 @@ export function ParallelPlot({ columns, config }: { config: IParallelCoordinates }, [rows, xScale, yScales]); return ( - - {paths - ? paths.slice(0, 2)?.map((path, i) => ( - - - - )) - : null} - - {allColumns && yScales && xScale - ? yScales.map((yScale) => { - return ( - - ); - }) - : null} - {/* */} - + + + {paths ? paths.slice(0, 2)?.map((path, i) => ) : null} + {allColumns && yScales && xScale + ? yScales.map((yScale) => { + return ( + + ); + }) + : null} + {/* */} + + ); } From 10070ac6430e972123f069ef9628860960d07701 Mon Sep 17 00:00:00 2001 From: dvmartinweigl Date: Mon, 19 Jun 2023 23:58:44 +0200 Subject: [PATCH 083/241] refactor and add ttest results --- package.json | 2 +- src/vis/correlation/CorrelationMatrix.tsx | 192 +++++++++--------- .../components/CircleCorrelationPair.tsx | 74 ++++--- .../components/CorrelationMatrixAxis.tsx | 69 +++++++ .../components/CorrelationPlotAxis.tsx | 32 --- src/vis/correlation/utils.ts | 1 - src/vis/stories/Iris.stories.tsx | 2 +- 7 files changed, 209 insertions(+), 163 deletions(-) create mode 100644 src/vis/correlation/components/CorrelationMatrixAxis.tsx delete mode 100644 src/vis/correlation/components/CorrelationPlotAxis.tsx diff --git a/package.json b/package.json index 6116a62ca..00543b0ee 100644 --- a/package.json +++ b/package.json @@ -150,10 +150,10 @@ "@types/react": "^18.2.0", "@types/react-dom": "^18.2.0", "@types/react-plotly.js": "^2.5.0", - "calculate-correlation": "^1.2.3", "d3-hexbin": "^0.2.2", "d3v7": "npm:d3@^7.4.0", "i18next": "^22.4.15", + "jstat": "^1.9.6", "lineupjs": "4.7.0", "lodash": "~4.17.20", "plotly.js-dist-min": "~2.12.0", diff --git a/src/vis/correlation/CorrelationMatrix.tsx b/src/vis/correlation/CorrelationMatrix.tsx index 56556de81..809db2fe2 100644 --- a/src/vis/correlation/CorrelationMatrix.tsx +++ b/src/vis/correlation/CorrelationMatrix.tsx @@ -1,132 +1,126 @@ import * as React from 'react'; import { scaleBand, scaleLinear } from 'd3v7'; -import { useMantineTheme } from '@mantine/core'; import { useResizeObserver } from '@mantine/hooks'; -import * as calculateCorrelation from 'calculate-correlation'; +import { corrcoeff, studentt } from 'jstat'; import { ICorrelationConfig, VisColumn } from '../interfaces'; import { useAsync } from '../../hooks/useAsync'; import { getCorrelationMatrixData } from './utils'; -import { CircleCorrelationPair, CircleCorrelationPairProps } from './components/CircleCorrelationPair'; -import { CorrelationPlotXAxis } from './components/CorrelationPlotAxis'; +import { CircleCorrelationPair, CorrelationPairProps } from './components/CircleCorrelationPair'; +import { AxisTop, AxisLeft } from './components/CorrelationMatrixAxis'; + +const padding = { top: 16, right: 16, bottom: 16, left: 16 }; +const margin = { + top: 20, + right: 20, + bottom: 20, + left: 20, +}; +const CIRCLE_MIN_SIZE = 10; export function CorrelationMatrix({ config, columns }: { config: ICorrelationConfig; columns: VisColumn[] }) { - const color = scaleLinear().domain([-1, 0, 1]).range(['#B22222', '#fff', '#000080']); const data = useAsync(getCorrelationMatrixData, [columns, config.numColumnsSelected]); - const theme = useMantineTheme(); - const borderColor = theme.colors.gray[4]; + const [ref, { width, height }] = useResizeObserver(); - const [hover, setHover] = React.useState<{ xi: number; yi: number }>(undefined); + const boundsWidth = width - margin.left - margin.right; + const boundsHeight = height - margin.top - margin.bottom; - const [ref, { width, height }] = useResizeObserver(); + // TODO: Use vis color scale + // @ts-ignore + const colorScale = scaleLinear().domain([-1, 0, 1]).range(['#B22222', '#fff', '#000080']); + // Scales const xScale = React.useMemo(() => { if (!data?.value?.numericalColumns) return null; return scaleBand() - .range([0, width]) + .range([0, boundsWidth]) .domain(data.value.numericalColumns.map((column) => column.info.name)); - }, [width, data]); + }, [data, boundsWidth]); const yScale = React.useMemo(() => { if (!data?.value?.numericalColumns) return null; return scaleBand() - .range([0, height]) + .range([0, boundsHeight]) .domain(data.value.numericalColumns.map((column) => column.info.name)); - }, [height, data]); - - const memoized = React.useMemo(() => { + }, [data, boundsHeight]); + + // TODO: The domain does not make sense + const radiusScale = React.useMemo(() => { + if (!xScale || !yScale) return null; + return scaleLinear() + .domain([0.2, 0]) + .range([CIRCLE_MIN_SIZE, Math.min(xScale.bandwidth() / 2 - padding.left, yScale.bandwidth() / 2 - padding.top)]); + }, [xScale, yScale]); + + // Build correlation pairs + const memoizedCorrelationPairs = React.useMemo(() => { if (!data?.value?.numericalColumns) return null; const cols = data.value.numericalColumns; + const correlationPairs = []; - for (let y = 1; y < cols.length; y++) { - for (let x = 0; x < y; x++) { - const correlation = calculateCorrelation( + for (let x = 1; x < cols.length; x++) { + for (let y = 0; y < x; y++) { + const correlation = corrcoeff( cols[x].resolvedValues.map((resolved) => resolved.val as number), cols[y].resolvedValues.map((resolved) => resolved.val as number), ); - - console.log(x, y, correlation); + const tStatistic = (correlation * Math.sqrt(cols[x].resolvedValues.length - 2)) / Math.sqrt(1 - correlation ** 2); + + const cdf = studentt.cdf(tStatistic, cols[x].resolvedValues.length - 2); + const pValue = 2 * Math.min(cdf, 1 - cdf); + + const xName = cols[x].info.name; + const yName = cols[y].info.name; + + const value: CorrelationPairProps = { + cxLT: xScale(yName) + xScale.bandwidth() / 2, + cyLT: yScale(xName) + yScale.bandwidth() / 2, + cxUT: xScale(xName) + xScale.bandwidth() / 2, + cyUT: yScale(yName) + yScale.bandwidth() / 2, + correlation, + tStatistic, + pValue, + xName, + yName, + radius: radiusScale(pValue), + }; + correlationPairs.push( + , + ); } } - return null; - }, [data]); - - return null; - - // const memoized = React.useMemo(() => { - // if (!data?.value?.numericalColumns) return null; - - // const circles = [] as CircleCorrelationPairProps[]; - // const texts = [] as { cx: number; cy: number; correlation: number }[]; - - // data.value.numericalColumns.forEach((column, i) => { - // const xname = column.info.name; - - // data.value.numericalColumns.forEach((column2, j) => { - // const yname = column2.info.name; - - // const correlation = calculateCorrelation( - // column.resolvedValues.map((resolved) => resolved.val as number), - // column2.resolvedValues.map((resolved) => resolved.val as number), - // ); - - // if (i > j) { - // circles.push({ cx: i, cy: j, correlation, xname: column.info.name, yname: column2.info.name }); - // } - // if (j > i) { - // texts.push({ cx: xScale(xname) + xScale.bandwidth() / 2, cy: yScale(yname) + yScale.bandwidth() / 2, correlation }); - // } - // }); - // }); - - // return { circle: circles, text: texts }; - // }, [xScale, yScale, data]); - - // const colorScale = scaleLinear().domain([-1, 0, 1]).range(['#B22222', '#fff', '#000080']); - - // return ( - // { - // const xi = Math.floor(event.nativeEvent.offsetX / (width / data.value.numericalColumns.length)); - // const yi = Math.floor(event.nativeEvent.offsetY / (height / data.value.numericalColumns.length)); - // setHover({ xi, yi }); - // }} - // onMouseLeave={() => { - // setHover(undefined); - // }} - // > - // {data.value?.numericalColumns.map((column) => { - // return ( - // <> - // - // - // - // ); - // })} - - // - // - - // {data.value?.numericalColumns ? ( - // ({ value: c.info.name, offset: 20 }))} /> - // ) : null} - - // {memoized?.circle.map((value) => { - // return ( - // - // ); - // })} - // - // ); + return correlationPairs; + }, [colorScale, data, radiusScale, xScale, yScale]); + + // Show labels on diagonal of matrix + const labelsDiagonal = React.useMemo(() => { + if (!data?.value?.numericalColumns) return null; + + const cols = data.value.numericalColumns; + const labels = []; + + cols.forEach((col) => { + const currentX = xScale(col.info.name) + xScale.bandwidth() / 2; + const currentY = yScale(col.info.name) + yScale.bandwidth() / 2; + labels.push( + + {col.info.name} + , + ); + }); + return labels; + }, [data, xScale, yScale]); + + return ( + + + ({ value: c.info.name, offset: 0 }))} width={boundsWidth} /> + ({ value: c.info.name, offset: 0 }))} height={boundsHeight} /> + {memoizedCorrelationPairs} + {labelsDiagonal} + + + ); } diff --git a/src/vis/correlation/components/CircleCorrelationPair.tsx b/src/vis/correlation/components/CircleCorrelationPair.tsx index 87f14090e..0e2d70594 100644 --- a/src/vis/correlation/components/CircleCorrelationPair.tsx +++ b/src/vis/correlation/components/CircleCorrelationPair.tsx @@ -1,40 +1,56 @@ +import { useMantineTheme } from '@mantine/core'; import * as React from 'react'; -const padding = { top: 16, right: 16, bottom: 16, left: 16 }; - export interface CorrelationPairProps { - cx: number; - cy: number; + cxLT: number; + cyLT: number; + cxUT: number; + cyUT: number; correlation: number; + tStatistic: number; pValue: number; xName: string; yName: string; + radius: number; } -export function CircleCorrelationPair({ value, fill, hover }: { value: CorrelationPairProps; fill: string; hover: boolean }) { - return null; - // const cx = xScale(value.xname) + xScale.bandwidth() / 2; - // const cy = yScale(value.yname) + yScale.bandwidth() / 2; +export function CircleCorrelationPair({ + value, + fill, + boundingRect, +}: { + value: CorrelationPairProps; + fill: string; + boundingRect: { width: number; height: number }; +}) { + const [hovered, setHovered] = React.useState(false); + const theme = useMantineTheme(); + const hoverColor = theme.colors.gray[3]; - // return ( - // <> - // - // - // {value.correlation.toFixed(2)} - // - // - // ); + return ( + <> + setHovered(true)} + onMouseLeave={() => setHovered(false)} + /> + setHovered(true)} onMouseLeave={() => setHovered(false)} /> + setHovered(true)} + onMouseLeave={() => setHovered(false)} + /> + + {value.correlation.toFixed(2)} + + + ); } diff --git a/src/vis/correlation/components/CorrelationMatrixAxis.tsx b/src/vis/correlation/components/CorrelationMatrixAxis.tsx new file mode 100644 index 000000000..ad36f1265 --- /dev/null +++ b/src/vis/correlation/components/CorrelationMatrixAxis.tsx @@ -0,0 +1,69 @@ +import * as React from 'react'; +import * as d3 from 'd3v7'; +import { useMantineTheme } from '@mantine/core'; + +export function AxisTop({ xScale, ticks, height }: { xScale: d3.ScaleBand; ticks: { value: string; offset: number }[]; height: number }) { + const theme = useMantineTheme(); + const borderColor = theme.colors.gray[4]; + + const axisTicks = React.useMemo(() => { + if (!xScale || !ticks) return null; + + return ticks.map(({ value, offset }) => { + const x = xScale(value) + xScale.bandwidth() / 2; + + return ( + // + + + {/* + {value} + */} + + ); + }); + }, [xScale, ticks, height, borderColor]); + + return axisTicks || null; +} + +export function AxisLeft({ yScale, ticks, width }: { yScale: d3.ScaleBand; ticks: { value: string; offset: number }[]; width: number }) { + const theme = useMantineTheme(); + const borderColor = theme.colors.gray[4]; + + const axisTicks = React.useMemo(() => { + if (!yScale || !ticks) return null; + + return ticks.map(({ value, offset }) => { + const y = yScale(value) + yScale.bandwidth() / 2; + + return ( + // + + + {/* + {value} + */} + + ); + }); + }, [yScale, ticks, width, borderColor]); + + return axisTicks || null; +} diff --git a/src/vis/correlation/components/CorrelationPlotAxis.tsx b/src/vis/correlation/components/CorrelationPlotAxis.tsx deleted file mode 100644 index c7dee6f47..000000000 --- a/src/vis/correlation/components/CorrelationPlotAxis.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import * as React from 'react'; -import * as d3 from 'd3v7'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faCaretLeft, faCaretRight } from '@fortawesome/free-solid-svg-icons'; -import { Center, Group } from '@mantine/core'; - -// code taken from https://wattenberger.com/blog/react-and-d3 -export function CorrelationPlotXAxis({ xScale, ticks }: { xScale: d3.ScaleBand; ticks: { value: string; offset: number }[] }) { - console.log(ticks); - return ( - <> - {ticks.map(({ value, offset }) => ( - - {/* */} - - {value} - - - ))} - - ); -} diff --git a/src/vis/correlation/utils.ts b/src/vis/correlation/utils.ts index c3b9d7124..31bf6a2c8 100644 --- a/src/vis/correlation/utils.ts +++ b/src/vis/correlation/utils.ts @@ -22,7 +22,6 @@ const defaultConfig: ICorrelationConfig = { export function correlationMergeDefaultConfig(columns: VisColumn[], config: ICorrelationConfig): IVisConfig { const merged = merge({}, defaultConfig, config); - return merged; } diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index 8432d3fc2..41a718ac8 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -50,7 +50,7 @@ export function fetchIrisData(): VisColumn[] { info: { description: 'data from description', id: 'petalLength', - name: 'Petal Length PEtal length petal length', + name: 'Petal Length', }, type: EColumnTypes.NUMERICAL, values: () => dataPromise.then((data) => data.map((r) => r.petalLength).map((val, i) => ({ id: i.toString(), val }))), From 39af1901e2e9e25992a54bd885f2055cda14e2da Mon Sep 17 00:00:00 2001 From: dvmartinweigl Date: Tue, 20 Jun 2023 08:10:15 +0200 Subject: [PATCH 084/241] add siginficance switch --- src/vis/correlation/CorrelationMatrix.tsx | 9 +++++++-- src/vis/correlation/CorrelationVisSidebar.tsx | 19 +++++++++++++------ .../components/CircleCorrelationPair.tsx | 4 ++-- src/vis/correlation/utils.ts | 1 + src/vis/interfaces.ts | 1 + src/vis/stories/Iris.stories.tsx | 1 + 6 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/vis/correlation/CorrelationMatrix.tsx b/src/vis/correlation/CorrelationMatrix.tsx index 809db2fe2..9fdd0a77a 100644 --- a/src/vis/correlation/CorrelationMatrix.tsx +++ b/src/vis/correlation/CorrelationMatrix.tsx @@ -86,7 +86,12 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon radius: radiusScale(pValue), }; correlationPairs.push( - , + , ); } } @@ -105,7 +110,7 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon const currentX = xScale(col.info.name) + xScale.bandwidth() / 2; const currentY = yScale(col.info.name) + yScale.bandwidth() / 2; labels.push( - + {col.info.name} , ); diff --git a/src/vis/correlation/CorrelationVisSidebar.tsx b/src/vis/correlation/CorrelationVisSidebar.tsx index 88a53b2aa..731a562fa 100644 --- a/src/vis/correlation/CorrelationVisSidebar.tsx +++ b/src/vis/correlation/CorrelationVisSidebar.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { useMemo } from 'react'; import merge from 'lodash/merge'; -import { Container, Divider } from '@mantine/core'; +import { Container, Divider, Stack, Switch } from '@mantine/core'; import { ColumnInfo, ESupportedPlotlyVis, IVisConfig, VisColumn, ICommonVisSideBarProps, EFilterOptions, ICorrelationConfig } from '../interfaces'; import { VisTypeSelect } from '../sidebar/VisTypeSelect'; import { NumericalColumnSelect } from '../sidebar/NumericalColumnSelect'; @@ -99,11 +99,18 @@ export function CorrelationVisSidebar({ setConfig({ ...(config as any), type })} currentSelected={config.type} /> - setConfig({ ...config, numColumnsSelected })} - columns={columns} - currentSelected={config.numColumnsSelected || []} - /> + + setConfig({ ...config, numColumnsSelected })} + columns={columns} + currentSelected={config.numColumnsSelected || []} + /> + setConfig({ ...config, showSignificant: !config.showSignificant })} + /> + ); } diff --git a/src/vis/correlation/components/CircleCorrelationPair.tsx b/src/vis/correlation/components/CircleCorrelationPair.tsx index 0e2d70594..38b35e4a2 100644 --- a/src/vis/correlation/components/CircleCorrelationPair.tsx +++ b/src/vis/correlation/components/CircleCorrelationPair.tsx @@ -28,7 +28,7 @@ export function CircleCorrelationPair({ const hoverColor = theme.colors.gray[3]; return ( - <> + {value.correlation.toFixed(2)} - + ); } diff --git a/src/vis/correlation/utils.ts b/src/vis/correlation/utils.ts index 31bf6a2c8..c7bf1f238 100644 --- a/src/vis/correlation/utils.ts +++ b/src/vis/correlation/utils.ts @@ -18,6 +18,7 @@ export function isCorrelation(s: IVisConfig): s is ICorrelationConfig { const defaultConfig: ICorrelationConfig = { type: ESupportedPlotlyVis.CORRELATION, numColumnsSelected: [], + showSignificant: false, }; export function correlationMergeDefaultConfig(columns: VisColumn[], config: ICorrelationConfig): IVisConfig { diff --git a/src/vis/interfaces.ts b/src/vis/interfaces.ts index 1b30aaef2..20dfeaf78 100644 --- a/src/vis/interfaces.ts +++ b/src/vis/interfaces.ts @@ -91,6 +91,7 @@ export interface IViolinConfig { export interface ICorrelationConfig { type: ESupportedPlotlyVis.CORRELATION; numColumnsSelected: ColumnInfo[]; + showSignificant: boolean; } export interface IScatterConfig { diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index 41a718ac8..348cd381e 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -180,6 +180,7 @@ export const CorrelationPlot: typeof Template = Template.bind({}); CorrelationPlot.args = { externalConfig: { type: ESupportedPlotlyVis.CORRELATION, + showSignificant: false, numColumnsSelected: [ { description: '', From 781f57c67c537dd58c1d49e7f0f6d6fa9445e66d Mon Sep 17 00:00:00 2001 From: dvmartinweigl Date: Tue, 20 Jun 2023 08:21:45 +0200 Subject: [PATCH 085/241] filter significant --- src/vis/correlation/CorrelationMatrix.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/vis/correlation/CorrelationMatrix.tsx b/src/vis/correlation/CorrelationMatrix.tsx index 9fdd0a77a..62009e0b0 100644 --- a/src/vis/correlation/CorrelationMatrix.tsx +++ b/src/vis/correlation/CorrelationMatrix.tsx @@ -99,6 +99,15 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon return correlationPairs; }, [colorScale, data, radiusScale, xScale, yScale]); + const filteredCorrelationPairs = React.useMemo(() => { + if (!memoizedCorrelationPairs) return null; + + if (config.showSignificant) { + return memoizedCorrelationPairs.filter((pair) => pair.props.value.pValue < 0.05); + } + return memoizedCorrelationPairs; + }, [config.showSignificant, memoizedCorrelationPairs]); + // Show labels on diagonal of matrix const labelsDiagonal = React.useMemo(() => { if (!data?.value?.numericalColumns) return null; @@ -123,7 +132,7 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon ({ value: c.info.name, offset: 0 }))} width={boundsWidth} /> ({ value: c.info.name, offset: 0 }))} height={boundsHeight} /> - {memoizedCorrelationPairs} + {filteredCorrelationPairs} {labelsDiagonal} From 2b7f65676c9131895e15e587018bce032eca9117 Mon Sep 17 00:00:00 2001 From: Daniela Date: Tue, 20 Jun 2023 09:38:53 +0200 Subject: [PATCH 086/241] fix iris data label --- src/vis/parallelCoordinates/ParallelPlot.tsx | 3 +-- src/vis/stories/Iris.stories.tsx | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/vis/parallelCoordinates/ParallelPlot.tsx b/src/vis/parallelCoordinates/ParallelPlot.tsx index d5026f813..c175c96d5 100644 --- a/src/vis/parallelCoordinates/ParallelPlot.tsx +++ b/src/vis/parallelCoordinates/ParallelPlot.tsx @@ -107,7 +107,7 @@ export function ParallelPlot({ columns, config }: { config: IParallelCoordinates }, [rows, xScale, yScales]); return ( - + {paths ? paths.slice(0, 2)?.map((path, i) => ) : null} {allColumns && yScales && xScale @@ -123,7 +123,6 @@ export function ParallelPlot({ columns, config }: { config: IParallelCoordinates ); }) : null} - {/* */} ); diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index aa00f52cf..bc6d0beaa 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -50,7 +50,7 @@ export function fetchIrisData(): VisColumn[] { info: { description: 'data from description', id: 'petalLength', - name: 'Petal Length PEtal length petal length', + name: 'Petal Length', }, type: EColumnTypes.NUMERICAL, values: () => dataPromise.then((data) => data.map((r) => r.petalLength).map((val, i) => ({ id: i.toString(), val }))), From e0009780fcd6fe027853676db1a0f53df77dc618 Mon Sep 17 00:00:00 2001 From: oltionchampari Date: Tue, 20 Jun 2023 10:48:17 +0200 Subject: [PATCH 087/241] Fix margin --- src/vis/parallelCoordinates/ParallelPlot.tsx | 2 +- src/vis/parallelCoordinates/ParallelVis.tsx | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vis/parallelCoordinates/ParallelPlot.tsx b/src/vis/parallelCoordinates/ParallelPlot.tsx index c175c96d5..39041ea32 100644 --- a/src/vis/parallelCoordinates/ParallelPlot.tsx +++ b/src/vis/parallelCoordinates/ParallelPlot.tsx @@ -59,7 +59,7 @@ export function ParallelPlot({ columns, config }: { config: IParallelCoordinates scale = d3v7 .scaleLinear() .domain(d3v7.extent(col.resolvedValues.map((v) => v.val as number))) - .range([height, margin.top]); + .range([height - margin.bottom, margin.top]); } else { scale = d3v7 .scaleBand() diff --git a/src/vis/parallelCoordinates/ParallelVis.tsx b/src/vis/parallelCoordinates/ParallelVis.tsx index a7ebeabee..f8ac08043 100644 --- a/src/vis/parallelCoordinates/ParallelVis.tsx +++ b/src/vis/parallelCoordinates/ParallelVis.tsx @@ -77,7 +77,6 @@ export function ParallelVis({ {config?.numColumnsSelected?.length > 1 ? : null} - test {showSidebar ? ( From 920d717ad8955ebf6569f00daf7eaab92aef7bb2 Mon Sep 17 00:00:00 2001 From: dvmartinweigl Date: Tue, 20 Jun 2023 10:50:56 +0200 Subject: [PATCH 088/241] small changes --- src/vis/correlation/CorrelationMatrix.tsx | 4 +--- src/vis/correlation/components/CircleCorrelationPair.tsx | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/vis/correlation/CorrelationMatrix.tsx b/src/vis/correlation/CorrelationMatrix.tsx index 62009e0b0..8acd8881b 100644 --- a/src/vis/correlation/CorrelationMatrix.tsx +++ b/src/vis/correlation/CorrelationMatrix.tsx @@ -25,9 +25,7 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon const boundsWidth = width - margin.left - margin.right; const boundsHeight = height - margin.top - margin.bottom; - // TODO: Use vis color scale - // @ts-ignore - const colorScale = scaleLinear().domain([-1, 0, 1]).range(['#B22222', '#fff', '#000080']); + const colorScale = scaleLinear().domain([-1, 0, 1]).range(['#003367', '#ffffff', '#6f0000']); // Scales const xScale = React.useMemo(() => { diff --git a/src/vis/correlation/components/CircleCorrelationPair.tsx b/src/vis/correlation/components/CircleCorrelationPair.tsx index 38b35e4a2..bd0007c7c 100644 --- a/src/vis/correlation/components/CircleCorrelationPair.tsx +++ b/src/vis/correlation/components/CircleCorrelationPair.tsx @@ -25,7 +25,7 @@ export function CircleCorrelationPair({ }) { const [hovered, setHovered] = React.useState(false); const theme = useMantineTheme(); - const hoverColor = theme.colors.gray[3]; + const hoverColor = theme.colors.gray[2]; return ( @@ -48,7 +48,7 @@ export function CircleCorrelationPair({ onMouseEnter={() => setHovered(true)} onMouseLeave={() => setHovered(false)} /> - + {value.correlation.toFixed(2)} From 66c1d8ca7881496a9c5b8c0f5cd70d1a4ca209aa Mon Sep 17 00:00:00 2001 From: oltionchampari Date: Tue, 20 Jun 2023 10:59:32 +0200 Subject: [PATCH 089/241] Add axis label --- src/vis/parallelCoordinates/ParallelPlot.tsx | 6 ++++-- src/vis/parallelCoordinates/YAxis.tsx | 10 +++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/vis/parallelCoordinates/ParallelPlot.tsx b/src/vis/parallelCoordinates/ParallelPlot.tsx index 39041ea32..6d98f96ee 100644 --- a/src/vis/parallelCoordinates/ParallelPlot.tsx +++ b/src/vis/parallelCoordinates/ParallelPlot.tsx @@ -12,9 +12,9 @@ import { ParallelPath } from './ParallelPath'; const margin = { top: 30, - right: 10, + right: 40, bottom: 10, - left: 30, + left: 40, }; const removeSpace = (col: string) => col.replace(' ', ''); @@ -69,6 +69,7 @@ export function ParallelPlot({ columns, config }: { config: IParallelCoordinates return { id: removeSpace(col.info.name), + axisLabel: col.info.name, type: col.type, scale, }; @@ -118,6 +119,7 @@ export function ParallelPlot({ columns, config }: { config: IParallelCoordinates yScale={yScale.scale} xRange={[margin.left, width + margin.left]} type={yScale.type} + axisLabel={yScale.axisLabel} horizontalPosition={xScale(yScale.id)} /> ); diff --git a/src/vis/parallelCoordinates/YAxis.tsx b/src/vis/parallelCoordinates/YAxis.tsx index c0ae7bfe8..65108b017 100644 --- a/src/vis/parallelCoordinates/YAxis.tsx +++ b/src/vis/parallelCoordinates/YAxis.tsx @@ -1,8 +1,9 @@ import * as React from 'react'; import { useMemo } from 'react'; import { EColumnTypes, IParallelCoordinatesConfig, VisColumn } from '../interfaces'; +import { Tooltip } from '@mantine/core'; // code taken from https://wattenberger.com/blog/react-and-d3 -export function ParallelYAxis({ yScale, xRange, horizontalPosition, type }) { +export function ParallelYAxis({ yScale, xRange, horizontalPosition, type, axisLabel }) { console.log(yScale); const ticks = useMemo(() => { if (type === EColumnTypes.NUMERICAL) { @@ -17,8 +18,15 @@ export function ParallelYAxis({ yScale, xRange, horizontalPosition, type }) { })); }, [type, yScale]); + const labelYOffset = 7; // offset for vertical position + const labelXOffset = 40; // magic number to center label horizontally return ( <> + + + {axisLabel} + + Date: Tue, 20 Jun 2023 11:07:51 +0200 Subject: [PATCH 090/241] m --- src/vis/correlation/CorrelationMatrix.tsx | 10 +- .../components/CorrelationMatrixAxis.tsx | 100 +++++++++--------- 2 files changed, 55 insertions(+), 55 deletions(-) diff --git a/src/vis/correlation/CorrelationMatrix.tsx b/src/vis/correlation/CorrelationMatrix.tsx index 8acd8881b..d14b4a3ce 100644 --- a/src/vis/correlation/CorrelationMatrix.tsx +++ b/src/vis/correlation/CorrelationMatrix.tsx @@ -6,11 +6,11 @@ import { ICorrelationConfig, VisColumn } from '../interfaces'; import { useAsync } from '../../hooks/useAsync'; import { getCorrelationMatrixData } from './utils'; import { CircleCorrelationPair, CorrelationPairProps } from './components/CircleCorrelationPair'; -import { AxisTop, AxisLeft } from './components/CorrelationMatrixAxis'; +import { Grid, Ticks } from './components/CorrelationMatrixAxis'; const padding = { top: 16, right: 16, bottom: 16, left: 16 }; const margin = { - top: 20, + top: 60, right: 20, bottom: 20, left: 20, @@ -25,7 +25,7 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon const boundsWidth = width - margin.left - margin.right; const boundsHeight = height - margin.top - margin.bottom; - const colorScale = scaleLinear().domain([-1, 0, 1]).range(['#003367', '#ffffff', '#6f0000']); + const colorScale = scaleLinear().domain([-1, 0, 1]).range(['#003367', '#ffffff', '#6f0000']); // Scales const xScale = React.useMemo(() => { @@ -128,8 +128,8 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon return ( - ({ value: c.info.name, offset: 0 }))} width={boundsWidth} /> - ({ value: c.info.name, offset: 0 }))} height={boundsHeight} /> + + {filteredCorrelationPairs} {labelsDiagonal} diff --git a/src/vis/correlation/components/CorrelationMatrixAxis.tsx b/src/vis/correlation/components/CorrelationMatrixAxis.tsx index ad36f1265..ce71e5bae 100644 --- a/src/vis/correlation/components/CorrelationMatrixAxis.tsx +++ b/src/vis/correlation/components/CorrelationMatrixAxis.tsx @@ -2,68 +2,68 @@ import * as React from 'react'; import * as d3 from 'd3v7'; import { useMantineTheme } from '@mantine/core'; -export function AxisTop({ xScale, ticks, height }: { xScale: d3.ScaleBand; ticks: { value: string; offset: number }[]; height: number }) { +export function Ticks() { + return
; +} + +export function Grid({ width, height, cells }: { width: number; height: number; cells: number }) { const theme = useMantineTheme(); const borderColor = theme.colors.gray[4]; - const axisTicks = React.useMemo(() => { - if (!xScale || !ticks) return null; + return ( + <> + {Array.from({ length: cells + 1 }).map((_, i) => { + const x = (width / cells) * i; + const y = (height / cells) * i; - return ticks.map(({ value, offset }) => { - const x = xScale(value) + xScale.bandwidth() / 2; + return ( + + + + + ); + })} + + ); +} - return ( - // - - - {/* - {value} - */} - - ); - }); - }, [xScale, ticks, height, borderColor]); +export function AxisTop({ xScale, ticks, height }: { xScale: d3.ScaleBand; ticks: { value: string; offset: number }[]; height: number }) { + const theme = useMantineTheme(); + const borderColor = theme.colors.gray[4]; + if (!xScale || !ticks) return null; - return axisTicks || null; + return ( + <> + {ticks.map(({ value, offset }) => { + const x = xScale(value); + + return ( + + + + ); + })} + + ); } export function AxisLeft({ yScale, ticks, width }: { yScale: d3.ScaleBand; ticks: { value: string; offset: number }[]; width: number }) { const theme = useMantineTheme(); const borderColor = theme.colors.gray[4]; - const axisTicks = React.useMemo(() => { - if (!yScale || !ticks) return null; - - return ticks.map(({ value, offset }) => { - const y = yScale(value) + yScale.bandwidth() / 2; + if (!yScale || !ticks) return null; - return ( - // - - - {/* - {value} - */} - - ); - }); - }, [yScale, ticks, width, borderColor]); + return ( + <> + {ticks.map(({ value, offset }) => { + const y = yScale(value) + yScale.bandwidth() / 2; - return axisTicks || null; + return ( + + + + ); + })} + + ); } From 1965b36d7022d98ab772cd6295150e40e2afe04d Mon Sep 17 00:00:00 2001 From: Daniela Date: Tue, 20 Jun 2023 11:24:48 +0200 Subject: [PATCH 091/241] clean up code --- src/vis/parallelCoordinates/ParallelPath.tsx | 2 +- src/vis/parallelCoordinates/ParallelPlot.tsx | 4 +-- src/vis/parallelCoordinates/YAxis.tsx | 28 +++++++++++--------- src/vis/parallelCoordinates/utils.ts | 2 -- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/vis/parallelCoordinates/ParallelPath.tsx b/src/vis/parallelCoordinates/ParallelPath.tsx index d6aa63e7f..a7ff5ab6f 100644 --- a/src/vis/parallelCoordinates/ParallelPath.tsx +++ b/src/vis/parallelCoordinates/ParallelPath.tsx @@ -11,5 +11,5 @@ export function ParallelPath({ onLeave: (e: React.MouseEvent) => void; onHover: (e: React.MouseEvent) => void; }) { - return ; + return ; } diff --git a/src/vis/parallelCoordinates/ParallelPlot.tsx b/src/vis/parallelCoordinates/ParallelPlot.tsx index 6d98f96ee..c70c30128 100644 --- a/src/vis/parallelCoordinates/ParallelPlot.tsx +++ b/src/vis/parallelCoordinates/ParallelPlot.tsx @@ -65,8 +65,8 @@ export function ParallelPlot({ columns, config }: { config: IParallelCoordinates .scaleBand() .domain(col.resolvedValues.map((c) => c.val as string)) .range([height, margin.top]); + console.log('scale: ', scale.bandwidth()); } - return { id: removeSpace(col.info.name), axisLabel: col.info.name, @@ -110,7 +110,7 @@ export function ParallelPlot({ columns, config }: { config: IParallelCoordinates return ( - {paths ? paths.slice(0, 2)?.map((path, i) => ) : null} + {paths ? paths?.map((path, i) => ) : null} {allColumns && yScales && xScale ? yScales.map((yScale) => { return ( diff --git a/src/vis/parallelCoordinates/YAxis.tsx b/src/vis/parallelCoordinates/YAxis.tsx index 65108b017..01a3e96f8 100644 --- a/src/vis/parallelCoordinates/YAxis.tsx +++ b/src/vis/parallelCoordinates/YAxis.tsx @@ -1,10 +1,9 @@ import * as React from 'react'; import { useMemo } from 'react'; -import { EColumnTypes, IParallelCoordinatesConfig, VisColumn } from '../interfaces'; import { Tooltip } from '@mantine/core'; +import { EColumnTypes, IParallelCoordinatesConfig, VisColumn } from '../interfaces'; // code taken from https://wattenberger.com/blog/react-and-d3 export function ParallelYAxis({ yScale, xRange, horizontalPosition, type, axisLabel }) { - console.log(yScale); const ticks = useMemo(() => { if (type === EColumnTypes.NUMERICAL) { return yScale.ticks(5).map((value) => ({ @@ -33,21 +32,24 @@ export function ParallelYAxis({ yScale, xRange, horizontalPosition, type, axisLa fill="none" stroke="lightgray" /> + {ticks.map(({ value, yOffset }) => ( - - {value} - + + + {value} + + ))} diff --git a/src/vis/parallelCoordinates/utils.ts b/src/vis/parallelCoordinates/utils.ts index 3fbe52711..3d78267b6 100644 --- a/src/vis/parallelCoordinates/utils.ts +++ b/src/vis/parallelCoordinates/utils.ts @@ -49,13 +49,11 @@ export async function getParallelData( info: ColumnInfo; }[]; }> { - console.log('num'); const numCols: VisNumericalColumn[] = numColumnsSelected.map((col) => columns.find((c) => c.info.id === col.id)) as VisNumericalColumn[]; const catCols: VisCategoricalColumn[] = catColumnsSelected.map((col) => columns.find((c) => c.info.id === col.id)) as VisCategoricalColumn[]; const numColVals = await resolveColumnValues(numCols); const catColVals = await resolveColumnValues(catCols); - console.log('num', numColVals); // const colorColVals = await resolveSingleColumn(colorColumn ? columns.find((col) => col.info.id === colorColumn.id) : null); return { numColVals, catColVals }; From 76d2d3324a32a4e48bc57458f4f12cd513c648ce Mon Sep 17 00:00:00 2001 From: Daniela Date: Tue, 20 Jun 2023 11:43:00 +0200 Subject: [PATCH 092/241] center labels of categorical columns --- src/vis/parallelCoordinates/ParallelPlot.tsx | 14 +++++++++----- src/vis/parallelCoordinates/YAxis.tsx | 3 ++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/vis/parallelCoordinates/ParallelPlot.tsx b/src/vis/parallelCoordinates/ParallelPlot.tsx index c70c30128..85557b6c4 100644 --- a/src/vis/parallelCoordinates/ParallelPlot.tsx +++ b/src/vis/parallelCoordinates/ParallelPlot.tsx @@ -65,7 +65,6 @@ export function ParallelPlot({ columns, config }: { config: IParallelCoordinates .scaleBand() .domain(col.resolvedValues.map((c) => c.val as string)) .range([height, margin.top]); - console.log('scale: ', scale.bandwidth()); } return { id: removeSpace(col.info.name), @@ -87,11 +86,16 @@ export function ParallelPlot({ columns, config }: { config: IParallelCoordinates }, [allColumns?.catColVals, allColumns?.numColVals, width]); const paths = React.useMemo(() => { - return rows?.map((r) => { - if (!r) return null; - const yPositions = Object.keys(r).map((col) => { + return rows?.map((row) => { + if (!row) return null; + const yPositions = Object.keys(row).map((col) => { const xPos = xScale(col); - const yPos = yScales?.find((yScale) => yScale.id === col)?.scale(r[col]) || 0; + let yPos = yScales?.find((yScale) => yScale.id === col)?.scale(row[col]) || 0; + // if the column is categorical, we need to offset the y position by half the bandwidth + if (allColumns?.catColVals.map((c) => c.info.name).includes(col)) { + const yScale = yScales?.find((scale) => scale.id === col).scale; + yPos += yScale.bandwidth() / 2 || 0; + } return [xPos, yPos]; }); diff --git a/src/vis/parallelCoordinates/YAxis.tsx b/src/vis/parallelCoordinates/YAxis.tsx index 01a3e96f8..360d306bf 100644 --- a/src/vis/parallelCoordinates/YAxis.tsx +++ b/src/vis/parallelCoordinates/YAxis.tsx @@ -13,7 +13,8 @@ export function ParallelYAxis({ yScale, xRange, horizontalPosition, type, axisLa } return yScale.domain().map((value) => ({ value, - yOffset: yScale(value), + // if we have a categorical column, we want to center the label + yOffset: yScale(value) + yScale.bandwidth() / 2, })); }, [type, yScale]); From 7f2a3c93ed0b2f3a9842502b0c883535d3c1a6eb Mon Sep 17 00:00:00 2001 From: Moritz Heckmann Date: Tue, 20 Jun 2023 12:53:10 +0200 Subject: [PATCH 093/241] ticks --- src/vis/correlation/CorrelationMatrix.tsx | 12 ++++--- .../components/CorrelationMatrixAxis.tsx | 32 ++++++++++++++----- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/vis/correlation/CorrelationMatrix.tsx b/src/vis/correlation/CorrelationMatrix.tsx index d14b4a3ce..cf04fafd7 100644 --- a/src/vis/correlation/CorrelationMatrix.tsx +++ b/src/vis/correlation/CorrelationMatrix.tsx @@ -10,10 +10,10 @@ import { Grid, Ticks } from './components/CorrelationMatrixAxis'; const padding = { top: 16, right: 16, bottom: 16, left: 16 }; const margin = { - top: 60, + top: 100, right: 20, bottom: 20, - left: 20, + left: 100, }; const CIRCLE_MIN_SIZE = 10; @@ -27,6 +27,10 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon const colorScale = scaleLinear().domain([-1, 0, 1]).range(['#003367', '#ffffff', '#6f0000']); + const names = React.useMemo(() => { + return data.value?.numericalColumns.map((column) => column.info.name); + }, [data]); + // Scales const xScale = React.useMemo(() => { if (!data?.value?.numericalColumns) return null; @@ -128,8 +132,8 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon return ( - - + {names ? : null} + {filteredCorrelationPairs} {labelsDiagonal} diff --git a/src/vis/correlation/components/CorrelationMatrixAxis.tsx b/src/vis/correlation/components/CorrelationMatrixAxis.tsx index ce71e5bae..075d7538e 100644 --- a/src/vis/correlation/components/CorrelationMatrixAxis.tsx +++ b/src/vis/correlation/components/CorrelationMatrixAxis.tsx @@ -2,22 +2,38 @@ import * as React from 'react'; import * as d3 from 'd3v7'; import { useMantineTheme } from '@mantine/core'; -export function Ticks() { - return
; -} - -export function Grid({ width, height, cells }: { width: number; height: number; cells: number }) { +export function Grid({ width, height, names }: { width: number; height: number; names: string[] }) { const theme = useMantineTheme(); const borderColor = theme.colors.gray[4]; + const xstep = width / names.length; + const ystep = height / names.length; + return ( <> - {Array.from({ length: cells + 1 }).map((_, i) => { - const x = (width / cells) * i; - const y = (height / cells) * i; + {Array.from({ length: names.length + 1 }).map((_, i) => { + const x = xstep * i; + const y = ystep * i; + + const xtick = x + xstep / 2; + const ytick = y + ystep / 2; return ( + {i !== names.length ? ( + + + {names[i]} + + + ) : null} + {i !== names.length ? ( + + + {names[i]} + + + ) : null} From b048b0c18d67b2f04d15e3c32ab8adc656b8b765 Mon Sep 17 00:00:00 2001 From: tschachinger Date: Tue, 20 Jun 2023 13:16:42 +0200 Subject: [PATCH 094/241] make it work + labels --- src/vis/heatmap/Heatmap.tsx | 123 +++++++++++++++++++++----------- src/vis/heatmap/HeatmapRect.tsx | 4 +- 2 files changed, 84 insertions(+), 43 deletions(-) diff --git a/src/vis/heatmap/Heatmap.tsx b/src/vis/heatmap/Heatmap.tsx index a8fbb4462..0603c6505 100644 --- a/src/vis/heatmap/Heatmap.tsx +++ b/src/vis/heatmap/Heatmap.tsx @@ -1,6 +1,6 @@ import { Group, Stack, Text, Tooltip } from '@mantine/core'; import { useResizeObserver } from '@mantine/hooks'; -import { table } from 'arquero'; +import { table, op } from 'arquero'; import * as d3 from 'd3v7'; import * as React from 'react'; @@ -13,8 +13,8 @@ const interRectDistance = 1; const margin = { top: 20, right: 20, - bottom: 10, - left: 20, + bottom: 100, + left: 100, }; export function Heatmap({ config, columns }: { config: IHeatmapConfig; columns: VisColumn[] }) { @@ -22,76 +22,117 @@ export function Heatmap({ config, columns }: { config: IHeatmapConfig; columns: const [ref, { width, height }] = useResizeObserver(); const [tooltipText, setTooltipText] = React.useState(null); - const hasEnoughCatCols = allColumns?.catColumn && allColumns?.catColumn?.length > 1; + const hasAtLeast2CatCols = allColumns?.catColumn && allColumns?.catColumn?.length > 1; const { xValues, yValues, groupedValues } = React.useMemo(() => { - if (!hasEnoughCatCols) return { xValues: [], yValues: [], groupedValues: [] }; + if (!hasAtLeast2CatCols) return { xValues: [], yValues: [], groupedValues: [] }; const myTable = table({ x: allColumns.catColumn[0]?.resolvedValues.map(({ val }) => val), y: allColumns.catColumn[1]?.resolvedValues.map(({ val }) => val), }); const xVals = [...new Set(allColumns.catColumn[0]?.resolvedValues.map(({ val }) => val))]; const yVals = [...new Set(allColumns.catColumn[1]?.resolvedValues.map(({ val }) => val))]; + return { xValues: xVals as string[], yValues: yVals as string[], - groupedValues: myTable.groupby('x', 'y').count().objects() as { x: string; y: string; count: number }[], + groupedValues: myTable + .groupby('x', 'y') + .count() + .impute({ count: () => 0 }, { expand: ['x', 'y'] }) + .objects() as { x: string; y: string; count: number }[], }; - }, [allColumns?.catColumn, hasEnoughCatCols]); + }, [allColumns?.catColumn, hasAtLeast2CatCols]); const rectWidth = React.useMemo( - () => (xValues.length && width ? (width - margin.left - margin.right - interRectDistance * xValues.length) / xValues.length : 0), - [width, xValues.length], + () => (groupedValues.length && xValues.length && width ? (width - margin.left - margin.right - interRectDistance * xValues.length) / xValues.length : 0), + [groupedValues?.length, width, xValues], ); const rectHeight = React.useMemo( - () => (yValues.length && height ? (height - margin.bottom - margin.top - interRectDistance * yValues.length) / yValues.length : 0), - [height, yValues.length], + () => (groupedValues.length && yValues.length && height ? (height - margin.bottom - margin.top - interRectDistance * yValues.length) / yValues.length : 0), + [groupedValues?.length, height, yValues], + ); + + const xScale = React.useMemo( + () => + d3 + .scaleBand() + .domain(xValues) + .range([0, width - margin.left - margin.right]), + [xValues, width], + ); + + const yScale = React.useMemo( + () => + d3 + .scaleBand() + .domain(yValues) + .range([0, height - margin.top - margin.bottom]), + [yValues, height], ); const colorScale = React.useMemo(() => { - if (!hasEnoughCatCols) return d3.scaleSequential(d3.interpolateReds); + if (!hasAtLeast2CatCols) return d3.scaleSequential(d3.interpolateReds); return d3.scaleSequential(d3.interpolateBlues).domain(d3.extent(groupedValues, (d) => d.count as number)); - }, [hasEnoughCatCols, groupedValues]); + }, [hasAtLeast2CatCols, groupedValues]); return ( - {!hasEnoughCatCols ? ( + {!hasAtLeast2CatCols ? ( Select at least 2 categorical columns to display heatmap - ) : ( - <> - + ) : null} + <> + + {hasAtLeast2CatCols && ( {allColumns.catColumn[1].info.name} - - - {xValues.map((x: string, iX: number) => - yValues.map((y: string, iY: number) => { - const count = groupedValues?.find((d) => d.x === x && d.y === y)?.count ?? 0; - return ( - setTooltipText(`${x} - ${y} (${count})`)} - unsetTooltipText={() => setTooltipText(null)} - /> - ); - }), - )} - - - + )} + + + {hasAtLeast2CatCols && + groupedValues.map((d) => { + const x = xScale(d.x) + margin.left; + const y = yScale(d.y) + margin.top; + const { count } = d; + return ( + setTooltipText(`${d.x} - ${d.y} (${count})`)} + unsetTooltipText={() => setTooltipText(null)} + /> + ); + })} + {hasAtLeast2CatCols && + xValues.map((xVal) => ( + + + {xVal} + + + ))} + {hasAtLeast2CatCols && + yValues.map((yVal) => ( + + {yVal} + + ))} + + + + {hasAtLeast2CatCols && ( {allColumns.catColumn[0].info.name ?? ''} - - )} + )} + ); } diff --git a/src/vis/heatmap/HeatmapRect.tsx b/src/vis/heatmap/HeatmapRect.tsx index bdd4c9544..571b23357 100644 --- a/src/vis/heatmap/HeatmapRect.tsx +++ b/src/vis/heatmap/HeatmapRect.tsx @@ -18,6 +18,6 @@ export function HeatmapRect({ setTooltipText(): void; unsetTooltipText(): void; }) { - const spring = useSpring({ from: { opacity: 0, width: 0, height: 0 }, to: { opacity: 1, width, height }, duration: 50 }); - return ; + const spring = useSpring({ from: { opacity: 0 }, to: { opacity: 1 } }); + return ; } From 9c81092e44414edbcb97e6e8388e87ceec686e69 Mon Sep 17 00:00:00 2001 From: Daniela Date: Tue, 20 Jun 2023 14:09:46 +0200 Subject: [PATCH 095/241] add white background for tick labels --- src/vis/parallelCoordinates/YAxis.tsx | 15 ++---------- .../parallelCoordinates/YAxisTickLabels.tsx | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+), 13 deletions(-) create mode 100644 src/vis/parallelCoordinates/YAxisTickLabels.tsx diff --git a/src/vis/parallelCoordinates/YAxis.tsx b/src/vis/parallelCoordinates/YAxis.tsx index 360d306bf..3bb1572fd 100644 --- a/src/vis/parallelCoordinates/YAxis.tsx +++ b/src/vis/parallelCoordinates/YAxis.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { useMemo } from 'react'; import { Tooltip } from '@mantine/core'; import { EColumnTypes, IParallelCoordinatesConfig, VisColumn } from '../interfaces'; +import { YAxisTickLabel } from './YAxisTickLabels'; // code taken from https://wattenberger.com/blog/react-and-d3 export function ParallelYAxis({ yScale, xRange, horizontalPosition, type, axisLabel }) { const ticks = useMemo(() => { @@ -38,19 +39,7 @@ export function ParallelYAxis({ yScale, xRange, horizontalPosition, type, axisLa {ticks.map(({ value, yOffset }) => ( - - - {value} - - + ))} diff --git a/src/vis/parallelCoordinates/YAxisTickLabels.tsx b/src/vis/parallelCoordinates/YAxisTickLabels.tsx new file mode 100644 index 000000000..9947d9cba --- /dev/null +++ b/src/vis/parallelCoordinates/YAxisTickLabels.tsx @@ -0,0 +1,24 @@ +import * as React from 'react'; +// code taken from https://wattenberger.com/blog/react-and-d3 +export function YAxisTickLabel({ value }: { value: string }) { + const ref = React.useRef(null); + const offset = 5; + const width = (ref.current?.getBBox().width || 10) + offset; + return ( + <> + + + {value} + + + ); +} From 9cfbe364a6a77aa6cf3fdcd859ac807de7401fdc Mon Sep 17 00:00:00 2001 From: oltionchampari Date: Tue, 20 Jun 2023 14:15:16 +0200 Subject: [PATCH 096/241] Add selection --- src/vis/parallelCoordinates/YAxis.tsx | 55 ++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/src/vis/parallelCoordinates/YAxis.tsx b/src/vis/parallelCoordinates/YAxis.tsx index 3bb1572fd..5985dcc91 100644 --- a/src/vis/parallelCoordinates/YAxis.tsx +++ b/src/vis/parallelCoordinates/YAxis.tsx @@ -1,21 +1,63 @@ import * as React from 'react'; import { useMemo } from 'react'; +import * as d3v7 from 'd3v7'; import { Tooltip } from '@mantine/core'; -import { EColumnTypes, IParallelCoordinatesConfig, VisColumn } from '../interfaces'; import { YAxisTickLabel } from './YAxisTickLabels'; +import { EColumnTypes } from '../interfaces'; + // code taken from https://wattenberger.com/blog/react-and-d3 -export function ParallelYAxis({ yScale, xRange, horizontalPosition, type, axisLabel }) { +export function ParallelYAxis({ + id, + yScale, + xRange, + horizontalPosition, + type, + axisLabel, + onSelectionChanged, +}: { + id: string; + yScale: d3v7.ScaleLinear | d3v7.ScaleBand; + xRange: number[]; + type: EColumnTypes.NUMERICAL | EColumnTypes.CATEGORICAL; + horizontalPosition: number | number; + axisLabel: string; + onSelectionChanged: (scaleId: string, selection: [number, number]) => void; +}) { + const ref = React.useRef(null); + const extent = useMemo( + () => + [ + [horizontalPosition - 10, yScale.range()[1]], + [horizontalPosition + 10, yScale.range()[0]], + ] as [[number, number], [number, number]], + [horizontalPosition, yScale], + ); + + React.useEffect(() => { + if (extent && ref.current) { + d3v7 + .select(ref.current) + .attr('class', 'brush') + .call( + d3v7 + .brushY() + .extent(extent) + .on('brush', (e) => onSelectionChanged(id, e.selection)), + ); + } + }); + const ticks = useMemo(() => { if (type === EColumnTypes.NUMERICAL) { - return yScale.ticks(5).map((value) => ({ + return (yScale as d3v7.ScaleLinear).ticks(5).map((value) => ({ value, - yOffset: yScale(value), + yOffset: yScale(value as any), })); } - return yScale.domain().map((value) => ({ + return (yScale as d3v7.ScaleBand).domain().map((value) => ({ value, // if we have a categorical column, we want to center the label - yOffset: yScale(value) + yScale.bandwidth() / 2, + yOffset: yScale(value as any) + (yScale as d3v7.ScaleBand).bandwidth() / 2, })); }, [type, yScale]); @@ -28,6 +70,7 @@ export function ParallelYAxis({ yScale, xRange, horizontalPosition, type, axisLa {axisLabel}
+ Date: Tue, 20 Jun 2023 14:38:19 +0200 Subject: [PATCH 097/241] added tooltip --- src/vis/correlation/CorrelationMatrix.tsx | 58 ++++++++++++++----- .../components/CircleCorrelationPair.tsx | 21 ++++--- .../components/CorrelationTooltip.tsx | 29 ++++++++++ 3 files changed, 87 insertions(+), 21 deletions(-) create mode 100644 src/vis/correlation/components/CorrelationTooltip.tsx diff --git a/src/vis/correlation/CorrelationMatrix.tsx b/src/vis/correlation/CorrelationMatrix.tsx index cf04fafd7..b4fd88bbc 100644 --- a/src/vis/correlation/CorrelationMatrix.tsx +++ b/src/vis/correlation/CorrelationMatrix.tsx @@ -1,12 +1,14 @@ import * as React from 'react'; import { scaleBand, scaleLinear } from 'd3v7'; +import { Popover } from '@mantine/core'; import { useResizeObserver } from '@mantine/hooks'; import { corrcoeff, studentt } from 'jstat'; import { ICorrelationConfig, VisColumn } from '../interfaces'; import { useAsync } from '../../hooks/useAsync'; import { getCorrelationMatrixData } from './utils'; import { CircleCorrelationPair, CorrelationPairProps } from './components/CircleCorrelationPair'; -import { Grid, Ticks } from './components/CorrelationMatrixAxis'; +import { Grid } from './components/CorrelationMatrixAxis'; +import { CorrelationTooltip } from './components/CorrelationTooltip'; const padding = { top: 16, right: 16, bottom: 16, left: 16 }; const margin = { @@ -25,6 +27,8 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon const boundsWidth = width - margin.left - margin.right; const boundsHeight = height - margin.top - margin.bottom; + const [hover, setHover] = React.useState<{ x: number; y: number } | null>(null); + const colorScale = scaleLinear().domain([-1, 0, 1]).range(['#003367', '#ffffff', '#6f0000']); const names = React.useMemo(() => { @@ -59,7 +63,7 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon if (!data?.value?.numericalColumns) return null; const cols = data.value.numericalColumns; - const correlationPairs = []; + const correlationPairs = [] as CorrelationPairProps[]; for (let x = 1; x < cols.length; x++) { for (let y = 0; y < x; y++) { @@ -76,6 +80,8 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon const yName = cols[y].info.name; const value: CorrelationPairProps = { + xi: x, + yi: y, cxLT: xScale(yName) + xScale.bandwidth() / 2, cyLT: yScale(xName) + yScale.bandwidth() / 2, cxUT: xScale(xName) + xScale.bandwidth() / 2, @@ -87,25 +93,18 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon yName, radius: radiusScale(pValue), }; - correlationPairs.push( - , - ); + correlationPairs.push(value); } } return correlationPairs; - }, [colorScale, data, radiusScale, xScale, yScale]); + }, [data, radiusScale, xScale, yScale]); const filteredCorrelationPairs = React.useMemo(() => { if (!memoizedCorrelationPairs) return null; if (config.showSignificant) { - return memoizedCorrelationPairs.filter((pair) => pair.props.value.pValue < 0.05); + return memoizedCorrelationPairs.filter((pair) => pair.pValue < 0.05); } return memoizedCorrelationPairs; }, [config.showSignificant, memoizedCorrelationPairs]); @@ -134,7 +133,40 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon {names ? : null} - {filteredCorrelationPairs} + {hover ? ( + + + + + + (value.xi === hover.x && value.yi === hover.y) || (value.xi === hover.y && value.yi === hover.x), + )} + /> + + + ) : null} + + {filteredCorrelationPairs?.map((value) => { + return ( + + ); + })} {labelsDiagonal} diff --git a/src/vis/correlation/components/CircleCorrelationPair.tsx b/src/vis/correlation/components/CircleCorrelationPair.tsx index bd0007c7c..3ccebba66 100644 --- a/src/vis/correlation/components/CircleCorrelationPair.tsx +++ b/src/vis/correlation/components/CircleCorrelationPair.tsx @@ -2,6 +2,8 @@ import { useMantineTheme } from '@mantine/core'; import * as React from 'react'; export interface CorrelationPairProps { + xi: number; + yi: number; cxLT: number; cyLT: number; cxUT: number; @@ -18,12 +20,15 @@ export function CircleCorrelationPair({ value, fill, boundingRect, + hover, + setHovered, }: { value: CorrelationPairProps; fill: string; boundingRect: { width: number; height: number }; + hover: boolean; + setHovered: ({ x, y }: { x: number; y: number }) => void; }) { - const [hovered, setHovered] = React.useState(false); const theme = useMantineTheme(); const hoverColor = theme.colors.gray[2]; @@ -34,19 +39,19 @@ export function CircleCorrelationPair({ height={boundingRect.height} x={value.cxUT - boundingRect.width / 2} y={value.cyUT - boundingRect.height / 2} - fill={hovered ? hoverColor : 'transparent'} - onMouseEnter={() => setHovered(true)} - onMouseLeave={() => setHovered(false)} + fill={hover ? hoverColor : 'transparent'} + onMouseEnter={() => setHovered({ x: value.xi, y: value.yi })} + onMouseLeave={() => setHovered(null)} /> - setHovered(true)} onMouseLeave={() => setHovered(false)} /> + setHovered(true)} - onMouseLeave={() => setHovered(false)} + fill={hover ? hoverColor : 'transparent'} + onMouseEnter={() => setHovered({ x: value.yi, y: value.xi })} + onMouseLeave={() => setHovered(null)} /> {value.correlation.toFixed(2)} diff --git a/src/vis/correlation/components/CorrelationTooltip.tsx b/src/vis/correlation/components/CorrelationTooltip.tsx new file mode 100644 index 000000000..99d2e81a3 --- /dev/null +++ b/src/vis/correlation/components/CorrelationTooltip.tsx @@ -0,0 +1,29 @@ +import { Table } from '@mantine/core'; +import * as React from 'react'; +import { CorrelationPairProps } from './CircleCorrelationPair'; + +export function CorrelationTooltip({ value }: { value: CorrelationPairProps }) { + return ( + + + + + + + + + + + + + + + + + + + + +
{`${value.xName} -> ${value.yName}`}
t-Statistic{value.tStatistic.toFixed(2)}
Correlation{value.correlation.toFixed(2)}
pValue{value.pValue < 0.001 ? 'p < 0.001' : value.pValue.toFixed(2)}
+ ); +} From 8efc94922298f79ee816642e3e7676c954924a98 Mon Sep 17 00:00:00 2001 From: Moritz Heckmann Date: Tue, 20 Jun 2023 14:53:03 +0200 Subject: [PATCH 098/241] finished scale --- src/vis/correlation/CorrelationMatrix.tsx | 7 ++- .../components/CorrelationLegend.tsx | 44 +++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 src/vis/correlation/components/CorrelationLegend.tsx diff --git a/src/vis/correlation/CorrelationMatrix.tsx b/src/vis/correlation/CorrelationMatrix.tsx index b4fd88bbc..99d4d640e 100644 --- a/src/vis/correlation/CorrelationMatrix.tsx +++ b/src/vis/correlation/CorrelationMatrix.tsx @@ -9,12 +9,13 @@ import { getCorrelationMatrixData } from './utils'; import { CircleCorrelationPair, CorrelationPairProps } from './components/CircleCorrelationPair'; import { Grid } from './components/CorrelationMatrixAxis'; import { CorrelationTooltip } from './components/CorrelationTooltip'; +import { Legend } from './components/CorrelationLegend'; const padding = { top: 16, right: 16, bottom: 16, left: 16 }; const margin = { top: 100, - right: 20, - bottom: 20, + right: 80, + bottom: 10, left: 100, }; const CIRCLE_MIN_SIZE = 10; @@ -168,6 +169,8 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon ); })} {labelsDiagonal} + +
); diff --git a/src/vis/correlation/components/CorrelationLegend.tsx b/src/vis/correlation/components/CorrelationLegend.tsx new file mode 100644 index 000000000..4fb16ed5e --- /dev/null +++ b/src/vis/correlation/components/CorrelationLegend.tsx @@ -0,0 +1,44 @@ +import { range, scaleLinear } from 'd3v7'; +import * as React from 'react'; + +export function Legend({ + xPos, + height, + colorScale, + margin, +}: { + xPos: number; + height: number; + colorScale: d3.ScaleLinear; + margin: { top: number; right: number; bottom: number; left: number }; +}) { + const legendYScale = scaleLinear().range([0, height]).domain([1, -1]); + + const getTicks = (): number[] => { + const t = []; + for (let i = 1.0; i >= -1.0; i -= 0.2) { + t.push(i); + } + return t; + }; + + return ( + + + + + + + + + + {getTicks().map((t) => { + return ( + + {t.toFixed(1)} + + ); + })} + + ); +} From c1bb1bd8927318841ae985c88e36c9092c05be8f Mon Sep 17 00:00:00 2001 From: Usama Ansari Date: Tue, 20 Jun 2023 15:07:53 +0200 Subject: [PATCH 099/241] feat: implement diverging /sequential color scales for numerical column wip: get colors in the Numerical Color Buttons from the actual scale --- .vscode/launch.json | 8 ++++++++ src/vis/heatmap/Heatmap.tsx | 10 +++++++--- src/vis/heatmap/HeatmapVisSidebar.tsx | 11 ++++++++++- src/vis/interfaces.ts | 3 ++- src/vis/stories/Iris.stories.tsx | 12 ++++++------ 5 files changed, 33 insertions(+), 11 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index acf771dca..f938ba51d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,6 +4,14 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ + { + "name": "Debug Storybook", + "request": "launch", + "type": "chrome", + "url": "http://localhost:6006", + "webRoot": "${workspaceFolder}" + }, + { "name": "Python: Module", "type": "python", diff --git a/src/vis/heatmap/Heatmap.tsx b/src/vis/heatmap/Heatmap.tsx index 0603c6505..03d1478a1 100644 --- a/src/vis/heatmap/Heatmap.tsx +++ b/src/vis/heatmap/Heatmap.tsx @@ -5,7 +5,7 @@ import * as d3 from 'd3v7'; import * as React from 'react'; import { useAsync } from '../../hooks'; -import { IHeatmapConfig, VisColumn } from '../interfaces'; +import { ENumericalColorScaleType, IHeatmapConfig, VisColumn } from '../interfaces'; import { HeatmapRect } from './HeatmapRect'; import { getHeatmapData } from './utils'; @@ -73,8 +73,12 @@ export function Heatmap({ config, columns }: { config: IHeatmapConfig; columns: const colorScale = React.useMemo(() => { if (!hasAtLeast2CatCols) return d3.scaleSequential(d3.interpolateReds); - return d3.scaleSequential(d3.interpolateBlues).domain(d3.extent(groupedValues, (d) => d.count as number)); - }, [hasAtLeast2CatCols, groupedValues]); + return config?.numColorScaleType === ENumericalColorScaleType.SEQUENTIAL + ? d3.scaleSequential(d3.interpolateBlues).domain(d3.extent(groupedValues, (d) => d.count as number)) + : config?.numColorScaleType === ENumericalColorScaleType.DIVERGENT + ? d3.scaleDiverging(d3.interpolatePiYG).domain(d3.extent(groupedValues, (d) => d.count as number)) + : null; + }, [config?.numColorScaleType, hasAtLeast2CatCols, groupedValues]); return ( diff --git a/src/vis/heatmap/HeatmapVisSidebar.tsx b/src/vis/heatmap/HeatmapVisSidebar.tsx index 17eb94715..5ea3f5460 100644 --- a/src/vis/heatmap/HeatmapVisSidebar.tsx +++ b/src/vis/heatmap/HeatmapVisSidebar.tsx @@ -1,8 +1,9 @@ import { Container, Stack } from '@mantine/core'; import * as React from 'react'; -import { ColumnInfo, ESupportedPlotlyVis, IHeatmapConfig, IVisConfig, VisColumn } from '../interfaces'; +import { ColumnInfo, ENumericalColorScaleType, ESupportedPlotlyVis, IHeatmapConfig, IVisConfig, VisColumn } from '../interfaces'; import { VisTypeSelect } from '../sidebar/VisTypeSelect'; import { CategoricalColumnSelect } from '../sidebar/CategoricalColumnSelect'; +import { ColorSelect } from '../sidebar/ColorSelect'; export function HeatmapVisSidebar({ config, columns, setConfig }: { config: IHeatmapConfig; columns: VisColumn[]; setConfig: (config: IVisConfig) => void }) { return ( @@ -14,6 +15,14 @@ export function HeatmapVisSidebar({ config, columns, setConfig }: { config: IHea currentSelected={config.catColumnsSelected || []} /> setConfig({ ...(config as any), type })} currentSelected={config.type} /> + + setConfig({ ...config, color })} + numTypeCallback={(numColorScaleType: ENumericalColorScaleType) => setConfig({ ...config, numColorScaleType })} + currentNumType={config.numColorScaleType} + columns={columns} + currentSelected={config.color} + /> ); diff --git a/src/vis/interfaces.ts b/src/vis/interfaces.ts index 97f0ad170..7513f8bb9 100644 --- a/src/vis/interfaces.ts +++ b/src/vis/interfaces.ts @@ -124,8 +124,9 @@ export interface IHexbinConfig { export interface IHeatmapConfig { type: ESupportedPlotlyVis.HEATMAP; - colorScale: Scales; + color: ColumnInfo | null; catColumnsSelected: ColumnInfo[]; + numColorScaleType: ENumericalColorScaleType; } type ValueGetter = () => T | Promise; diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index 7bbe05cf8..43be86198 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -203,23 +203,23 @@ export const Heatmap: typeof Template = Template.bind({}); Heatmap.args = { externalConfig: { type: ESupportedPlotlyVis.HEATMAP, - colorScale: null, + color: { + description: '', + id: 'sepalWidth', + name: 'Sepal Width', + }, catColumnsSelected: [ { description: '', id: 'state', name: 'US States', }, - { - description: '', - id: 'randomThing', - name: 'Random Thing', - }, { description: '', id: 'year', name: 'Years', }, ], + numColorScaleType: ENumericalColorScaleType.DIVERGENT, }, }; From 6bdf35693d2e69cdea790593144606ff86814c49 Mon Sep 17 00:00:00 2001 From: tschachinger Date: Tue, 20 Jun 2023 15:17:05 +0200 Subject: [PATCH 100/241] add grid layout when multiple columns are selected --- src/vis/heatmap/Heatmap.tsx | 190 +++++++++++++------------------- src/vis/heatmap/HeatmapGrid.tsx | 44 ++++++++ src/vis/heatmap/HeatmapVis.tsx | 8 +- 3 files changed, 127 insertions(+), 115 deletions(-) create mode 100644 src/vis/heatmap/HeatmapGrid.tsx diff --git a/src/vis/heatmap/Heatmap.tsx b/src/vis/heatmap/Heatmap.tsx index 0603c6505..f962ef651 100644 --- a/src/vis/heatmap/Heatmap.tsx +++ b/src/vis/heatmap/Heatmap.tsx @@ -1,138 +1,106 @@ import { Group, Stack, Text, Tooltip } from '@mantine/core'; import { useResizeObserver } from '@mantine/hooks'; -import { table, op } from 'arquero'; +import { table } from 'arquero'; import * as d3 from 'd3v7'; import * as React from 'react'; - -import { useAsync } from '../../hooks'; -import { IHeatmapConfig, VisColumn } from '../interfaces'; +import { ColumnInfo, EColumnTypes, VisCategoricalValue, VisNumericalValue } from '../interfaces'; import { HeatmapRect } from './HeatmapRect'; -import { getHeatmapData } from './utils'; const interRectDistance = 1; -const margin = { - top: 20, - right: 20, - bottom: 100, - left: 100, + +type CatColumn = { + resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; + type: EColumnTypes.NUMERICAL | EColumnTypes.CATEGORICAL; + info: ColumnInfo; }; -export function Heatmap({ config, columns }: { config: IHeatmapConfig; columns: VisColumn[] }) { - const { value: allColumns } = useAsync(getHeatmapData, [columns, config?.catColumnsSelected]); +export function Heatmap({ + column1, + column2, + margin, +}: { + column1: CatColumn; + column2: CatColumn; + margin: { top: number; right: number; bottom: number; left: number }; +}) { const [ref, { width, height }] = useResizeObserver(); const [tooltipText, setTooltipText] = React.useState(null); - const hasAtLeast2CatCols = allColumns?.catColumn && allColumns?.catColumn?.length > 1; - - const { xValues, yValues, groupedValues } = React.useMemo(() => { - if (!hasAtLeast2CatCols) return { xValues: [], yValues: [], groupedValues: [] }; + const { xValues, yValues, groupedValues, rectHeight, rectWidth, yScale, xScale, colorScale } = React.useMemo(() => { const myTable = table({ - x: allColumns.catColumn[0]?.resolvedValues.map(({ val }) => val), - y: allColumns.catColumn[1]?.resolvedValues.map(({ val }) => val), + x: column1?.resolvedValues.map(({ val }) => val), + y: column2?.resolvedValues.map(({ val }) => val), }); - const xVals = [...new Set(allColumns.catColumn[0]?.resolvedValues.map(({ val }) => val))]; - const yVals = [...new Set(allColumns.catColumn[1]?.resolvedValues.map(({ val }) => val))]; + const xVals = [...new Set(column1?.resolvedValues.map(({ val }) => val))] as string[]; + const yVals = [...new Set(column2?.resolvedValues.map(({ val }) => val))] as string[]; - return { - xValues: xVals as string[], - yValues: yVals as string[], - groupedValues: myTable - .groupby('x', 'y') - .count() - .impute({ count: () => 0 }, { expand: ['x', 'y'] }) - .objects() as { x: string; y: string; count: number }[], - }; - }, [allColumns?.catColumn, hasAtLeast2CatCols]); - - const rectWidth = React.useMemo( - () => (groupedValues.length && xValues.length && width ? (width - margin.left - margin.right - interRectDistance * xValues.length) / xValues.length : 0), - [groupedValues?.length, width, xValues], - ); - const rectHeight = React.useMemo( - () => (groupedValues.length && yValues.length && height ? (height - margin.bottom - margin.top - interRectDistance * yValues.length) / yValues.length : 0), - [groupedValues?.length, height, yValues], - ); + const gropuedVals = myTable + .groupby('x', 'y') + .count() + .impute({ count: () => 0 }, { expand: ['x', 'y'] }) + .objects() as { x: string; y: string; count: number }[]; - const xScale = React.useMemo( - () => - d3 + return { + xValues: xVals, + yValues: yVals, + groupedValues: gropuedVals, + rectWidth: (width - margin.left - margin.right - interRectDistance * xVals.length) / xVals.length, + rectHeight: (height - margin.bottom - margin.top - interRectDistance * yVals.length) / yVals.length, + xScale: d3 .scaleBand() - .domain(xValues) + .domain(xVals) .range([0, width - margin.left - margin.right]), - [xValues, width], - ); - - const yScale = React.useMemo( - () => - d3 + yScale: d3 .scaleBand() - .domain(yValues) + .domain(yVals) .range([0, height - margin.top - margin.bottom]), - [yValues, height], - ); - - const colorScale = React.useMemo(() => { - if (!hasAtLeast2CatCols) return d3.scaleSequential(d3.interpolateReds); - return d3.scaleSequential(d3.interpolateBlues).domain(d3.extent(groupedValues, (d) => d.count as number)); - }, [hasAtLeast2CatCols, groupedValues]); + colorScale: d3.scaleSequential(d3.interpolateBlues).domain(d3.extent(gropuedVals, (d) => d.count as number)), + }; + }, [column1?.resolvedValues, column2?.resolvedValues, height, margin, width]); return ( - {!hasAtLeast2CatCols ? ( - - Select at least 2 categorical columns to display heatmap + + + {column2.info.name} - ) : null} - <> - - {hasAtLeast2CatCols && ( - - {allColumns.catColumn[1].info.name} - - )} - - - {hasAtLeast2CatCols && - groupedValues.map((d) => { - const x = xScale(d.x) + margin.left; - const y = yScale(d.y) + margin.top; - const { count } = d; - return ( - setTooltipText(`${d.x} - ${d.y} (${count})`)} - unsetTooltipText={() => setTooltipText(null)} - /> - ); - })} - {hasAtLeast2CatCols && - xValues.map((xVal) => ( - - - {xVal} - - - ))} - {hasAtLeast2CatCols && - yValues.map((yVal) => ( - - {yVal} - - ))} - - - - {hasAtLeast2CatCols && ( - - {allColumns.catColumn[0].info.name ?? ''} - - )} - + + + {groupedValues.map((d) => { + const x = xScale(d.x) + margin.left; + const y = yScale(d.y) + margin.top; + const { count } = d; + return ( + setTooltipText(`${d.x} - ${d.y} (${count})`)} + unsetTooltipText={() => setTooltipText(null)} + /> + ); + })} + {xValues.map((xVal) => ( + + + {xVal} + + + ))} + {yValues.map((yVal) => ( + + {yVal} + + ))} + + + + + {column1.info.name} + ); } diff --git a/src/vis/heatmap/HeatmapGrid.tsx b/src/vis/heatmap/HeatmapGrid.tsx new file mode 100644 index 000000000..61deed58c --- /dev/null +++ b/src/vis/heatmap/HeatmapGrid.tsx @@ -0,0 +1,44 @@ +import { SimpleGrid, Stack, Text } from '@mantine/core'; +import * as React from 'react'; +import { useAsync } from '../../hooks/useAsync'; +import { IHeatmapConfig, VisColumn } from '../interfaces'; +import { getHeatmapData } from './utils'; +import { Heatmap } from './Heatmap'; + +export function HeatmapGrid({ config, columns }: { config: IHeatmapConfig; columns: VisColumn[] }) { + const { value: allColumns } = useAsync(getHeatmapData, [columns, config?.catColumnsSelected]); + const hasAtLeast2CatCols = allColumns?.catColumn && allColumns?.catColumn?.length > 1; + + const margin = React.useMemo(() => { + if (!hasAtLeast2CatCols) return { top: 0, right: 0, bottom: 0, left: 0 }; + return { + top: 20 / allColumns.catColumn.length, + right: 20 / allColumns.catColumn.length, + bottom: 100 / allColumns.catColumn.length, + left: 100 / allColumns.catColumn.length, + }; + }, [allColumns?.catColumn?.length, hasAtLeast2CatCols]); + + return ( + + {!hasAtLeast2CatCols ? ( + + Select at least 2 categorical columns to display heatmap + + ) : allColumns.catColumn.length > 2 ? ( + + {allColumns.catColumn.map((col1) => + allColumns.catColumn.map((col2) => { + if (col1.info.id === col2.info.id) { + return
; + } + return ; + }), + )} + + ) : ( + + )} + + ); +} diff --git a/src/vis/heatmap/HeatmapVis.tsx b/src/vis/heatmap/HeatmapVis.tsx index 6c7878683..79f245e64 100644 --- a/src/vis/heatmap/HeatmapVis.tsx +++ b/src/vis/heatmap/HeatmapVis.tsx @@ -1,10 +1,10 @@ -import { Group, Text } from '@mantine/core'; +import { Group } from '@mantine/core'; import * as React from 'react'; +import { VisSidebarOpenButton } from '../VisSidebarOpenButton'; import { VisSidebarWrapper } from '../VisSidebarWrapper'; import { IHeatmapConfig, IVisConfig, VisColumn } from '../interfaces'; +import { HeatmapGrid } from './HeatmapGrid'; import { HeatmapVisSidebar } from './HeatmapVisSidebar'; -import { VisSidebarOpenButton } from '../VisSidebarOpenButton'; -import { Heatmap } from './Heatmap'; export function HeatmapVis({ config, @@ -30,7 +30,7 @@ export function HeatmapVis({ return ( {enableSidebar ? setShowSidebar(!showSidebar)} isOpen={showSidebar} /> : null} - + {showSidebar ? ( From a7f0060b4bd674c74df6fb7d6982ca0cc2213a0b Mon Sep 17 00:00:00 2001 From: Moritz Heckmann Date: Tue, 20 Jun 2023 15:25:16 +0200 Subject: [PATCH 101/241] finish up --- src/vis/correlation/CorrelationMatrix.tsx | 110 +++++++++--------- .../components/CircleCorrelationPair.tsx | 45 +++---- .../components/CorrelationGrid.tsx | 43 +++++++ .../components/CorrelationMatrixAxis.tsx | 85 -------------- 4 files changed, 118 insertions(+), 165 deletions(-) create mode 100644 src/vis/correlation/components/CorrelationGrid.tsx delete mode 100644 src/vis/correlation/components/CorrelationMatrixAxis.tsx diff --git a/src/vis/correlation/CorrelationMatrix.tsx b/src/vis/correlation/CorrelationMatrix.tsx index 99d4d640e..7f3cea4f1 100644 --- a/src/vis/correlation/CorrelationMatrix.tsx +++ b/src/vis/correlation/CorrelationMatrix.tsx @@ -1,13 +1,13 @@ import * as React from 'react'; import { scaleBand, scaleLinear } from 'd3v7'; -import { Popover } from '@mantine/core'; +import { AspectRatio, Box, Group, Popover } from '@mantine/core'; import { useResizeObserver } from '@mantine/hooks'; import { corrcoeff, studentt } from 'jstat'; import { ICorrelationConfig, VisColumn } from '../interfaces'; import { useAsync } from '../../hooks/useAsync'; import { getCorrelationMatrixData } from './utils'; import { CircleCorrelationPair, CorrelationPairProps } from './components/CircleCorrelationPair'; -import { Grid } from './components/CorrelationMatrixAxis'; +import { CorrelationGrid } from './components/CorrelationGrid'; import { CorrelationTooltip } from './components/CorrelationTooltip'; import { Legend } from './components/CorrelationLegend'; @@ -27,6 +27,7 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon const boundsWidth = width - margin.left - margin.right; const boundsHeight = height - margin.top - margin.bottom; + const availableSize = Math.min(boundsWidth, boundsHeight); const [hover, setHover] = React.useState<{ x: number; y: number } | null>(null); @@ -40,24 +41,16 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon const xScale = React.useMemo(() => { if (!data?.value?.numericalColumns) return null; return scaleBand() - .range([0, boundsWidth]) + .range([0, availableSize]) .domain(data.value.numericalColumns.map((column) => column.info.name)); - }, [data, boundsWidth]); + }, [data, availableSize]); const yScale = React.useMemo(() => { if (!data?.value?.numericalColumns) return null; return scaleBand() - .range([0, boundsHeight]) + .range([0, availableSize]) .domain(data.value.numericalColumns.map((column) => column.info.name)); - }, [data, boundsHeight]); - - // TODO: The domain does not make sense - const radiusScale = React.useMemo(() => { - if (!xScale || !yScale) return null; - return scaleLinear() - .domain([0.2, 0]) - .range([CIRCLE_MIN_SIZE, Math.min(xScale.bandwidth() / 2 - padding.left, yScale.bandwidth() / 2 - padding.top)]); - }, [xScale, yScale]); + }, [data, availableSize]); // Build correlation pairs const memoizedCorrelationPairs = React.useMemo(() => { @@ -92,14 +85,14 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon pValue, xName, yName, - radius: radiusScale(pValue), + radius: Math.min(xScale.bandwidth() / 2 - 4, yScale.bandwidth() / 2 - 4), }; correlationPairs.push(value); } } return correlationPairs; - }, [data, radiusScale, xScale, yScale]); + }, [data, xScale, yScale]); const filteredCorrelationPairs = React.useMemo(() => { if (!memoizedCorrelationPairs) return null; @@ -130,48 +123,49 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon }, [data, xScale, yScale]); return ( - - - {names ? : null} - - {hover ? ( - - - + + + {names ? : null} + + {hover ? ( + + + + + + (value.xi === hover.x && value.yi === hover.y) || (value.xi === hover.y && value.yi === hover.x), + )} + /> + + + ) : null} + + {filteredCorrelationPairs?.map((value) => { + return ( + - - - (value.xi === hover.x && value.yi === hover.y) || (value.xi === hover.y && value.yi === hover.x), - )} - /> - - - ) : null} - - {filteredCorrelationPairs?.map((value) => { - return ( - - ); - })} - {labelsDiagonal} - - - - + ); + })} + + + + + ); } diff --git a/src/vis/correlation/components/CircleCorrelationPair.tsx b/src/vis/correlation/components/CircleCorrelationPair.tsx index 3ccebba66..fd8f81ae5 100644 --- a/src/vis/correlation/components/CircleCorrelationPair.tsx +++ b/src/vis/correlation/components/CircleCorrelationPair.tsx @@ -34,28 +34,29 @@ export function CircleCorrelationPair({ return ( - setHovered({ x: value.xi, y: value.yi })} - onMouseLeave={() => setHovered(null)} - /> - - setHovered({ x: value.yi, y: value.xi })} - onMouseLeave={() => setHovered(null)} - /> - - {value.correlation.toFixed(2)} - + setHovered({ x: value.xi, y: value.yi })} onMouseLeave={() => setHovered(null)}> + {' '} + + + + setHovered({ x: value.yi, y: value.xi })} onMouseLeave={() => setHovered(null)}> + + + {value.correlation.toFixed(2)} + + ); } diff --git a/src/vis/correlation/components/CorrelationGrid.tsx b/src/vis/correlation/components/CorrelationGrid.tsx new file mode 100644 index 000000000..e830defff --- /dev/null +++ b/src/vis/correlation/components/CorrelationGrid.tsx @@ -0,0 +1,43 @@ +import * as React from 'react'; +import { useMantineTheme } from '@mantine/core'; + +export function CorrelationGrid({ width, height, names }: { width: number; height: number; names: string[] }) { + const theme = useMantineTheme(); + const borderColor = theme.colors.gray[4]; + + const xstep = width / names.length; + const ystep = height / names.length; + + return ( + <> + {Array.from({ length: names.length + 1 }).map((_, i) => { + const x = xstep * i; + const y = ystep * i; + + const xtick = x + xstep / 2; + const ytick = y + ystep / 2; + + return ( + + {i !== names.length ? ( + + + {names[i]} + + + ) : null} + {i !== names.length ? ( + + + {names[i]} + + + ) : null} + + + + ); + })} + + ); +} diff --git a/src/vis/correlation/components/CorrelationMatrixAxis.tsx b/src/vis/correlation/components/CorrelationMatrixAxis.tsx deleted file mode 100644 index 075d7538e..000000000 --- a/src/vis/correlation/components/CorrelationMatrixAxis.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import * as React from 'react'; -import * as d3 from 'd3v7'; -import { useMantineTheme } from '@mantine/core'; - -export function Grid({ width, height, names }: { width: number; height: number; names: string[] }) { - const theme = useMantineTheme(); - const borderColor = theme.colors.gray[4]; - - const xstep = width / names.length; - const ystep = height / names.length; - - return ( - <> - {Array.from({ length: names.length + 1 }).map((_, i) => { - const x = xstep * i; - const y = ystep * i; - - const xtick = x + xstep / 2; - const ytick = y + ystep / 2; - - return ( - - {i !== names.length ? ( - - - {names[i]} - - - ) : null} - {i !== names.length ? ( - - - {names[i]} - - - ) : null} - - - - ); - })} - - ); -} - -export function AxisTop({ xScale, ticks, height }: { xScale: d3.ScaleBand; ticks: { value: string; offset: number }[]; height: number }) { - const theme = useMantineTheme(); - const borderColor = theme.colors.gray[4]; - if (!xScale || !ticks) return null; - - return ( - <> - {ticks.map(({ value, offset }) => { - const x = xScale(value); - - return ( - - - - ); - })} - - ); -} - -export function AxisLeft({ yScale, ticks, width }: { yScale: d3.ScaleBand; ticks: { value: string; offset: number }[]; width: number }) { - const theme = useMantineTheme(); - const borderColor = theme.colors.gray[4]; - - if (!yScale || !ticks) return null; - - return ( - <> - {ticks.map(({ value, offset }) => { - const y = yScale(value) + yScale.bandwidth() / 2; - - return ( - - - - ); - })} - - ); -} From 0dfe7f79eb8c7d95c704c0c8f2ab0f38de0a39a1 Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Tue, 20 Jun 2023 15:44:01 +0200 Subject: [PATCH 102/241] something happens --- src/vis/Vis.tsx | 16 ++++- src/vis/interfaces.ts | 9 ++- src/vis/raincloud/Raincloud.tsx | 27 +++++++ src/vis/raincloud/RaincloudVis.tsx | 68 ++++++++++++++++++ src/vis/raincloud/RaincloudVisSidebar.tsx | 57 +++++++++++++++ src/vis/raincloud/cloud/SplitViolin.tsx | 85 +++++++++++++++++++++++ src/vis/raincloud/utils.ts | 43 ++++++++++++ src/vis/stories/Iris.stories.tsx | 19 +++++ 8 files changed, 322 insertions(+), 2 deletions(-) create mode 100644 src/vis/raincloud/Raincloud.tsx create mode 100644 src/vis/raincloud/RaincloudVis.tsx create mode 100644 src/vis/raincloud/RaincloudVisSidebar.tsx create mode 100644 src/vis/raincloud/cloud/SplitViolin.tsx create mode 100644 src/vis/raincloud/utils.ts diff --git a/src/vis/Vis.tsx b/src/vis/Vis.tsx index 361a23dc1..820c58d34 100644 --- a/src/vis/Vis.tsx +++ b/src/vis/Vis.tsx @@ -24,6 +24,8 @@ import { useSyncedRef } from '../hooks/useSyncedRef'; import { hexinbMergeDefaultConfig, isHexbin } from './hexbin/utils'; import { HexbinVis } from './hexbin/HexbinVis'; import { BarVis } from './barGood/BarVis'; +import { isRaincloud } from './raincloud/utils'; +import { RaincloudVis } from './raincloud/RaincloudVis'; const DEFAULT_SHAPES = ['circle', 'square', 'triangle-up', 'star']; @@ -239,6 +241,19 @@ export function EagerVis({ /> ) : null} + {isRaincloud(visConfig) ? ( + + ) : null} + {isViolin(visConfig) ? ( ) : null} diff --git a/src/vis/interfaces.ts b/src/vis/interfaces.ts index 45e99396a..87011bcc8 100644 --- a/src/vis/interfaces.ts +++ b/src/vis/interfaces.ts @@ -5,6 +5,7 @@ export enum ESupportedPlotlyVis { VIOLIN = 'Violin plot', BAR = 'Bar chart', HEXBIN = 'Hexbin plot', + RAINCLOUD = 'Raincloud plot', } export const allVisTypes: ESupportedPlotlyVis[] = [ @@ -12,9 +13,10 @@ export const allVisTypes: ESupportedPlotlyVis[] = [ ESupportedPlotlyVis.BAR, ESupportedPlotlyVis.VIOLIN, ESupportedPlotlyVis.HEXBIN, + ESupportedPlotlyVis.RAINCLOUD, ]; -export type IVisConfig = IScatterConfig | IViolinConfig | IBarConfig | IHexbinConfig; +export type IVisConfig = IScatterConfig | IViolinConfig | IBarConfig | IHexbinConfig | IRaincloudConfig; export enum EBarDisplayType { ABSOLUTE = 'Absolute', @@ -86,6 +88,11 @@ export interface IViolinConfig { violinOverlay: EViolinOverlay; } +export interface IRaincloudConfig { + type: ESupportedPlotlyVis.RAINCLOUD; + numColumnsSelected: ColumnInfo[]; +} + export interface IScatterConfig { type: ESupportedPlotlyVis.SCATTER; numColumnsSelected: ColumnInfo[]; diff --git a/src/vis/raincloud/Raincloud.tsx b/src/vis/raincloud/Raincloud.tsx new file mode 100644 index 000000000..c0d97e26a --- /dev/null +++ b/src/vis/raincloud/Raincloud.tsx @@ -0,0 +1,27 @@ +import React, { useCallback, useMemo } from 'react'; +import { Box, Container } from '@mantine/core'; +import { useResizeObserver } from '@mantine/hooks'; +import { EAggregateTypes, EBarDirection, EBarDisplayType, EBarGroupingType, IBarConfig, IRaincloudConfig, VisColumn } from '../interfaces'; +import { getRaincloudData } from './utils'; + +import { useAsync } from '../../hooks/useAsync'; +import { SplitViolin } from './cloud/SplitViolin'; + +const margin = { + top: 30, + bottom: 60, + left: 60, + right: 25, +}; + +export function Raincloud({ columns, config }: { columns: VisColumn[]; config: IRaincloudConfig }) { + const [ref, { width, height }] = useResizeObserver(); + + const { value: data } = useAsync(getRaincloudData, [columns, config.numColumnsSelected]); + + return ( + + {data ? : null} + + ); +} diff --git a/src/vis/raincloud/RaincloudVis.tsx b/src/vis/raincloud/RaincloudVis.tsx new file mode 100644 index 000000000..ac3aa9c9d --- /dev/null +++ b/src/vis/raincloud/RaincloudVis.tsx @@ -0,0 +1,68 @@ +import * as React from 'react'; +import merge from 'lodash/merge'; +import { useMemo, useRef } from 'react'; +import { Group, SimpleGrid, Stack, Text } from '@mantine/core'; + +import { VisColumn, IVisConfig, IHexbinConfig, EScatterSelectSettings, EFilterOptions, IRaincloudConfig } from '../interfaces'; +import { InvalidCols } from '../general'; +import { i18n } from '../../i18n'; +import { VisSidebarWrapper } from '../VisSidebarWrapper'; +import { VisSidebarOpenButton } from '../VisSidebarOpenButton'; +import { VisFilterAndSelectSettings } from '../VisFilterAndSelectSettings'; +import { RaincloudVisSidebar } from './RaincloudVisSidebar'; +import { Raincloud } from './Raincloud'; + +const defaultExtensions = { + prePlot: null, + postPlot: null, + preSidebar: null, + postSidebar: null, +}; + +export function RaincloudVis({ + config, + extensions, + columns, + setConfig, + selectionCallback = () => null, + selected = {}, + enableSidebar, + setShowSidebar, + showSidebar, + showDragModeOptions = true, + filterCallback = () => null, +}: { + config: IRaincloudConfig; + extensions?: { + prePlot?: React.ReactNode; + postPlot?: React.ReactNode; + preSidebar?: React.ReactNode; + postSidebar?: React.ReactNode; + }; + columns: VisColumn[]; + setConfig: (config: IVisConfig) => void; + selectionCallback?: (ids: string[]) => void; + selected?: { [key: string]: boolean }; + showSidebar?: boolean; + setShowSidebar?(show: boolean): void; + showDragModeOptions?: boolean; + enableSidebar?: boolean; + filterCallback?: (s: EFilterOptions) => void; +}) { + const ref = useRef(); + + return ( + + {enableSidebar ? setShowSidebar(!showSidebar)} isOpen={showSidebar} /> : null} + + + + + {showSidebar ? ( + + + + ) : null} + + ); +} diff --git a/src/vis/raincloud/RaincloudVisSidebar.tsx b/src/vis/raincloud/RaincloudVisSidebar.tsx new file mode 100644 index 000000000..4d217a01f --- /dev/null +++ b/src/vis/raincloud/RaincloudVisSidebar.tsx @@ -0,0 +1,57 @@ +import * as React from 'react'; +import { useMemo } from 'react'; +import merge from 'lodash/merge'; +import { Container, Divider, Stack } from '@mantine/core'; +import { ColumnInfo, ESupportedPlotlyVis, IScatterConfig, IVisConfig, VisColumn, ICommonVisSideBarProps, EColumnTypes, IRaincloudConfig } from '../interfaces'; +import { VisTypeSelect } from '../sidebar/VisTypeSelect'; +import { NumericalColumnSelect } from '../sidebar/NumericalColumnSelect'; +import { ColorSelect } from '../sidebar/ColorSelect'; +import { FilterButtons } from '../sidebar/FilterButtons'; +import { SingleColumnSelect } from '../sidebar/SingleColumnSelect'; +import { OpacitySlider } from '../sidebar/OpacitySlider'; + +export function RaincloudVisSidebar({ + config, + optionsConfig, + extensions, + columns, + setConfig, +}: { + config: IRaincloudConfig; + optionsConfig?: { + color?: { + enable?: boolean; + customComponent?: React.ReactNode; + }; + shape?: { + enable?: boolean; + customComponent?: React.ReactNode; + }; + filter?: { + enable?: boolean; + customComponent?: React.ReactNode; + }; + }; + extensions?: { + prePlot?: React.ReactNode; + postPlot?: React.ReactNode; + preSidebar?: React.ReactNode; + postSidebar?: React.ReactNode; + }; + columns: VisColumn[]; + setConfig: (config: IVisConfig) => void; +} & ICommonVisSideBarProps) { + return ( + + + setConfig({ ...(config as any), type })} currentSelected={config.type} /> + + setConfig({ ...config, numColumnsSelected })} + columns={columns} + currentSelected={config.numColumnsSelected || []} + /> + + + ); +} diff --git a/src/vis/raincloud/cloud/SplitViolin.tsx b/src/vis/raincloud/cloud/SplitViolin.tsx new file mode 100644 index 000000000..448de8ca9 --- /dev/null +++ b/src/vis/raincloud/cloud/SplitViolin.tsx @@ -0,0 +1,85 @@ +import React, { useCallback, useMemo } from 'react'; +import { Box, Container } from '@mantine/core'; +import { useResizeObserver } from '@mantine/hooks'; +import * as d3 from 'd3v7'; + +import { ColumnInfo, EColumnTypes, IRaincloudConfig, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; + +const margin = { + top: 20, + bottom: 20, + left: 20, + right: 20, +}; + +function kernelDensityEstimator(kernel, X) { + return function (V) { + return X.map(function (x) { + return [ + x, + d3.mean(V, function (v) { + return kernel(x - v); + }), + ]; + }); + }; +} +function kernelEpanechnikov(k) { + return function (v) { + return Math.abs((v /= k)) <= 1 ? (0.75 * (1 - v * v)) / k : 0; + }; +} + +export function SplitViolin({ + numCol, + config, + width, + height, +}: { + numCol: { + resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; + type: EColumnTypes; + info: ColumnInfo; + }; + config: IRaincloudConfig; + width: number; + height: number; +}) { + const xScale = useMemo(() => { + const scale = d3 + .scaleLinear() + .domain(d3.extent(numCol.resolvedValues.map((val) => val.val as number))) + .range([margin.left, width - margin.right]); + + return scale; + }, [numCol.resolvedValues, width]); + + const kdeVal: [number, number][] = useMemo(() => { + const kde = kernelDensityEstimator(kernelEpanechnikov(0.2), xScale.ticks(50)); + + return kde(numCol.resolvedValues.map((val) => val.val as number)); + }, [numCol.resolvedValues, xScale]); + + const yScale = useMemo(() => { + const scale = d3 + .scaleLinear() + .domain([d3.max(kdeVal.map((val) => val[1] as number)), 0]) + .range([margin.top, height - margin.bottom]); + + return scale; + }, [height, kdeVal]); + + console.log(kdeVal, yScale.domain()); + + const line = useMemo(() => { + const myLine = d3 + .line() + .curve(d3.curveBasis) + .x((d) => xScale(d[0])) + .y((d) => yScale(d[1])); + + return myLine(kdeVal); + }, [kdeVal, xScale, yScale]); + + return ; +} diff --git a/src/vis/raincloud/utils.ts b/src/vis/raincloud/utils.ts new file mode 100644 index 000000000..0f045a548 --- /dev/null +++ b/src/vis/raincloud/utils.ts @@ -0,0 +1,43 @@ +import { merge } from 'lodash'; +import { + ColumnInfo, + EColumnTypes, + ESupportedPlotlyVis, + IRaincloudConfig, + IVisConfig, + VisCategoricalValue, + VisColumn, + VisNumericalColumn, + VisNumericalValue, +} from '../interfaces'; +import { resolveColumnValues, resolveSingleColumn } from '../general/layoutUtils'; + +export function isRaincloud(s: IVisConfig): s is IRaincloudConfig { + return s.type === ESupportedPlotlyVis.RAINCLOUD; +} + +const defaultConfig: IRaincloudConfig = { + type: ESupportedPlotlyVis.RAINCLOUD, + numColumnsSelected: [], +}; + +export function raincloudMergeDefaultConfig(columns: VisColumn[], config: IRaincloudConfig): IVisConfig { + const merged = merge({}, defaultConfig, config); + + return merged; +} + +export async function getRaincloudData( + columns: VisColumn[], + numColumnsSelected: ColumnInfo[], +): Promise<{ + numColVals: { + resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; + type: EColumnTypes.NUMERICAL | EColumnTypes.CATEGORICAL; + info: ColumnInfo; + }[]; +}> { + const numColVals = await resolveColumnValues(columns.filter((col) => numColumnsSelected.find((numCol: ColumnInfo) => numCol.id === col.info.id))); + + return { numColVals }; +} diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index 1b60054f1..c9800c5e1 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -138,6 +138,25 @@ ScatterPlot.args = { }, }; +export const RaincloudPlot: typeof Template = Template.bind({}); +RaincloudPlot.args = { + externalConfig: { + type: ESupportedPlotlyVis.RAINCLOUD, + numColumnsSelected: [ + { + description: '', + id: 'sepalLength', + name: 'Sepal Length', + }, + { + description: '', + id: 'sepalWidth', + name: 'Sepal Width', + }, + ], + }, +}; + export const BarChart: typeof Template = Template.bind({}); BarChart.args = { externalConfig: { From 1dd55705e9d3851fd9b5acd9004496eeabe34aab Mon Sep 17 00:00:00 2001 From: Daniela Date: Tue, 20 Jun 2023 16:13:31 +0200 Subject: [PATCH 103/241] fix density plot --- src/vis/raincloud/cloud/SplitViolin.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/vis/raincloud/cloud/SplitViolin.tsx b/src/vis/raincloud/cloud/SplitViolin.tsx index 448de8ca9..20a54da0b 100644 --- a/src/vis/raincloud/cloud/SplitViolin.tsx +++ b/src/vis/raincloud/cloud/SplitViolin.tsx @@ -55,7 +55,7 @@ export function SplitViolin({ }, [numCol.resolvedValues, width]); const kdeVal: [number, number][] = useMemo(() => { - const kde = kernelDensityEstimator(kernelEpanechnikov(0.2), xScale.ticks(50)); + const kde = kernelDensityEstimator(kernelEpanechnikov(0.3), xScale.ticks(50)); return kde(numCol.resolvedValues.map((val) => val.val as number)); }, [numCol.resolvedValues, xScale]); @@ -78,8 +78,7 @@ export function SplitViolin({ .x((d) => xScale(d[0])) .y((d) => yScale(d[1])); - return myLine(kdeVal); + return `${myLine(kdeVal)}L${xScale.range()[1]},${yScale.range()[1]}L${xScale.range()[0]},${yScale.range()[1]}Z`; }, [kdeVal, xScale, yScale]); - - return ; + return ; } From 44cc27464cbbbeb793c82d82dbe208211cfb6cac Mon Sep 17 00:00:00 2001 From: dvmartinweigl Date: Tue, 20 Jun 2023 16:13:33 +0200 Subject: [PATCH 104/241] highlight significant --- src/vis/correlation/CorrelationMatrix.tsx | 36 +++++++++---------- src/vis/correlation/CorrelationVisSidebar.tsx | 6 ++-- .../components/CircleCorrelationPair.tsx | 11 +++++- src/vis/correlation/utils.ts | 2 +- src/vis/interfaces.ts | 2 +- src/vis/stories/Iris.stories.tsx | 2 +- 6 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/vis/correlation/CorrelationMatrix.tsx b/src/vis/correlation/CorrelationMatrix.tsx index 7f3cea4f1..9bde1c775 100644 --- a/src/vis/correlation/CorrelationMatrix.tsx +++ b/src/vis/correlation/CorrelationMatrix.tsx @@ -31,7 +31,7 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon const [hover, setHover] = React.useState<{ x: number; y: number } | null>(null); - const colorScale = scaleLinear().domain([-1, 0, 1]).range(['#003367', '#ffffff', '#6f0000']); + const colorScale = scaleLinear().domain([-1, 0, 1]).range(['#000080', '#fff', '#B22222']); const names = React.useMemo(() => { return data.value?.numericalColumns.map((column) => column.info.name); @@ -52,12 +52,18 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon .domain(data.value.numericalColumns.map((column) => column.info.name)); }, [data, availableSize]); - // Build correlation pairs - const memoizedCorrelationPairs = React.useMemo(() => { + const circleSizeScale = React.useMemo(() => { + if (!data?.value?.numericalColumns) return null; + const maxSize = Math.min(xScale.bandwidth() / 2 - 4, yScale.bandwidth() / 2 - 4); + return scaleLinear().domain([-1, 1]).range([CIRCLE_MIN_SIZE, maxSize]); + }, [data, xScale, yScale]); + + // Calculate correlation results + const memoizedCorrelationResults = React.useMemo(() => { if (!data?.value?.numericalColumns) return null; const cols = data.value.numericalColumns; - const correlationPairs = [] as CorrelationPairProps[]; + const correlationResults = [] as CorrelationPairProps[]; for (let x = 1; x < cols.length; x++) { for (let y = 0; y < x; y++) { @@ -85,23 +91,14 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon pValue, xName, yName, - radius: Math.min(xScale.bandwidth() / 2 - 4, yScale.bandwidth() / 2 - 4), + radius: circleSizeScale(Math.abs(correlation)), }; - correlationPairs.push(value); + correlationResults.push(value); } } - return correlationPairs; - }, [data, xScale, yScale]); - - const filteredCorrelationPairs = React.useMemo(() => { - if (!memoizedCorrelationPairs) return null; - - if (config.showSignificant) { - return memoizedCorrelationPairs.filter((pair) => pair.pValue < 0.05); - } - return memoizedCorrelationPairs; - }, [config.showSignificant, memoizedCorrelationPairs]); + return correlationResults; + }, [circleSizeScale, data, xScale, yScale]); // Show labels on diagonal of matrix const labelsDiagonal = React.useMemo(() => { @@ -142,7 +139,7 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon (value.xi === hover.x && value.yi === hover.y) || (value.xi === hover.y && value.yi === hover.x), )} /> @@ -150,7 +147,7 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon ) : null} - {filteredCorrelationPairs?.map((value) => { + {memoizedCorrelationResults?.map((value) => { return ( ); })} diff --git a/src/vis/correlation/CorrelationVisSidebar.tsx b/src/vis/correlation/CorrelationVisSidebar.tsx index 731a562fa..4d22dfdca 100644 --- a/src/vis/correlation/CorrelationVisSidebar.tsx +++ b/src/vis/correlation/CorrelationVisSidebar.tsx @@ -106,9 +106,9 @@ export function CorrelationVisSidebar({ currentSelected={config.numColumnsSelected || []} /> setConfig({ ...config, showSignificant: !config.showSignificant })} + label="Significant" + checked={config.highlightSignificant || false} + onChange={() => setConfig({ ...config, highlightSignificant: !config.highlightSignificant })} /> diff --git a/src/vis/correlation/components/CircleCorrelationPair.tsx b/src/vis/correlation/components/CircleCorrelationPair.tsx index fd8f81ae5..a475fccab 100644 --- a/src/vis/correlation/components/CircleCorrelationPair.tsx +++ b/src/vis/correlation/components/CircleCorrelationPair.tsx @@ -22,12 +22,14 @@ export function CircleCorrelationPair({ boundingRect, hover, setHovered, + highlightSignificant, }: { value: CorrelationPairProps; fill: string; boundingRect: { width: number; height: number }; hover: boolean; setHovered: ({ x, y }: { x: number; y: number }) => void; + highlightSignificant: boolean; }) { const theme = useMantineTheme(); const hoverColor = theme.colors.gray[2]; @@ -53,7 +55,14 @@ export function CircleCorrelationPair({ y={value.cyLT - boundingRect.height / 2} fill={hover ? hoverColor : 'transparent'} /> - + = 0.05 ? theme.colors.gray[2] : 'none'} + > {value.correlation.toFixed(2)} diff --git a/src/vis/correlation/utils.ts b/src/vis/correlation/utils.ts index c7bf1f238..92106931b 100644 --- a/src/vis/correlation/utils.ts +++ b/src/vis/correlation/utils.ts @@ -18,7 +18,7 @@ export function isCorrelation(s: IVisConfig): s is ICorrelationConfig { const defaultConfig: ICorrelationConfig = { type: ESupportedPlotlyVis.CORRELATION, numColumnsSelected: [], - showSignificant: false, + highlightSignificant: false, }; export function correlationMergeDefaultConfig(columns: VisColumn[], config: ICorrelationConfig): IVisConfig { diff --git a/src/vis/interfaces.ts b/src/vis/interfaces.ts index 20dfeaf78..a9fb00730 100644 --- a/src/vis/interfaces.ts +++ b/src/vis/interfaces.ts @@ -91,7 +91,7 @@ export interface IViolinConfig { export interface ICorrelationConfig { type: ESupportedPlotlyVis.CORRELATION; numColumnsSelected: ColumnInfo[]; - showSignificant: boolean; + highlightSignificant: boolean; } export interface IScatterConfig { diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index 348cd381e..9042b5b0a 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -180,7 +180,7 @@ export const CorrelationPlot: typeof Template = Template.bind({}); CorrelationPlot.args = { externalConfig: { type: ESupportedPlotlyVis.CORRELATION, - showSignificant: false, + highlightSignificant: false, numColumnsSelected: [ { description: '', From 56e1f818b8ad5dddf34fc5882e68493a1e6db61f Mon Sep 17 00:00:00 2001 From: Daniela Date: Tue, 20 Jun 2023 16:33:57 +0200 Subject: [PATCH 105/241] starting rain --- src/vis/raincloud/Raincloud.tsx | 8 ++++- src/vis/raincloud/cloud/SplitViolin.tsx | 10 ++---- src/vis/raincloud/hooks/useXScale.tsx | 32 +++++++++++++++++ src/vis/raincloud/rain/DotPlot.tsx | 46 +++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 9 deletions(-) create mode 100644 src/vis/raincloud/hooks/useXScale.tsx create mode 100644 src/vis/raincloud/rain/DotPlot.tsx diff --git a/src/vis/raincloud/Raincloud.tsx b/src/vis/raincloud/Raincloud.tsx index c0d97e26a..bba88290f 100644 --- a/src/vis/raincloud/Raincloud.tsx +++ b/src/vis/raincloud/Raincloud.tsx @@ -6,6 +6,7 @@ import { getRaincloudData } from './utils'; import { useAsync } from '../../hooks/useAsync'; import { SplitViolin } from './cloud/SplitViolin'; +import { DotPlot } from './rain/DotPlot'; const margin = { top: 30, @@ -21,7 +22,12 @@ export function Raincloud({ columns, config }: { columns: VisColumn[]; config: I return ( - {data ? : null} + {data ? ( + + + + + ) : null} ); } diff --git a/src/vis/raincloud/cloud/SplitViolin.tsx b/src/vis/raincloud/cloud/SplitViolin.tsx index 20a54da0b..e70d2b353 100644 --- a/src/vis/raincloud/cloud/SplitViolin.tsx +++ b/src/vis/raincloud/cloud/SplitViolin.tsx @@ -4,6 +4,7 @@ import { useResizeObserver } from '@mantine/hooks'; import * as d3 from 'd3v7'; import { ColumnInfo, EColumnTypes, IRaincloudConfig, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; +import { useXScale } from '../hooks/useXScale'; const margin = { top: 20, @@ -45,14 +46,7 @@ export function SplitViolin({ width: number; height: number; }) { - const xScale = useMemo(() => { - const scale = d3 - .scaleLinear() - .domain(d3.extent(numCol.resolvedValues.map((val) => val.val as number))) - .range([margin.left, width - margin.right]); - - return scale; - }, [numCol.resolvedValues, width]); + const xScale = useXScale({ range: [margin.left, width - margin.right], column: numCol }); const kdeVal: [number, number][] = useMemo(() => { const kde = kernelDensityEstimator(kernelEpanechnikov(0.3), xScale.ticks(50)); diff --git a/src/vis/raincloud/hooks/useXScale.tsx b/src/vis/raincloud/hooks/useXScale.tsx new file mode 100644 index 000000000..46856c023 --- /dev/null +++ b/src/vis/raincloud/hooks/useXScale.tsx @@ -0,0 +1,32 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +import * as d3 from 'd3v7'; +import * as React from 'react'; +import { ColumnInfo, EColumnTypes, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; + +/** + * @param range + * @param column + * @returns xScale + */ +export function useXScale({ + range, + column, +}: { + range: [number, number]; + column: { + resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; + type: EColumnTypes; + info: ColumnInfo; + }; +}) { + const xScale = React.useMemo(() => { + const scale = d3 + .scaleLinear() + .domain(d3.extent(column.resolvedValues.map((val) => val.val as number))) + .range(range); + + return scale; + }, [column, range]); + + return xScale; +} diff --git a/src/vis/raincloud/rain/DotPlot.tsx b/src/vis/raincloud/rain/DotPlot.tsx new file mode 100644 index 000000000..ee8eeb3d8 --- /dev/null +++ b/src/vis/raincloud/rain/DotPlot.tsx @@ -0,0 +1,46 @@ +import React, { useMemo } from 'react'; + +import { table } from 'arquero'; +import { ColumnInfo, EColumnTypes, IRaincloudConfig, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; +import { useXScale } from '../hooks/useXScale'; + +const margin = { + top: 20, + bottom: 20, + left: 20, + right: 20, +}; + +export function DotPlot({ + numCol, + config, + width, + height, +}: { + numCol: { + resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; + type: EColumnTypes; + info: ColumnInfo; + }; + config: IRaincloudConfig; + width: number; + height: number; +}) { + const xScale = useXScale({ range: [margin.left, width - margin.right], column: numCol }); + + // const yScale = useMemo(() => { + // const scale = d3 + // .scaleLinear() + // .domain([d3.max(kdeVal.map((val) => val[1] as number)), 0]) + // .range([margin.top, height - margin.bottom]); + + // return scale; + // }, [height, kdeVal]); + + const dt = useMemo(() => { + return table({ values: numCol.resolvedValues.map((v) => v.val) }); + }, [numCol.resolvedValues]); + dt.print(); + return null; + // return ; +} From 4c865135861b5d7e232b4c6242717c2a4ee9906d Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Tue, 20 Jun 2023 16:44:12 +0200 Subject: [PATCH 106/241] idk --- src/vis/raincloud/rain/DotPlot.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vis/raincloud/rain/DotPlot.tsx b/src/vis/raincloud/rain/DotPlot.tsx index ee8eeb3d8..92703400b 100644 --- a/src/vis/raincloud/rain/DotPlot.tsx +++ b/src/vis/raincloud/rain/DotPlot.tsx @@ -1,6 +1,6 @@ import React, { useMemo } from 'react'; -import { table } from 'arquero'; +import { table, op } from 'arquero'; import { ColumnInfo, EColumnTypes, IRaincloudConfig, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; import { useXScale } from '../hooks/useXScale'; @@ -38,7 +38,7 @@ export function DotPlot({ // }, [height, kdeVal]); const dt = useMemo(() => { - return table({ values: numCol.resolvedValues.map((v) => v.val) }); + return table({ values: numCol.resolvedValues.map((v) => v.val) }).rollup({ bins: (d) => op.bins(d.values) }); }, [numCol.resolvedValues]); dt.print(); return null; From bcd02f45bcbfb81d7b5e1d66ed98155bb63584e9 Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Tue, 20 Jun 2023 18:59:58 +0200 Subject: [PATCH 107/241] adding raincloud plot --- src/vis/raincloud/Raincloud.tsx | 50 ++++++++++------- src/vis/raincloud/RaincloudGrid.tsx | 20 +++++++ src/vis/raincloud/RaincloudVis.tsx | 40 +++----------- src/vis/raincloud/RaincloudVisSidebar.tsx | 30 +---------- src/vis/raincloud/cloud/SplitViolin.tsx | 8 ++- .../raincloud/lightning/MeanAndInterval.tsx | 53 +++++++++++++++++++ src/vis/raincloud/rain/DotPlot.tsx | 45 ++++++++++------ 7 files changed, 146 insertions(+), 100 deletions(-) create mode 100644 src/vis/raincloud/RaincloudGrid.tsx create mode 100644 src/vis/raincloud/lightning/MeanAndInterval.tsx diff --git a/src/vis/raincloud/Raincloud.tsx b/src/vis/raincloud/Raincloud.tsx index bba88290f..a117e287a 100644 --- a/src/vis/raincloud/Raincloud.tsx +++ b/src/vis/raincloud/Raincloud.tsx @@ -1,33 +1,45 @@ -import React, { useCallback, useMemo } from 'react'; -import { Box, Container } from '@mantine/core'; +import React from 'react'; import { useResizeObserver } from '@mantine/hooks'; -import { EAggregateTypes, EBarDirection, EBarDisplayType, EBarGroupingType, IBarConfig, IRaincloudConfig, VisColumn } from '../interfaces'; -import { getRaincloudData } from './utils'; +import { ColumnInfo, EColumnTypes, IRaincloudConfig, VisCategoricalValue, VisNumericalValue } from '../interfaces'; -import { useAsync } from '../../hooks/useAsync'; import { SplitViolin } from './cloud/SplitViolin'; import { DotPlot } from './rain/DotPlot'; +import { MeanAndInterval } from './lightning/MeanAndInterval'; +import { useXScale } from './hooks/useXScale'; +import { XAxis } from '../hexbin/XAxis'; const margin = { - top: 30, - bottom: 60, - left: 60, - right: 25, + top: 0, + left: 20, + right: 20, + bottom: 0, }; - -export function Raincloud({ columns, config }: { columns: VisColumn[]; config: IRaincloudConfig }) { +export function Raincloud({ + column, + config, +}: { + column: { + resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; + type: EColumnTypes; + info: ColumnInfo; + }; + config: IRaincloudConfig; +}) { const [ref, { width, height }] = useResizeObserver(); - const { value: data } = useAsync(getRaincloudData, [columns, config.numColumnsSelected]); + const xScale = useXScale({ range: [margin.left, width - margin.right], column }); return ( - - {data ? ( - - - - - ) : null} + + + {column.info.name} + + + + + + + ); } diff --git a/src/vis/raincloud/RaincloudGrid.tsx b/src/vis/raincloud/RaincloudGrid.tsx new file mode 100644 index 000000000..8d26cbc87 --- /dev/null +++ b/src/vis/raincloud/RaincloudGrid.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { SimpleGrid } from '@mantine/core'; +import { IRaincloudConfig, VisColumn } from '../interfaces'; +import { getRaincloudData } from './utils'; + +import { useAsync } from '../../hooks/useAsync'; +import { Raincloud } from './Raincloud'; + +export function RaincloudGrid({ columns, config }: { columns: VisColumn[]; config: IRaincloudConfig }) { + const { value: data } = useAsync(getRaincloudData, [columns, config.numColumnsSelected]); + + return ( + + {data && + data.numColVals.map((numCol) => { + return ; + })} + + ); +} diff --git a/src/vis/raincloud/RaincloudVis.tsx b/src/vis/raincloud/RaincloudVis.tsx index ac3aa9c9d..1d8f7ec04 100644 --- a/src/vis/raincloud/RaincloudVis.tsx +++ b/src/vis/raincloud/RaincloudVis.tsx @@ -1,53 +1,29 @@ import * as React from 'react'; -import merge from 'lodash/merge'; -import { useMemo, useRef } from 'react'; -import { Group, SimpleGrid, Stack, Text } from '@mantine/core'; +import { useRef } from 'react'; +import { Group, Stack } from '@mantine/core'; -import { VisColumn, IVisConfig, IHexbinConfig, EScatterSelectSettings, EFilterOptions, IRaincloudConfig } from '../interfaces'; -import { InvalidCols } from '../general'; -import { i18n } from '../../i18n'; +import { VisColumn, IVisConfig, IRaincloudConfig } from '../interfaces'; import { VisSidebarWrapper } from '../VisSidebarWrapper'; import { VisSidebarOpenButton } from '../VisSidebarOpenButton'; -import { VisFilterAndSelectSettings } from '../VisFilterAndSelectSettings'; import { RaincloudVisSidebar } from './RaincloudVisSidebar'; -import { Raincloud } from './Raincloud'; - -const defaultExtensions = { - prePlot: null, - postPlot: null, - preSidebar: null, - postSidebar: null, -}; +import { RaincloudGrid } from './RaincloudGrid'; export function RaincloudVis({ config, - extensions, columns, setConfig, - selectionCallback = () => null, - selected = {}, + enableSidebar, setShowSidebar, showSidebar, - showDragModeOptions = true, - filterCallback = () => null, }: { config: IRaincloudConfig; - extensions?: { - prePlot?: React.ReactNode; - postPlot?: React.ReactNode; - preSidebar?: React.ReactNode; - postSidebar?: React.ReactNode; - }; columns: VisColumn[]; setConfig: (config: IVisConfig) => void; - selectionCallback?: (ids: string[]) => void; - selected?: { [key: string]: boolean }; + showSidebar?: boolean; setShowSidebar?(show: boolean): void; - showDragModeOptions?: boolean; enableSidebar?: boolean; - filterCallback?: (s: EFilterOptions) => void; }) { const ref = useRef(); @@ -56,11 +32,11 @@ export function RaincloudVis({ {enableSidebar ? setShowSidebar(!showSidebar)} isOpen={showSidebar} /> : null} - + {showSidebar ? ( - + ) : null} diff --git a/src/vis/raincloud/RaincloudVisSidebar.tsx b/src/vis/raincloud/RaincloudVisSidebar.tsx index 4d217a01f..7ec8a82d7 100644 --- a/src/vis/raincloud/RaincloudVisSidebar.tsx +++ b/src/vis/raincloud/RaincloudVisSidebar.tsx @@ -1,43 +1,15 @@ import * as React from 'react'; -import { useMemo } from 'react'; -import merge from 'lodash/merge'; import { Container, Divider, Stack } from '@mantine/core'; -import { ColumnInfo, ESupportedPlotlyVis, IScatterConfig, IVisConfig, VisColumn, ICommonVisSideBarProps, EColumnTypes, IRaincloudConfig } from '../interfaces'; +import { ColumnInfo, ESupportedPlotlyVis, IVisConfig, VisColumn, ICommonVisSideBarProps, IRaincloudConfig } from '../interfaces'; import { VisTypeSelect } from '../sidebar/VisTypeSelect'; import { NumericalColumnSelect } from '../sidebar/NumericalColumnSelect'; -import { ColorSelect } from '../sidebar/ColorSelect'; -import { FilterButtons } from '../sidebar/FilterButtons'; -import { SingleColumnSelect } from '../sidebar/SingleColumnSelect'; -import { OpacitySlider } from '../sidebar/OpacitySlider'; export function RaincloudVisSidebar({ config, - optionsConfig, - extensions, columns, setConfig, }: { config: IRaincloudConfig; - optionsConfig?: { - color?: { - enable?: boolean; - customComponent?: React.ReactNode; - }; - shape?: { - enable?: boolean; - customComponent?: React.ReactNode; - }; - filter?: { - enable?: boolean; - customComponent?: React.ReactNode; - }; - }; - extensions?: { - prePlot?: React.ReactNode; - postPlot?: React.ReactNode; - preSidebar?: React.ReactNode; - postSidebar?: React.ReactNode; - }; columns: VisColumn[]; setConfig: (config: IVisConfig) => void; } & ICommonVisSideBarProps) { diff --git a/src/vis/raincloud/cloud/SplitViolin.tsx b/src/vis/raincloud/cloud/SplitViolin.tsx index e70d2b353..8f24700be 100644 --- a/src/vis/raincloud/cloud/SplitViolin.tsx +++ b/src/vis/raincloud/cloud/SplitViolin.tsx @@ -7,8 +7,8 @@ import { ColumnInfo, EColumnTypes, IRaincloudConfig, VisCategoricalValue, VisNum import { useXScale } from '../hooks/useXScale'; const margin = { - top: 20, - bottom: 20, + top: 30, + bottom: 0, left: 20, right: 20, }; @@ -63,8 +63,6 @@ export function SplitViolin({ return scale; }, [height, kdeVal]); - console.log(kdeVal, yScale.domain()); - const line = useMemo(() => { const myLine = d3 .line() @@ -74,5 +72,5 @@ export function SplitViolin({ return `${myLine(kdeVal)}L${xScale.range()[1]},${yScale.range()[1]}L${xScale.range()[0]},${yScale.range()[1]}Z`; }, [kdeVal, xScale, yScale]); - return ; + return ; } diff --git a/src/vis/raincloud/lightning/MeanAndInterval.tsx b/src/vis/raincloud/lightning/MeanAndInterval.tsx new file mode 100644 index 000000000..d4c86d237 --- /dev/null +++ b/src/vis/raincloud/lightning/MeanAndInterval.tsx @@ -0,0 +1,53 @@ +import React, { useCallback, useMemo } from 'react'; +import { table, bin, op } from 'arquero'; +import { Box, Container } from '@mantine/core'; +import { useResizeObserver } from '@mantine/hooks'; +import * as d3 from 'd3v7'; + +import { ColumnInfo, EColumnTypes, IRaincloudConfig, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; +import { useXScale } from '../hooks/useXScale'; + +const margin = { + top: 0, + bottom: 0, + left: 20, + right: 20, +}; + +export function MeanAndInterval({ + numCol, + config, + width, + height, + yPos, +}: { + numCol: { + resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; + type: EColumnTypes; + info: ColumnInfo; + }; + config: IRaincloudConfig; + width: number; + height: number; + yPos: number; +}) { + const xScale = useXScale({ range: [margin.left, width - margin.right], column: numCol }); + + const vals = useMemo(() => { + return table({ values: numCol.resolvedValues.map((v) => v.val) }).rollup({ mean: op.mean('values'), stdev: op.stdev('values') }); + }, [numCol.resolvedValues]); + + return ( + + {vals.objects().map((val: { mean: number; stdev: number }) => { + return ( + + + + + + ); + })} + + ); +} diff --git a/src/vis/raincloud/rain/DotPlot.tsx b/src/vis/raincloud/rain/DotPlot.tsx index 92703400b..8522c2dd6 100644 --- a/src/vis/raincloud/rain/DotPlot.tsx +++ b/src/vis/raincloud/rain/DotPlot.tsx @@ -1,11 +1,11 @@ import React, { useMemo } from 'react'; -import { table, op } from 'arquero'; +import { table, op, bin } from 'arquero'; import { ColumnInfo, EColumnTypes, IRaincloudConfig, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; import { useXScale } from '../hooks/useXScale'; const margin = { - top: 20, + top: 30, bottom: 20, left: 20, right: 20, @@ -16,6 +16,7 @@ export function DotPlot({ config, width, height, + yPos, }: { numCol: { resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; @@ -25,22 +26,36 @@ export function DotPlot({ config: IRaincloudConfig; width: number; height: number; + yPos: number; }) { const xScale = useXScale({ range: [margin.left, width - margin.right], column: numCol }); - // const yScale = useMemo(() => { - // const scale = d3 - // .scaleLinear() - // .domain([d3.max(kdeVal.map((val) => val[1] as number)), 0]) - // .range([margin.top, height - margin.bottom]); + const bins = useMemo(() => { + return table({ values: numCol.resolvedValues.map((v) => v.val) }) + .groupby('values', { bins: bin('values', { maxbins: 20 }) }) + .count() + .groupby('bins') + .rollup({ count: op.sum('count'), average: op.mean('values') }); + }, [numCol.resolvedValues]); - // return scale; - // }, [height, kdeVal]); + const circles = useMemo(() => { + return ( + + {bins.objects().map((singleBin: { binVal: number; count: number; average: number }) => { + return ( + + {[...Array(singleBin.count).keys()].map((val) => { + return ( + // TODO:: What happens when we run out of space + + ); + })} + + ); + })} + + ); + }, [bins, xScale, yPos]); - const dt = useMemo(() => { - return table({ values: numCol.resolvedValues.map((v) => v.val) }).rollup({ bins: (d) => op.bins(d.values) }); - }, [numCol.resolvedValues]); - dt.print(); - return null; - // return ; + return circles; } From 0ec2989c6038047b2fd60d48942de4baec7e3243 Mon Sep 17 00:00:00 2001 From: dvmartinweigl Date: Wed, 21 Jun 2023 10:58:59 +0200 Subject: [PATCH 108/241] add pvalue control --- src/vis/correlation/CorrelationMatrix.tsx | 2 +- src/vis/correlation/CorrelationVisSidebar.tsx | 19 +++++++++- .../components/CircleCorrelationPair.tsx | 38 +++++++++---------- src/vis/interfaces.ts | 6 +++ src/vis/stories/Iris.stories.tsx | 2 + 5 files changed, 43 insertions(+), 24 deletions(-) diff --git a/src/vis/correlation/CorrelationMatrix.tsx b/src/vis/correlation/CorrelationMatrix.tsx index 9bde1c775..7aa288b84 100644 --- a/src/vis/correlation/CorrelationMatrix.tsx +++ b/src/vis/correlation/CorrelationMatrix.tsx @@ -156,7 +156,7 @@ export function CorrelationMatrix({ config, columns }: { config: ICorrelationCon setHovered={setHover} fill={colorScale(value.correlation)} boundingRect={{ width: xScale.bandwidth(), height: yScale.bandwidth() }} - highlightSignificant={config.highlightSignificant} + config={config} /> ); })} diff --git a/src/vis/correlation/CorrelationVisSidebar.tsx b/src/vis/correlation/CorrelationVisSidebar.tsx index 4d22dfdca..00bef232c 100644 --- a/src/vis/correlation/CorrelationVisSidebar.tsx +++ b/src/vis/correlation/CorrelationVisSidebar.tsx @@ -1,8 +1,17 @@ import * as React from 'react'; import { useMemo } from 'react'; import merge from 'lodash/merge'; -import { Container, Divider, Stack, Switch } from '@mantine/core'; -import { ColumnInfo, ESupportedPlotlyVis, IVisConfig, VisColumn, ICommonVisSideBarProps, EFilterOptions, ICorrelationConfig } from '../interfaces'; +import { Container, Divider, SegmentedControl, Stack, Switch } from '@mantine/core'; +import { + ColumnInfo, + ESupportedPlotlyVis, + IVisConfig, + VisColumn, + ICommonVisSideBarProps, + EFilterOptions, + ICorrelationConfig, + ECorrelationPlotMode, +} from '../interfaces'; import { VisTypeSelect } from '../sidebar/VisTypeSelect'; import { NumericalColumnSelect } from '../sidebar/NumericalColumnSelect'; @@ -110,6 +119,12 @@ export function CorrelationVisSidebar({ checked={config.highlightSignificant || false} onChange={() => setConfig({ ...config, highlightSignificant: !config.highlightSignificant })} /> + setConfig({ ...config, mode: ECorrelationPlotMode[v] })} + /> ); diff --git a/src/vis/correlation/components/CircleCorrelationPair.tsx b/src/vis/correlation/components/CircleCorrelationPair.tsx index a475fccab..a7b409f46 100644 --- a/src/vis/correlation/components/CircleCorrelationPair.tsx +++ b/src/vis/correlation/components/CircleCorrelationPair.tsx @@ -1,5 +1,8 @@ import { useMantineTheme } from '@mantine/core'; import * as React from 'react'; +import { ECorrelationPlotMode, ICorrelationConfig } from '../../interfaces'; + +const marginRect = { top: 3, right: 3, bottom: 3, left: 3 }; export interface CorrelationPairProps { xi: number; @@ -22,14 +25,14 @@ export function CircleCorrelationPair({ boundingRect, hover, setHovered, - highlightSignificant, + config, }: { value: CorrelationPairProps; fill: string; boundingRect: { width: number; height: number }; hover: boolean; setHovered: ({ x, y }: { x: number; y: number }) => void; - highlightSignificant: boolean; + config: ICorrelationConfig; }) { const theme = useMantineTheme(); const hoverColor = theme.colors.gray[2]; @@ -39,31 +42,24 @@ export function CircleCorrelationPair({ setHovered({ x: value.xi, y: value.yi })} onMouseLeave={() => setHovered(null)}> {' '} setHovered({ x: value.yi, y: value.xi })} onMouseLeave={() => setHovered(null)}> - = 0.05 ? theme.colors.gray[2] : 'none'} - > - {value.correlation.toFixed(2)} + + {config.mode === ECorrelationPlotMode.CORRELATION ? value.correlation.toFixed(2) : value.pValue < 0.001 ? '< 0.001' : value.pValue.toFixed(3)} diff --git a/src/vis/interfaces.ts b/src/vis/interfaces.ts index a9fb00730..667d4ccb2 100644 --- a/src/vis/interfaces.ts +++ b/src/vis/interfaces.ts @@ -81,6 +81,11 @@ export enum EScatterSelectSettings { PAN = 'pan', } +export enum ECorrelationPlotMode { + PVALUE = 'p-value', + CORRELATION = 'correlation', +} + export interface IViolinConfig { type: ESupportedPlotlyVis.VIOLIN; numColumnsSelected: ColumnInfo[]; @@ -92,6 +97,7 @@ export interface ICorrelationConfig { type: ESupportedPlotlyVis.CORRELATION; numColumnsSelected: ColumnInfo[]; highlightSignificant: boolean; + mode: ECorrelationPlotMode; } export interface IScatterConfig { diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index 9042b5b0a..90b3fb2db 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -7,6 +7,7 @@ import { EBarDisplayType, EBarGroupingType, EColumnTypes, + ECorrelationPlotMode, ENumericalColorScaleType, EScatterSelectSettings, ESupportedPlotlyVis, @@ -181,6 +182,7 @@ CorrelationPlot.args = { externalConfig: { type: ESupportedPlotlyVis.CORRELATION, highlightSignificant: false, + mode: ECorrelationPlotMode.CORRELATION, numColumnsSelected: [ { description: '', From 41ce8486124361ca276b2bb0998843bf7a2fa79d Mon Sep 17 00:00:00 2001 From: Daniela Date: Wed, 21 Jun 2023 11:27:26 +0200 Subject: [PATCH 109/241] start heatmap --- src/vis/raincloud/Raincloud.tsx | 4 +- src/vis/raincloud/cloud/Heatmap.tsx | 74 +++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 src/vis/raincloud/cloud/Heatmap.tsx diff --git a/src/vis/raincloud/Raincloud.tsx b/src/vis/raincloud/Raincloud.tsx index a117e287a..8bfcf74ee 100644 --- a/src/vis/raincloud/Raincloud.tsx +++ b/src/vis/raincloud/Raincloud.tsx @@ -7,6 +7,7 @@ import { DotPlot } from './rain/DotPlot'; import { MeanAndInterval } from './lightning/MeanAndInterval'; import { useXScale } from './hooks/useXScale'; import { XAxis } from '../hexbin/XAxis'; +import { Heatmap } from './cloud/Heatmap'; const margin = { top: 0, @@ -35,7 +36,8 @@ export function Raincloud({ {column.info.name} - + {/* */} + diff --git a/src/vis/raincloud/cloud/Heatmap.tsx b/src/vis/raincloud/cloud/Heatmap.tsx new file mode 100644 index 000000000..9b273d05d --- /dev/null +++ b/src/vis/raincloud/cloud/Heatmap.tsx @@ -0,0 +1,74 @@ +import React, { useCallback, useMemo } from 'react'; +import * as d3 from 'd3v7'; + +import { bin, op, table } from 'arquero'; +import { ColumnInfo, EColumnTypes, IRaincloudConfig, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; +import { useXScale } from '../hooks/useXScale'; + +const margin = { + top: 30, + bottom: 0, + left: 20, + right: 20, +}; + +function kernelDensityEstimator(kernel, X) { + return function (V) { + return X.map(function (x) { + return [ + x, + d3.mean(V, function (v) { + return kernel(x - v); + }), + ]; + }); + }; +} +function kernelEpanechnikov(k) { + return function (v) { + return Math.abs((v /= k)) <= 1 ? (0.75 * (1 - v * v)) / k : 0; + }; +} + +export function Heatmap({ + numCol, + config, + width, + height, +}: { + numCol: { + resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; + type: EColumnTypes; + info: ColumnInfo; + }; + config: IRaincloudConfig; + width: number; + height: number; +}) { + const xScale = useXScale({ range: [margin.left, width - margin.right], column: numCol }); + + const kdeVal: [number, number][] = useMemo(() => { + const kde = kernelDensityEstimator(kernelEpanechnikov(0.3), xScale.ticks(100)); + + return kde(numCol.resolvedValues.map((val) => val.val as number)); + }, [numCol.resolvedValues, xScale]); + + const bins = useMemo(() => { + return table({ values: numCol.resolvedValues.map((v) => v.val) }) + .groupby('values', { bin: bin('values', { maxbins: 100 }) }) + .count() + .groupby('bin') + .rollup({ count: op.sum('count'), average: op.mean('values') }) + .orderby('bin'); + }, [numCol.resolvedValues]); + + const colorScale = d3.scaleSequential(d3.interpolateGreys).domain([d3.max(kdeVal.map((val) => val[1] as number)), 0]); + + // @ts-ignore + const binWidth = useMemo(() => xScale(bins.objects()[1].bin) - xScale(bins.objects()[0].bin), [bins, xScale]); + console.log(binWidth); + console.log(bins.objects()); + return bins.objects().map((singleBin: { bin: number; count: number; average: number }) => { + return ; + }); +} From 4fbd839bf529a0768a76d75dbc9497c6ebb035a4 Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Wed, 21 Jun 2023 13:37:52 +0200 Subject: [PATCH 110/241] blubb --- src/vis/interfaces.ts | 14 ++++++++++++ src/vis/raincloud/RaincloudVisSidebar.tsx | 2 ++ src/vis/raincloud/cloud/Heatmap.tsx | 26 +++++++++-------------- src/vis/raincloud/cloud/SplitViolin.tsx | 4 +--- src/vis/raincloud/utils.ts | 2 ++ src/vis/sidebar/RaincloudCloudSelect.tsx | 17 +++++++++++++++ src/vis/stories/Iris.stories.tsx | 2 ++ 7 files changed, 48 insertions(+), 19 deletions(-) create mode 100644 src/vis/sidebar/RaincloudCloudSelect.tsx diff --git a/src/vis/interfaces.ts b/src/vis/interfaces.ts index 87011bcc8..2f0feddaa 100644 --- a/src/vis/interfaces.ts +++ b/src/vis/interfaces.ts @@ -88,9 +88,23 @@ export interface IViolinConfig { violinOverlay: EViolinOverlay; } +export enum ECloudType { + SPLIT_VIOLIN = 'Split violin', + HEATMAP = 'Heatmap', +} + +export enum ELightningType { + MEAN_AND_DEV = 'Mean and deviation', +} + +export enum ERainType { + DOTPLOT = 'Dot plot', +} + export interface IRaincloudConfig { type: ESupportedPlotlyVis.RAINCLOUD; numColumnsSelected: ColumnInfo[]; + cloudType: ECloudType; } export interface IScatterConfig { diff --git a/src/vis/raincloud/RaincloudVisSidebar.tsx b/src/vis/raincloud/RaincloudVisSidebar.tsx index 7ec8a82d7..07f24ae57 100644 --- a/src/vis/raincloud/RaincloudVisSidebar.tsx +++ b/src/vis/raincloud/RaincloudVisSidebar.tsx @@ -3,6 +3,7 @@ import { Container, Divider, Stack } from '@mantine/core'; import { ColumnInfo, ESupportedPlotlyVis, IVisConfig, VisColumn, ICommonVisSideBarProps, IRaincloudConfig } from '../interfaces'; import { VisTypeSelect } from '../sidebar/VisTypeSelect'; import { NumericalColumnSelect } from '../sidebar/NumericalColumnSelect'; +import { RaincloudCloudSelect } from '../sidebar/RaincloudCloudSelect'; export function RaincloudVisSidebar({ config, @@ -23,6 +24,7 @@ export function RaincloudVisSidebar({ columns={columns} currentSelected={config.numColumnsSelected || []} /> + setConfig({ ...config, cloudType: cloud })} currentSelected={config.cloudType} /> ); diff --git a/src/vis/raincloud/cloud/Heatmap.tsx b/src/vis/raincloud/cloud/Heatmap.tsx index 9b273d05d..162596884 100644 --- a/src/vis/raincloud/cloud/Heatmap.tsx +++ b/src/vis/raincloud/cloud/Heatmap.tsx @@ -53,22 +53,16 @@ export function Heatmap({ return kde(numCol.resolvedValues.map((val) => val.val as number)); }, [numCol.resolvedValues, xScale]); - const bins = useMemo(() => { - return table({ values: numCol.resolvedValues.map((v) => v.val) }) - .groupby('values', { bin: bin('values', { maxbins: 100 }) }) - .count() - .groupby('bin') - .rollup({ count: op.sum('count'), average: op.mean('values') }) - .orderby('bin'); - }, [numCol.resolvedValues]); - - const colorScale = d3.scaleSequential(d3.interpolateGreys).domain([d3.max(kdeVal.map((val) => val[1] as number)), 0]); + const colorScale = d3.scaleSequential(d3.interpolateGreys).domain([d3.max(kdeVal.map((val) => val[1] as number)), 0].reverse()); // @ts-ignore - const binWidth = useMemo(() => xScale(bins.objects()[1].bin) - xScale(bins.objects()[0].bin), [bins, xScale]); - console.log(binWidth); - console.log(bins.objects()); - return bins.objects().map((singleBin: { bin: number; count: number; average: number }) => { - return ; - }); + const binWidth = useMemo(() => xScale(kdeVal[1][0]) - xScale(kdeVal[0][0]), [kdeVal, xScale]); + console.log(kdeVal); + return ( + + {kdeVal.map((val) => { + return ; + })} + + ); } diff --git a/src/vis/raincloud/cloud/SplitViolin.tsx b/src/vis/raincloud/cloud/SplitViolin.tsx index 8f24700be..6e9a86d15 100644 --- a/src/vis/raincloud/cloud/SplitViolin.tsx +++ b/src/vis/raincloud/cloud/SplitViolin.tsx @@ -1,6 +1,4 @@ -import React, { useCallback, useMemo } from 'react'; -import { Box, Container } from '@mantine/core'; -import { useResizeObserver } from '@mantine/hooks'; +import React, { useMemo } from 'react'; import * as d3 from 'd3v7'; import { ColumnInfo, EColumnTypes, IRaincloudConfig, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; diff --git a/src/vis/raincloud/utils.ts b/src/vis/raincloud/utils.ts index 0f045a548..29fd52383 100644 --- a/src/vis/raincloud/utils.ts +++ b/src/vis/raincloud/utils.ts @@ -1,6 +1,7 @@ import { merge } from 'lodash'; import { ColumnInfo, + ECloudType, EColumnTypes, ESupportedPlotlyVis, IRaincloudConfig, @@ -19,6 +20,7 @@ export function isRaincloud(s: IVisConfig): s is IRaincloudConfig { const defaultConfig: IRaincloudConfig = { type: ESupportedPlotlyVis.RAINCLOUD, numColumnsSelected: [], + cloudType: ECloudType.SPLIT_VIOLIN, }; export function raincloudMergeDefaultConfig(columns: VisColumn[], config: IRaincloudConfig): IVisConfig { diff --git a/src/vis/sidebar/RaincloudCloudSelect.tsx b/src/vis/sidebar/RaincloudCloudSelect.tsx new file mode 100644 index 000000000..ae2f33ab2 --- /dev/null +++ b/src/vis/sidebar/RaincloudCloudSelect.tsx @@ -0,0 +1,17 @@ +import { Select } from '@mantine/core'; +import * as React from 'react'; +import { i18n } from '../../i18n'; +import { ECloudType } from '../interfaces'; + +interface HexbinOptionSelectProps { + callback: (c: ECloudType) => void; + currentSelected: ECloudType; +} + +export function RaincloudCloudSelect({ callback, currentSelected }: HexbinOptionSelectProps) { + const options = [ + { value: ECloudType.HEATMAP, label: ECloudType.HEATMAP }, + { value: ECloudType.SPLIT_VIOLIN, label: ECloudType.SPLIT_VIOLIN }, + ]; + return callback(e as ELightningType)} data={options} value={currentSelected} /> + ); +} diff --git a/src/vis/sidebar/RaincloudRainSelect.tsx b/src/vis/sidebar/RaincloudRainSelect.tsx new file mode 100644 index 000000000..e25011b0e --- /dev/null +++ b/src/vis/sidebar/RaincloudRainSelect.tsx @@ -0,0 +1,14 @@ +import { Select } from '@mantine/core'; +import * as React from 'react'; +import { i18n } from '../../i18n'; +import { ERainType } from '../interfaces'; + +interface HexbinOptionSelectProps { + callback: (c: ERainType) => void; + currentSelected: ERainType; +} + +export function RaincloudRainSelect({ callback, currentSelected }: HexbinOptionSelectProps) { + const options = [{ value: ERainType.DOTPLOT, label: ERainType.DOTPLOT }]; + return callback(e as ECloudType)} data={options} value={currentSelected} />; } diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index c52f18b9d..1dc34fd56 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -157,7 +157,7 @@ RaincloudPlot.args = { name: 'Sepal Width', }, ], - cloudType: ECloudType.HEATMAP, + cloudType: ECloudType.HISTOGRAM, lightningType: ELightningType.MEAN_AND_DEV, rainType: ERainType.DOTPLOT, }, From fb57b5278b90b9c767e433f0b1ec566476f856cb Mon Sep 17 00:00:00 2001 From: dvmartinweigl Date: Wed, 21 Jun 2023 14:50:23 +0200 Subject: [PATCH 115/241] fix pvalue segement control --- src/vis/correlation/CorrelationVisSidebar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vis/correlation/CorrelationVisSidebar.tsx b/src/vis/correlation/CorrelationVisSidebar.tsx index 00bef232c..838f8ee74 100644 --- a/src/vis/correlation/CorrelationVisSidebar.tsx +++ b/src/vis/correlation/CorrelationVisSidebar.tsx @@ -123,7 +123,7 @@ export function CorrelationVisSidebar({ size="sm" data={Object.values(ECorrelationPlotMode)} value={config.mode} - onChange={(v) => setConfig({ ...config, mode: ECorrelationPlotMode[v] })} + onChange={(v) => setConfig({ ...config, mode: v as ECorrelationPlotMode })} /> From e1bc54aae2f5e18fd63f01501a44486c160876c6 Mon Sep 17 00:00:00 2001 From: dvmartinweigl Date: Wed, 21 Jun 2023 14:55:18 +0200 Subject: [PATCH 116/241] improve tooltip --- src/vis/correlation/components/CorrelationTooltip.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/vis/correlation/components/CorrelationTooltip.tsx b/src/vis/correlation/components/CorrelationTooltip.tsx index 99d2e81a3..0f35bafb6 100644 --- a/src/vis/correlation/components/CorrelationTooltip.tsx +++ b/src/vis/correlation/components/CorrelationTooltip.tsx @@ -8,17 +8,18 @@ export function CorrelationTooltip({ value }: { value: CorrelationPairProps }) { {`${value.xName} -> ${value.yName}`} + - - t-Statistic - {value.tStatistic.toFixed(2)} - Correlation {value.correlation.toFixed(2)} + + t-Statistic + {value.tStatistic.toFixed(2)} + pValue {value.pValue < 0.001 ? 'p < 0.001' : value.pValue.toFixed(2)} From 32962c3d5355b9444bbf8bc3b647173b9a5e946a Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Wed, 21 Jun 2023 14:57:11 +0200 Subject: [PATCH 117/241] add beeswarm rain --- src/vis/interfaces.ts | 1 + src/vis/raincloud/Raincloud.tsx | 10 +++- src/vis/raincloud/rain/BeeSwarm.tsx | 78 +++++++++++++++++++++++++ src/vis/sidebar/RaincloudRainSelect.tsx | 5 +- 4 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 src/vis/raincloud/rain/BeeSwarm.tsx diff --git a/src/vis/interfaces.ts b/src/vis/interfaces.ts index 1689124a0..694cb7fc1 100644 --- a/src/vis/interfaces.ts +++ b/src/vis/interfaces.ts @@ -100,6 +100,7 @@ export enum ELightningType { export enum ERainType { DOTPLOT = 'Dot plot', + BEESWARM = 'Beeswarm', } export interface IRaincloudConfig { diff --git a/src/vis/raincloud/Raincloud.tsx b/src/vis/raincloud/Raincloud.tsx index 7fc5ac1c9..a9eb7d665 100644 --- a/src/vis/raincloud/Raincloud.tsx +++ b/src/vis/raincloud/Raincloud.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { useResizeObserver } from '@mantine/hooks'; -import { ColumnInfo, ECloudType, EColumnTypes, IRaincloudConfig, VisCategoricalValue, VisNumericalValue } from '../interfaces'; +import { ColumnInfo, ECloudType, EColumnTypes, ERainType, IRaincloudConfig, VisCategoricalValue, VisNumericalValue } from '../interfaces'; import { SplitViolin } from './cloud/SplitViolin'; import { DotPlot } from './rain/DotPlot'; @@ -9,6 +9,7 @@ import { useXScale } from './hooks/useXScale'; import { XAxis } from '../hexbin/XAxis'; import { Heatmap } from './cloud/Heatmap'; import { Histogram } from './cloud/Histogram'; +import { BeeSwarm } from './rain/BeeSwarm'; const margin = { top: 0, @@ -45,7 +46,12 @@ export function Raincloud({ )} - + {config.rainType === ERainType.DOTPLOT ? ( + + ) : config.rainType === ERainType.BEESWARM ? ( + + ) : null} + diff --git a/src/vis/raincloud/rain/BeeSwarm.tsx b/src/vis/raincloud/rain/BeeSwarm.tsx new file mode 100644 index 000000000..c85cfdc39 --- /dev/null +++ b/src/vis/raincloud/rain/BeeSwarm.tsx @@ -0,0 +1,78 @@ +import React, { useMemo } from 'react'; + +import { table, op, bin } from 'arquero'; +import * as d3 from 'd3v7'; +import { ColumnInfo, EColumnTypes, IRaincloudConfig, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; +import { useXScale } from '../hooks/useXScale'; + +const margin = { + top: 30, + bottom: 20, + left: 20, + right: 20, +}; + +export function BeeSwarm({ + numCol, + config, + width, + height, + yPos, +}: { + numCol: { + resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; + type: EColumnTypes; + info: ColumnInfo; + }; + config: IRaincloudConfig; + width: number; + height: number; + yPos: number; +}) { + const xScale = useXScale({ range: [margin.left, width - margin.right], column: numCol }); + + const forceDirectedNode = useMemo(() => { + if (xScale) { + const force = d3 + .forceSimulation(numCol.resolvedValues.map((col) => col.val as number).map((d) => ({ x: xScale(d), y: (height - margin.bottom + margin.top) / 2 }))) + .force( + 'y', + d3 + .forceY() + .strength(0.1) + .y((height - margin.bottom - margin.top) / 2), + ) + .force( + 'x', + d3 + .forceX() + .strength(1) + .x((d) => d.x), + ) + .force('collide', d3.forceCollide().radius(4.6)); + + force.restart(); + + const newSim = force.tick(200); + + return newSim.nodes(); + } + return null; + }, [height, numCol.resolvedValues, xScale]); + + console.log(forceDirectedNode); + + const circles = useMemo(() => { + return ( + + {forceDirectedNode.map((circle) => { + return ; + })} + + ); + }, [forceDirectedNode, yPos]); + + console.log(circles); + + return circles; +} diff --git a/src/vis/sidebar/RaincloudRainSelect.tsx b/src/vis/sidebar/RaincloudRainSelect.tsx index e25011b0e..c5e101fb8 100644 --- a/src/vis/sidebar/RaincloudRainSelect.tsx +++ b/src/vis/sidebar/RaincloudRainSelect.tsx @@ -9,6 +9,9 @@ interface HexbinOptionSelectProps { } export function RaincloudRainSelect({ callback, currentSelected }: HexbinOptionSelectProps) { - const options = [{ value: ERainType.DOTPLOT, label: ERainType.DOTPLOT }]; + const options = [ + { value: ERainType.DOTPLOT, label: ERainType.DOTPLOT }, + { value: ERainType.BEESWARM, label: ERainType.BEESWARM }, + ]; return callback(e as ECloudType)} data={options} value={currentSelected} />; + return callback(e as ELightningType)} data={options} value={currentSelected} /> - ); + return callback(e as ERainType)} data={options} value={currentSelected} />; + return callback(e)} + name="numColumns" + data={availableFilterValues} + value={currentSelected || null} + /> + ); +} diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index 8541cd4f1..08094f099 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -185,7 +185,9 @@ CorrelationPlot.args = { correlationType: ECorrelationType.PEARSON, highlightSignificant: false, mode: ECorrelationPlotMode.CORRELATION, - catColumnSelected: null, + filterCriteria: null, + availableFilterValues: [], + filterValue: null, numColumnsSelected: [ { description: '', From f65d5a284e546fc26be7c4617bf6c4f2fe9f3e7b Mon Sep 17 00:00:00 2001 From: dvmartinweigl Date: Tue, 27 Jun 2023 14:41:07 +0200 Subject: [PATCH 136/241] add merge config to Vis for correlation matrix --- src/vis/Vis.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/vis/Vis.tsx b/src/vis/Vis.tsx index fa3af68e4..143d728a5 100644 --- a/src/vis/Vis.tsx +++ b/src/vis/Vis.tsx @@ -23,7 +23,7 @@ import { getCssValue } from '../utils'; import { useSyncedRef } from '../hooks/useSyncedRef'; import { hexinbMergeDefaultConfig, isHexbin } from './hexbin/utils'; import { HexbinVis } from './hexbin/HexbinVis'; -import { isCorrelation } from './correlation'; +import { correlationMergeDefaultConfig, isCorrelation } from './correlation'; import { CorrelationVis } from './correlation/CorrelationVis'; const DEFAULT_SHAPES = ['circle', 'square', 'triangle-up', 'star']; @@ -159,6 +159,10 @@ export function EagerVis({ const newConfig = hexinbMergeDefaultConfig(columns, inconsistentVisConfig); _setVisConfig({ current: newConfig, consistent: newConfig }); } + if (isCorrelation(inconsistentVisConfig)) { + const newConfig = correlationMergeDefaultConfig(columns, inconsistentVisConfig); + _setVisConfig({ current: newConfig, consistent: newConfig }); + } // DANGER:: this useEffect should only occur when the visConfig.type changes. adding visconfig into the dep array will cause an infinite loop. // eslint-disable-next-line react-hooks/exhaustive-deps }, [inconsistentVisConfig.type]); From 1abc1fd19958051e9c728cdde7a251009d5fa9f8 Mon Sep 17 00:00:00 2001 From: tschachinger Date: Tue, 27 Jun 2023 15:20:30 +0200 Subject: [PATCH 137/241] 0 counts are now visible again in the heatmap --- src/vis/heatmap/Heatmap.tsx | 4 ++-- src/vis/heatmap/HeatmapVis.tsx | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/vis/heatmap/Heatmap.tsx b/src/vis/heatmap/Heatmap.tsx index 00fc718b6..28c655107 100644 --- a/src/vis/heatmap/Heatmap.tsx +++ b/src/vis/heatmap/Heatmap.tsx @@ -82,7 +82,7 @@ export function Heatmap({ .impute({ count: () => 0 }, { expand: ['xVal', 'yVal'] }); const idTable = valueTable.groupby('xVal', 'yVal').rollup({ ids: op.array_agg('id') }); - const groupedVals = countTable.join(idTable).objects() as { xVal: string; yVal: string; count: number; ids: string[] }[]; + const groupedVals = countTable.join_left(idTable).objects() as { xVal: string; yVal: string; count: number; ids: string[] }[]; const colorSc = config?.numColorScaleType === ENumericalColorScaleType.SEQUENTIAL @@ -170,7 +170,7 @@ export function Heatmap({ y={y} width={rectWidth} height={rectHeight} - color={selected && ids.some((id) => selected[id]) ? 'orange' : color} + color={selected && ids?.some((id) => selected[id]) ? 'orange' : color} setTooltipText={() => setTooltipText(`${xVal} - ${yVal} (${count})`)} unsetTooltipText={() => setTooltipText(null)} setSelected={() => selectionCallback(ids)} diff --git a/src/vis/heatmap/HeatmapVis.tsx b/src/vis/heatmap/HeatmapVis.tsx index 6fa6f6c36..afc37a250 100644 --- a/src/vis/heatmap/HeatmapVis.tsx +++ b/src/vis/heatmap/HeatmapVis.tsx @@ -1,10 +1,8 @@ import { Group } from '@mantine/core'; import * as React from 'react'; import { VisSidebarOpenButton } from '../VisSidebarOpenButton'; -import { VisSidebarWrapper } from '../VisSidebarWrapper'; -import { ICommonVisProps, IHeatmapConfig, IVisConfig, VisColumn } from '../interfaces'; +import { ICommonVisProps, IHeatmapConfig } from '../interfaces'; import { HeatmapGrid } from './HeatmapGrid'; -import { HeatmapVisSidebar } from './HeatmapVisSidebar'; export function HeatmapVis({ externalConfig, From d2cabf16e806c5dd950dfe08c1c4c27e0c994534 Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Tue, 27 Jun 2023 16:39:01 +0200 Subject: [PATCH 138/241] adding lightning types, cleanup --- src/vis/hexbin/XAxis.tsx | 10 ++- src/vis/interfaces.ts | 4 ++ src/vis/raincloud/Raincloud.tsx | 32 +++++++-- src/vis/raincloud/RaincloudVis.tsx | 2 - src/vis/raincloud/cloud/Heatmap.tsx | 17 ++++- src/vis/raincloud/cloud/SplitViolin.tsx | 2 +- src/vis/raincloud/lightning/Boxplot.tsx | 71 +++++++++++++++++++ src/vis/raincloud/lightning/Mean.tsx | 54 ++++++++++++++ .../raincloud/lightning/MeanAndInterval.tsx | 11 +-- .../raincloud/lightning/MedianAndInterval.tsx | 58 +++++++++++++++ src/vis/raincloud/rain/Circle.tsx | 23 ++++-- src/vis/raincloud/rain/StripPlot.tsx | 48 +++++++++++++ src/vis/sidebar/RaincloudLightningSelect.tsx | 7 +- src/vis/sidebar/RaincloudRainSelect.tsx | 1 + src/vis/stories/Iris.stories.tsx | 8 +-- 15 files changed, 321 insertions(+), 27 deletions(-) create mode 100644 src/vis/raincloud/lightning/Boxplot.tsx create mode 100644 src/vis/raincloud/lightning/Mean.tsx create mode 100644 src/vis/raincloud/lightning/MedianAndInterval.tsx create mode 100644 src/vis/raincloud/rain/StripPlot.tsx diff --git a/src/vis/hexbin/XAxis.tsx b/src/vis/hexbin/XAxis.tsx index 14facd59d..d619eaf92 100644 --- a/src/vis/hexbin/XAxis.tsx +++ b/src/vis/hexbin/XAxis.tsx @@ -12,13 +12,17 @@ export function XAxis({ xScale, yRange, vertPosition }) { return ( <> - - + {yRange ? ( + + ) : null} + {yRange ? ( + + ) : null} {ticks.map(({ value, xOffset }) => ( - + {yRange ? : null} MAX_NON_AGGREGATED_COUNT ? aggregatedTable : baseTable} /> + ) : config.rainType === ERainType.STRIPPLOT ? ( + MAX_NON_AGGREGATED_COUNT ? aggregatedTable : baseTable} + /> ) : null} {circlesRendered} + {config.lightningType === ELightningType.MEAN_AND_DEV ? ( + + ) : config.lightningType === ELightningType.MEAN ? ( + + ) : config.lightningType === ELightningType.MEDIAN_AND_DEV ? ( + + ) : config.lightningType === ELightningType.BOXPLOT ? ( + + ) : null} - - + diff --git a/src/vis/raincloud/RaincloudVis.tsx b/src/vis/raincloud/RaincloudVis.tsx index 944945c34..296e3d292 100644 --- a/src/vis/raincloud/RaincloudVis.tsx +++ b/src/vis/raincloud/RaincloudVis.tsx @@ -22,8 +22,6 @@ export function RaincloudVis({ return ( - {enableSidebar ? setShowSidebar(!showSidebar)} isOpen={showSidebar} /> : null} - diff --git a/src/vis/raincloud/cloud/Heatmap.tsx b/src/vis/raincloud/cloud/Heatmap.tsx index a79eb8f00..f89bac644 100644 --- a/src/vis/raincloud/cloud/Heatmap.tsx +++ b/src/vis/raincloud/cloud/Heatmap.tsx @@ -53,7 +53,22 @@ export function Heatmap({ return kde(numCol.resolvedValues.map((val) => val.val as number)); }, [numCol.resolvedValues, xScale]); - const colorScale = d3.scaleSequential(d3.interpolateGreys).domain([d3.max(kdeVal.map((val) => val[1] as number)), 0].reverse()); + const colorScale = d3 + .scaleSequential( + d3.piecewise(d3.interpolateRgb.gamma(2.2), [ + '#E9ECEF', + '#DEE2E6', + '#C8CED3', + '#BCC3C9', + '#ACB4BC', + '#99A1A9', + '#878E95', + '#71787E', + '#62686F', + '#505459', + ]), + ) + .domain([d3.max(kdeVal.map((val) => val[1] as number)), 0].reverse()); // @ts-ignore const binWidth = useMemo(() => xScale(kdeVal[1][0]) - xScale(kdeVal[0][0]), [kdeVal, xScale]); diff --git a/src/vis/raincloud/cloud/SplitViolin.tsx b/src/vis/raincloud/cloud/SplitViolin.tsx index 56d26e50c..b52be6891 100644 --- a/src/vis/raincloud/cloud/SplitViolin.tsx +++ b/src/vis/raincloud/cloud/SplitViolin.tsx @@ -96,5 +96,5 @@ export function SplitViolin({ return `${myLine(kdeVal)}L${xScale.range()[1]},${yScale.range()[1]}L${xScale.range()[0]},${yScale.range()[1]}Z`; }, [kdeVal, xScale, yScale]); - return ; + return ; } diff --git a/src/vis/raincloud/lightning/Boxplot.tsx b/src/vis/raincloud/lightning/Boxplot.tsx new file mode 100644 index 000000000..8c33693ea --- /dev/null +++ b/src/vis/raincloud/lightning/Boxplot.tsx @@ -0,0 +1,71 @@ +import React, { useCallback, useMemo } from 'react'; +import { table, bin, op } from 'arquero'; +import { Box, Container } from '@mantine/core'; +import { useResizeObserver } from '@mantine/hooks'; +import * as d3 from 'd3v7'; + +import ColumnTable from 'arquero/dist/types/table/column-table'; +import { ColumnInfo, EColumnTypes, IRaincloudConfig, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; +import { useXScale } from '../hooks/useXScale'; + +const margin = { + top: 0, + bottom: 0, + left: 20, + right: 20, +}; + +const BOXHEIGHT = 10; + +export function Boxplot({ + numCol, + config, + width, + height, + yPos, + baseTable, +}: { + numCol: { + resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; + type: EColumnTypes; + info: ColumnInfo; + }; + config: IRaincloudConfig; + width: number; + height: number; + yPos: number; + baseTable: ColumnTable; +}) { + const xScale = useXScale({ range: [margin.left, width - margin.right], column: numCol }); + + const vals = useMemo(() => { + return baseTable.rollup({ + median: op.median('values'), + firstQuartile: op.quantile('values', 0.25), + thirdQuartile: op.quantile('values', 0.75), + max: op.max('values'), + min: op.min('values'), + }); + }, [baseTable]); + + return ( + + {vals.objects().map((val: { median: number; firstQuartile: number; thirdQuartile: number; max: number; min: number }) => { + return ( + + + + + + + + + + + + + ); + })} + + ); +} diff --git a/src/vis/raincloud/lightning/Mean.tsx b/src/vis/raincloud/lightning/Mean.tsx new file mode 100644 index 000000000..7cbd85b72 --- /dev/null +++ b/src/vis/raincloud/lightning/Mean.tsx @@ -0,0 +1,54 @@ +import React, { useCallback, useMemo } from 'react'; +import { table, bin, op } from 'arquero'; +import { Box, Container } from '@mantine/core'; +import { useResizeObserver } from '@mantine/hooks'; +import * as d3 from 'd3v7'; + +import ColumnTable from 'arquero/dist/types/table/column-table'; +import { ColumnInfo, EColumnTypes, IRaincloudConfig, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; +import { useXScale } from '../hooks/useXScale'; + +const margin = { + top: 0, + bottom: 0, + left: 20, + right: 20, +}; + +export function Mean({ + numCol, + config, + width, + height, + yPos, + baseTable, +}: { + numCol: { + resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; + type: EColumnTypes; + info: ColumnInfo; + }; + config: IRaincloudConfig; + width: number; + height: number; + yPos: number; + baseTable: ColumnTable; +}) { + const xScale = useXScale({ range: [margin.left, width - margin.right], column: numCol }); + + const vals = useMemo(() => { + return baseTable.rollup({ mean: op.mean('values') }); + }, [baseTable]); + + return ( + + {vals.objects().map((val: { mean: number }) => { + return ( + + + + ); + })} + + ); +} diff --git a/src/vis/raincloud/lightning/MeanAndInterval.tsx b/src/vis/raincloud/lightning/MeanAndInterval.tsx index d4c86d237..b328b83c3 100644 --- a/src/vis/raincloud/lightning/MeanAndInterval.tsx +++ b/src/vis/raincloud/lightning/MeanAndInterval.tsx @@ -4,6 +4,7 @@ import { Box, Container } from '@mantine/core'; import { useResizeObserver } from '@mantine/hooks'; import * as d3 from 'd3v7'; +import ColumnTable from 'arquero/dist/types/table/column-table'; import { ColumnInfo, EColumnTypes, IRaincloudConfig, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; import { useXScale } from '../hooks/useXScale'; @@ -20,6 +21,7 @@ export function MeanAndInterval({ width, height, yPos, + baseTable, }: { numCol: { resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; @@ -30,12 +32,13 @@ export function MeanAndInterval({ width: number; height: number; yPos: number; + baseTable: ColumnTable; }) { const xScale = useXScale({ range: [margin.left, width - margin.right], column: numCol }); const vals = useMemo(() => { - return table({ values: numCol.resolvedValues.map((v) => v.val) }).rollup({ mean: op.mean('values'), stdev: op.stdev('values') }); - }, [numCol.resolvedValues]); + return baseTable.rollup({ mean: op.mean('values'), stdev: op.stdev('values') }); + }, [baseTable]); return ( @@ -43,8 +46,8 @@ export function MeanAndInterval({ return ( - - + + ); })} diff --git a/src/vis/raincloud/lightning/MedianAndInterval.tsx b/src/vis/raincloud/lightning/MedianAndInterval.tsx new file mode 100644 index 000000000..4218ffbcb --- /dev/null +++ b/src/vis/raincloud/lightning/MedianAndInterval.tsx @@ -0,0 +1,58 @@ +import React, { useCallback, useMemo } from 'react'; +import { table, bin, op } from 'arquero'; +import { Box, Container } from '@mantine/core'; +import { useResizeObserver } from '@mantine/hooks'; +import * as d3 from 'd3v7'; + +import ColumnTable from 'arquero/dist/types/table/column-table'; +import { ColumnInfo, EColumnTypes, IRaincloudConfig, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; +import { useXScale } from '../hooks/useXScale'; + +const margin = { + top: 0, + bottom: 0, + left: 20, + right: 20, +}; + +export function MedianAndInterval({ + numCol, + config, + width, + height, + yPos, + baseTable, +}: { + numCol: { + resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; + type: EColumnTypes; + info: ColumnInfo; + }; + config: IRaincloudConfig; + width: number; + height: number; + yPos: number; + baseTable: ColumnTable; +}) { + const xScale = useXScale({ range: [margin.left, width - margin.right], column: numCol }); + + const vals = useMemo(() => { + return baseTable.rollup({ median: op.median('values'), stdev: op.stdev('values') }); + }, [baseTable]); + + return ( + + {vals.objects().map((val: { median: number; stdev: number }) => { + return ( + + + + + + + + ); + })} + + ); +} diff --git a/src/vis/raincloud/rain/Circle.tsx b/src/vis/raincloud/rain/Circle.tsx index 54b2a03f9..3ee167cf5 100644 --- a/src/vis/raincloud/rain/Circle.tsx +++ b/src/vis/raincloud/rain/Circle.tsx @@ -3,20 +3,34 @@ import React, { useEffect, useRef, useState } from 'react'; import { useSpring, easings, animated } from 'react-spring'; import { ERainType } from '../../interfaces'; -export function Circle({ x, y, id, raincloudType, color }: { x: number; y: number; id: string; raincloudType: ERainType; color: string }) { +export function Circle({ + x, + y, + id, + raincloudType, + color, + isStrip, +}: { + x: number; + y: number; + id: string; + raincloudType: ERainType; + color: string; + isStrip: boolean; +}) { const raincloudTypeRef = useRef(raincloudType); const [props] = useSpring( () => ({ immediate: () => { return raincloudTypeRef.current === raincloudType; }, - to: { cx: x, cy: y }, + to: { cx: x, cy: y, x: x - 4, y: y - 4, height: isStrip ? 50 : 8, width: isStrip ? 4 : 8, rx: isStrip ? 0 : 100 }, config: { duration: 750, easing: easings.easeInOutSine, }, }), - [raincloudType, x, y], + [raincloudType, x, y, isStrip], ); useEffect(() => { @@ -25,7 +39,8 @@ export function Circle({ x, y, id, raincloudType, color }: { x: number; y: numbe return ( - + {!isStrip ? : null} + {isStrip ? : null} ); } diff --git a/src/vis/raincloud/rain/StripPlot.tsx b/src/vis/raincloud/rain/StripPlot.tsx new file mode 100644 index 000000000..43fda8bcb --- /dev/null +++ b/src/vis/raincloud/rain/StripPlot.tsx @@ -0,0 +1,48 @@ +import React, { useEffect, useMemo } from 'react'; + +import { table, op, bin } from 'arquero'; +import ColumnTable from 'arquero/dist/types/table/column-table'; +import { ColumnInfo, EColumnTypes, IRaincloudConfig, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; +import { useXScale } from '../hooks/useXScale'; +import { Circle } from './Circle'; + +const margin = { + top: 30, + bottom: 20, + left: 20, + right: 20, +}; + +export function StripPlot({ + numCol, + config, + width, + height, + yPos, + baseTable, + circleCallback, +}: { + numCol: { + resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; + type: EColumnTypes; + info: ColumnInfo; + }; + config: IRaincloudConfig; + width: number; + height: number; + yPos: number; + baseTable: ColumnTable; + + circleCallback: (circles: { id: string; x: number; y: number }[]) => void; +}) { + const xScale = useXScale({ range: [margin.left, width - margin.right], column: numCol }); + useEffect(() => { + const circles = baseTable.objects().map((singlePoint: { values: number; ids: string }) => { + return { id: singlePoint.ids, x: xScale(singlePoint.values), y: yPos + margin.top }; + }); + + circleCallback(circles.flat()); + }, [baseTable, circleCallback, xScale, yPos]); + + return null; +} diff --git a/src/vis/sidebar/RaincloudLightningSelect.tsx b/src/vis/sidebar/RaincloudLightningSelect.tsx index 6117d666e..b3f73e56b 100644 --- a/src/vis/sidebar/RaincloudLightningSelect.tsx +++ b/src/vis/sidebar/RaincloudLightningSelect.tsx @@ -9,6 +9,11 @@ interface HexbinOptionSelectProps { } export function RaincloudLightningSelect({ callback, currentSelected }: HexbinOptionSelectProps) { - const options = [{ value: ELightningType.MEAN_AND_DEV, label: ELightningType.MEAN_AND_DEV }]; + const options = [ + { value: ELightningType.MEAN_AND_DEV, label: ELightningType.MEAN_AND_DEV }, + { value: ELightningType.MEAN, label: ELightningType.MEAN }, + { value: ELightningType.MEDIAN_AND_DEV, label: ELightningType.MEDIAN_AND_DEV }, + { value: ELightningType.BOXPLOT, label: ELightningType.BOXPLOT }, + ]; return callback(e as ERainType)} data={options} value={currentSelected} />; } diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index c88145f73..639a3cacf 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -152,15 +152,11 @@ RaincloudPlot.args = { id: 'sepalLength', name: 'Sepal Length', }, - { - description: '', - id: 'sepalWidth', - name: 'Sepal Width', - }, ], - cloudType: ECloudType.HISTOGRAM, + cloudType: ECloudType.SPLIT_VIOLIN, lightningType: ELightningType.MEAN_AND_DEV, rainType: ERainType.DOTPLOT, + aggregateRain: false, }, }; From dd53af7d0186b5f018e20314144ce72199f87522 Mon Sep 17 00:00:00 2001 From: dvmartinweigl Date: Wed, 28 Jun 2023 08:00:35 +0200 Subject: [PATCH 139/241] increase margin bottom --- src/vis/correlation/CorrelationMatrix.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vis/correlation/CorrelationMatrix.tsx b/src/vis/correlation/CorrelationMatrix.tsx index a2f1b9124..a0de5e747 100644 --- a/src/vis/correlation/CorrelationMatrix.tsx +++ b/src/vis/correlation/CorrelationMatrix.tsx @@ -16,7 +16,7 @@ const CIRCLE_MIN_SIZE = 4; const margin = { top: 100, right: 80, - bottom: 10, + bottom: 40, left: 100, }; From 59756e02e39023b463c6d892096066eb9ea3b1c2 Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Wed, 28 Jun 2023 10:43:45 +0200 Subject: [PATCH 140/241] adding tooltips to circles --- src/vis/raincloud/rain/Circle.tsx | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/vis/raincloud/rain/Circle.tsx b/src/vis/raincloud/rain/Circle.tsx index 3ee167cf5..93821f5dd 100644 --- a/src/vis/raincloud/rain/Circle.tsx +++ b/src/vis/raincloud/rain/Circle.tsx @@ -1,5 +1,5 @@ import { Tooltip } from '@mantine/core'; -import React, { useEffect, useRef, useState } from 'react'; +import React, { useEffect, useMemo, useRef, useState } from 'react'; import { useSpring, easings, animated } from 'react-spring'; import { ERainType } from '../../interfaces'; @@ -19,6 +19,7 @@ export function Circle({ isStrip: boolean; }) { const raincloudTypeRef = useRef(raincloudType); + const [isHover, setIsHover] = useState(false); const [props] = useSpring( () => ({ immediate: () => { @@ -37,10 +38,20 @@ export function Circle({ raincloudTypeRef.current = raincloudType; }, [raincloudType]); - return ( - - {!isStrip ? : null} - {isStrip ? : null} - + const gEle = useMemo(() => { + return ( + setIsHover(true)} onMouseLeave={() => setIsHover(false)}> + {!isStrip ? : null} + {isStrip ? : null} + + ); + }, [color, id, isStrip, props]); + + return isHover ? ( + + {gEle} + + ) : ( + gEle ); } From 0a81a3138d98652628434872a13b6ac4ebbf8658 Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Wed, 28 Jun 2023 12:03:00 +0200 Subject: [PATCH 141/241] fixing with new vis setup --- src/vis/parallelCoordinates/ParallelVis.tsx | 70 +++------------------ src/vis/provider/utils.ts | 10 +++ 2 files changed, 17 insertions(+), 63 deletions(-) diff --git a/src/vis/parallelCoordinates/ParallelVis.tsx b/src/vis/parallelCoordinates/ParallelVis.tsx index f8ac08043..d0cccd9f5 100644 --- a/src/vis/parallelCoordinates/ParallelVis.tsx +++ b/src/vis/parallelCoordinates/ParallelVis.tsx @@ -4,7 +4,7 @@ import * as d3v7 from 'd3v7'; import { Group, Stack } from '@mantine/core'; import { useResizeObserver } from '@mantine/hooks'; import { Text } from '@mantine/core'; -import { IVisConfig, VisColumn, IParallelCoordinatesConfig } from '../interfaces'; +import { IVisConfig, VisColumn, IParallelCoordinatesConfig, ICommonVisProps } from '../interfaces'; import { useAsync } from '../../hooks'; import { VisSidebarWrapper } from '../VisSidebarWrapper'; import { VisSidebarOpenButton } from '../VisSidebarOpenButton'; @@ -20,69 +20,13 @@ const defaultExtensions = { }; export function ParallelVis({ - config, - optionsConfig, - extensions, + externalConfig, + columns, - setConfig, - enableSidebar, - setShowSidebar, - showSidebar, -}: { - config: IParallelCoordinatesConfig; - optionsConfig?: { - color?: { - enable?: boolean; - customComponent?: React.ReactNode; - }; - shape?: { - enable?: boolean; - customComponent?: React.ReactNode; - }; - filter?: { - enable?: boolean; - customComponent?: React.ReactNode; - }; - }; - extensions?: { - prePlot?: React.ReactNode; - postPlot?: React.ReactNode; - preSidebar?: React.ReactNode; - postSidebar?: React.ReactNode; - }; - columns: VisColumn[]; - setConfig: (config: IVisConfig) => void; - showSidebar?: boolean; - setShowSidebar?(show: boolean): void; - enableSidebar?: boolean; -}) { +}: ICommonVisProps) { return ( - - {enableSidebar ? setShowSidebar(!showSidebar)} isOpen={showSidebar} /> : null} - - - {config?.numColumnsSelected?.length > 1 ? : null} - - {showSidebar ? ( - - - - ) : null} - + + {externalConfig?.numColumnsSelected?.length > 1 ? : null} + ); } diff --git a/src/vis/provider/utils.ts b/src/vis/provider/utils.ts index be191c1c0..1b2fcb1da 100644 --- a/src/vis/provider/utils.ts +++ b/src/vis/provider/utils.ts @@ -12,11 +12,21 @@ import { BarVisSidebar } from '../bar/BarVisSidebar'; import { HexbinVis } from '../hexbin/HexbinVis'; import { ESupportedPlotlyVis } from '../interfaces'; import { createVis, visMap } from './Provider'; +import { ParallelVis } from '../parallelCoordinates/ParallelVis'; +import { ParallelVisSidebar } from '../parallelCoordinates/ParallelVisSidebar'; +import { parallelCoordinatesMergeDefaultConfig } from '../parallelCoordinates/utils'; export function registerAllVis() { visMap[ESupportedPlotlyVis.SCATTER] = createVis(ESupportedPlotlyVis.SCATTER, ScatterVis, ScatterVisSidebar, scatterMergeDefaultConfig); visMap[ESupportedPlotlyVis.BAR] = createVis(ESupportedPlotlyVis.BAR, BarVis, BarVisSidebar, barMergeDefaultConfig); visMap[ESupportedPlotlyVis.VIOLIN] = createVis(ESupportedPlotlyVis.VIOLIN, ViolinVis, ViolinVisSidebar, violinMergeDefaultConfig); visMap[ESupportedPlotlyVis.HEXBIN] = createVis(ESupportedPlotlyVis.HEXBIN, HexbinVis, HexbinVisSidebar, hexinbMergeDefaultConfig); + visMap[ESupportedPlotlyVis.PARALLEL_COORDINATES] = createVis( + ESupportedPlotlyVis.PARALLEL_COORDINATES, + ParallelVis, + ParallelVisSidebar, + parallelCoordinatesMergeDefaultConfig, + ); + // visMap[ESupportedPlotlyVis.SANKEY] = createVis(ESupportedPlotlyVis.SANKEY, SankeyVis, SankeyVisSidebar); } From 0dbbcc75b02fca656ed42761848249e7d578a37c Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Wed, 28 Jun 2023 15:59:36 +0200 Subject: [PATCH 142/241] adding brushes --- src/vis/parallelCoordinates/Line.tsx | 5 - src/vis/parallelCoordinates/ParallelPath.tsx | 46 +++- src/vis/parallelCoordinates/ParallelPlot.tsx | 203 +++++++++++------- src/vis/parallelCoordinates/ParallelVis.tsx | 10 +- .../ParallelVisSidebar.tsx | 4 +- src/vis/parallelCoordinates/YAxis.tsx | 2 +- src/vis/parallelCoordinates/utils.ts | 1 - src/vis/stories/Random.stories.tsx | 4 +- 8 files changed, 169 insertions(+), 106 deletions(-) delete mode 100644 src/vis/parallelCoordinates/Line.tsx diff --git a/src/vis/parallelCoordinates/Line.tsx b/src/vis/parallelCoordinates/Line.tsx deleted file mode 100644 index 2590ed7c8..000000000 --- a/src/vis/parallelCoordinates/Line.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import React from 'react'; - -export function Line({ x1, y1, x2, y2, label }: { x1: number; y1: number; x2: number; y2: number; label: string }) { - ; -} diff --git a/src/vis/parallelCoordinates/ParallelPath.tsx b/src/vis/parallelCoordinates/ParallelPath.tsx index a7ff5ab6f..1c7b17cc4 100644 --- a/src/vis/parallelCoordinates/ParallelPath.tsx +++ b/src/vis/parallelCoordinates/ParallelPath.tsx @@ -1,15 +1,47 @@ +import { Tooltip } from '@mantine/core'; import * as React from 'react'; +import { useMemo, useState } from 'react'; export function ParallelPath({ path, - index, - onHover, - onLeave, + hovered, + id, + onHover = () => null, + onLeave = () => null, + isSelected, }: { path: string; - index: number; - onLeave: (e: React.MouseEvent) => void; - onHover: (e: React.MouseEvent) => void; + hovered: string | null; + id: string; + onLeave?: () => void; + onHover?: () => void; + isSelected?: boolean | null; }) { - return ; + const pathEle = useMemo(() => { + return ( + + { + onHover(); + }} + onMouseOut={() => { + onLeave(); + }} + fill="none" + stroke="cornflowerblue" + opacity={isSelected === null ? 0.7 : isSelected ? 0.7 : 0.05} + strokeWidth={2} + d={path} + /> + + ); + }, [isSelected, onHover, onLeave, path]); + + return hovered && hovered === id ? ( + + {pathEle} + + ) : ( + pathEle + ); } diff --git a/src/vis/parallelCoordinates/ParallelPlot.tsx b/src/vis/parallelCoordinates/ParallelPlot.tsx index 85557b6c4..801c7f524 100644 --- a/src/vis/parallelCoordinates/ParallelPlot.tsx +++ b/src/vis/parallelCoordinates/ParallelPlot.tsx @@ -1,8 +1,8 @@ import * as React from 'react'; import * as d3v7 from 'd3v7'; import { useResizeObserver } from '@mantine/hooks'; -import { table } from 'arquero'; -import { Tooltip } from '@mantine/core'; +import { escape, table } from 'arquero'; +import { useEffect, useMemo, useState } from 'react'; import { EColumnTypes, IParallelCoordinatesConfig, VisColumn } from '../interfaces'; import { ParallelYAxis } from './YAxis'; @@ -12,48 +12,50 @@ import { ParallelPath } from './ParallelPath'; const margin = { top: 30, - right: 40, + right: 60, bottom: 10, left: 40, }; -const removeSpace = (col: string) => col.replace(' ', ''); - -export function ParallelPlot({ columns, config }: { config: IParallelCoordinatesConfig; columns: VisColumn[] }) { +export function ParallelPlot({ + columns, + config, + selectionCallback, + selectedMap, +}: { + config: IParallelCoordinatesConfig; + columns: VisColumn[]; + selectionCallback: (ids: string[]) => void; + selectedMap: Record; +}) { const [ref, { width, height }] = useResizeObserver(); - const { value: allColumns, status: colsStatus, error } = useAsync(getParallelData, [columns, config?.numColumnsSelected, config?.catColumnsSelected]); + const { value: allColumns } = useAsync(getParallelData, [columns, config?.numColumnsSelected, config?.catColumnsSelected]); - const [showTooltip, setShowTooltip] = React.useState(false); - const [tooltipContent, setTooltipContent] = React.useState(''); + const [hovered, setHovered] = React.useState(null); - const rows = React.useMemo(() => { - const all = [...(allColumns?.numColVals || []), ...(allColumns?.catColVals || [])]; - if (all.length === 0) return null; - const dt = table(all.reduce((acc, col) => ({ ...acc, [removeSpace(col.info.name)]: col.resolvedValues.map((v) => v.val) }), {})); - return dt.objects(); - }, [allColumns]); + const [brushes, setBrushes] = useState>({}); - const onPathHover = React.useCallback( - (e: React.MouseEvent) => { - const { index } = e.currentTarget.dataset; - setShowTooltip(true); - setTooltipContent( - Object.keys(rows[index]) - .map((label) => `${label}: ${rows[index][label]}`) - .join('; '), - ); - }, - [rows], - ); + const myTable = React.useMemo(() => { + if (!allColumns) return null; + + const all = [...allColumns.numColVals, ...allColumns.catColVals]; - const onPathLeave = React.useCallback((e: React.MouseEvent) => { - setShowTooltip(false); - }, []); + const dt = table({ + ...all.reduce((total, curr) => ({ ...total, [curr.info.id]: curr.resolvedValues.map((v) => v.val) }), {}), + id: all[0]?.resolvedValues.map((v) => v.id), + }); + + return dt; + }, [allColumns]); const yScales = React.useMemo(() => { - const all = [...(allColumns?.numColVals || []), ...(allColumns?.catColVals || [])]; - if (all.length === 0) return null; - return all?.map((col) => { + if (!allColumns) return null; + + const all = [...allColumns.numColVals, ...allColumns.catColVals]; + + const scales: Record | d3.ScalePoint }> = {}; + + all.forEach((col) => { let scale; if (col.type === EColumnTypes.NUMERICAL) { scale = d3v7 @@ -62,74 +64,111 @@ export function ParallelPlot({ columns, config }: { config: IParallelCoordinates .range([height - margin.bottom, margin.top]); } else { scale = d3v7 - .scaleBand() + .scalePoint() .domain(col.resolvedValues.map((c) => c.val as string)) - .range([height, margin.top]); + .range([height - margin.bottom, margin.top]); } - return { - id: removeSpace(col.info.name), + + scales[col.info.id] = { axisLabel: col.info.name, type: col.type, scale, }; }); + + return scales; }, [allColumns, height]); const xScale = React.useMemo(() => { - const all = [...(allColumns?.numColVals || []), ...(allColumns?.catColVals || [])]; - if (all.length === 0) return null; + if (!allColumns) return null; + + const all = [...allColumns.numColVals, ...allColumns.catColVals]; return d3v7 - .scaleBand() - .domain(all.map((c) => removeSpace(c.info.name))) + .scalePoint() + .domain(all.map((c) => c.info.id)) .range([margin.left, width - margin.right]); - }, [allColumns?.catColVals, allColumns?.numColVals, width]); + }, [allColumns, width]); + + const paths: Record = React.useMemo(() => { + if (!myTable || !yScales || !xScale) return null; + + const myPaths: Record = {}; + + myTable.objects().forEach((row: { id: string } & Record) => { + let svgPath = 'M '; + + Object.keys(row).forEach((col) => { + if (col === 'id') return; - const paths = React.useMemo(() => { - return rows?.map((row) => { - if (!row) return null; - const yPositions = Object.keys(row).map((col) => { const xPos = xScale(col); - let yPos = yScales?.find((yScale) => yScale.id === col)?.scale(row[col]) || 0; - // if the column is categorical, we need to offset the y position by half the bandwidth - if (allColumns?.catColVals.map((c) => c.info.name).includes(col)) { - const yScale = yScales?.find((scale) => scale.id === col).scale; - yPos += yScale.bandwidth() / 2 || 0; - } - return [xPos, yPos]; + const yPos = yScales[col].scale(row[col]); + svgPath += `${xPos},${yPos} L`; }); - let svgPath = ''; - yPositions.forEach((yPos, i) => { - if (i === 0) { - svgPath += `M ${yPos[0]},${yPos[1]}`; - } else { - svgPath += `L ${yPos[0]},${yPos[1]}`; - } - }); - return svgPath; + myPaths[row.id] = svgPath.slice(0, -2); + }); + + return myPaths; + }, [myTable, xScale, yScales]); + + useEffect(() => { + let filteredTable = myTable; + if (!brushes) return; + Object.keys(brushes).forEach((id) => { + const range = brushes[id]; + if (range === null) return; + const { scale } = yScales[id]; + + if (yScales[id].type === EColumnTypes.CATEGORICAL) { + const vals = yScales[id].scale.domain().filter((d) => yScales[id].scale(d) >= range[0] && yScales[id].scale(d) <= range[1]); + + console.log(vals); + + filteredTable = filteredTable.filter(escape((d) => vals.includes(d[id]))); + } else { + const newRange = range.map((r) => (scale as d3.ScaleLinear).invert(r)); + filteredTable = filteredTable.filter(escape((d) => d[id] >= newRange[1] && d[id] <= newRange[0])); + } }); - }, [rows, xScale, yScales]); + + const selectedIds = filteredTable?.objects().map((d: { id: string }) => d.id); + selectionCallback(selectedIds); + }, [brushes, myTable, selectionCallback, yScales]); return ( - - - {paths ? paths?.map((path, i) => ) : null} - {allColumns && yScales && xScale - ? yScales.map((yScale) => { - return ( - - ); - }) - : null} - - + + {paths + ? Object.keys(paths).map((pathId) => ( + setHovered(pathId)} + isSelected={selectedMap[pathId]} + onLeave={() => setHovered(null)} + hovered={hovered} + id={pathId} + /> + )) + : null} + {allColumns && yScales && xScale + ? Object.keys(yScales).map((scaleId) => { + return ( + { + setBrushes((prev) => ({ ...prev, [id]: range })); + }} + key={scaleId} + yScale={yScales[scaleId].scale} + xRange={[margin.left, width + margin.left]} + type={yScales[scaleId].type} + axisLabel={yScales[scaleId].axisLabel} + horizontalPosition={xScale(scaleId)} + /> + ); + }) + : null} + ); } diff --git a/src/vis/parallelCoordinates/ParallelVis.tsx b/src/vis/parallelCoordinates/ParallelVis.tsx index d0cccd9f5..8e88b4db2 100644 --- a/src/vis/parallelCoordinates/ParallelVis.tsx +++ b/src/vis/parallelCoordinates/ParallelVis.tsx @@ -19,14 +19,12 @@ const defaultExtensions = { postSidebar: null, }; -export function ParallelVis({ - externalConfig, - - columns, -}: ICommonVisProps) { +export function ParallelVis({ externalConfig, selectionCallback, columns, selectedMap }: ICommonVisProps) { return ( - {externalConfig?.numColumnsSelected?.length > 1 ? : null} + {externalConfig?.numColumnsSelected?.length > 1 ? ( + + ) : null} ); } diff --git a/src/vis/parallelCoordinates/ParallelVisSidebar.tsx b/src/vis/parallelCoordinates/ParallelVisSidebar.tsx index 790051ce5..505c13917 100644 --- a/src/vis/parallelCoordinates/ParallelVisSidebar.tsx +++ b/src/vis/parallelCoordinates/ParallelVisSidebar.tsx @@ -62,7 +62,7 @@ export function ParallelVisSidebar({ columns: VisColumn[]; filterCallback?: (s: EFilterOptions) => void; setConfig: (config: IVisConfig) => void; -} & ICommonVisSideBarProps) { +} & ICommonVisSideBarProps) { const mergedOptionsConfig = useMemo(() => { return merge({}, defaultConfig, optionsConfig); }, [optionsConfig]); @@ -87,9 +87,7 @@ export function ParallelVisSidebar({ columns={columns} currentSelected={config.catColumnsSelected || []} /> - {mergedExtensions.preSidebar} - {mergedOptionsConfig.filter.enable ? mergedOptionsConfig.filter.customComponent || : null} {mergedExtensions.postSidebar} diff --git a/src/vis/parallelCoordinates/YAxis.tsx b/src/vis/parallelCoordinates/YAxis.tsx index 5985dcc91..0221b8dab 100644 --- a/src/vis/parallelCoordinates/YAxis.tsx +++ b/src/vis/parallelCoordinates/YAxis.tsx @@ -42,7 +42,7 @@ export function ParallelYAxis({ d3v7 .brushY() .extent(extent) - .on('brush', (e) => onSelectionChanged(id, e.selection)), + .on('brush end', (e) => onSelectionChanged(id, e.selection)), ); } }); diff --git a/src/vis/parallelCoordinates/utils.ts b/src/vis/parallelCoordinates/utils.ts index 3d78267b6..86c380d6d 100644 --- a/src/vis/parallelCoordinates/utils.ts +++ b/src/vis/parallelCoordinates/utils.ts @@ -54,7 +54,6 @@ export async function getParallelData( const numColVals = await resolveColumnValues(numCols); const catColVals = await resolveColumnValues(catCols); - // const colorColVals = await resolveSingleColumn(colorColumn ? columns.find((col) => col.info.id === colorColumn.id) : null); return { numColVals, catColVals }; } diff --git a/src/vis/stories/Random.stories.tsx b/src/vis/stories/Random.stories.tsx index 36df9725e..1872d0225 100644 --- a/src/vis/stories/Random.stories.tsx +++ b/src/vis/stories/Random.stories.tsx @@ -94,10 +94,12 @@ const Template: ComponentStory = (args) => { // @ts-ignore TODO: The pointCount is an injected property, but we are using typeof Vis such that this prop does not exist. const columns = React.useMemo(() => fetchData(args.pointCount), [args.pointCount]); + const [selected, setSelected] = React.useState([]); + return (
- +
); From a6db441f3c28cb72c47504f8d898a7cb20d1c4f2 Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Wed, 28 Jun 2023 16:02:50 +0200 Subject: [PATCH 143/241] cleanup --- src/vis/parallelCoordinates/ParallelPlot.tsx | 7 +++---- src/vis/parallelCoordinates/YAxis.tsx | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/vis/parallelCoordinates/ParallelPlot.tsx b/src/vis/parallelCoordinates/ParallelPlot.tsx index 801c7f524..395fa59aa 100644 --- a/src/vis/parallelCoordinates/ParallelPlot.tsx +++ b/src/vis/parallelCoordinates/ParallelPlot.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import * as d3v7 from 'd3v7'; import { useResizeObserver } from '@mantine/hooks'; import { escape, table } from 'arquero'; -import { useEffect, useMemo, useState } from 'react'; +import { useEffect, useState } from 'react'; import { EColumnTypes, IParallelCoordinatesConfig, VisColumn } from '../interfaces'; import { ParallelYAxis } from './YAxis'; @@ -121,9 +121,8 @@ export function ParallelPlot({ const { scale } = yScales[id]; if (yScales[id].type === EColumnTypes.CATEGORICAL) { - const vals = yScales[id].scale.domain().filter((d) => yScales[id].scale(d) >= range[0] && yScales[id].scale(d) <= range[1]); - - console.log(vals); + const currScale = yScales[id].scale as d3.ScalePoint; + const vals = currScale.domain().filter((d) => currScale(d) >= range[0] && currScale(d) <= range[1]); filteredTable = filteredTable.filter(escape((d) => vals.includes(d[id]))); } else { diff --git a/src/vis/parallelCoordinates/YAxis.tsx b/src/vis/parallelCoordinates/YAxis.tsx index 0221b8dab..27747e7a3 100644 --- a/src/vis/parallelCoordinates/YAxis.tsx +++ b/src/vis/parallelCoordinates/YAxis.tsx @@ -16,7 +16,7 @@ export function ParallelYAxis({ onSelectionChanged, }: { id: string; - yScale: d3v7.ScaleLinear | d3v7.ScaleBand; + yScale: d3v7.ScaleLinear | d3v7.ScalePoint; xRange: number[]; type: EColumnTypes.NUMERICAL | EColumnTypes.CATEGORICAL; horizontalPosition: number | number; From 10cfcfa1cc99a7dba8417adf13356b6e70b74173 Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Wed, 28 Jun 2023 16:06:29 +0200 Subject: [PATCH 144/241] adding padding --- src/vis/parallelCoordinates/ParallelPlot.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vis/parallelCoordinates/ParallelPlot.tsx b/src/vis/parallelCoordinates/ParallelPlot.tsx index 395fa59aa..4570f0fbb 100644 --- a/src/vis/parallelCoordinates/ParallelPlot.tsx +++ b/src/vis/parallelCoordinates/ParallelPlot.tsx @@ -65,6 +65,7 @@ export function ParallelPlot({ } else { scale = d3v7 .scalePoint() + .padding(0.5) .domain(col.resolvedValues.map((c) => c.val as string)) .range([height - margin.bottom, margin.top]); } From 08e722cd7a20dc4473d66a330607de3ed89ad5c0 Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Wed, 28 Jun 2023 16:09:14 +0200 Subject: [PATCH 145/241] allowing outside selection --- src/vis/parallelCoordinates/ParallelPlot.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vis/parallelCoordinates/ParallelPlot.tsx b/src/vis/parallelCoordinates/ParallelPlot.tsx index 4570f0fbb..20c4f7044 100644 --- a/src/vis/parallelCoordinates/ParallelPlot.tsx +++ b/src/vis/parallelCoordinates/ParallelPlot.tsx @@ -115,7 +115,7 @@ export function ParallelPlot({ useEffect(() => { let filteredTable = myTable; - if (!brushes) return; + if (!brushes || Object.keys(brushes).length === 0) return; Object.keys(brushes).forEach((id) => { const range = brushes[id]; if (range === null) return; From 6eed9523ef1a5d3e7897fc8b8411ca9f947aaf29 Mon Sep 17 00:00:00 2001 From: dvzacharycutler Date: Thu, 29 Jun 2023 16:44:29 +0200 Subject: [PATCH 146/241] fixing bugs + cleaning up --- src/vis/bar/BarVisSidebar.tsx | 10 +- src/vis/barGood/BarChart.tsx | 30 +++--- src/vis/barGood/BarVis.tsx | 100 ++---------------- src/vis/barGood/barComponents/SingleBar.tsx | 2 +- src/vis/barGood/hooks/useGetBarScales.ts | 1 - .../barGood/hooks/useGetGroupedBarScales.ts | 34 ++++-- src/vis/barGood/utils.ts | 7 +- src/vis/provider/utils.ts | 6 +- src/vis/sankey/SankeyVis.tsx | 1 - src/vis/sidebar/AggregateTypeSelect.tsx | 1 + src/vis/sidebar/BarDisplayTypeButtons.tsx | 6 +- src/vis/sidebar/ColorSelect.tsx | 2 +- src/vis/sidebar/GroupSelect.tsx | 12 ++- src/vis/sidebar/SingleColumnSelect.tsx | 7 +- src/vis/stories/Random.stories.tsx | 12 +++ 15 files changed, 101 insertions(+), 130 deletions(-) diff --git a/src/vis/bar/BarVisSidebar.tsx b/src/vis/bar/BarVisSidebar.tsx index 5c7238f1b..4fc332b9a 100644 --- a/src/vis/bar/BarVisSidebar.tsx +++ b/src/vis/bar/BarVisSidebar.tsx @@ -82,9 +82,14 @@ export function BarVisSidebar({ { if (config.aggregateColumn === null) { - setConfig({ ...config, aggregateType, aggregateColumn: columns.find((col) => col.type === EColumnTypes.NUMERICAL).info }); + setConfig({ + ...config, + aggregateType, + aggregateColumn: columns.find((col) => col.type === EColumnTypes.NUMERICAL).info, + display: aggregateType === EAggregateTypes.COUNT ? config.display : EBarDisplayType.ABSOLUTE, + }); } else { - setConfig({ ...config, aggregateType }); + setConfig({ ...config, aggregateType, display: aggregateType === EAggregateTypes.COUNT ? config.display : EBarDisplayType.ABSOLUTE }); } }} aggregateColumnSelectCallback={(aggregateColumn: ColumnInfo) => setConfig({ ...config, aggregateColumn })} @@ -99,6 +104,7 @@ export function BarVisSidebar({ {mergedOptionsConfig.group.enable ? mergedOptionsConfig.group.customComponent || ( setConfig({ ...config, group })} groupTypeSelectCallback={(groupType: EBarGroupingType) => setConfig({ ...config, groupType })} groupDisplaySelectCallback={(display: EBarDisplayType) => setConfig({ ...config, display })} diff --git a/src/vis/barGood/BarChart.tsx b/src/vis/barGood/BarChart.tsx index 5cec08b03..2e9422b14 100644 --- a/src/vis/barGood/BarChart.tsx +++ b/src/vis/barGood/BarChart.tsx @@ -78,20 +78,22 @@ export function BarChart({ return ( - {groupColorScale ? ( - console.log('hello')} - stepSize={allColumns.groupColVals?.type === EColumnTypes.NUMERICAL ? groupedTable.get('group_max', 0) - groupedTable.get('group', 0) : 0} - /> - ) : null} + + {groupColorScale ? ( + console.log('hello')} + stepSize={allColumns.groupColVals?.type === EColumnTypes.NUMERICAL ? groupedTable.get('group_max', 0) - groupedTable.get('group', 0) : 0} + /> + ) : null} + {colsStatus !== 'success' ? ( diff --git a/src/vis/barGood/BarVis.tsx b/src/vis/barGood/BarVis.tsx index 67f3538d9..93ef84fbc 100644 --- a/src/vis/barGood/BarVis.tsx +++ b/src/vis/barGood/BarVis.tsx @@ -1,99 +1,13 @@ -import React, { useEffect, useMemo, useRef, useState } from 'react'; -import { merge, uniqueId } from 'lodash'; -import { ActionIcon, Container, Group, Tooltip } from '@mantine/core'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faGear } from '@fortawesome/free-solid-svg-icons'; -import { useSyncedRef } from '../../hooks/useSyncedRef'; -import { EFilterOptions, IBarConfig, IVisConfig, Scales, VisColumn } from '../interfaces'; -import { i18n } from '../../i18n/I18nextManager'; -import { BarChart } from './BarChart'; -import { VisSidebarWrapper } from '../VisSidebarWrapper'; -import { BarVisSidebar } from '../bar/BarVisSidebar'; -import { VisSidebarOpenButton } from '../VisSidebarOpenButton'; - -const defaultExtensions = { - prePlot: null, - postPlot: null, - preSidebar: null, - postSidebar: null, -}; - -export function BarVis({ - config, - optionsConfig, - extensions, - columns, - setConfig, - scales, - selectionCallback = () => null, - selectedMap = {}, - selectedList = [], - enableSidebar, - showSidebar, - setShowSidebar, - showCloseButton = false, - closeButtonCallback = () => null, - filterCallback = () => null, -}: { - config: IBarConfig; - optionsConfig?: { - group?: { - enable?: boolean; - customComponent?: React.ReactNode; - }; - multiples?: { - enable?: boolean; - customComponent?: React.ReactNode; - }; - direction?: { - enable?: boolean; - customComponent?: React.ReactNode; - }; - groupingType?: { - enable?: boolean; - customComponent?: React.ReactNode; - }; - display?: { - enable?: boolean; - customComponent?: React.ReactNode; - }; - }; - extensions?: { - prePlot?: React.ReactNode; - postPlot?: React.ReactNode; - preSidebar?: React.ReactNode; - postSidebar?: React.ReactNode; - }; - columns: VisColumn[]; - closeButtonCallback?: () => void; - showCloseButton?: boolean; - selectionCallback?: (ids: string[]) => void; - selectedMap?: { [key: string]: boolean }; - selectedList: string[]; - setConfig: (config: IVisConfig) => void; - scales: Scales; - showSidebar?: boolean; - setShowSidebar?(show: boolean): void; - enableSidebar?: boolean; - filterCallback?: (s: EFilterOptions) => void; -}) { - const mergedExtensions = useMemo(() => { - return merge({}, defaultExtensions, extensions); - }, [extensions]); +import React from 'react'; +import { Group } from '@mantine/core'; - const ref = useRef(); - const id = React.useMemo(() => uniqueId('HexbinVis'), []); +import { IBarConfig, ICommonVisProps } from '../interfaces'; +import { BarChart } from './BarChart'; +export function BarVis({ externalConfig, columns, selectionCallback = () => null, selectedMap = {}, selectedList = [] }: ICommonVisProps) { return ( - - {enableSidebar ? setShowSidebar(!showSidebar)} isOpen={showSidebar} /> : null} - - - {showSidebar ? ( - - - - ) : null} + + ); } diff --git a/src/vis/barGood/barComponents/SingleBar.tsx b/src/vis/barGood/barComponents/SingleBar.tsx index c608d2052..22eab2c9e 100644 --- a/src/vis/barGood/barComponents/SingleBar.tsx +++ b/src/vis/barGood/barComponents/SingleBar.tsx @@ -58,7 +58,7 @@ export function SingleBar({ ) : ( - + )} diff --git a/src/vis/barGood/hooks/useGetBarScales.ts b/src/vis/barGood/hooks/useGetBarScales.ts index 08ab5973d..e60908d4e 100644 --- a/src/vis/barGood/hooks/useGetBarScales.ts +++ b/src/vis/barGood/hooks/useGetBarScales.ts @@ -18,7 +18,6 @@ export function useGetBarScales( aggregateType: EAggregateTypes, ): { aggregatedTable: ColumnTable; baseTable: ColumnTable; countScale: d3.ScaleLinear; categoryScale: d3.ScaleBand } { const baseTable = useMemo(() => { - console.log(allColumns); if (allColumns?.catColVals) { return table({ category: allColumns.catColVals.resolvedValues.map((val) => val.val), diff --git a/src/vis/barGood/hooks/useGetGroupedBarScales.ts b/src/vis/barGood/hooks/useGetGroupedBarScales.ts index 3e8fda3b4..0badddbfe 100644 --- a/src/vis/barGood/hooks/useGetGroupedBarScales.ts +++ b/src/vis/barGood/hooks/useGetGroupedBarScales.ts @@ -40,10 +40,12 @@ export function useGetGroupedBarScales( ); const groupedTable = useMemo(() => { - if (allColumns?.groupColVals) { + if (!allColumns) return null; + + if (allColumns.groupColVals) { let filteredTable = baseTable; - if (categoryFilter && allColumns?.multiplesColVals) { + if (categoryFilter && allColumns.multiplesColVals) { filteredTable = baseTable.params({ categoryFilter }).filter((d) => d.multiples === categoryFilter); } @@ -53,7 +55,7 @@ export function useGetGroupedBarScales( } return null; - }, [aggregateType, allColumns?.groupColVals, allColumns?.multiplesColVals, baseTable, categoryFilter]); + }, [aggregateType, allColumns, baseTable, categoryFilter]); const groupColorScale = useMemo(() => { if (!groupedTable) return null; @@ -78,11 +80,17 @@ export function useGetGroupedBarScales( }, [categoryScale, groupedTable]); const newCountScale = useMemo(() => { - if (!allColumns?.multiplesColVals) { + if (!allColumns) return null; + + + // No multiples, only group + if (!allColumns.multiplesColVals) { + // No group or group is a stack of count, dont need to change scale if (!groupedTable || (groupType === EBarGroupingType.STACK && aggregateType === EAggregateTypes.COUNT)) { return countScale; } + // Group is a stack of something other than count, change max. if (groupType === EBarGroupingType.STACK) { const max = +d3.max( groupedTable @@ -93,21 +101,35 @@ export function useGetGroupedBarScales( return countScale.copy().domain([0, max + max / 25]); } + // Group is not stacked, change max. const max = +d3.max(groupedTable.array('aggregateVal')); return countScale.copy().domain([0, max + max / 25]); } - if (!groupedTable || groupType === EBarGroupingType.STACK) { + // Multiples only, or multiples and stacked. + if (!groupedTable || (groupType === EBarGroupingType.STACK && aggregateType === EAggregateTypes.COUNT)) { const max = +d3.max(rollupByAggregateType(baseTable.groupby('category', 'multiples'), aggregateType).array('aggregateVal')); return countScale.copy().domain([0, max + max / 25]); } + // Multiples + stacking with something other than count. Tricky one. Change max + if (groupType === EBarGroupingType.STACK) { + const max = +d3.max( + rollupByAggregateType(baseTable.groupby('category', 'group', 'multiples'), aggregateType) + .groupby('category', 'multiples') + .rollup({ sum: (d) => op.sum(d.aggregateVal) }) + .array('sum'), + ); + return countScale.copy().domain([0, max + max / 25]); + } + + // Multiples + grouped but not stacked. Change max. const max = +d3.max(rollupByAggregateType(baseTable.groupby('group', 'category', 'multiples'), aggregateType).array('aggregateVal')); const tempScale = countScale.copy().domain([0, max + max / 25]); return tempScale; - }, [aggregateType, allColumns?.multiplesColVals, baseTable, countScale, groupType, groupedTable]); + }, [aggregateType, allColumns, baseTable, countScale, groupType, groupedTable]); return { aggregatedTable, diff --git a/src/vis/barGood/utils.ts b/src/vis/barGood/utils.ts index 4ecd6b715..10286cc7f 100644 --- a/src/vis/barGood/utils.ts +++ b/src/vis/barGood/utils.ts @@ -11,6 +11,7 @@ export enum SortTypes { COUNT_DESC = 'COUNT_DESC', } +// Helper function for the bar chart which sorts the data depending on the sort type. export function sortTableBySortType(tempTable: ColumnTable, sortType: SortTypes) { switch (sortType) { case SortTypes.CAT_ASC: @@ -26,6 +27,7 @@ export function sortTableBySortType(tempTable: ColumnTable, sortType: SortTypes) } } +// Helper function for the bar chart which bins the data depending on the aggregate type. Used for numerical column grouping export function binByAggregateType(tempTable: ColumnTable, aggregateType: EAggregateTypes) { switch (aggregateType) { case EAggregateTypes.COUNT: @@ -78,7 +80,8 @@ export function binByAggregateType(tempTable: ColumnTable, aggregateType: EAggre return null; } } - +// Helper function for the bar chart which aggregates the data based on the aggregate type. +// Mostly just code duplication with the different aggregate types. export function groupByAggregateType(tempTable: ColumnTable, aggregateType: EAggregateTypes) { switch (aggregateType) { case EAggregateTypes.COUNT: @@ -132,6 +135,8 @@ export function groupByAggregateType(tempTable: ColumnTable, aggregateType: EAgg } } +// Helper function for the bar chart which rolls up the data depending on the aggregate type. +// Mostly just code duplication with the different aggregate types. export function rollupByAggregateType(tempTable: ColumnTable, aggregateType: EAggregateTypes) { switch (aggregateType) { case EAggregateTypes.COUNT: diff --git a/src/vis/provider/utils.ts b/src/vis/provider/utils.ts index be191c1c0..971c21794 100644 --- a/src/vis/provider/utils.ts +++ b/src/vis/provider/utils.ts @@ -6,16 +6,18 @@ import { SankeyVisSidebar } from '../sankey/SankeyVisSidebar'; import { ViolinVisSidebar } from '../violin/ViolinVisSidebar'; import { ScatterVis, scatterMergeDefaultConfig } from '../scatter'; import { hexinbMergeDefaultConfig } from '../hexbin/utils'; -import { BarVis } from '../bar/BarVis'; import { barMergeDefaultConfig } from '../bar/utils'; import { BarVisSidebar } from '../bar/BarVisSidebar'; import { HexbinVis } from '../hexbin/HexbinVis'; import { ESupportedPlotlyVis } from '../interfaces'; import { createVis, visMap } from './Provider'; +import { BarVis as BarGood } from '../barGood/BarVis'; +import { BarVis } from '../bar/BarVis'; export function registerAllVis() { visMap[ESupportedPlotlyVis.SCATTER] = createVis(ESupportedPlotlyVis.SCATTER, ScatterVis, ScatterVisSidebar, scatterMergeDefaultConfig); - visMap[ESupportedPlotlyVis.BAR] = createVis(ESupportedPlotlyVis.BAR, BarVis, BarVisSidebar, barMergeDefaultConfig); + visMap[ESupportedPlotlyVis.BAR] = createVis(ESupportedPlotlyVis.BAR, BarGood, BarVisSidebar, barMergeDefaultConfig); + // visMap[ESupportedPlotlyVis.BAR] = createVis(ESupportedPlotlyVis.BAR, BarVis, BarVisSidebar, barMergeDefaultConfig); visMap[ESupportedPlotlyVis.VIOLIN] = createVis(ESupportedPlotlyVis.VIOLIN, ViolinVis, ViolinVisSidebar, violinMergeDefaultConfig); visMap[ESupportedPlotlyVis.HEXBIN] = createVis(ESupportedPlotlyVis.HEXBIN, HexbinVis, HexbinVisSidebar, hexinbMergeDefaultConfig); // visMap[ESupportedPlotlyVis.SANKEY] = createVis(ESupportedPlotlyVis.SANKEY, SankeyVis, SankeyVisSidebar); diff --git a/src/vis/sankey/SankeyVis.tsx b/src/vis/sankey/SankeyVis.tsx index 6b31ad2d2..022728b32 100644 --- a/src/vis/sankey/SankeyVis.tsx +++ b/src/vis/sankey/SankeyVis.tsx @@ -207,7 +207,6 @@ export function SankeyVis({ externalConfig, columns }: ICommonVisProps aggregateColumnSelectCallback(c)} columns={columns} diff --git a/src/vis/sidebar/BarDisplayTypeButtons.tsx b/src/vis/sidebar/BarDisplayTypeButtons.tsx index 136d70894..9b2535eca 100644 --- a/src/vis/sidebar/BarDisplayTypeButtons.tsx +++ b/src/vis/sidebar/BarDisplayTypeButtons.tsx @@ -5,14 +5,16 @@ import { EBarDisplayType } from '../interfaces'; interface BarDisplayProps { callback: (s: EBarDisplayType) => void; currentSelected: EBarDisplayType; + isCount: boolean; } -export function BarDisplayButtons({ callback, currentSelected }: BarDisplayProps) { +export function BarDisplayButtons({ callback, currentSelected, isCount }: BarDisplayProps) { return ( null, currentNum onChange={(e) => callback(columns.find((c) => c.info.id === e)?.info)} name="colorSelect" data={columns.map((c) => ({ value: c.info.id, label: c.info.name, description: c.info.description }))} - value={currentSelected?.id} + value={currentSelected?.id || null} /> {currentNumType && currentSelected && getCol(columns, currentSelected).type === EColumnTypes.NUMERICAL ? ( diff --git a/src/vis/sidebar/GroupSelect.tsx b/src/vis/sidebar/GroupSelect.tsx index ec02260a8..b84d5526e 100644 --- a/src/vis/sidebar/GroupSelect.tsx +++ b/src/vis/sidebar/GroupSelect.tsx @@ -1,6 +1,6 @@ import { Select, Stack } from '@mantine/core'; import * as React from 'react'; -import { ColumnInfo, EBarDisplayType, EBarGroupingType, EColumnTypes, VisColumn } from '../interfaces'; +import { ColumnInfo, EAggregateTypes, EBarDisplayType, EBarGroupingType, EColumnTypes, VisColumn } from '../interfaces'; import { BarDisplayButtons } from './BarDisplayTypeButtons'; import { BarGroupTypeButtons } from './BarGroupTypeButtons'; import { SelectDropdownItem } from './utils'; @@ -13,6 +13,7 @@ interface GroupSelectProps { displayType: EBarDisplayType; columns: VisColumn[]; currentSelected: ColumnInfo | null; + aggregateType: EAggregateTypes; } export function GroupSelect({ @@ -23,6 +24,7 @@ export function GroupSelect({ displayType, columns, currentSelected, + aggregateType, }: GroupSelectProps) { return ( @@ -36,13 +38,17 @@ export function GroupSelect({ data={columns .filter((c) => c.type === EColumnTypes.CATEGORICAL || c.type === EColumnTypes.NUMERICAL) .map((c) => ({ value: c.info.id, label: c.info.name, description: c.info.description }))} - value={currentSelected?.id} + value={currentSelected?.id || null} /> {currentSelected ? ( groupTypeSelectCallback(newGroupType)} currentSelected={groupType} /> ) : null} {currentSelected && groupType === EBarGroupingType.STACK ? ( - groupDisplaySelectCallback(display)} currentSelected={displayType} /> + groupDisplaySelectCallback(display)} + currentSelected={displayType} + isCount={aggregateType === EAggregateTypes.COUNT} + /> ) : null} ); diff --git a/src/vis/sidebar/SingleColumnSelect.tsx b/src/vis/sidebar/SingleColumnSelect.tsx index 174d041ea..eec93c996 100644 --- a/src/vis/sidebar/SingleColumnSelect.tsx +++ b/src/vis/sidebar/SingleColumnSelect.tsx @@ -9,9 +9,10 @@ interface SingleColumnSelectProps { currentSelected: ColumnInfo; label: string; type: EColumnTypes[]; + isClearable?: boolean; } -export function SingleColumnSelect({ callback, columns, currentSelected, label, type }: SingleColumnSelectProps) { +export function SingleColumnSelect({ callback, columns, currentSelected, label, type, isClearable = true }: SingleColumnSelectProps) { const filteredColumnsByType = React.useMemo(() => { return columns.filter((c) => type.includes(c.type)).map((c) => ({ value: c.info.id, label: c.info.name, description: c.info.description })); }, [columns, type]); @@ -20,13 +21,13 @@ export function SingleColumnSelect({ callback, columns, currentSelected, label, callback(e as ECloudType)} data={options} value={currentSelected} />; +} diff --git a/src/vis/sidebar/RaincloudLightningSelect.tsx b/src/vis/sidebar/RaincloudLightningSelect.tsx new file mode 100644 index 000000000..b3f73e56b --- /dev/null +++ b/src/vis/sidebar/RaincloudLightningSelect.tsx @@ -0,0 +1,19 @@ +import { Select } from '@mantine/core'; +import * as React from 'react'; +import { i18n } from '../../i18n'; +import { ELightningType } from '../interfaces'; + +interface HexbinOptionSelectProps { + callback: (c: ELightningType) => void; + currentSelected: ELightningType; +} + +export function RaincloudLightningSelect({ callback, currentSelected }: HexbinOptionSelectProps) { + const options = [ + { value: ELightningType.MEAN_AND_DEV, label: ELightningType.MEAN_AND_DEV }, + { value: ELightningType.MEAN, label: ELightningType.MEAN }, + { value: ELightningType.MEDIAN_AND_DEV, label: ELightningType.MEDIAN_AND_DEV }, + { value: ELightningType.BOXPLOT, label: ELightningType.BOXPLOT }, + ]; + return callback(e as ERainType)} data={options} value={currentSelected} />; +} diff --git a/src/vis/sidebar/SingleColumnSelect.tsx b/src/vis/sidebar/SingleColumnSelect.tsx index 174d041ea..eec93c996 100644 --- a/src/vis/sidebar/SingleColumnSelect.tsx +++ b/src/vis/sidebar/SingleColumnSelect.tsx @@ -9,9 +9,10 @@ interface SingleColumnSelectProps { currentSelected: ColumnInfo; label: string; type: EColumnTypes[]; + isClearable?: boolean; } -export function SingleColumnSelect({ callback, columns, currentSelected, label, type }: SingleColumnSelectProps) { +export function SingleColumnSelect({ callback, columns, currentSelected, label, type, isClearable = true }: SingleColumnSelectProps) { const filteredColumnsByType = React.useMemo(() => { return columns.filter((c) => type.includes(c.type)).map((c) => ({ value: c.info.id, label: c.info.name, description: c.info.description })); }, [columns, type]); @@ -20,13 +21,13 @@ export function SingleColumnSelect({ callback, columns, currentSelected, label, callback(e as ESupportedPlotlyVis)} name="visTypes" - data={getAllVisTypes().map((t) => { + data={visTypes.map((t) => { return { - value: t, - label: t, + value: t.type, + label: t.type, }; })} value={currentSelected} diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index 0a3e3c509..9f43dbd3a 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -1,18 +1,9 @@ -import React, { useState } from 'react'; import { ComponentStory } from '@storybook/react'; +import React, { useState } from 'react'; import { Vis } from '../LazyVis'; -import { - EAggregateTypes, - EBarDirection, - EBarDisplayType, - EBarGroupingType, - EColumnTypes, - ENumericalColorScaleType, - EScatterSelectSettings, - ESupportedPlotlyVis, - EViolinOverlay, - VisColumn, -} from '../interfaces'; +import { EBarDirection, EBarDisplayType, EBarGroupingType } from '../barGood/utils'; +import { BaseConfig, EAggregateTypes, EColumnTypes, ENumericalColorScaleType, EScatterSelectSettings, ESupportedPlotlyVis, VisColumn } from '../interfaces'; +import { EViolinOverlay } from '../violin/utils'; export function fetchIrisData(): VisColumn[] { const dataPromise = import('./irisData').then((m) => @@ -136,7 +127,7 @@ ScatterPlot.args = { shape: null, dragMode: EScatterSelectSettings.RECTANGLE, alphaSliderVal: 1, - }, + } as BaseConfig, }; export const BarChart: typeof Template = Template.bind({}); @@ -156,7 +147,7 @@ BarChart.args = { }, aggregateColumn: null, aggregateType: EAggregateTypes.COUNT, - }, + } as BaseConfig, }; export const ViolinPlot: typeof Template = Template.bind({}); @@ -183,5 +174,5 @@ ViolinPlot.args = { }, ], violinOverlay: EViolinOverlay.NONE, - }, + } as BaseConfig, }; diff --git a/src/vis/stories/Vis/Bar/BarRandom.stories.tsx b/src/vis/stories/Vis/Bar/BarRandom.stories.tsx index d2baf6f01..b916127e2 100644 --- a/src/vis/stories/Vis/Bar/BarRandom.stories.tsx +++ b/src/vis/stories/Vis/Bar/BarRandom.stories.tsx @@ -1,7 +1,8 @@ -import React from 'react'; import { ComponentStory } from '@storybook/react'; +import React from 'react'; import { Vis } from '../../../LazyVis'; -import { EAggregateTypes, EBarDirection, EBarDisplayType, EBarGroupingType, EColumnTypes, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; +import { EBarDirection, EBarDisplayType, EBarGroupingType } from '../../../barGood/utils'; +import { BaseConfig, EAggregateTypes, EColumnTypes, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; function RNG(seed) { const m = 2 ** 35 - 31; @@ -144,7 +145,7 @@ Basic.args = { aggregateType: EAggregateTypes.COUNT, aggregateColumn: null, numColumnsSelected: [], - }, + } as BaseConfig, }; export const Vertical: typeof Template = Template.bind({}) as typeof Template; @@ -164,7 +165,7 @@ Vertical.args = { aggregateType: EAggregateTypes.COUNT, aggregateColumn: null, numColumnsSelected: [], - }, + } as BaseConfig, }; export const Grouped: typeof Template = Template.bind({}) as typeof Template; @@ -188,7 +189,7 @@ Grouped.args = { aggregateType: EAggregateTypes.COUNT, aggregateColumn: null, numColumnsSelected: [], - }, + } as BaseConfig, }; export const GroupedStack: typeof Template = Template.bind({}) as typeof Template; @@ -212,7 +213,7 @@ GroupedStack.args = { aggregateType: EAggregateTypes.COUNT, aggregateColumn: null, numColumnsSelected: [], - }, + } as BaseConfig, }; export const GroupedNumerical: typeof Template = Template.bind({}) as typeof Template; @@ -236,7 +237,7 @@ GroupedNumerical.args = { aggregateType: EAggregateTypes.COUNT, aggregateColumn: null, numColumnsSelected: [], - }, + } as BaseConfig, }; export const GroupedNumericalStack: typeof Template = Template.bind({}) as typeof Template; @@ -260,7 +261,7 @@ GroupedNumericalStack.args = { aggregateType: EAggregateTypes.COUNT, aggregateColumn: null, numColumnsSelected: [], - }, + } as BaseConfig, }; export const Multiples: typeof Template = Template.bind({}) as typeof Template; @@ -284,7 +285,7 @@ Multiples.args = { aggregateType: EAggregateTypes.COUNT, aggregateColumn: null, numColumnsSelected: [], - }, + } as BaseConfig, }; export const MultiplesAndGrouped: typeof Template = Template.bind({}) as typeof Template; @@ -312,7 +313,7 @@ MultiplesAndGrouped.args = { aggregateType: EAggregateTypes.COUNT, aggregateColumn: null, numColumnsSelected: [], - }, + } as BaseConfig, }; export const MultiplesAndGroupedStack: typeof Template = Template.bind({}) as typeof Template; @@ -340,7 +341,7 @@ MultiplesAndGroupedStack.args = { aggregateType: EAggregateTypes.COUNT, aggregateColumn: null, numColumnsSelected: [], - }, + } as BaseConfig, }; export const AggregateAverage: typeof Template = Template.bind({}) as typeof Template; @@ -364,5 +365,5 @@ AggregateAverage.args = { name: 'value', }, numColumnsSelected: [], - }, + } as BaseConfig, }; diff --git a/src/vis/stories/Vis/Correlation/CorrelationIris.stories.tsx b/src/vis/stories/Vis/Correlation/CorrelationIris.stories.tsx index c41ade1ad..941b9abc1 100644 --- a/src/vis/stories/Vis/Correlation/CorrelationIris.stories.tsx +++ b/src/vis/stories/Vis/Correlation/CorrelationIris.stories.tsx @@ -1,7 +1,7 @@ -import React, { useState } from 'react'; import { ComponentStory } from '@storybook/react'; +import React, { useState } from 'react'; import { Vis } from '../../../LazyVis'; -import { ECorrelationType, ENumericalColorScaleType, EScaleType, EScatterSelectSettings, ESupportedPlotlyVis } from '../../../interfaces'; +import { BaseConfig, ECorrelationType, EScaleType, ESupportedPlotlyVis } from '../../../interfaces'; import { fetchIrisData } from '../../fetchIrisData'; // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export @@ -60,7 +60,7 @@ Basic.args = { correlationType: ECorrelationType.PEARSON, pScaleType: EScaleType.LINEAR, pDomain: [0.5, 0.01], - }, + } as BaseConfig, }; Basic.parameters = { diff --git a/src/vis/stories/Vis/Heatmap/HeatmapRandom.stories.tsx b/src/vis/stories/Vis/Heatmap/HeatmapRandom.stories.tsx index 20220a685..8a276b5ac 100644 --- a/src/vis/stories/Vis/Heatmap/HeatmapRandom.stories.tsx +++ b/src/vis/stories/Vis/Heatmap/HeatmapRandom.stories.tsx @@ -1,16 +1,8 @@ -import React from 'react'; import { ComponentStory } from '@storybook/react'; import * as d3 from 'd3v7'; +import React from 'react'; import { Vis } from '../../../LazyVis'; -import { - EAggregateTypes, - EColumnTypes, - ENumericalColorScaleType, - EScatterSelectSettings, - ESortTypes, - ESupportedPlotlyVis, - VisColumn, -} from '../../../interfaces'; +import { BaseConfig, EAggregateTypes, EColumnTypes, ENumericalColorScaleType, ESortTypes, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; function RNG(seed) { const m = 2 ** 35 - 31; @@ -162,7 +154,7 @@ Basic.args = { numColorScaleType: ENumericalColorScaleType.SEQUENTIAL, aggregateColumn: null, aggregateType: EAggregateTypes.COUNT, - }, + } as BaseConfig, }; export const Multiples: typeof Template = Template.bind({}) as typeof Template; @@ -191,5 +183,5 @@ Multiples.args = { numColorScaleType: ENumericalColorScaleType.SEQUENTIAL, aggregateColumn: null, aggregateType: EAggregateTypes.COUNT, - }, + } as BaseConfig, }; diff --git a/src/vis/stories/Vis/Hexbin/HexbinRandom.stories.tsx b/src/vis/stories/Vis/Hexbin/HexbinRandom.stories.tsx index 3b683dbe8..a2780d2dc 100644 --- a/src/vis/stories/Vis/Hexbin/HexbinRandom.stories.tsx +++ b/src/vis/stories/Vis/Hexbin/HexbinRandom.stories.tsx @@ -1,7 +1,7 @@ -import React from 'react'; import { ComponentStory } from '@storybook/react'; +import React from 'react'; import { Vis } from '../../../LazyVis'; -import { EColumnTypes, EHexbinOptions, EScatterSelectSettings, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; +import { BaseConfig, EColumnTypes, EHexbinOptions, EScatterSelectSettings, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; function RNG(seed) { const m = 2 ** 35 - 31; @@ -126,7 +126,7 @@ LargeData.args = { isOpacityScale: true, isSizeScale: false, hexbinOptions: EHexbinOptions.COLOR, - }, + } as BaseConfig, }; export const LargeDataMultiples: typeof Template = Template.bind({}) as typeof Template; @@ -156,7 +156,7 @@ LargeDataMultiples.args = { isOpacityScale: true, isSizeScale: false, hexbinOptions: EHexbinOptions.COLOR, - }, + } as BaseConfig, }; export const ColorByCategory: typeof Template = Template.bind({}) as typeof Template; @@ -185,7 +185,7 @@ ColorByCategory.args = { isOpacityScale: true, isSizeScale: false, hexbinOptions: EHexbinOptions.COLOR, - }, + } as BaseConfig, }; export const PieCharts: typeof Template = Template.bind({}) as typeof Template; @@ -214,7 +214,7 @@ PieCharts.args = { isOpacityScale: true, isSizeScale: false, hexbinOptions: EHexbinOptions.PIE, - }, + } as BaseConfig, }; export const ColorBins: typeof Template = Template.bind({}) as typeof Template; @@ -243,5 +243,5 @@ ColorBins.args = { isOpacityScale: true, isSizeScale: false, hexbinOptions: EHexbinOptions.BINS, - }, + } as BaseConfig, }; diff --git a/src/vis/stories/Vis/Raincloud/RaincloudRandom.stories.tsx b/src/vis/stories/Vis/Raincloud/RaincloudRandom.stories.tsx index 22700a751..90a5ffb0a 100644 --- a/src/vis/stories/Vis/Raincloud/RaincloudRandom.stories.tsx +++ b/src/vis/stories/Vis/Raincloud/RaincloudRandom.stories.tsx @@ -1,18 +1,7 @@ -import React from 'react'; import { ComponentStory } from '@storybook/react'; +import React from 'react'; import { Vis } from '../../../LazyVis'; -import { - EAggregateTypes, - EBarDirection, - EBarDisplayType, - EBarGroupingType, - ECloudType, - EColumnTypes, - ELightningType, - ERainType, - ESupportedPlotlyVis, - VisColumn, -} from '../../../interfaces'; +import { BaseConfig, ECloudType, EColumnTypes, ELightningType, ERainType, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; function RNG(seed) { const m = 2 ** 35 - 31; @@ -162,7 +151,7 @@ Violin.args = { cloudType: ECloudType.SPLIT_VIOLIN, lightningType: ELightningType.MEAN_AND_DEV, rainType: ERainType.BEESWARM, - }, + } as BaseConfig, }; export const Heatmap: typeof Template = Template.bind({}) as typeof Template; @@ -180,7 +169,7 @@ Heatmap.args = { cloudType: ECloudType.HEATMAP, lightningType: ELightningType.MEAN_AND_DEV, rainType: ERainType.BEESWARM, - }, + } as BaseConfig, }; export const Histogram: typeof Template = Template.bind({}) as typeof Template; @@ -198,7 +187,7 @@ Histogram.args = { cloudType: ECloudType.HISTOGRAM, lightningType: ELightningType.MEAN_AND_DEV, rainType: ERainType.BEESWARM, - }, + } as BaseConfig, }; export const Boxplot: typeof Template = Template.bind({}) as typeof Template; @@ -216,7 +205,7 @@ Boxplot.args = { cloudType: ECloudType.SPLIT_VIOLIN, lightningType: ELightningType.BOXPLOT, rainType: ERainType.BEESWARM, - }, + } as BaseConfig, }; export const MeanOnly: typeof Template = Template.bind({}) as typeof Template; @@ -234,7 +223,7 @@ MeanOnly.args = { cloudType: ECloudType.SPLIT_VIOLIN, lightningType: ELightningType.MEAN, rainType: ERainType.BEESWARM, - }, + } as BaseConfig, }; export const MeanAndDev: typeof Template = Template.bind({}) as typeof Template; @@ -252,7 +241,7 @@ MeanAndDev.args = { cloudType: ECloudType.SPLIT_VIOLIN, lightningType: ELightningType.MEAN_AND_DEV, rainType: ERainType.BEESWARM, - }, + } as BaseConfig, }; export const MedianAndDev: typeof Template = Template.bind({}) as typeof Template; @@ -270,7 +259,7 @@ MedianAndDev.args = { cloudType: ECloudType.SPLIT_VIOLIN, lightningType: ELightningType.MEDIAN_AND_DEV, rainType: ERainType.BEESWARM, - }, + } as BaseConfig, }; export const Beeswarm: typeof Template = Template.bind({}) as typeof Template; @@ -288,7 +277,7 @@ Beeswarm.args = { cloudType: ECloudType.SPLIT_VIOLIN, lightningType: ELightningType.MEAN_AND_DEV, rainType: ERainType.BEESWARM, - }, + } as BaseConfig, }; export const Dotplot: typeof Template = Template.bind({}) as typeof Template; @@ -306,7 +295,7 @@ Dotplot.args = { cloudType: ECloudType.SPLIT_VIOLIN, lightningType: ELightningType.MEAN_AND_DEV, rainType: ERainType.DOTPLOT, - }, + } as BaseConfig, }; export const Stripplot: typeof Template = Template.bind({}) as typeof Template; @@ -324,7 +313,7 @@ Stripplot.args = { cloudType: ECloudType.SPLIT_VIOLIN, lightningType: ELightningType.MEAN_AND_DEV, rainType: ERainType.STRIPPLOT, - }, + } as BaseConfig, }; export const Wheatplot: typeof Template = Template.bind({}) as typeof Template; @@ -342,5 +331,5 @@ Wheatplot.args = { cloudType: ECloudType.SPLIT_VIOLIN, lightningType: ELightningType.MEAN_AND_DEV, rainType: ERainType.WHEATPLOT, - }, + } as BaseConfig, }; diff --git a/src/vis/stories/Vis/Scatter/ScatterIris.stories.tsx b/src/vis/stories/Vis/Scatter/ScatterIris.stories.tsx index 41fbae1fb..9b012f356 100644 --- a/src/vis/stories/Vis/Scatter/ScatterIris.stories.tsx +++ b/src/vis/stories/Vis/Scatter/ScatterIris.stories.tsx @@ -1,7 +1,7 @@ -import React, { useState } from 'react'; import { ComponentStory } from '@storybook/react'; +import React, { useState } from 'react'; import { Vis } from '../../../LazyVis'; -import { ENumericalColorScaleType, EScatterSelectSettings, ESupportedPlotlyVis } from '../../../interfaces'; +import { BaseConfig, ENumericalColorScaleType, EScatterSelectSettings, ESupportedPlotlyVis } from '../../../interfaces'; import { fetchIrisData } from '../../fetchIrisData'; // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export @@ -49,7 +49,7 @@ Basic.args = { shape: null, dragMode: EScatterSelectSettings.RECTANGLE, alphaSliderVal: 1, - }, + } as BaseConfig, }; export const ColorByCategory: typeof Template = Template.bind({}) as typeof Template; @@ -77,7 +77,7 @@ ColorByCategory.args = { shape: null, dragMode: EScatterSelectSettings.RECTANGLE, alphaSliderVal: 0.5, - }, + } as BaseConfig, }; export const ColorByNumerical: typeof Template = Template.bind({}) as typeof Template; @@ -105,7 +105,7 @@ ColorByNumerical.args = { shape: null, dragMode: EScatterSelectSettings.RECTANGLE, alphaSliderVal: 0.5, - }, + } as BaseConfig, }; export const SmallMultiples: typeof Template = Template.bind({}) as typeof Template; @@ -134,5 +134,5 @@ SmallMultiples.args = { shape: null, dragMode: EScatterSelectSettings.RECTANGLE, alphaSliderVal: 0.5, - }, + } as BaseConfig, }; diff --git a/src/vis/stories/Vis/Scatter/ScatterRandom.stories.tsx b/src/vis/stories/Vis/Scatter/ScatterRandom.stories.tsx index 6a97da7f3..5f0de5820 100644 --- a/src/vis/stories/Vis/Scatter/ScatterRandom.stories.tsx +++ b/src/vis/stories/Vis/Scatter/ScatterRandom.stories.tsx @@ -1,7 +1,7 @@ -import React from 'react'; import { ComponentStory } from '@storybook/react'; +import React from 'react'; import { Vis } from '../../../LazyVis'; -import { EColumnTypes, ENumericalColorScaleType, EScatterSelectSettings, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; +import { BaseConfig, EColumnTypes, ENumericalColorScaleType, EScatterSelectSettings, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; function RNG(seed) { const m = 2 ** 35 - 31; @@ -137,7 +137,7 @@ LargeData.args = { shape: null, dragMode: EScatterSelectSettings.RECTANGLE, alphaSliderVal: 0.2, - }, + } as BaseConfig, }; export const LargeDataMuliples: typeof Template = Template.bind({}) as typeof Template; @@ -166,5 +166,5 @@ LargeDataMuliples.args = { shape: null, dragMode: EScatterSelectSettings.RECTANGLE, alphaSliderVal: 0.2, - }, + } as BaseConfig, }; diff --git a/src/vis/stories/Vis/Violin/ViolinIris.stories.tsx b/src/vis/stories/Vis/Violin/ViolinIris.stories.tsx index 1afd4aac9..56965797e 100644 --- a/src/vis/stories/Vis/Violin/ViolinIris.stories.tsx +++ b/src/vis/stories/Vis/Violin/ViolinIris.stories.tsx @@ -1,7 +1,8 @@ -import React from 'react'; import { ComponentStory } from '@storybook/react'; +import React from 'react'; import { Vis } from '../../../LazyVis'; -import { ESupportedPlotlyVis, EViolinOverlay } from '../../../interfaces'; +import { BaseConfig, ESupportedPlotlyVis } from '../../../interfaces'; +import { EViolinOverlay } from '../../../violin/utils'; import { fetchIrisData } from '../../fetchIrisData'; // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export @@ -50,7 +51,7 @@ Basic.args = { }, ], violinOverlay: EViolinOverlay.NONE, - }, + } as BaseConfig, }; export const BoxplotOverlay: typeof Template = Template.bind({}) as typeof Template; @@ -77,5 +78,5 @@ BoxplotOverlay.args = { }, ], violinOverlay: EViolinOverlay.BOX, - }, + } as BaseConfig, }; diff --git a/src/vis/violin/ViolinVis.tsx b/src/vis/violin/ViolinVis.tsx index 0fc0fee6a..00b465760 100644 --- a/src/vis/violin/ViolinVis.tsx +++ b/src/vis/violin/ViolinVis.tsx @@ -8,8 +8,8 @@ import { PlotlyComponent, PlotlyTypes } from '../../plotly'; import { Plotly } from '../../plotly/full'; import { InvalidCols } from '../general'; import { beautifyLayout } from '../general/layoutUtils'; -import { ICommonVisProps, IViolinConfig } from '../interfaces'; -import { createViolinTraces } from './utils'; +import { ICommonVisProps } from '../interfaces'; +import { IViolinConfig, createViolinTraces } from './utils'; export function ViolinVis({ config, columns, scales, dimensions, selectedList, selectedMap, selectionCallback }: ICommonVisProps) { const { value: traces, status: traceStatus, error: traceError } = useAsync(createViolinTraces, [columns, config, scales, selectedList, selectedMap]); diff --git a/src/vis/violin/ViolinVisSidebar.tsx b/src/vis/violin/ViolinVisSidebar.tsx index 8e1af8827..11f6fcb36 100644 --- a/src/vis/violin/ViolinVisSidebar.tsx +++ b/src/vis/violin/ViolinVisSidebar.tsx @@ -1,13 +1,14 @@ +import { Container, Divider, Stack } from '@mantine/core'; +import merge from 'lodash/merge'; import * as React from 'react'; import { useMemo } from 'react'; -import merge from 'lodash/merge'; -import { Container, Divider, Stack } from '@mantine/core'; -import { ColumnInfo, ESupportedPlotlyVis, EViolinOverlay, IViolinConfig, ICommonVisSideBarProps } from '../interfaces'; -import { VisTypeSelect } from '../sidebar/VisTypeSelect'; -import { NumericalColumnSelect } from '../sidebar/NumericalColumnSelect'; +import { ColumnInfo, ESupportedPlotlyVis, ICommonVisSideBarProps } from '../interfaces'; import { CategoricalColumnSelect } from '../sidebar/CategoricalColumnSelect'; -import { ViolinOverlayButtons } from '../sidebar/ViolinOverlayButtons'; import { FilterButtons } from '../sidebar/FilterButtons'; +import { NumericalColumnSelect } from '../sidebar/NumericalColumnSelect'; +import { ViolinOverlayButtons } from '../sidebar/ViolinOverlayButtons'; +import { VisTypeSelect } from '../sidebar/VisTypeSelect'; +import { EViolinOverlay, IViolinConfig } from './utils'; const defaultConfig = { overlay: { diff --git a/src/vis/violin/utils.ts b/src/vis/violin/utils.ts index 0b86a779e..7e67b9e83 100644 --- a/src/vis/violin/utils.ts +++ b/src/vis/violin/utils.ts @@ -1,19 +1,31 @@ import merge from 'lodash/merge'; +import { i18n } from '../../i18n'; +import { SELECT_COLOR } from '../general/constants'; +import { columnNameWithDescription, resolveColumnValues } from '../general/layoutUtils'; import { - PlotlyInfo, - PlotlyData, - VisCategoricalColumn, + BaseConfig, + ColumnInfo, EColumnTypes, ESupportedPlotlyVis, - VisNumericalColumn, + PlotlyData, + PlotlyInfo, Scales, + VisCategoricalColumn, VisColumn, - IViolinConfig, - EViolinOverlay, + VisNumericalColumn, } from '../interfaces'; -import { columnNameWithDescription, resolveColumnValues } from '../general/layoutUtils'; -import { i18n } from '../../i18n'; -import { SELECT_COLOR } from '../general/constants'; + +export enum EViolinOverlay { + NONE = 'None', + BOX = 'Box', +} + +export interface IViolinConfig extends BaseConfig { + type: ESupportedPlotlyVis.VIOLIN; + numColumnsSelected: ColumnInfo[]; + catColumnsSelected: ColumnInfo[]; + violinOverlay: EViolinOverlay; +} const defaultConfig: IViolinConfig = { type: ESupportedPlotlyVis.VIOLIN, From 07e6ebbdead73626d5dc1eea7e992b2ea54ef87b Mon Sep 17 00:00:00 2001 From: Michael Puehringer Date: Wed, 23 Aug 2023 08:48:25 +0200 Subject: [PATCH 231/241] Improved typing of externalConfig --- src/demo/MainApp.tsx | 7 ++-- src/views/visyn/demo/interfaces.ts | 4 +- src/vis/EagerVis.tsx | 41 +++++++++++-------- src/vis/Provider.tsx | 6 +-- src/vis/barGood/utils.ts | 13 +++++- src/vis/correlation/utils.ts | 6 +-- src/vis/heatmap/utils.ts | 4 +- src/vis/hexbin/utils.tsx | 4 +- src/vis/interfaces.ts | 2 +- src/vis/raincloud/utils.ts | 4 +- src/vis/sankey/utils.ts | 4 +- src/vis/scatter/utils.ts | 4 +- src/vis/stories/Iris.stories.tsx | 8 ++-- src/vis/stories/Vis/Bar/BarRandom.stories.tsx | 22 +++++----- .../Correlation/CorrelationIris.stories.tsx | 4 +- .../Vis/Heatmap/HeatmapRandom.stories.tsx | 6 +-- .../Vis/Hexbin/HexbinRandom.stories.tsx | 12 +++--- .../Vis/Raincloud/RaincloudRandom.stories.tsx | 24 +++++------ .../Vis/Scatter/ScatterIris.stories.tsx | 10 ++--- .../Vis/Scatter/ScatterRandom.stories.tsx | 6 +-- .../stories/Vis/Violin/ViolinIris.stories.tsx | 6 +-- src/vis/violin/utils.ts | 4 +- 22 files changed, 110 insertions(+), 91 deletions(-) diff --git a/src/demo/MainApp.tsx b/src/demo/MainApp.tsx index 05962cd50..a2fd18378 100644 --- a/src/demo/MainApp.tsx +++ b/src/demo/MainApp.tsx @@ -3,14 +3,15 @@ import * as React from 'react'; import { VisynApp, VisynHeader, useVisynAppContext } from '../app'; import { VisynRanking } from '../ranking'; import { IBuiltVisynRanking } from '../ranking/EagerVisynRanking'; -import { BaseConfig, ENumericalColorScaleType, EScatterSelectSettings, ESupportedPlotlyVis, Vis } from '../vis'; +import { BaseVisConfig, ENumericalColorScaleType, EScatterSelectSettings, ESupportedPlotlyVis, Vis } from '../vis'; import { fetchIrisData } from '../vis/stories/Iris.stories'; import { iris } from '../vis/stories/irisData'; import { MyNumberScore, MyStringScore } from './scoresUtils'; +import { IScatterConfig } from '../vis/scatter'; export function MainApp() { const { user } = useVisynAppContext(); - const [visConfig, setVisConfig] = React.useState({ + const [visConfig, setVisConfig] = React.useState({ type: ESupportedPlotlyVis.SCATTER, numColumnsSelected: [ { @@ -33,7 +34,7 @@ export function MainApp() { shape: null, dragMode: EScatterSelectSettings.RECTANGLE, alphaSliderVal: 1, - } as BaseConfig); + } as IScatterConfig); const columns = React.useMemo(() => (user ? fetchIrisData() : []), [user]); const [selection, setSelection] = React.useState([]); diff --git a/src/views/visyn/demo/interfaces.ts b/src/views/visyn/demo/interfaces.ts index 373f82c5e..dbce3fb2f 100644 --- a/src/views/visyn/demo/interfaces.ts +++ b/src/views/visyn/demo/interfaces.ts @@ -1,8 +1,8 @@ -import type { BaseConfig, VisColumn } from '../../../vis/interfaces'; +import type { BaseVisConfig, VisColumn } from '../../../vis/interfaces'; import { VisynSimpleViewPluginType } from '../interfaces'; export type DemoVisynViewPluginType = VisynSimpleViewPluginType<{ columns: VisColumn[] | null; - config: BaseConfig | null; + config: BaseVisConfig | null; dataLength: number; }>; diff --git a/src/vis/EagerVis.tsx b/src/vis/EagerVis.tsx index d7948f598..2ec4bb549 100644 --- a/src/vis/EagerVis.tsx +++ b/src/vis/EagerVis.tsx @@ -8,7 +8,7 @@ import { getCssValue } from '../utils'; import { createVis, useVisProvider } from './Provider'; import { VisSidebarWrapper } from './VisSidebarWrapper'; import { - BaseConfig, + BaseVisConfig, EAggregateTypes, EColumnTypes, EFilterOptions, @@ -23,26 +23,26 @@ import { VisSidebar } from './VisSidebar'; import { VisSidebarOpenButton } from './VisSidebarOpenButton'; import { BarVis } from './barGood/BarVis'; import { BarVisSidebar } from './barGood/BarVisSidebar'; -import { EBarDirection, EBarDisplayType, EBarGroupingType, barMergeDefaultConfig } from './barGood/utils'; -import { correlationMergeDefaultConfig } from './correlation'; +import { EBarDirection, EBarDisplayType, EBarGroupingType, IBarConfig, barMergeDefaultConfig } from './barGood/utils'; +import { ICorrelationConfig, correlationMergeDefaultConfig } from './correlation'; import { CorrelationVis } from './correlation/CorrelationVis'; import { CorrelationVisSidebar } from './correlation/CorrelationVisSidebar'; import { HeatmapVis } from './heatmap/HeatmapVis'; import { HeatmapVisSidebar } from './heatmap/HeatmapVisSidebar'; -import { heatmapMergeDefaultConfig } from './heatmap/utils'; +import { IHeatmapConfig, heatmapMergeDefaultConfig } from './heatmap/utils'; import { HexbinVis } from './hexbin/HexbinVis'; import { HexbinVisSidebar } from './hexbin/HexbinVisSidebar'; -import { hexinbMergeDefaultConfig } from './hexbin/utils'; +import { IHexbinConfig, hexinbMergeDefaultConfig } from './hexbin/utils'; import { RaincloudVis } from './raincloud/RaincloudVis'; import { RaincloudVisSidebar } from './raincloud/RaincloudVisSidebar'; -import { raincloudMergeDefaultConfig } from './raincloud/utils'; +import { IRaincloudConfig, raincloudMergeDefaultConfig } from './raincloud/utils'; import { SankeyVis } from './sankey/SankeyVis'; import { SankeyVisSidebar } from './sankey/SankeyVisSidebar'; -import { sankeyMergeDefaultConfig } from './sankey/utils'; -import { scatterMergeDefaultConfig } from './scatter'; +import { ISankeyConfig, sankeyMergeDefaultConfig } from './sankey/utils'; +import { IScatterConfig, scatterMergeDefaultConfig } from './scatter'; import { ScatterVis } from './scatter/ScatterVis'; import { ScatterVisSidebar } from './scatter/ScatterVisSidebar'; -import { ViolinVis, violinMergeDefaultConfig } from './violin'; +import { IViolinConfig, ViolinVis, violinMergeDefaultConfig } from './violin'; import { ViolinVisSidebar } from './violin/ViolinVisSidebar'; const DEFAULT_SHAPES = ['circle', 'square', 'triangle-up', 'star']; @@ -110,10 +110,19 @@ export function EagerVis({ * Optional Prop which is called when a filter is applied. Returns a string identifying what type of filter is desired. This logic will be simplified in the future. */ filterCallback?: (s: EFilterOptions) => void; - setExternalConfig?: (config: BaseConfig) => void; + setExternalConfig?: (config: BaseVisConfig) => void; closeCallback?: () => void; showCloseButton?: boolean; - externalConfig?: BaseConfig; + externalConfig?: + | IScatterConfig + | IBarConfig + | IHexbinConfig + | ISankeyConfig + | IHeatmapConfig + | IViolinConfig + | IRaincloudConfig + | ICorrelationConfig + | BaseVisConfig; enableSidebar?: boolean; showSidebar?: boolean; showDragModeOptions?: boolean; @@ -138,8 +147,8 @@ export function EagerVis({ // To ensure that we never render an incosistent config, keep a consistent and a current in the config. Always render the consistent. // eslint-disable-next-line @typescript-eslint/naming-convention const [{ consistent: visConfig, current: inconsistentVisConfig }, _setVisConfig] = React.useState<{ - consistent: BaseConfig; - current: BaseConfig; + consistent: BaseVisConfig; + current: BaseVisConfig; }>( externalConfig ? { consistent: null, current: externalConfig } @@ -154,7 +163,7 @@ export function EagerVis({ shape: null, dragMode: EScatterSelectSettings.RECTANGLE, alphaSliderVal: 0.5, - } as BaseConfig, + } as BaseVisConfig, } : { consistent: null, @@ -169,7 +178,7 @@ export function EagerVis({ catColumnSelected: null, aggregateColumn: null, aggregateType: EAggregateTypes.COUNT, - } as BaseConfig, + } as BaseVisConfig, }, ); @@ -179,7 +188,7 @@ export function EagerVis({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [JSON.stringify(visConfig), setExternalConfigRef]); - const setVisConfig = React.useCallback((newConfig: BaseConfig) => { + const setVisConfig = React.useCallback((newConfig: BaseVisConfig) => { _setVisConfig((oldConfig) => { return { current: newConfig, diff --git a/src/vis/Provider.tsx b/src/vis/Provider.tsx index 930556ceb..8e6fb9225 100644 --- a/src/vis/Provider.tsx +++ b/src/vis/Provider.tsx @@ -1,10 +1,10 @@ import * as React from 'react'; -import { BaseConfig, ICommonVisProps, ICommonVisSideBarProps, VisColumn } from './interfaces'; +import { BaseVisConfig, ICommonVisProps, ICommonVisSideBarProps, VisColumn } from './interfaces'; /** * The general visualization interface. Holds the type and the renderers. */ -export interface GeneralVis { +export interface GeneralVis { type: string; renderer: (props: ICommonVisProps) => React.JSX.Element; sidebarRenderer: (props: ICommonVisSideBarProps) => React.JSX.Element; @@ -14,7 +14,7 @@ export interface GeneralVis { /** * Generic utility function for creating a vis object. */ -export function createVis( +export function createVis( type: string, /** The main vis renderer. Required in all visualizations. */ diff --git a/src/vis/barGood/utils.ts b/src/vis/barGood/utils.ts index d2bee31b6..4f11ac378 100644 --- a/src/vis/barGood/utils.ts +++ b/src/vis/barGood/utils.ts @@ -2,7 +2,16 @@ import { bin, desc, op } from 'arquero'; import ColumnTable from 'arquero/dist/types/table/column-table'; import merge from 'lodash/merge'; import { resolveSingleColumn } from '../general/layoutUtils'; -import { BaseConfig, ColumnInfo, EAggregateTypes, EColumnTypes, ESupportedPlotlyVis, VisCategoricalValue, VisColumn, VisNumericalValue } from '../interfaces'; +import { + BaseVisConfig, + ColumnInfo, + EAggregateTypes, + EColumnTypes, + ESupportedPlotlyVis, + VisCategoricalValue, + VisColumn, + VisNumericalValue, +} from '../interfaces'; export enum SortTypes { NONE = 'NONE', @@ -56,7 +65,7 @@ export function barMergeDefaultConfig(columns: VisColumn[], config: IBarConfig): return merged; } -export interface IBarConfig extends BaseConfig { +export interface IBarConfig extends BaseVisConfig { type: ESupportedPlotlyVis.BAR; multiples: ColumnInfo | null; group: ColumnInfo | null; diff --git a/src/vis/correlation/utils.ts b/src/vis/correlation/utils.ts index aa46216fe..ba2385bab 100644 --- a/src/vis/correlation/utils.ts +++ b/src/vis/correlation/utils.ts @@ -1,7 +1,7 @@ import merge from 'lodash/merge'; import { resolveColumnValues } from '../general/layoutUtils'; import { - BaseConfig, + BaseVisConfig, ColumnInfo, EColumnTypes, ECorrelationType, @@ -12,7 +12,7 @@ import { VisNumericalValue, } from '../interfaces'; -export interface ICorrelationConfig extends BaseConfig { +export interface ICorrelationConfig extends BaseVisConfig { type: ESupportedPlotlyVis.CORRELATION; correlationType: ECorrelationType; numColumnsSelected: ColumnInfo[]; @@ -20,7 +20,7 @@ export interface ICorrelationConfig extends BaseConfig { pDomain: [number, number]; } -export function isCorrelation(s: BaseConfig): s is ICorrelationConfig { +export function isCorrelation(s: BaseVisConfig): s is ICorrelationConfig { return s.type === ESupportedPlotlyVis.CORRELATION; } diff --git a/src/vis/heatmap/utils.ts b/src/vis/heatmap/utils.ts index b035ec90d..f62543690 100644 --- a/src/vis/heatmap/utils.ts +++ b/src/vis/heatmap/utils.ts @@ -1,7 +1,7 @@ import merge from 'lodash/merge'; import { resolveColumnValues, resolveSingleColumn } from '../general/layoutUtils'; import { - BaseConfig, + BaseVisConfig, ColumnInfo, EAggregateTypes, EColumnTypes, @@ -23,7 +23,7 @@ export interface IHeatmapConfig { aggregateColumn: ColumnInfo | null; } -export function isHeatmap(vis: BaseConfig): vis is IHeatmapConfig { +export function isHeatmap(vis: BaseVisConfig): vis is IHeatmapConfig { return vis.type === ESupportedPlotlyVis.HEATMAP; } diff --git a/src/vis/hexbin/utils.tsx b/src/vis/hexbin/utils.tsx index 89344a29f..606f9d738 100644 --- a/src/vis/hexbin/utils.tsx +++ b/src/vis/hexbin/utils.tsx @@ -1,7 +1,7 @@ import merge from 'lodash/merge'; import { resolveColumnValues, resolveSingleColumn } from '../general/layoutUtils'; import { - BaseConfig, + BaseVisConfig, ColumnInfo, EColumnTypes, EHexbinOptions, @@ -13,7 +13,7 @@ import { VisNumericalValue, } from '../interfaces'; -export interface IHexbinConfig extends BaseConfig { +export interface IHexbinConfig extends BaseVisConfig { type: ESupportedPlotlyVis.HEXBIN; numColumnsSelected: ColumnInfo[]; color: ColumnInfo | null; diff --git a/src/vis/interfaces.ts b/src/vis/interfaces.ts index b1e6c26c5..35fb58f10 100644 --- a/src/vis/interfaces.ts +++ b/src/vis/interfaces.ts @@ -12,7 +12,7 @@ export enum ESupportedPlotlyVis { CORRELATION = 'Correlation plot', } -export interface BaseConfig { +export interface BaseVisConfig { type: string; } diff --git a/src/vis/raincloud/utils.ts b/src/vis/raincloud/utils.ts index 0e69c0ba5..f3a11390b 100644 --- a/src/vis/raincloud/utils.ts +++ b/src/vis/raincloud/utils.ts @@ -1,7 +1,7 @@ import { merge } from 'lodash'; import { resolveColumnValues } from '../general/layoutUtils'; import { - BaseConfig, + BaseVisConfig, ColumnInfo, ECloudType, EColumnTypes, @@ -22,7 +22,7 @@ export interface IRaincloudConfig { aggregateRain: boolean; } -export function isRaincloud(s: BaseConfig): s is IRaincloudConfig { +export function isRaincloud(s: BaseVisConfig): s is IRaincloudConfig { return s.type === ESupportedPlotlyVis.RAINCLOUD; } diff --git a/src/vis/sankey/utils.ts b/src/vis/sankey/utils.ts index 865906827..dac88ccf9 100644 --- a/src/vis/sankey/utils.ts +++ b/src/vis/sankey/utils.ts @@ -1,7 +1,7 @@ import { merge } from 'lodash'; -import { BaseConfig, ColumnInfo, ESupportedPlotlyVis, VisColumn } from '../interfaces'; +import { BaseVisConfig, ColumnInfo, ESupportedPlotlyVis, VisColumn } from '../interfaces'; -export interface ISankeyConfig extends BaseConfig { +export interface ISankeyConfig extends BaseVisConfig { type: ESupportedPlotlyVis.SANKEY; catColumnsSelected: ColumnInfo[]; } diff --git a/src/vis/scatter/utils.ts b/src/vis/scatter/utils.ts index e01ee6646..ad7a4097c 100644 --- a/src/vis/scatter/utils.ts +++ b/src/vis/scatter/utils.ts @@ -5,7 +5,7 @@ import { getCssValue } from '../../utils'; import { DEFAULT_COLOR, SELECT_COLOR } from '../general/constants'; import { columnNameWithDescription, resolveColumnValues, resolveSingleColumn } from '../general/layoutUtils'; import { - BaseConfig, + BaseVisConfig, ColumnInfo, EColumnTypes, ENumericalColorScaleType, @@ -21,7 +21,7 @@ import { } from '../interfaces'; import { getCol } from '../sidebar'; -export interface IScatterConfig extends BaseConfig { +export interface IScatterConfig extends BaseVisConfig { type: ESupportedPlotlyVis.SCATTER; numColumnsSelected: ColumnInfo[]; color: ColumnInfo | null; diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index 9f43dbd3a..b59641075 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -2,7 +2,7 @@ import { ComponentStory } from '@storybook/react'; import React, { useState } from 'react'; import { Vis } from '../LazyVis'; import { EBarDirection, EBarDisplayType, EBarGroupingType } from '../barGood/utils'; -import { BaseConfig, EAggregateTypes, EColumnTypes, ENumericalColorScaleType, EScatterSelectSettings, ESupportedPlotlyVis, VisColumn } from '../interfaces'; +import { BaseVisConfig, EAggregateTypes, EColumnTypes, ENumericalColorScaleType, EScatterSelectSettings, ESupportedPlotlyVis, VisColumn } from '../interfaces'; import { EViolinOverlay } from '../violin/utils'; export function fetchIrisData(): VisColumn[] { @@ -127,7 +127,7 @@ ScatterPlot.args = { shape: null, dragMode: EScatterSelectSettings.RECTANGLE, alphaSliderVal: 1, - } as BaseConfig, + } as BaseVisConfig, }; export const BarChart: typeof Template = Template.bind({}); @@ -147,7 +147,7 @@ BarChart.args = { }, aggregateColumn: null, aggregateType: EAggregateTypes.COUNT, - } as BaseConfig, + } as BaseVisConfig, }; export const ViolinPlot: typeof Template = Template.bind({}); @@ -174,5 +174,5 @@ ViolinPlot.args = { }, ], violinOverlay: EViolinOverlay.NONE, - } as BaseConfig, + } as BaseVisConfig, }; diff --git a/src/vis/stories/Vis/Bar/BarRandom.stories.tsx b/src/vis/stories/Vis/Bar/BarRandom.stories.tsx index b916127e2..de24a1a63 100644 --- a/src/vis/stories/Vis/Bar/BarRandom.stories.tsx +++ b/src/vis/stories/Vis/Bar/BarRandom.stories.tsx @@ -2,7 +2,7 @@ import { ComponentStory } from '@storybook/react'; import React from 'react'; import { Vis } from '../../../LazyVis'; import { EBarDirection, EBarDisplayType, EBarGroupingType } from '../../../barGood/utils'; -import { BaseConfig, EAggregateTypes, EColumnTypes, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; +import { BaseVisConfig, EAggregateTypes, EColumnTypes, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; function RNG(seed) { const m = 2 ** 35 - 31; @@ -145,7 +145,7 @@ Basic.args = { aggregateType: EAggregateTypes.COUNT, aggregateColumn: null, numColumnsSelected: [], - } as BaseConfig, + } as BaseVisConfig, }; export const Vertical: typeof Template = Template.bind({}) as typeof Template; @@ -165,7 +165,7 @@ Vertical.args = { aggregateType: EAggregateTypes.COUNT, aggregateColumn: null, numColumnsSelected: [], - } as BaseConfig, + } as BaseVisConfig, }; export const Grouped: typeof Template = Template.bind({}) as typeof Template; @@ -189,7 +189,7 @@ Grouped.args = { aggregateType: EAggregateTypes.COUNT, aggregateColumn: null, numColumnsSelected: [], - } as BaseConfig, + } as BaseVisConfig, }; export const GroupedStack: typeof Template = Template.bind({}) as typeof Template; @@ -213,7 +213,7 @@ GroupedStack.args = { aggregateType: EAggregateTypes.COUNT, aggregateColumn: null, numColumnsSelected: [], - } as BaseConfig, + } as BaseVisConfig, }; export const GroupedNumerical: typeof Template = Template.bind({}) as typeof Template; @@ -237,7 +237,7 @@ GroupedNumerical.args = { aggregateType: EAggregateTypes.COUNT, aggregateColumn: null, numColumnsSelected: [], - } as BaseConfig, + } as BaseVisConfig, }; export const GroupedNumericalStack: typeof Template = Template.bind({}) as typeof Template; @@ -261,7 +261,7 @@ GroupedNumericalStack.args = { aggregateType: EAggregateTypes.COUNT, aggregateColumn: null, numColumnsSelected: [], - } as BaseConfig, + } as BaseVisConfig, }; export const Multiples: typeof Template = Template.bind({}) as typeof Template; @@ -285,7 +285,7 @@ Multiples.args = { aggregateType: EAggregateTypes.COUNT, aggregateColumn: null, numColumnsSelected: [], - } as BaseConfig, + } as BaseVisConfig, }; export const MultiplesAndGrouped: typeof Template = Template.bind({}) as typeof Template; @@ -313,7 +313,7 @@ MultiplesAndGrouped.args = { aggregateType: EAggregateTypes.COUNT, aggregateColumn: null, numColumnsSelected: [], - } as BaseConfig, + } as BaseVisConfig, }; export const MultiplesAndGroupedStack: typeof Template = Template.bind({}) as typeof Template; @@ -341,7 +341,7 @@ MultiplesAndGroupedStack.args = { aggregateType: EAggregateTypes.COUNT, aggregateColumn: null, numColumnsSelected: [], - } as BaseConfig, + } as BaseVisConfig, }; export const AggregateAverage: typeof Template = Template.bind({}) as typeof Template; @@ -365,5 +365,5 @@ AggregateAverage.args = { name: 'value', }, numColumnsSelected: [], - } as BaseConfig, + } as BaseVisConfig, }; diff --git a/src/vis/stories/Vis/Correlation/CorrelationIris.stories.tsx b/src/vis/stories/Vis/Correlation/CorrelationIris.stories.tsx index 941b9abc1..bd8854410 100644 --- a/src/vis/stories/Vis/Correlation/CorrelationIris.stories.tsx +++ b/src/vis/stories/Vis/Correlation/CorrelationIris.stories.tsx @@ -1,7 +1,7 @@ import { ComponentStory } from '@storybook/react'; import React, { useState } from 'react'; import { Vis } from '../../../LazyVis'; -import { BaseConfig, ECorrelationType, EScaleType, ESupportedPlotlyVis } from '../../../interfaces'; +import { BaseVisConfig, ECorrelationType, EScaleType, ESupportedPlotlyVis } from '../../../interfaces'; import { fetchIrisData } from '../../fetchIrisData'; // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export @@ -60,7 +60,7 @@ Basic.args = { correlationType: ECorrelationType.PEARSON, pScaleType: EScaleType.LINEAR, pDomain: [0.5, 0.01], - } as BaseConfig, + } as BaseVisConfig, }; Basic.parameters = { diff --git a/src/vis/stories/Vis/Heatmap/HeatmapRandom.stories.tsx b/src/vis/stories/Vis/Heatmap/HeatmapRandom.stories.tsx index 8a276b5ac..0b443e0a8 100644 --- a/src/vis/stories/Vis/Heatmap/HeatmapRandom.stories.tsx +++ b/src/vis/stories/Vis/Heatmap/HeatmapRandom.stories.tsx @@ -2,7 +2,7 @@ import { ComponentStory } from '@storybook/react'; import * as d3 from 'd3v7'; import React from 'react'; import { Vis } from '../../../LazyVis'; -import { BaseConfig, EAggregateTypes, EColumnTypes, ENumericalColorScaleType, ESortTypes, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; +import { BaseVisConfig, EAggregateTypes, EColumnTypes, ENumericalColorScaleType, ESortTypes, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; function RNG(seed) { const m = 2 ** 35 - 31; @@ -154,7 +154,7 @@ Basic.args = { numColorScaleType: ENumericalColorScaleType.SEQUENTIAL, aggregateColumn: null, aggregateType: EAggregateTypes.COUNT, - } as BaseConfig, + } as BaseVisConfig, }; export const Multiples: typeof Template = Template.bind({}) as typeof Template; @@ -183,5 +183,5 @@ Multiples.args = { numColorScaleType: ENumericalColorScaleType.SEQUENTIAL, aggregateColumn: null, aggregateType: EAggregateTypes.COUNT, - } as BaseConfig, + } as BaseVisConfig, }; diff --git a/src/vis/stories/Vis/Hexbin/HexbinRandom.stories.tsx b/src/vis/stories/Vis/Hexbin/HexbinRandom.stories.tsx index a2780d2dc..5e74fd99d 100644 --- a/src/vis/stories/Vis/Hexbin/HexbinRandom.stories.tsx +++ b/src/vis/stories/Vis/Hexbin/HexbinRandom.stories.tsx @@ -1,7 +1,7 @@ import { ComponentStory } from '@storybook/react'; import React from 'react'; import { Vis } from '../../../LazyVis'; -import { BaseConfig, EColumnTypes, EHexbinOptions, EScatterSelectSettings, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; +import { BaseVisConfig, EColumnTypes, EHexbinOptions, EScatterSelectSettings, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; function RNG(seed) { const m = 2 ** 35 - 31; @@ -126,7 +126,7 @@ LargeData.args = { isOpacityScale: true, isSizeScale: false, hexbinOptions: EHexbinOptions.COLOR, - } as BaseConfig, + } as BaseVisConfig, }; export const LargeDataMultiples: typeof Template = Template.bind({}) as typeof Template; @@ -156,7 +156,7 @@ LargeDataMultiples.args = { isOpacityScale: true, isSizeScale: false, hexbinOptions: EHexbinOptions.COLOR, - } as BaseConfig, + } as BaseVisConfig, }; export const ColorByCategory: typeof Template = Template.bind({}) as typeof Template; @@ -185,7 +185,7 @@ ColorByCategory.args = { isOpacityScale: true, isSizeScale: false, hexbinOptions: EHexbinOptions.COLOR, - } as BaseConfig, + } as BaseVisConfig, }; export const PieCharts: typeof Template = Template.bind({}) as typeof Template; @@ -214,7 +214,7 @@ PieCharts.args = { isOpacityScale: true, isSizeScale: false, hexbinOptions: EHexbinOptions.PIE, - } as BaseConfig, + } as BaseVisConfig, }; export const ColorBins: typeof Template = Template.bind({}) as typeof Template; @@ -243,5 +243,5 @@ ColorBins.args = { isOpacityScale: true, isSizeScale: false, hexbinOptions: EHexbinOptions.BINS, - } as BaseConfig, + } as BaseVisConfig, }; diff --git a/src/vis/stories/Vis/Raincloud/RaincloudRandom.stories.tsx b/src/vis/stories/Vis/Raincloud/RaincloudRandom.stories.tsx index 90a5ffb0a..c0284fce9 100644 --- a/src/vis/stories/Vis/Raincloud/RaincloudRandom.stories.tsx +++ b/src/vis/stories/Vis/Raincloud/RaincloudRandom.stories.tsx @@ -1,7 +1,7 @@ import { ComponentStory } from '@storybook/react'; import React from 'react'; import { Vis } from '../../../LazyVis'; -import { BaseConfig, ECloudType, EColumnTypes, ELightningType, ERainType, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; +import { BaseVisConfig, ECloudType, EColumnTypes, ELightningType, ERainType, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; function RNG(seed) { const m = 2 ** 35 - 31; @@ -151,7 +151,7 @@ Violin.args = { cloudType: ECloudType.SPLIT_VIOLIN, lightningType: ELightningType.MEAN_AND_DEV, rainType: ERainType.BEESWARM, - } as BaseConfig, + } as BaseVisConfig, }; export const Heatmap: typeof Template = Template.bind({}) as typeof Template; @@ -169,7 +169,7 @@ Heatmap.args = { cloudType: ECloudType.HEATMAP, lightningType: ELightningType.MEAN_AND_DEV, rainType: ERainType.BEESWARM, - } as BaseConfig, + } as BaseVisConfig, }; export const Histogram: typeof Template = Template.bind({}) as typeof Template; @@ -187,7 +187,7 @@ Histogram.args = { cloudType: ECloudType.HISTOGRAM, lightningType: ELightningType.MEAN_AND_DEV, rainType: ERainType.BEESWARM, - } as BaseConfig, + } as BaseVisConfig, }; export const Boxplot: typeof Template = Template.bind({}) as typeof Template; @@ -205,7 +205,7 @@ Boxplot.args = { cloudType: ECloudType.SPLIT_VIOLIN, lightningType: ELightningType.BOXPLOT, rainType: ERainType.BEESWARM, - } as BaseConfig, + } as BaseVisConfig, }; export const MeanOnly: typeof Template = Template.bind({}) as typeof Template; @@ -223,7 +223,7 @@ MeanOnly.args = { cloudType: ECloudType.SPLIT_VIOLIN, lightningType: ELightningType.MEAN, rainType: ERainType.BEESWARM, - } as BaseConfig, + } as BaseVisConfig, }; export const MeanAndDev: typeof Template = Template.bind({}) as typeof Template; @@ -241,7 +241,7 @@ MeanAndDev.args = { cloudType: ECloudType.SPLIT_VIOLIN, lightningType: ELightningType.MEAN_AND_DEV, rainType: ERainType.BEESWARM, - } as BaseConfig, + } as BaseVisConfig, }; export const MedianAndDev: typeof Template = Template.bind({}) as typeof Template; @@ -259,7 +259,7 @@ MedianAndDev.args = { cloudType: ECloudType.SPLIT_VIOLIN, lightningType: ELightningType.MEDIAN_AND_DEV, rainType: ERainType.BEESWARM, - } as BaseConfig, + } as BaseVisConfig, }; export const Beeswarm: typeof Template = Template.bind({}) as typeof Template; @@ -277,7 +277,7 @@ Beeswarm.args = { cloudType: ECloudType.SPLIT_VIOLIN, lightningType: ELightningType.MEAN_AND_DEV, rainType: ERainType.BEESWARM, - } as BaseConfig, + } as BaseVisConfig, }; export const Dotplot: typeof Template = Template.bind({}) as typeof Template; @@ -295,7 +295,7 @@ Dotplot.args = { cloudType: ECloudType.SPLIT_VIOLIN, lightningType: ELightningType.MEAN_AND_DEV, rainType: ERainType.DOTPLOT, - } as BaseConfig, + } as BaseVisConfig, }; export const Stripplot: typeof Template = Template.bind({}) as typeof Template; @@ -313,7 +313,7 @@ Stripplot.args = { cloudType: ECloudType.SPLIT_VIOLIN, lightningType: ELightningType.MEAN_AND_DEV, rainType: ERainType.STRIPPLOT, - } as BaseConfig, + } as BaseVisConfig, }; export const Wheatplot: typeof Template = Template.bind({}) as typeof Template; @@ -331,5 +331,5 @@ Wheatplot.args = { cloudType: ECloudType.SPLIT_VIOLIN, lightningType: ELightningType.MEAN_AND_DEV, rainType: ERainType.WHEATPLOT, - } as BaseConfig, + } as BaseVisConfig, }; diff --git a/src/vis/stories/Vis/Scatter/ScatterIris.stories.tsx b/src/vis/stories/Vis/Scatter/ScatterIris.stories.tsx index 9b012f356..0ed90ce52 100644 --- a/src/vis/stories/Vis/Scatter/ScatterIris.stories.tsx +++ b/src/vis/stories/Vis/Scatter/ScatterIris.stories.tsx @@ -1,7 +1,7 @@ import { ComponentStory } from '@storybook/react'; import React, { useState } from 'react'; import { Vis } from '../../../LazyVis'; -import { BaseConfig, ENumericalColorScaleType, EScatterSelectSettings, ESupportedPlotlyVis } from '../../../interfaces'; +import { BaseVisConfig, ENumericalColorScaleType, EScatterSelectSettings, ESupportedPlotlyVis } from '../../../interfaces'; import { fetchIrisData } from '../../fetchIrisData'; // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export @@ -49,7 +49,7 @@ Basic.args = { shape: null, dragMode: EScatterSelectSettings.RECTANGLE, alphaSliderVal: 1, - } as BaseConfig, + } as BaseVisConfig, }; export const ColorByCategory: typeof Template = Template.bind({}) as typeof Template; @@ -77,7 +77,7 @@ ColorByCategory.args = { shape: null, dragMode: EScatterSelectSettings.RECTANGLE, alphaSliderVal: 0.5, - } as BaseConfig, + } as BaseVisConfig, }; export const ColorByNumerical: typeof Template = Template.bind({}) as typeof Template; @@ -105,7 +105,7 @@ ColorByNumerical.args = { shape: null, dragMode: EScatterSelectSettings.RECTANGLE, alphaSliderVal: 0.5, - } as BaseConfig, + } as BaseVisConfig, }; export const SmallMultiples: typeof Template = Template.bind({}) as typeof Template; @@ -134,5 +134,5 @@ SmallMultiples.args = { shape: null, dragMode: EScatterSelectSettings.RECTANGLE, alphaSliderVal: 0.5, - } as BaseConfig, + } as BaseVisConfig, }; diff --git a/src/vis/stories/Vis/Scatter/ScatterRandom.stories.tsx b/src/vis/stories/Vis/Scatter/ScatterRandom.stories.tsx index 5f0de5820..1b4f64de9 100644 --- a/src/vis/stories/Vis/Scatter/ScatterRandom.stories.tsx +++ b/src/vis/stories/Vis/Scatter/ScatterRandom.stories.tsx @@ -1,7 +1,7 @@ import { ComponentStory } from '@storybook/react'; import React from 'react'; import { Vis } from '../../../LazyVis'; -import { BaseConfig, EColumnTypes, ENumericalColorScaleType, EScatterSelectSettings, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; +import { BaseVisConfig, EColumnTypes, ENumericalColorScaleType, EScatterSelectSettings, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; function RNG(seed) { const m = 2 ** 35 - 31; @@ -137,7 +137,7 @@ LargeData.args = { shape: null, dragMode: EScatterSelectSettings.RECTANGLE, alphaSliderVal: 0.2, - } as BaseConfig, + } as BaseVisConfig, }; export const LargeDataMuliples: typeof Template = Template.bind({}) as typeof Template; @@ -166,5 +166,5 @@ LargeDataMuliples.args = { shape: null, dragMode: EScatterSelectSettings.RECTANGLE, alphaSliderVal: 0.2, - } as BaseConfig, + } as BaseVisConfig, }; diff --git a/src/vis/stories/Vis/Violin/ViolinIris.stories.tsx b/src/vis/stories/Vis/Violin/ViolinIris.stories.tsx index 56965797e..c0afc6a0d 100644 --- a/src/vis/stories/Vis/Violin/ViolinIris.stories.tsx +++ b/src/vis/stories/Vis/Violin/ViolinIris.stories.tsx @@ -1,7 +1,7 @@ import { ComponentStory } from '@storybook/react'; import React from 'react'; import { Vis } from '../../../LazyVis'; -import { BaseConfig, ESupportedPlotlyVis } from '../../../interfaces'; +import { BaseVisConfig, ESupportedPlotlyVis } from '../../../interfaces'; import { EViolinOverlay } from '../../../violin/utils'; import { fetchIrisData } from '../../fetchIrisData'; @@ -51,7 +51,7 @@ Basic.args = { }, ], violinOverlay: EViolinOverlay.NONE, - } as BaseConfig, + } as BaseVisConfig, }; export const BoxplotOverlay: typeof Template = Template.bind({}) as typeof Template; @@ -78,5 +78,5 @@ BoxplotOverlay.args = { }, ], violinOverlay: EViolinOverlay.BOX, - } as BaseConfig, + } as BaseVisConfig, }; diff --git a/src/vis/violin/utils.ts b/src/vis/violin/utils.ts index 7e67b9e83..efa186bcf 100644 --- a/src/vis/violin/utils.ts +++ b/src/vis/violin/utils.ts @@ -3,7 +3,7 @@ import { i18n } from '../../i18n'; import { SELECT_COLOR } from '../general/constants'; import { columnNameWithDescription, resolveColumnValues } from '../general/layoutUtils'; import { - BaseConfig, + BaseVisConfig, ColumnInfo, EColumnTypes, ESupportedPlotlyVis, @@ -20,7 +20,7 @@ export enum EViolinOverlay { BOX = 'Box', } -export interface IViolinConfig extends BaseConfig { +export interface IViolinConfig extends BaseVisConfig { type: ESupportedPlotlyVis.VIOLIN; numColumnsSelected: ColumnInfo[]; catColumnsSelected: ColumnInfo[]; From b7b709eef72377da42a8eb6407521f90e9dfe008 Mon Sep 17 00:00:00 2001 From: Michael Puehringer Date: Wed, 23 Aug 2023 09:00:59 +0200 Subject: [PATCH 232/241] Added sizeSliderVal --- src/vis/scatter/ScatterVis.tsx | 1 + src/vis/scatter/utils.ts | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/vis/scatter/ScatterVis.tsx b/src/vis/scatter/ScatterVis.tsx index d9bb9f2e6..b1cfa8a06 100644 --- a/src/vis/scatter/ScatterVis.tsx +++ b/src/vis/scatter/ScatterVis.tsx @@ -50,6 +50,7 @@ export function ScatterVis({ config.shape, config.color, config.alphaSliderVal, + config.sizeSliderVal, config.numColorScaleType, scales, shapes, diff --git a/src/vis/scatter/utils.ts b/src/vis/scatter/utils.ts index ad7a4097c..5c5589a91 100644 --- a/src/vis/scatter/utils.ts +++ b/src/vis/scatter/utils.ts @@ -29,6 +29,7 @@ export interface IScatterConfig extends BaseVisConfig { shape: ColumnInfo | null; dragMode: EScatterSelectSettings; alphaSliderVal: number; + sizeSliderVal: number; } function calculateDomain(domain: [number | undefined, number | undefined], vals: number[]): [number, number] { @@ -52,6 +53,7 @@ const defaultConfig: IScatterConfig = { shape: null, dragMode: EScatterSelectSettings.RECTANGLE, alphaSliderVal: 0.5, + sizeSliderVal: 8, }; export function scatterMergeDefaultConfig(columns: VisColumn[], config: IScatterConfig): IScatterConfig { @@ -91,6 +93,7 @@ export async function createScatterTraces( shape: ColumnInfo, color: ColumnInfo, alphaSliderVal: number, + sizeSliderVal: number, colorScaleType: ENumericalColorScaleType, scales: Scales, shapes: string[] | null, @@ -200,7 +203,7 @@ export async function createScatterTraces( width: 0, }, opacity: 1, - size: 8, + size: sizeSliderVal, }, }, unselected: { @@ -210,7 +213,7 @@ export async function createScatterTraces( }, color: DEFAULT_COLOR, opacity: alphaSliderVal, - size: 8, + size: sizeSliderVal, }, }, }, @@ -293,7 +296,7 @@ export async function createScatterTraces( }, symbol: shapeCol ? shapeCol.resolvedValues.map((v) => shapeScale(v.val as string)) : 'circle', opacity: 1, - size: 8, + size: sizeSliderVal, }, }, unselected: { @@ -304,7 +307,7 @@ export async function createScatterTraces( symbol: shapeCol ? shapeCol.resolvedValues.map((v) => shapeScale(v.val as string)) : 'circle', color: DEFAULT_COLOR, opacity: alphaSliderVal, - size: 8, + size: sizeSliderVal, }, }, }, @@ -344,7 +347,7 @@ export async function createScatterTraces( width: 0, }, symbol: 'circle', - size: 8, + size: sizeSliderVal, color: colorCol ? colorCol.resolvedValues.map((v) => (colorCol.color ? colorCol.color[v.val] : scales.color(v.val))) : DEFAULT_COLOR, opacity: 1, }, @@ -390,7 +393,7 @@ export async function createScatterTraces( width: 0, }, opacity: alphaSliderVal, - size: 8, + size: sizeSliderVal, symbol: shapeCol ? shapeCol.resolvedValues.map((v) => shapeScale(v.val as string)) : 'circle', color: DEFAULT_COLOR, }, From 35c402bce88161cd90f6d48359aadd17417163df Mon Sep 17 00:00:00 2001 From: Michael Puehringer Date: Wed, 23 Aug 2023 14:14:02 +0200 Subject: [PATCH 233/241] Fixed bug where default vis config was not applied --- src/vis/EagerVis.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vis/EagerVis.tsx b/src/vis/EagerVis.tsx index 2ec4bb549..c79aa64e8 100644 --- a/src/vis/EagerVis.tsx +++ b/src/vis/EagerVis.tsx @@ -206,7 +206,7 @@ export function EagerVis({ // DANGER:: this useEffect should only occur when the visConfig.type changes. adding visconfig into the dep array will cause an infinite loop. // eslint-disable-next-line react-hooks/exhaustive-deps - }, [inconsistentVisConfig.type]); + }, [inconsistentVisConfig?.type, getVisByType]); useEffect(() => { if (externalConfig) { From 650ec31ecd8cd423eb2e63d915df64e3aff0b44d Mon Sep 17 00:00:00 2001 From: Michael Puehringer Date: Wed, 23 Aug 2023 16:01:57 +0200 Subject: [PATCH 234/241] More casing fixes --- src/demo/MainApp.tsx | 1 + src/vis/sidebar/CategoricalColumnSelect.tsx | 5 +-- src/vis/sidebar/ColorSelect.tsx | 2 +- src/vis/sidebar/GroupSelect.tsx | 2 +- src/vis/sidebar/NumericalColumnSelect.tsx | 6 +-- src/vis/sidebar/utils.tsx | 43 --------------------- src/vis/stories/Iris.stories.tsx | 2 +- 7 files changed, 8 insertions(+), 53 deletions(-) diff --git a/src/demo/MainApp.tsx b/src/demo/MainApp.tsx index a2fd18378..2f71d7c1d 100644 --- a/src/demo/MainApp.tsx +++ b/src/demo/MainApp.tsx @@ -34,6 +34,7 @@ export function MainApp() { shape: null, dragMode: EScatterSelectSettings.RECTANGLE, alphaSliderVal: 1, + sizeSliderVal: 5, } as IScatterConfig); const columns = React.useMemo(() => (user ? fetchIrisData() : []), [user]); const [selection, setSelection] = React.useState([]); diff --git a/src/vis/sidebar/CategoricalColumnSelect.tsx b/src/vis/sidebar/CategoricalColumnSelect.tsx index 51f273c6e..eec786bef 100644 --- a/src/vis/sidebar/CategoricalColumnSelect.tsx +++ b/src/vis/sidebar/CategoricalColumnSelect.tsx @@ -1,7 +1,7 @@ import { MultiSelect } from '@mantine/core'; import * as React from 'react'; import { ColumnInfo, EColumnTypes, VisColumn } from '../interfaces'; -import { SelectDropdownItem, SelectLabelComponent } from './utils'; +import { SelectDropdownItem } from './utils'; interface CategoricalColumnSelectProps { callback: (s: ColumnInfo[]) => void; @@ -17,9 +17,8 @@ export function CategoricalColumnSelect({ callback, columns, currentSelected }: return ( callback(e.map((id) => columns.find((c) => c.info.id === id).info))} diff --git a/src/vis/sidebar/ColorSelect.tsx b/src/vis/sidebar/ColorSelect.tsx index 10db8a8ba..6b2d88e5a 100644 --- a/src/vis/sidebar/ColorSelect.tsx +++ b/src/vis/sidebar/ColorSelect.tsx @@ -19,7 +19,7 @@ export function ColorSelect({ callback, numTypeCallback = () => null, currentNum withinPortal itemComponent={SelectDropdownItem} clearable - placeholder="Select Column" + placeholder="Select columns" label="Color" onChange={(e) => callback(columns.find((c) => c.info.id === e)?.info)} name="colorSelect" diff --git a/src/vis/sidebar/GroupSelect.tsx b/src/vis/sidebar/GroupSelect.tsx index b57cf72e7..087f48949 100644 --- a/src/vis/sidebar/GroupSelect.tsx +++ b/src/vis/sidebar/GroupSelect.tsx @@ -33,7 +33,7 @@ export function GroupSelect({ withinPortal clearable itemComponent={SelectDropdownItem} - placeholder="Select Column" + placeholder="Select columns" label="Group" onChange={(e) => groupColumnSelectCallback(columns.find((c) => c.info.id === e)?.info)} data={columns diff --git a/src/vis/sidebar/NumericalColumnSelect.tsx b/src/vis/sidebar/NumericalColumnSelect.tsx index da6aedce4..f82919d13 100644 --- a/src/vis/sidebar/NumericalColumnSelect.tsx +++ b/src/vis/sidebar/NumericalColumnSelect.tsx @@ -1,8 +1,7 @@ import * as React from 'react'; -import { Group, MultiSelect, Stack, Text, Tooltip } from '@mantine/core'; -import { forwardRef } from 'react'; +import { MultiSelect } from '@mantine/core'; import { ColumnInfo, EColumnTypes, VisColumn } from '../interfaces'; -import { SelectDropdownItem, SelectLabelComponent } from './utils'; +import { SelectDropdownItem } from './utils'; interface NumericalColumnSelectProps { callback: (s: ColumnInfo[]) => void; @@ -21,7 +20,6 @@ export function NumericalColumnSelect({ callback, columns, currentSelected }: Nu { diff --git a/src/vis/sidebar/utils.tsx b/src/vis/sidebar/utils.tsx index a76f27e39..eb7c153f2 100644 --- a/src/vis/sidebar/utils.tsx +++ b/src/vis/sidebar/utils.tsx @@ -37,46 +37,3 @@ export const SelectDropdownItem = forwardRef(({ value
)); - -export function SelectLabelComponent({ - value, - label, - description, - onRemove, - classNames, - ...others -}: MultiSelectValueProps & { value: string; description: string }) { - return ( -
- - {label} - - {description} - - - } - > - ({ - display: 'flex', - cursor: 'default', - alignItems: 'center', - backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[7] : theme.colors.gray[1], - paddingLeft: theme.spacing.xs, - borderRadius: theme.radius.sm, - })} - > - - {label} - - - - -
- ); -} diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index b59641075..dee46f256 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -51,7 +51,7 @@ export function fetchIrisData(): VisColumn[] { info: { description: 'data from description', id: 'petalLength', - name: 'Petal Length PEtal length petal length', + name: 'Petal Length', }, type: EColumnTypes.NUMERICAL, values: () => dataPromise.then((data) => data.map((r) => r.petalLength).map((val, i) => ({ id: i.toString(), val }))), From e8f5a208589672299b10b3c88649995242ab6952 Mon Sep 17 00:00:00 2001 From: Moritz Heckmann Date: Mon, 2 Oct 2023 09:31:16 +0200 Subject: [PATCH 235/241] this branch currently has merge conflicts, so the develop pin is redone here --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements.txt b/requirements.txt index 7067d4b0c..ffb020183 100644 --- a/requirements.txt +++ b/requirements.txt @@ -33,3 +33,5 @@ itsdangerous>=1.1.0 pyyaml>=5.3.1 ujson>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0 orjson>=3.2.1 +# pin werkzeug version because the new major version 3.0.0 breaks our applications on Oct 2 2023; the version can be removed later again when the other packages support v3.0.0 +werkzeug==2.3.7 From b688fa1965aee6d45a42db4b129eb18e1a755802 Mon Sep 17 00:00:00 2001 From: Moritz Heckmann Date: Mon, 2 Oct 2023 10:08:15 +0200 Subject: [PATCH 236/241] resolved vis merge conflicts --- src/vis/EagerVis.tsx | 96 +++++++-- src/vis/Provider.tsx | 22 ++- src/vis/VisFilterAndSelectSettings.tsx | 48 ----- src/vis/VisSidebarOpenButton.tsx | 11 +- src/vis/VisSidebarWrapper.tsx | 23 ++- src/vis/{barGood => bar}/BarChart.tsx | 3 +- src/vis/bar/BarDirectionButtons.tsx | 25 +++ .../BarDisplayTypeButtons.tsx | 2 +- .../{sidebar => bar}/BarGroupTypeButtons.tsx | 2 +- src/vis/{barGood => bar}/BarVis.tsx | 4 +- src/vis/bar/BarVisSidebar.tsx | 120 +++++++++++ src/vis/{sidebar => bar}/GroupSelect.tsx | 4 +- src/vis/{barGood => bar}/SingleBarChart.tsx | 3 +- .../{barGood => bar}/barComponents/Legend.tsx | 0 .../barComponents/SingleBar.tsx | 0 .../{barGood => bar}/barComponents/XAxis.tsx | 2 +- .../{barGood => bar}/barComponents/YAxis.tsx | 2 +- .../{barGood => bar}/barTypes/GroupedBars.tsx | 0 .../{barGood => bar}/barTypes/SimpleBars.tsx | 0 .../{barGood => bar}/barTypes/StackedBars.tsx | 0 .../{barGood => bar}/hooks/useGetBarScales.ts | 13 +- .../hooks/useGetGroupedBarScales.ts | 33 ++-- src/vis/bar/interfaces.ts | 53 +++++ src/vis/{barGood => bar}/utils.ts | 85 ++------ src/vis/barGood/BarVisSidebar.tsx | 130 ------------ src/vis/correlation/CorrelationMatrix.tsx | 5 +- src/vis/correlation/CorrelationVis.tsx | 9 +- src/vis/correlation/CorrelationVisSidebar.tsx | 187 +++++++++--------- .../components/CorrelationPair.tsx | 2 +- src/vis/correlation/interfaces.ts | 18 ++ src/vis/correlation/utils.ts | 25 +-- src/vis/general/InvalidCols.tsx | 4 +- src/vis/heatmap/AnimatedLine.tsx | 18 +- src/vis/heatmap/AnimatedText.tsx | 4 +- src/vis/heatmap/Heatmap.tsx | 138 ++++++++++--- src/vis/heatmap/HeatmapGrid.tsx | 10 +- src/vis/heatmap/HeatmapRect.tsx | 4 +- src/vis/heatmap/HeatmapText.tsx | 16 +- src/vis/heatmap/HeatmapVis.tsx | 4 +- src/vis/heatmap/HeatmapVisSidebar.tsx | 71 +++---- src/vis/heatmap/interfaces.ts | 24 +++ src/vis/heatmap/utils.ts | 23 +-- .../{sidebar => hexbin}/HexOpacitySwitch.tsx | 0 src/vis/hexbin/HexSizeSlider.tsx | 37 ++++ src/vis/{sidebar => hexbin}/HexSizeSwitch.tsx | 0 .../HexbinOptionSelect.tsx | 2 +- src/vis/hexbin/HexbinVis.tsx | 177 +++++++++++++---- src/vis/hexbin/HexbinVisSidebar.tsx | 64 +++--- src/vis/hexbin/Hexplot.tsx | 149 ++++---------- src/vis/hexbin/SingleHex.tsx | 2 +- src/vis/hexbin/interfaces.ts | 22 +++ src/vis/hexbin/utils.tsx | 26 +-- src/vis/index.ts | 10 + src/vis/interfaces.ts | 51 ----- .../AggregateRainSwitch.tsx | 2 +- src/vis/raincloud/Raincloud.tsx | 4 +- .../RaincloudCloudSelect.tsx | 3 +- src/vis/raincloud/RaincloudGrid.tsx | 11 +- .../RaincloudLightningSelect.tsx | 3 +- .../RaincloudRainSelect.tsx | 3 +- src/vis/raincloud/RaincloudVis.tsx | 2 +- src/vis/raincloud/RaincloudVisSidebar.tsx | 40 ++-- src/vis/raincloud/cloud/Heatmap.tsx | 2 +- src/vis/raincloud/cloud/Histogram.tsx | 2 +- src/vis/raincloud/cloud/SplitViolin.tsx | 2 +- src/vis/raincloud/interfaces.ts | 40 ++++ src/vis/raincloud/lightning/Boxplot.tsx | 2 +- src/vis/raincloud/lightning/Mean.tsx | 2 +- .../raincloud/lightning/MeanAndInterval.tsx | 2 +- .../raincloud/lightning/MedianAndInterval.tsx | 2 +- src/vis/raincloud/rain/BeeSwarm.tsx | 2 +- src/vis/raincloud/rain/Circle.tsx | 2 +- src/vis/raincloud/rain/DotPlot.tsx | 2 +- src/vis/raincloud/rain/StripPlot.tsx | 2 +- src/vis/raincloud/rain/WheatPlot.tsx | 2 +- src/vis/raincloud/utils.ts | 33 +--- src/vis/sankey/SankeyVis.tsx | 6 +- src/vis/sankey/SankeyVisSidebar.tsx | 21 +- src/vis/sankey/interfaces.ts | 10 + src/vis/sankey/utils.ts | 8 +- src/vis/{sidebar => scatter}/ColorSelect.tsx | 4 +- src/vis/scatter/OpacitySlider.tsx | 38 ++++ src/vis/scatter/ScatterVis.tsx | 3 +- src/vis/scatter/ScatterVisSidebar.tsx | 97 ++++----- src/vis/scatter/interfaces.ts | 16 ++ src/vis/scatter/utils.ts | 19 +- src/vis/sidebar/BarDirectionButtons.tsx | 28 --- src/vis/sidebar/CategoricalColumnSelect.tsx | 3 +- src/vis/sidebar/CloseButton.tsx | 9 - src/vis/sidebar/FilterButtons.tsx | 11 +- src/vis/sidebar/HexSizeSlider.tsx | 42 ---- src/vis/sidebar/NumericalColorButtons.tsx | 58 +++--- src/vis/sidebar/NumericalColumnSelect.tsx | 3 +- src/vis/sidebar/OpacitySlider.tsx | 43 ---- src/vis/sidebar/SingleValueSelect.tsx | 25 --- src/vis/sidebar/ViolinOverlayButtons.tsx | 28 --- src/vis/sidebar/VisTypeSelect.tsx | 44 ++++- src/vis/sidebar/index.ts | 14 +- src/vis/sidebar/utils.tsx | 43 ++++ src/vis/stories/Iris.stories.tsx | 4 +- src/vis/stories/Vis/Bar/BarRandom.stories.tsx | 2 +- .../Correlation/CorrelationIris.stories.tsx | 3 +- .../Vis/Heatmap/HeatmapRandom.stories.tsx | 9 +- .../Vis/Hexbin/HexbinRandom.stories.tsx | 3 +- .../Vis/Raincloud/RaincloudRandom.stories.tsx | 3 +- .../stories/Vis/Violin/ViolinIris.stories.tsx | 2 +- src/vis/violin/ViolinOverlayButtons.tsx | 25 +++ src/vis/violin/ViolinVis.tsx | 3 +- src/vis/violin/ViolinVisSidebar.tsx | 37 ++-- src/vis/violin/interfaces.ts | 17 ++ src/vis/violin/utils.ts | 26 +-- 111 files changed, 1411 insertions(+), 1244 deletions(-) delete mode 100644 src/vis/VisFilterAndSelectSettings.tsx rename src/vis/{barGood => bar}/BarChart.tsx (97%) create mode 100644 src/vis/bar/BarDirectionButtons.tsx rename src/vis/{sidebar => bar}/BarDisplayTypeButtons.tsx (94%) rename src/vis/{sidebar => bar}/BarGroupTypeButtons.tsx (93%) rename src/vis/{barGood => bar}/BarVis.tsx (80%) create mode 100644 src/vis/bar/BarVisSidebar.tsx rename src/vis/{sidebar => bar}/GroupSelect.tsx (94%) rename src/vis/{barGood => bar}/SingleBarChart.tsx (99%) rename src/vis/{barGood => bar}/barComponents/Legend.tsx (100%) rename src/vis/{barGood => bar}/barComponents/SingleBar.tsx (100%) rename src/vis/{barGood => bar}/barComponents/XAxis.tsx (98%) rename src/vis/{barGood => bar}/barComponents/YAxis.tsx (98%) rename src/vis/{barGood => bar}/barTypes/GroupedBars.tsx (100%) rename src/vis/{barGood => bar}/barTypes/SimpleBars.tsx (100%) rename src/vis/{barGood => bar}/barTypes/StackedBars.tsx (100%) rename src/vis/{barGood => bar}/hooks/useGetBarScales.ts (89%) rename src/vis/{barGood => bar}/hooks/useGetGroupedBarScales.ts (82%) create mode 100644 src/vis/bar/interfaces.ts rename src/vis/{barGood => bar}/utils.ts (77%) delete mode 100644 src/vis/barGood/BarVisSidebar.tsx create mode 100644 src/vis/correlation/interfaces.ts create mode 100644 src/vis/heatmap/interfaces.ts rename src/vis/{sidebar => hexbin}/HexOpacitySwitch.tsx (100%) create mode 100644 src/vis/hexbin/HexSizeSlider.tsx rename src/vis/{sidebar => hexbin}/HexSizeSwitch.tsx (100%) rename src/vis/{sidebar => hexbin}/HexbinOptionSelect.tsx (93%) create mode 100644 src/vis/hexbin/interfaces.ts rename src/vis/{sidebar => raincloud}/AggregateRainSwitch.tsx (66%) rename src/vis/{sidebar => raincloud}/RaincloudCloudSelect.tsx (89%) rename src/vis/{sidebar => raincloud}/RaincloudLightningSelect.tsx (90%) rename src/vis/{sidebar => raincloud}/RaincloudRainSelect.tsx (89%) create mode 100644 src/vis/raincloud/interfaces.ts create mode 100644 src/vis/sankey/interfaces.ts rename src/vis/{sidebar => scatter}/ColorSelect.tsx (90%) create mode 100644 src/vis/scatter/OpacitySlider.tsx create mode 100644 src/vis/scatter/interfaces.ts delete mode 100644 src/vis/sidebar/BarDirectionButtons.tsx delete mode 100644 src/vis/sidebar/CloseButton.tsx delete mode 100644 src/vis/sidebar/HexSizeSlider.tsx delete mode 100644 src/vis/sidebar/OpacitySlider.tsx delete mode 100644 src/vis/sidebar/SingleValueSelect.tsx delete mode 100644 src/vis/sidebar/ViolinOverlayButtons.tsx create mode 100644 src/vis/violin/ViolinOverlayButtons.tsx create mode 100644 src/vis/violin/interfaces.ts diff --git a/src/vis/EagerVis.tsx b/src/vis/EagerVis.tsx index c79aa64e8..9518be019 100644 --- a/src/vis/EagerVis.tsx +++ b/src/vis/EagerVis.tsx @@ -21,42 +21,98 @@ import { import { VisSidebar } from './VisSidebar'; import { VisSidebarOpenButton } from './VisSidebarOpenButton'; -import { BarVis } from './barGood/BarVis'; -import { BarVisSidebar } from './barGood/BarVisSidebar'; -import { EBarDirection, EBarDisplayType, EBarGroupingType, IBarConfig, barMergeDefaultConfig } from './barGood/utils'; -import { ICorrelationConfig, correlationMergeDefaultConfig } from './correlation'; +import { BarVis } from './bar/BarVis'; +import { BarVisSidebar } from './bar/BarVisSidebar'; +import { EBarDirection, EBarDisplayType, EBarGroupingType, IBarConfig } from './bar/interfaces'; +import { barMergeDefaultConfig } from './bar/utils'; +import { correlationMergeDefaultConfig } from './correlation'; import { CorrelationVis } from './correlation/CorrelationVis'; import { CorrelationVisSidebar } from './correlation/CorrelationVisSidebar'; +import { ICorrelationConfig } from './correlation/interfaces'; import { HeatmapVis } from './heatmap/HeatmapVis'; import { HeatmapVisSidebar } from './heatmap/HeatmapVisSidebar'; -import { IHeatmapConfig, heatmapMergeDefaultConfig } from './heatmap/utils'; +import { IHeatmapConfig } from './heatmap/interfaces'; +import { heatmapMergeDefaultConfig } from './heatmap/utils'; import { HexbinVis } from './hexbin/HexbinVis'; import { HexbinVisSidebar } from './hexbin/HexbinVisSidebar'; -import { IHexbinConfig, hexinbMergeDefaultConfig } from './hexbin/utils'; +import { IHexbinConfig } from './hexbin/interfaces'; +import { hexinbMergeDefaultConfig } from './hexbin/utils'; import { RaincloudVis } from './raincloud/RaincloudVis'; import { RaincloudVisSidebar } from './raincloud/RaincloudVisSidebar'; -import { IRaincloudConfig, raincloudMergeDefaultConfig } from './raincloud/utils'; +import { IRaincloudConfig } from './raincloud/interfaces'; +import { raincloudMergeDefaultConfig } from './raincloud/utils'; import { SankeyVis } from './sankey/SankeyVis'; import { SankeyVisSidebar } from './sankey/SankeyVisSidebar'; -import { ISankeyConfig, sankeyMergeDefaultConfig } from './sankey/utils'; -import { IScatterConfig, scatterMergeDefaultConfig } from './scatter'; +import { ISankeyConfig } from './sankey/interfaces'; +import { sankeyMergeDefaultConfig } from './sankey/utils'; +import { scatterMergeDefaultConfig } from './scatter'; import { ScatterVis } from './scatter/ScatterVis'; import { ScatterVisSidebar } from './scatter/ScatterVisSidebar'; -import { IViolinConfig, ViolinVis, violinMergeDefaultConfig } from './violin'; +import { IScatterConfig } from './scatter/interfaces'; +import { ViolinVis, violinMergeDefaultConfig } from './violin'; import { ViolinVisSidebar } from './violin/ViolinVisSidebar'; +import { IViolinConfig } from './violin/interfaces'; const DEFAULT_SHAPES = ['circle', 'square', 'triangle-up', 'star']; function registerAllVis() { return [ - createVis(ESupportedPlotlyVis.SCATTER, ScatterVis, ScatterVisSidebar, scatterMergeDefaultConfig), - createVis(ESupportedPlotlyVis.BAR, BarVis, BarVisSidebar, barMergeDefaultConfig), - createVis(ESupportedPlotlyVis.HEXBIN, HexbinVis, HexbinVisSidebar, hexinbMergeDefaultConfig), - createVis(ESupportedPlotlyVis.SANKEY, SankeyVis, SankeyVisSidebar, sankeyMergeDefaultConfig), - createVis(ESupportedPlotlyVis.HEATMAP, HeatmapVis, HeatmapVisSidebar, heatmapMergeDefaultConfig), - createVis(ESupportedPlotlyVis.VIOLIN, ViolinVis, ViolinVisSidebar, violinMergeDefaultConfig), - createVis(ESupportedPlotlyVis.RAINCLOUD, RaincloudVis, RaincloudVisSidebar, raincloudMergeDefaultConfig), - createVis(ESupportedPlotlyVis.CORRELATION, CorrelationVis, CorrelationVisSidebar, correlationMergeDefaultConfig), + createVis({ + type: ESupportedPlotlyVis.SCATTER, + renderer: ScatterVis, + sidebarRenderer: ScatterVisSidebar, + mergeConfig: scatterMergeDefaultConfig, + description: 'Visualizes two variables as individual data points in two-dimensional space', + }), + createVis({ + type: ESupportedPlotlyVis.BAR, + renderer: BarVis, + sidebarRenderer: BarVisSidebar, + mergeConfig: barMergeDefaultConfig, + description: 'Visualizes categorical data with rectangular bars', + }), + createVis({ + type: ESupportedPlotlyVis.HEXBIN, + renderer: HexbinVis, + sidebarRenderer: HexbinVisSidebar, + mergeConfig: hexinbMergeDefaultConfig, + description: 'Visualizes 2D data points within hexagons', + }), + createVis({ + type: ESupportedPlotlyVis.SANKEY, + renderer: SankeyVis, + sidebarRenderer: SankeyVisSidebar, + mergeConfig: sankeyMergeDefaultConfig, + description: 'Visualizes the flow of data between different categories', + }), + createVis({ + type: ESupportedPlotlyVis.HEATMAP, + renderer: HeatmapVis, + sidebarRenderer: HeatmapVisSidebar, + mergeConfig: heatmapMergeDefaultConfig, + description: 'Visualizes matrix data using color gradients', + }), + createVis({ + type: ESupportedPlotlyVis.VIOLIN, + renderer: ViolinVis, + sidebarRenderer: ViolinVisSidebar, + mergeConfig: violinMergeDefaultConfig, + description: 'Visualizes numerical data distribution by combining a box plot and a kernel density plot', + }), + createVis({ + type: ESupportedPlotlyVis.RAINCLOUD, + renderer: RaincloudVis, + sidebarRenderer: RaincloudVisSidebar, + mergeConfig: raincloudMergeDefaultConfig, + description: 'Visualizes a combination of boxplot, violin plot, and jitter plot', + }), + createVis({ + type: ESupportedPlotlyVis.CORRELATION, + renderer: CorrelationVis, + sidebarRenderer: CorrelationVisSidebar, + mergeConfig: correlationMergeDefaultConfig, + description: 'Visualizes statistical relationships between pairs of numerical variables', + }), ]; } @@ -277,7 +333,7 @@ export function EagerVis({ }, }} > - {enableSidebar ? setShowSidebar(!showSidebar)} isOpen={showSidebar} /> : null} + {enableSidebar && !showSidebar ? setShowSidebar(!showSidebar)} /> : null} {Renderer ? ( @@ -307,7 +363,7 @@ export function EagerVis({ ) : null} {showSidebar ? ( - + setShowSidebar(false)}> ) : null} diff --git a/src/vis/Provider.tsx b/src/vis/Provider.tsx index 8e6fb9225..59dc021df 100644 --- a/src/vis/Provider.tsx +++ b/src/vis/Provider.tsx @@ -9,27 +9,37 @@ export interface GeneralVis { renderer: (props: ICommonVisProps) => React.JSX.Element; sidebarRenderer: (props: ICommonVisSideBarProps) => React.JSX.Element; mergeConfig: (columns: VisColumn[], config: T) => T; + description: string; } /** * Generic utility function for creating a vis object. */ -export function createVis( - type: string, +export function createVis({ + type, + renderer, + sidebarRenderer, + mergeConfig, + description = '', +}: { + type: string; /** The main vis renderer. Required in all visualizations. */ - renderer: (props: ICommonVisProps) => React.JSX.Element, + renderer: (props: ICommonVisProps) => React.JSX.Element; /** The sidebar renderer. Required in all visualizations. */ - sidebarRenderer: (props: ICommonVisSideBarProps) => React.JSX.Element, + sidebarRenderer: (props: ICommonVisSideBarProps) => React.JSX.Element; + + mergeConfig: (columns: VisColumn[], config: T) => T; - mergeConfig: (columns: VisColumn[], config: T) => T, -): GeneralVis { + description: string; +}): GeneralVis { return { type, renderer, sidebarRenderer, mergeConfig, + description, }; } diff --git a/src/vis/VisFilterAndSelectSettings.tsx b/src/vis/VisFilterAndSelectSettings.tsx deleted file mode 100644 index d550636c6..000000000 --- a/src/vis/VisFilterAndSelectSettings.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { ActionIcon, Divider, Group, Tooltip } from '@mantine/core'; -import * as React from 'react'; -import { FilterClear } from '../assets/icons/FilterClear'; -import { FilterEmpty } from '../assets/icons/FilterEmpty'; -import { FilterFilled } from '../assets/icons/FilterFilled'; -import { EFilterOptions, EScatterSelectSettings } from './interfaces'; -import { BrushOptionButtons } from './sidebar/BrushOptionButtons'; - -export function VisFilterAndSelectSettings({ - onBrushOptionsCallback, - onFilterCallback, - dragMode, - showSelect, - selectOptions = [EScatterSelectSettings.RECTANGLE, EScatterSelectSettings.LASSO, EScatterSelectSettings.PAN, EScatterSelectSettings.ZOOM], -}: { - onBrushOptionsCallback: (dragMode: EScatterSelectSettings) => void; - onFilterCallback: (opt: EFilterOptions) => void; - dragMode: EScatterSelectSettings; - showSelect: boolean; - selectOptions?: EScatterSelectSettings[]; -}) { - return ( - - - - onFilterCallback(EFilterOptions.OUT)}> - - - - - - - onFilterCallback(EFilterOptions.IN)}> - - - - - - - onFilterCallback(EFilterOptions.CLEAR)}> - - - - - {showSelect ? : null} - - ); -} diff --git a/src/vis/VisSidebarOpenButton.tsx b/src/vis/VisSidebarOpenButton.tsx index 8933e2430..634eef632 100644 --- a/src/vis/VisSidebarOpenButton.tsx +++ b/src/vis/VisSidebarOpenButton.tsx @@ -1,15 +1,14 @@ -import * as React from 'react'; -import { ActionIcon, Center, Container, Group, Stack, Tooltip } from '@mantine/core'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faGear } from '@fortawesome/free-solid-svg-icons/faGear'; -import { faClose } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { ActionIcon, Tooltip } from '@mantine/core'; +import * as React from 'react'; import { i18n } from '../i18n'; export function VisSidebarOpenButton({ isOpen, onClick }: { isOpen?: boolean; onClick: () => void }) { return ( - - + + ); diff --git a/src/vis/VisSidebarWrapper.tsx b/src/vis/VisSidebarWrapper.tsx index 2efe3ec60..e3fa3cd0e 100644 --- a/src/vis/VisSidebarWrapper.tsx +++ b/src/vis/VisSidebarWrapper.tsx @@ -1,16 +1,33 @@ -import { Box, Group, ScrollArea } from '@mantine/core'; +import { faClose } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { ActionIcon, Box, Divider, Group, ScrollArea, Stack, Text, Tooltip } from '@mantine/core'; import * as React from 'react'; import { ReactNode } from 'react'; +import { i18n } from '../i18n'; +import { VisTypeSelect } from './sidebar/VisTypeSelect'; +import { HelpHoverCard } from '../components/HelpHoverCard'; const sidebarSize = 200; -export function VisSidebarWrapper({ children }: { children: ReactNode }) { +export function VisSidebarWrapper({ children, config, setConfig, onClick }: { children: ReactNode; config; setConfig; onClick }) { return ( - {children} + + + Settings + + + + + + + setConfig({ ...config, type })} currentSelected={config.type} /> + + {children} + diff --git a/src/vis/barGood/BarChart.tsx b/src/vis/bar/BarChart.tsx similarity index 97% rename from src/vis/barGood/BarChart.tsx rename to src/vis/bar/BarChart.tsx index 174f157c0..40ff0ecff 100644 --- a/src/vis/barGood/BarChart.tsx +++ b/src/vis/bar/BarChart.tsx @@ -6,7 +6,8 @@ import { EColumnTypes, VisColumn } from '../interfaces'; import { SingleBarChart } from './SingleBarChart'; import { Legend } from './barComponents/Legend'; import { useGetGroupedBarScales } from './hooks/useGetGroupedBarScales'; -import { IBarConfig, SortTypes, getBarData } from './utils'; +import { getBarData } from './utils'; +import { IBarConfig, SortTypes } from './interfaces'; export function BarChart({ config, diff --git a/src/vis/bar/BarDirectionButtons.tsx b/src/vis/bar/BarDirectionButtons.tsx new file mode 100644 index 000000000..371597b19 --- /dev/null +++ b/src/vis/bar/BarDirectionButtons.tsx @@ -0,0 +1,25 @@ +import { Input, SegmentedControl } from '@mantine/core'; +import * as React from 'react'; +import { EBarDirection } from './interfaces'; + +interface BarDirectionProps { + callback: (s: EBarDirection) => void; + currentSelected: EBarDirection; +} + +export function BarDirectionButtons({ callback, currentSelected }: BarDirectionProps) { + return ( + + + + ); +} diff --git a/src/vis/sidebar/BarDisplayTypeButtons.tsx b/src/vis/bar/BarDisplayTypeButtons.tsx similarity index 94% rename from src/vis/sidebar/BarDisplayTypeButtons.tsx rename to src/vis/bar/BarDisplayTypeButtons.tsx index feda3b14d..54c5a6b2d 100644 --- a/src/vis/sidebar/BarDisplayTypeButtons.tsx +++ b/src/vis/bar/BarDisplayTypeButtons.tsx @@ -1,6 +1,6 @@ import { Container, SegmentedControl, Stack } from '@mantine/core'; import * as React from 'react'; -import { EBarDisplayType } from '../barGood/utils'; +import { EBarDisplayType } from './interfaces'; interface BarDisplayProps { callback: (s: EBarDisplayType) => void; diff --git a/src/vis/sidebar/BarGroupTypeButtons.tsx b/src/vis/bar/BarGroupTypeButtons.tsx similarity index 93% rename from src/vis/sidebar/BarGroupTypeButtons.tsx rename to src/vis/bar/BarGroupTypeButtons.tsx index f439b5a4f..a0c300f17 100644 --- a/src/vis/sidebar/BarGroupTypeButtons.tsx +++ b/src/vis/bar/BarGroupTypeButtons.tsx @@ -1,6 +1,6 @@ import { Container, SegmentedControl, Stack } from '@mantine/core'; import * as React from 'react'; -import { EBarGroupingType } from '../barGood/utils'; +import { EBarGroupingType } from './interfaces'; interface BarGroupTypeProps { callback: (s: EBarGroupingType) => void; diff --git a/src/vis/barGood/BarVis.tsx b/src/vis/bar/BarVis.tsx similarity index 80% rename from src/vis/barGood/BarVis.tsx rename to src/vis/bar/BarVis.tsx index 0f6ff6dfa..31c9b42fb 100644 --- a/src/vis/barGood/BarVis.tsx +++ b/src/vis/bar/BarVis.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { InvalidCols } from '../general/InvalidCols'; import { ICommonVisProps } from '../interfaces'; import { BarChart } from './BarChart'; -import { IBarConfig } from './utils'; +import { IBarConfig } from './interfaces'; export function BarVis({ config, columns, selectionCallback = () => null, selectedMap = {}, selectedList = [] }: ICommonVisProps) { return ( @@ -12,7 +12,7 @@ export function BarVis({ config, columns, selectionCallback = () => null, select {config.catColumnSelected ? ( ) : ( - + )}
); diff --git a/src/vis/bar/BarVisSidebar.tsx b/src/vis/bar/BarVisSidebar.tsx new file mode 100644 index 000000000..755fb983b --- /dev/null +++ b/src/vis/bar/BarVisSidebar.tsx @@ -0,0 +1,120 @@ +import merge from 'lodash/merge'; +import * as React from 'react'; +import { useMemo } from 'react'; +import { ColumnInfo, EAggregateTypes, EColumnTypes, ICommonVisSideBarProps } from '../interfaces'; +import { AggregateTypeSelect } from '../sidebar/AggregateTypeSelect'; +import { FilterButtons } from '../sidebar/FilterButtons'; +import { SingleColumnSelect } from '../sidebar/SingleColumnSelect'; +import { BarDirectionButtons } from './BarDirectionButtons'; +import { GroupSelect } from './GroupSelect'; +import { EBarDirection, EBarDisplayType, EBarGroupingType, IBarConfig } from './interfaces'; + +const defaultConfig = { + group: { + enable: true, + customComponent: null, + }, + multiples: { + enable: true, + customComponent: null, + }, + direction: { + enable: true, + customComponent: null, + }, + filter: { + enable: true, + customComponent: null, + }, + groupType: { + enable: true, + customComponent: null, + }, + display: { + enable: true, + customComponent: null, + }, +}; + +export function BarVisSidebar({ + config, + optionsConfig, + columns, + setConfig, + className = '', + filterCallback, + style: { width = '20em', ...style } = {}, +}: ICommonVisSideBarProps) { + const mergedOptionsConfig = useMemo(() => { + return merge({}, defaultConfig, optionsConfig); + }, [optionsConfig]); + + return ( + <> + + setConfig({ + ...config, + catColumnSelected, + multiples: config.multiples && config.multiples.id === catColumnSelected?.id ? null : config.multiples, + group: config.group && config.group.id === catColumnSelected?.id ? null : config.group, + }) + } + columns={columns} + currentSelected={config.catColumnSelected} + type={[EColumnTypes.CATEGORICAL]} + label="Categorical column" + /> + { + if (config.aggregateColumn === null) { + setConfig({ + ...config, + aggregateType, + aggregateColumn: columns.find((col) => col.type === EColumnTypes.NUMERICAL).info, + display: aggregateType === EAggregateTypes.COUNT ? config.display : EBarDisplayType.ABSOLUTE, + }); + } else { + setConfig({ ...config, aggregateType, display: aggregateType === EAggregateTypes.COUNT ? config.display : EBarDisplayType.ABSOLUTE }); + } + }} + aggregateColumnSelectCallback={(aggregateColumn: ColumnInfo) => setConfig({ ...config, aggregateColumn })} + columns={columns} + currentSelected={config.aggregateType} + aggregateColumn={config.aggregateColumn} + /> + + {mergedOptionsConfig.group.enable + ? mergedOptionsConfig.group.customComponent || ( + setConfig({ ...config, group })} + groupTypeSelectCallback={(groupType: EBarGroupingType) => setConfig({ ...config, groupType })} + groupDisplaySelectCallback={(display: EBarDisplayType) => setConfig({ ...config, display })} + displayType={config.display} + groupType={config.groupType} + columns={columns.filter((c) => config.catColumnSelected && c.info.id !== config.catColumnSelected.id)} + currentSelected={config.group} + /> + ) + : null} + {mergedOptionsConfig.multiples.enable + ? mergedOptionsConfig.multiples.customComponent || ( + setConfig({ ...config, multiples })} + columns={columns.filter((c) => config.catColumnSelected && c.info.id !== config.catColumnSelected.id)} + currentSelected={config.multiples} + label="Multiples" + type={[EColumnTypes.CATEGORICAL]} + /> + ) + : null} + {mergedOptionsConfig.direction.enable + ? mergedOptionsConfig.direction.customComponent || ( + setConfig({ ...config, direction })} currentSelected={config.direction} /> + ) + : null} + {mergedOptionsConfig.filter.enable ? mergedOptionsConfig.filter.customComponent || : null} + + ); +} diff --git a/src/vis/sidebar/GroupSelect.tsx b/src/vis/bar/GroupSelect.tsx similarity index 94% rename from src/vis/sidebar/GroupSelect.tsx rename to src/vis/bar/GroupSelect.tsx index 087f48949..078a123e6 100644 --- a/src/vis/sidebar/GroupSelect.tsx +++ b/src/vis/bar/GroupSelect.tsx @@ -1,10 +1,10 @@ import { Select, Stack } from '@mantine/core'; import * as React from 'react'; -import { EBarDisplayType, EBarGroupingType } from '../barGood/utils'; +import { EBarDisplayType, EBarGroupingType } from './interfaces'; import { ColumnInfo, EAggregateTypes, EColumnTypes, VisColumn } from '../interfaces'; import { BarDisplayButtons } from './BarDisplayTypeButtons'; import { BarGroupTypeButtons } from './BarGroupTypeButtons'; -import { SelectDropdownItem } from './utils'; +import { SelectDropdownItem } from '../sidebar/utils'; interface GroupSelectProps { groupColumnSelectCallback: (c: ColumnInfo) => void; diff --git a/src/vis/barGood/SingleBarChart.tsx b/src/vis/bar/SingleBarChart.tsx similarity index 99% rename from src/vis/barGood/SingleBarChart.tsx rename to src/vis/bar/SingleBarChart.tsx index 49e329e4e..c92cde259 100644 --- a/src/vis/barGood/SingleBarChart.tsx +++ b/src/vis/bar/SingleBarChart.tsx @@ -8,7 +8,8 @@ import { GroupedBars } from './barTypes/GroupedBars'; import { SimpleBars } from './barTypes/SimpleBars'; import { StackedBars } from './barTypes/StackedBars'; import { useGetGroupedBarScales } from './hooks/useGetGroupedBarScales'; -import { EBarDirection, EBarDisplayType, EBarGroupingType, IBarConfig, SortTypes, getBarData } from './utils'; +import { getBarData } from './utils'; +import { EBarDirection, EBarDisplayType, EBarGroupingType, IBarConfig, SortTypes } from './interfaces'; const margin = { top: 30, diff --git a/src/vis/barGood/barComponents/Legend.tsx b/src/vis/bar/barComponents/Legend.tsx similarity index 100% rename from src/vis/barGood/barComponents/Legend.tsx rename to src/vis/bar/barComponents/Legend.tsx diff --git a/src/vis/barGood/barComponents/SingleBar.tsx b/src/vis/bar/barComponents/SingleBar.tsx similarity index 100% rename from src/vis/barGood/barComponents/SingleBar.tsx rename to src/vis/bar/barComponents/SingleBar.tsx diff --git a/src/vis/barGood/barComponents/XAxis.tsx b/src/vis/bar/barComponents/XAxis.tsx similarity index 98% rename from src/vis/barGood/barComponents/XAxis.tsx rename to src/vis/bar/barComponents/XAxis.tsx index 935b5b0dc..c3ff07e53 100644 --- a/src/vis/barGood/barComponents/XAxis.tsx +++ b/src/vis/bar/barComponents/XAxis.tsx @@ -4,7 +4,7 @@ import * as d3 from 'd3v7'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faCaretLeft, faCaretRight } from '@fortawesome/free-solid-svg-icons'; import { Center, Group, Text, Tooltip } from '@mantine/core'; -import { SortTypes } from '../utils'; +import { SortTypes } from '../interfaces'; // code taken from https://wattenberger.com/blog/react-and-d3 export function XAxis({ diff --git a/src/vis/barGood/barComponents/YAxis.tsx b/src/vis/bar/barComponents/YAxis.tsx similarity index 98% rename from src/vis/barGood/barComponents/YAxis.tsx rename to src/vis/bar/barComponents/YAxis.tsx index 870cac6b8..56ddb1576 100644 --- a/src/vis/barGood/barComponents/YAxis.tsx +++ b/src/vis/bar/barComponents/YAxis.tsx @@ -4,7 +4,7 @@ import { Center, Group, Text } from '@mantine/core'; import * as d3 from 'd3v7'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faCaretLeft, faCaretRight } from '@fortawesome/free-solid-svg-icons'; -import { SortTypes } from '../utils'; +import { SortTypes } from '../interfaces'; type IsEqual = Type1 | Type2 extends Type1 & Type2 ? true : never; diff --git a/src/vis/barGood/barTypes/GroupedBars.tsx b/src/vis/bar/barTypes/GroupedBars.tsx similarity index 100% rename from src/vis/barGood/barTypes/GroupedBars.tsx rename to src/vis/bar/barTypes/GroupedBars.tsx diff --git a/src/vis/barGood/barTypes/SimpleBars.tsx b/src/vis/bar/barTypes/SimpleBars.tsx similarity index 100% rename from src/vis/barGood/barTypes/SimpleBars.tsx rename to src/vis/bar/barTypes/SimpleBars.tsx diff --git a/src/vis/barGood/barTypes/StackedBars.tsx b/src/vis/bar/barTypes/StackedBars.tsx similarity index 100% rename from src/vis/barGood/barTypes/StackedBars.tsx rename to src/vis/bar/barTypes/StackedBars.tsx diff --git a/src/vis/barGood/hooks/useGetBarScales.ts b/src/vis/bar/hooks/useGetBarScales.ts similarity index 89% rename from src/vis/barGood/hooks/useGetBarScales.ts rename to src/vis/bar/hooks/useGetBarScales.ts index e60908d4e..f7a7dd977 100644 --- a/src/vis/barGood/hooks/useGetBarScales.ts +++ b/src/vis/bar/hooks/useGetBarScales.ts @@ -3,7 +3,8 @@ import ColumnTable from 'arquero/dist/types/table/column-table'; import { desc, op, table, addFunction } from 'arquero'; import { useMemo } from 'react'; import * as d3 from 'd3v7'; -import { SortTypes, getBarData, sortTableBySortType } from '../utils'; +import { getBarData, sortTableBySortType } from '../utils'; +import { SortTypes } from '../interfaces'; import { EAggregateTypes } from '../../interfaces'; export function useGetBarScales( @@ -24,7 +25,7 @@ export function useGetBarScales( group: allColumns?.groupColVals?.resolvedValues.map((val) => val.val), multiples: allColumns?.multiplesColVals?.resolvedValues.map((val) => val.val) || [], selected: allColumns.catColVals.resolvedValues.map((val) => (selectedMap[val.id] ? 1 : 0)), - aggregateValues: allColumns?.aggregateColVals?.resolvedValues.map((val) => val.val) || [], + aggregateVal: allColumns?.aggregateColVals?.resolvedValues.map((val) => val.val) || [], id: allColumns.catColVals.resolvedValues.map((val) => val.id), }); } @@ -37,13 +38,13 @@ export function useGetBarScales( case EAggregateTypes.COUNT: return (d) => op.count(); case EAggregateTypes.AVG: - return (d) => op.average(d.aggregateValues); + return (d) => op.average(d.aggregateVal); case EAggregateTypes.MIN: - return (d) => op.min(d.aggregateValues); + return (d) => op.min(d.aggregateVal); case EAggregateTypes.MED: - return (d) => op.median(d.aggregateValues); + return (d) => op.median(d.aggregateVal); case EAggregateTypes.MAX: - return (d) => op.max(d.aggregateValues); + return (d) => op.max(d.aggregateVal); default: return (d) => op.count(); } diff --git a/src/vis/barGood/hooks/useGetGroupedBarScales.ts b/src/vis/bar/hooks/useGetGroupedBarScales.ts similarity index 82% rename from src/vis/barGood/hooks/useGetGroupedBarScales.ts rename to src/vis/bar/hooks/useGetGroupedBarScales.ts index c92b94c53..7117cd7a4 100644 --- a/src/vis/barGood/hooks/useGetGroupedBarScales.ts +++ b/src/vis/bar/hooks/useGetGroupedBarScales.ts @@ -4,7 +4,8 @@ import ColumnTable from 'arquero/dist/types/table/column-table'; import * as d3 from 'd3v7'; import { useMemo } from 'react'; import { EAggregateTypes, EColumnTypes } from '../../interfaces'; -import { EBarGroupingType, SortTypes, binByAggregateType, getBarData, groupByAggregateType, rollupByAggregateType } from '../utils'; +import { binByAggregateType, getBarData, groupByAggregateType, rollupByAggregateType } from '../utils'; +import { EBarGroupingType, SortTypes } from '../interfaces'; import { useGetBarScales } from './useGetBarScales'; export function useGetGroupedBarScales( @@ -47,7 +48,6 @@ export function useGetGroupedBarScales( if (categoryFilter && allColumns.multiplesColVals) { filteredTable = baseTable.filter(escape((d) => d.multiples === categoryFilter)); } - return allColumns.groupColVals.type === EColumnTypes.NUMERICAL ? binByAggregateType(filteredTable, aggregateType) : groupByAggregateType(filteredTable, aggregateType); @@ -59,16 +59,27 @@ export function useGetGroupedBarScales( const groupColorScale = useMemo(() => { if (!groupedTable) return null; - const newGroup = groupedTable.ungroup().groupby('group').count(); + const colorScale = ['#337ab7', '#ec6836', '#75c4c2', '#e9d36c', '#24b466', '#e891ae', '#db933c', '#b08aa6', '#8a6044', '#7b7b7b']; + let i = -1; - return d3 - .scaleOrdinal() - .domain(newGroup.array('group').sort()) - .range( - allColumns.groupColVals.type === EColumnTypes.NUMERICAL - ? d3.schemeBlues[newGroup.array('group').length > 3 ? newGroup.array('group').length : 3] - : ['#337ab7', '#ec6836', '#75c4c2', '#e9d36c', '#24b466', '#e891ae', '#db933c', '#b08aa6', '#8a6044', '#7b7b7b'], - ); + const newGroup = groupedTable.ungroup().groupby('group').count(); + const categoricalColors = allColumns.groupColVals.color + ? newGroup + .array('group') + .sort() + .map((value) => { + i += 1; + return allColumns.groupColVals.color[value] || colorScale[i % colorScale.length]; + }) + : colorScale; + + const domain = newGroup.array('group').sort(); + const range = + allColumns.groupColVals.type === EColumnTypes.NUMERICAL + ? d3.schemeBlues[newGroup.array('group').length > 3 ? newGroup.array('group').length : 3] + : categoricalColors; + + return d3.scaleOrdinal().domain(domain).range(range); }, [groupedTable, allColumns]); const groupScale = useMemo(() => { diff --git a/src/vis/bar/interfaces.ts b/src/vis/bar/interfaces.ts new file mode 100644 index 000000000..6f2a1f42b --- /dev/null +++ b/src/vis/bar/interfaces.ts @@ -0,0 +1,53 @@ +import { BaseVisConfig, ColumnInfo, EAggregateTypes, ESupportedPlotlyVis } from '../interfaces'; + +export enum SortTypes { + NONE = 'NONE', + CAT_ASC = 'CAT_ASC', + CAT_DESC = 'CAT_DESC', + COUNT_ASC = 'COUNT_ASC', + COUNT_DESC = 'COUNT_DESC', +} + +export enum EBarGroupingType { + STACK = 'Stacked', + GROUP = 'Grouped', +} + +export enum EBarDisplayType { + ABSOLUTE = 'Absolute', + NORMALIZED = 'Normalized', +} +export enum EBarDirection { + VERTICAL = 'Vertical', + HORIZONTAL = 'Horizontal', +} + +export interface IBarConfig extends BaseVisConfig { + type: ESupportedPlotlyVis.BAR; + multiples: ColumnInfo | null; + group: ColumnInfo | null; + direction: EBarDirection; + display: EBarDisplayType; + groupType: EBarGroupingType; + numColumnsSelected: ColumnInfo[]; + catColumnSelected: ColumnInfo; + aggregateType: EAggregateTypes; + aggregateColumn: ColumnInfo | null; +} + +export const defaultConfig: IBarConfig = { + type: ESupportedPlotlyVis.BAR, + numColumnsSelected: [], + catColumnSelected: null, + group: null, + groupType: EBarGroupingType.STACK, + multiples: null, + display: EBarDisplayType.ABSOLUTE, + direction: EBarDirection.HORIZONTAL, + aggregateColumn: null, + aggregateType: EAggregateTypes.COUNT, +}; + +export function isBarConfig(s: BaseVisConfig): s is IBarConfig { + return s.type === ESupportedPlotlyVis.BAR; +} diff --git a/src/vis/barGood/utils.ts b/src/vis/bar/utils.ts similarity index 77% rename from src/vis/barGood/utils.ts rename to src/vis/bar/utils.ts index 4f11ac378..1797eafd6 100644 --- a/src/vis/barGood/utils.ts +++ b/src/vis/bar/utils.ts @@ -2,51 +2,8 @@ import { bin, desc, op } from 'arquero'; import ColumnTable from 'arquero/dist/types/table/column-table'; import merge from 'lodash/merge'; import { resolveSingleColumn } from '../general/layoutUtils'; -import { - BaseVisConfig, - ColumnInfo, - EAggregateTypes, - EColumnTypes, - ESupportedPlotlyVis, - VisCategoricalValue, - VisColumn, - VisNumericalValue, -} from '../interfaces'; - -export enum SortTypes { - NONE = 'NONE', - CAT_ASC = 'CAT_ASC', - CAT_DESC = 'CAT_DESC', - COUNT_ASC = 'COUNT_ASC', - COUNT_DESC = 'COUNT_DESC', -} - -export enum EBarGroupingType { - STACK = 'Stacked', - GROUP = 'Grouped', -} - -export enum EBarDisplayType { - ABSOLUTE = 'Absolute', - NORMALIZED = 'Normalized', -} -export enum EBarDirection { - VERTICAL = 'Vertical', - HORIZONTAL = 'Horizontal', -} - -const defaultConfig: IBarConfig = { - type: ESupportedPlotlyVis.BAR, - numColumnsSelected: [], - catColumnSelected: null, - group: null, - groupType: EBarGroupingType.STACK, - multiples: null, - display: EBarDisplayType.ABSOLUTE, - direction: EBarDirection.HORIZONTAL, - aggregateColumn: null, - aggregateType: EAggregateTypes.COUNT, -}; +import { ColumnInfo, EAggregateTypes, EColumnTypes, VisCategoricalValue, VisColumn, VisNumericalValue } from '../interfaces'; +import { IBarConfig, defaultConfig, SortTypes } from './interfaces'; export function barMergeDefaultConfig(columns: VisColumn[], config: IBarConfig): IBarConfig { const merged = merge({}, defaultConfig, config); @@ -65,19 +22,6 @@ export function barMergeDefaultConfig(columns: VisColumn[], config: IBarConfig): return merged; } -export interface IBarConfig extends BaseVisConfig { - type: ESupportedPlotlyVis.BAR; - multiples: ColumnInfo | null; - group: ColumnInfo | null; - direction: EBarDirection; - display: EBarDisplayType; - groupType: EBarGroupingType; - numColumnsSelected: ColumnInfo[]; - catColumnSelected: ColumnInfo; - aggregateType: EAggregateTypes; - aggregateColumn: ColumnInfo | null; -} - // Helper function for the bar chart which sorts the data depending on the sort type. export function sortTableBySortType(tempTable: ColumnTable, sortType: SortTypes) { switch (sortType) { @@ -108,7 +52,7 @@ export function binByAggregateType(tempTable: ColumnTable, aggregateType: EAggre return tempTable .groupby('category', { group: bin('group', { maxbins: 9 }), group_max: bin('group', { maxbins: 9, offset: 1 }) }) .rollup({ - aggregateVal: (d) => op.average(d.aggregateValues), + aggregateVal: (d) => op.average(d.aggregateVal), count: op.count(), selectedCount: (d) => op.sum(d.selected), ids: (d) => op.array_agg(d.id), @@ -119,7 +63,7 @@ export function binByAggregateType(tempTable: ColumnTable, aggregateType: EAggre case EAggregateTypes.MIN: return tempTable .groupby('category', { group: bin('group', { maxbins: 9 }), group_max: bin('group', { maxbins: 9, offset: 1 }) }) - .rollup({ aggregateVal: (d) => op.min(d.aggregateValues), count: op.count(), selectedCount: (d) => op.sum(d.selected), ids: (d) => op.array_agg(d.id) }) + .rollup({ aggregateVal: (d) => op.min(d.aggregateVal), count: op.count(), selectedCount: (d) => op.sum(d.selected), ids: (d) => op.array_agg(d.id) }) .orderby('group') .groupby('category') .derive({ categoryCount: (d) => op.sum(d.count) }); @@ -127,7 +71,7 @@ export function binByAggregateType(tempTable: ColumnTable, aggregateType: EAggre return tempTable .groupby('category', { group: bin('group', { maxbins: 9 }), group_max: bin('group', { maxbins: 9, offset: 1 }) }) .rollup({ - aggregateVal: (d) => op.median(d.aggregateValues), + aggregateVal: (d) => op.median(d.aggregateVal), count: op.count(), selectedCount: (d) => op.sum(d.selected), ids: (d) => op.array_agg(d.id), @@ -139,7 +83,7 @@ export function binByAggregateType(tempTable: ColumnTable, aggregateType: EAggre case EAggregateTypes.MAX: return tempTable .groupby('category', { group: bin('group', { maxbins: 9 }), group_max: bin('group', { maxbins: 9, offset: 1 }) }) - .rollup({ aggregateVal: (d) => op.max(d.aggregateValues), count: op.count(), selectedCount: (d) => op.sum(d.selected), ids: (d) => op.array_agg(d.id) }) + .rollup({ aggregateVal: (d) => op.max(d.aggregateVal), count: op.count(), selectedCount: (d) => op.sum(d.selected), ids: (d) => op.array_agg(d.id) }) .orderby('group') .groupby('category') .derive({ categoryCount: (d) => op.sum(d.count) }); @@ -162,7 +106,7 @@ export function groupByAggregateType(tempTable: ColumnTable, aggregateType: EAgg return tempTable .groupby('category', 'group') .rollup({ - aggregateVal: (d) => op.average(d.aggregateValues), + aggregateVal: (d) => op.average(d.aggregateVal), count: op.count(), selectedCount: (d) => op.sum(d.selected), ids: (d) => op.array_agg(d.id), @@ -173,7 +117,7 @@ export function groupByAggregateType(tempTable: ColumnTable, aggregateType: EAgg case EAggregateTypes.MIN: return tempTable .groupby('category', 'group') - .rollup({ aggregateVal: (d) => op.min(d.aggregateValues), count: op.count(), selectedCount: (d) => op.sum(d.selected), ids: (d) => op.array_agg(d.id) }) + .rollup({ aggregateVal: (d) => op.min(d.aggregateVal), count: op.count(), selectedCount: (d) => op.sum(d.selected), ids: (d) => op.array_agg(d.id) }) .orderby('category') .groupby('category') .derive({ categoryCount: (d) => op.sum(d.count) }); @@ -181,7 +125,7 @@ export function groupByAggregateType(tempTable: ColumnTable, aggregateType: EAgg return tempTable .groupby('category', 'group') .rollup({ - aggregateVal: (d) => op.median(d.aggregateValues), + aggregateVal: (d) => op.median(d.aggregateVal), count: op.count(), selectedCount: (d) => op.sum(d.selected), ids: (d) => op.array_agg(d.id), @@ -193,7 +137,7 @@ export function groupByAggregateType(tempTable: ColumnTable, aggregateType: EAgg case EAggregateTypes.MAX: return tempTable .groupby('category', 'group') - .rollup({ aggregateVal: (d) => op.max(d.aggregateValues), count: op.count(), selectedCount: (d) => op.sum(d.selected), ids: (d) => op.array_agg(d.id) }) + .rollup({ aggregateVal: (d) => op.max(d.aggregateVal), count: op.count(), selectedCount: (d) => op.sum(d.selected), ids: (d) => op.array_agg(d.id) }) .orderby('category') .groupby('category') .derive({ categoryCount: (d) => op.sum(d.count) }); @@ -209,15 +153,15 @@ export function rollupByAggregateType(tempTable: ColumnTable, aggregateType: EAg case EAggregateTypes.COUNT: return tempTable.rollup({ aggregateVal: () => op.count() }); case EAggregateTypes.AVG: - return tempTable.rollup({ aggregateVal: (d) => op.average(d.aggregateValues) }); + return tempTable.rollup({ aggregateVal: (d) => op.average(d.aggregateVal) }); case EAggregateTypes.MIN: - return tempTable.rollup({ aggregateVal: (d) => op.min(d.aggregateValues) }); + return tempTable.rollup({ aggregateVal: (d) => op.min(d.aggregateVal) }); case EAggregateTypes.MED: - return tempTable.rollup({ aggregateVal: (d) => op.median(d.aggregateValues) }); + return tempTable.rollup({ aggregateVal: (d) => op.median(d.aggregateVal) }); case EAggregateTypes.MAX: - return tempTable.rollup({ aggregateVal: (d) => op.max(d.aggregateValues) }); + return tempTable.rollup({ aggregateVal: (d) => op.max(d.aggregateVal) }); default: return null; @@ -240,6 +184,7 @@ export async function getBarData( resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; type: EColumnTypes.NUMERICAL | EColumnTypes.CATEGORICAL; info: ColumnInfo; + color?: Record; }; multiplesColVals: { resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; diff --git a/src/vis/barGood/BarVisSidebar.tsx b/src/vis/barGood/BarVisSidebar.tsx deleted file mode 100644 index c161f6e0a..000000000 --- a/src/vis/barGood/BarVisSidebar.tsx +++ /dev/null @@ -1,130 +0,0 @@ -import { Container, Divider, Stack } from '@mantine/core'; -import merge from 'lodash/merge'; -import * as React from 'react'; -import { useMemo } from 'react'; -import { ColumnInfo, EAggregateTypes, EColumnTypes, ICommonVisSideBarProps } from '../interfaces'; -import { AggregateTypeSelect } from '../sidebar/AggregateTypeSelect'; -import { BarDirectionButtons } from '../sidebar/BarDirectionButtons'; -import { FilterButtons } from '../sidebar/FilterButtons'; -import { GroupSelect } from '../sidebar/GroupSelect'; -import { SingleColumnSelect } from '../sidebar/SingleColumnSelect'; -import { VisTypeSelect } from '../sidebar/VisTypeSelect'; -import { EBarDirection, EBarDisplayType, EBarGroupingType, IBarConfig } from './utils'; - -const defaultConfig = { - group: { - enable: true, - customComponent: null, - }, - multiples: { - enable: true, - customComponent: null, - }, - direction: { - enable: true, - customComponent: null, - }, - filter: { - enable: true, - customComponent: null, - }, - groupType: { - enable: true, - customComponent: null, - }, - display: { - enable: true, - customComponent: null, - }, -}; - -export function BarVisSidebar({ - config, - optionsConfig, - columns, - setConfig, - className = '', - filterCallback, - style: { width = '20em', ...style } = {}, -}: ICommonVisSideBarProps) { - const mergedOptionsConfig = useMemo(() => { - return merge({}, defaultConfig, optionsConfig); - }, [optionsConfig]); - - return ( - - setConfig({ ...(config as any), type })} currentSelected={config.type} /> - - - - setConfig({ - ...config, - catColumnSelected, - multiples: config.multiples && config.multiples.id === catColumnSelected?.id ? null : config.multiples, - group: config.group && config.group.id === catColumnSelected?.id ? null : config.group, - }) - } - columns={columns} - currentSelected={config.catColumnSelected} - type={[EColumnTypes.CATEGORICAL]} - label="Categorical column" - /> - { - if (config.aggregateColumn === null) { - setConfig({ - ...config, - aggregateType, - aggregateColumn: columns.find((col) => col.type === EColumnTypes.NUMERICAL).info, - display: aggregateType === EAggregateTypes.COUNT ? config.display : EBarDisplayType.ABSOLUTE, - }); - } else { - setConfig({ ...config, aggregateType, display: aggregateType === EAggregateTypes.COUNT ? config.display : EBarDisplayType.ABSOLUTE }); - } - }} - aggregateColumnSelectCallback={(aggregateColumn: ColumnInfo) => setConfig({ ...config, aggregateColumn })} - columns={columns} - currentSelected={config.aggregateType} - aggregateColumn={config.aggregateColumn} - /> - - - - - {mergedOptionsConfig.group.enable - ? mergedOptionsConfig.group.customComponent || ( - setConfig({ ...config, group })} - groupTypeSelectCallback={(groupType: EBarGroupingType) => setConfig({ ...config, groupType })} - groupDisplaySelectCallback={(display: EBarDisplayType) => setConfig({ ...config, display })} - displayType={config.display} - groupType={config.groupType} - columns={columns.filter((c) => config.catColumnSelected && c.info.id !== config.catColumnSelected.id)} - currentSelected={config.group} - /> - ) - : null} - {mergedOptionsConfig.multiples.enable - ? mergedOptionsConfig.multiples.customComponent || ( - setConfig({ ...config, multiples })} - columns={columns.filter((c) => config.catColumnSelected && c.info.id !== config.catColumnSelected.id)} - currentSelected={config.multiples} - label="Multiples" - type={[EColumnTypes.CATEGORICAL]} - /> - ) - : null} - - - {mergedOptionsConfig.direction.enable - ? mergedOptionsConfig.direction.customComponent || ( - setConfig({ ...config, direction })} currentSelected={config.direction} /> - ) - : null} - {mergedOptionsConfig.filter.enable ? mergedOptionsConfig.filter.customComponent || : null} - - ); -} diff --git a/src/vis/correlation/CorrelationMatrix.tsx b/src/vis/correlation/CorrelationMatrix.tsx index de8ccd5e0..11cbe75a1 100644 --- a/src/vis/correlation/CorrelationMatrix.tsx +++ b/src/vis/correlation/CorrelationMatrix.tsx @@ -6,10 +6,11 @@ import { corrcoeff, spearmancoeff, tukeyhsd } from 'jstat'; import * as React from 'react'; import { useMemo } from 'react'; import { useAsync } from '../../hooks/useAsync'; -import { ColumnInfo, EColumnTypes, ECorrelationType, EScaleType, VisCategoricalValue, VisColumn, VisNumericalValue } from '../interfaces'; +import { ColumnInfo, EColumnTypes, EScaleType, VisCategoricalValue, VisColumn, VisNumericalValue } from '../interfaces'; import { ColorLegendVert } from '../legend/ColorLegendVert'; import { CorrelationPair, CorrelationPairProps } from './components/CorrelationPair'; -import { ICorrelationConfig, getCorrelationMatrixData } from './utils'; +import { ECorrelationType, ICorrelationConfig } from './interfaces'; +import { getCorrelationMatrixData } from './utils'; const paddingCircle = { top: 5, right: 5, bottom: 5, left: 5 }; const CIRCLE_MIN_SIZE = 4; diff --git a/src/vis/correlation/CorrelationVis.tsx b/src/vis/correlation/CorrelationVis.tsx index f9d3fd576..a1c6cc46a 100644 --- a/src/vis/correlation/CorrelationVis.tsx +++ b/src/vis/correlation/CorrelationVis.tsx @@ -1,8 +1,13 @@ import * as React from 'react'; +import { InvalidCols } from '../general/InvalidCols'; import { ICommonVisProps } from '../interfaces'; import { CorrelationMatrix } from './CorrelationMatrix'; -import { ICorrelationConfig } from './utils'; +import { ICorrelationConfig } from './interfaces'; export function CorrelationVis({ config, columns }: ICommonVisProps) { - return config.numColumnsSelected.length > 1 ? : null; + return config.numColumnsSelected.length > 1 ? ( + + ) : ( + + ); } diff --git a/src/vis/correlation/CorrelationVisSidebar.tsx b/src/vis/correlation/CorrelationVisSidebar.tsx index 0f3afc5f9..06f477ab4 100644 --- a/src/vis/correlation/CorrelationVisSidebar.tsx +++ b/src/vis/correlation/CorrelationVisSidebar.tsx @@ -1,12 +1,11 @@ import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { ActionIcon, Container, Divider, Group, NumberInput, SegmentedControl, Stack, Text, Tooltip } from '@mantine/core'; +import { ActionIcon, Group, Input, NumberInput, SegmentedControl, Text, Tooltip } from '@mantine/core'; import * as d3 from 'd3v7'; import * as React from 'react'; -import { ColumnInfo, ECorrelationType, EScaleType, ESupportedPlotlyVis, ICommonVisSideBarProps, VisColumn } from '../interfaces'; +import { ColumnInfo, EScaleType, ICommonVisSideBarProps, VisColumn } from '../interfaces'; import { NumericalColumnSelect } from '../sidebar/NumericalColumnSelect'; -import { VisTypeSelect } from '../sidebar/VisTypeSelect'; -import { ICorrelationConfig } from './utils'; +import { ECorrelationType, ICorrelationConfig } from './interfaces'; export function CorrelationVisSidebar({ config, @@ -20,98 +19,94 @@ export function CorrelationVisSidebar({ setConfig: (config: ICorrelationConfig) => void; } & ICommonVisSideBarProps) { return ( - - setConfig({ ...config, type })} currentSelected={config.type} /> - - - setConfig({ ...config, numColumnsSelected })} - columns={columns} - currentSelected={config.numColumnsSelected || []} + <> + setConfig({ ...config, numColumnsSelected })} + columns={columns} + currentSelected={config.numColumnsSelected || []} + /> + + + setConfig({ ...config, correlationType: v as ECorrelationType })} + /> + + + + setConfig({ ...config, pScaleType: v as EScaleType })} /> - - - Correlation type - - setConfig({ ...config, correlationType: v as ECorrelationType })} - /> - - P value scale type - - setConfig({ ...config, pScaleType: v as EScaleType })} - /> - { - return d3.format('.3~g')(+value); - }} - onChange={(val) => setConfig({ ...config, pDomain: [+val, config.pDomain[1]] })} - label={ - - Maximum P Value - - Sets the maximum p value for the size scale. Any p value at or above this value will have the smallest possible circle - - } - > - - - - -
- } - value={config.pDomain[0]} - /> - { - return d3.format('.3~g')(+value); - }} - onChange={(val) => setConfig({ ...config, pDomain: [config.pDomain[0], +val] })} - label={ - - Minimum P Value - - Sets the minimum p value for the size scale. Any p value at or below this value will have the largest possible circle - - } - > - - - - - - } - value={config.pDomain[1]} - /> - - - + + { + return d3.format('.3~g')(+value); + }} + onChange={(val) => setConfig({ ...config, pDomain: [+val, config.pDomain[1]] })} + label={ + + Maximum p-value + + Sets the maximum p-value for the size scale. Any p-value at or above this value will have the smallest possible circle + + } + > + + + + + + } + value={config.pDomain[0]} + /> + { + return d3.format('.3~g')(+value); + }} + onChange={(val) => setConfig({ ...config, pDomain: [config.pDomain[0], +val] })} + label={ + + Minimum p-value + + Sets the minimum p-value for the size scale. Any p-value at or below this value will have the largest possible circle + + } + > + + + + + + } + value={config.pDomain[1]} + /> + ); } diff --git a/src/vis/correlation/components/CorrelationPair.tsx b/src/vis/correlation/components/CorrelationPair.tsx index a1fbe808f..f10a4bf6a 100644 --- a/src/vis/correlation/components/CorrelationPair.tsx +++ b/src/vis/correlation/components/CorrelationPair.tsx @@ -2,7 +2,7 @@ import { Center, Stack, Text, Tooltip, useMantineTheme } from '@mantine/core'; import * as d3 from 'd3v7'; import * as React from 'react'; import { useMemo } from 'react'; -import { ICorrelationConfig } from '../utils'; +import { ICorrelationConfig } from '../interfaces'; const marginRect = { top: 0, right: 0, bottom: 0, left: 0 }; diff --git a/src/vis/correlation/interfaces.ts b/src/vis/correlation/interfaces.ts new file mode 100644 index 000000000..b92cb914d --- /dev/null +++ b/src/vis/correlation/interfaces.ts @@ -0,0 +1,18 @@ +import { BaseVisConfig, ColumnInfo, EScaleType, ESupportedPlotlyVis } from '../interfaces'; + +export interface ICorrelationConfig extends BaseVisConfig { + type: ESupportedPlotlyVis.CORRELATION; + correlationType: ECorrelationType; + numColumnsSelected: ColumnInfo[]; + pScaleType: EScaleType; + pDomain: [number, number]; +} + +export enum ECorrelationType { + PEARSON = 'Pearson', + SPEARMAN = 'Spearman', +} + +export function isCorrelationConfig(s: BaseVisConfig): s is ICorrelationConfig { + return s.type === ESupportedPlotlyVis.CORRELATION; +} diff --git a/src/vis/correlation/utils.ts b/src/vis/correlation/utils.ts index ba2385bab..5aca9a339 100644 --- a/src/vis/correlation/utils.ts +++ b/src/vis/correlation/utils.ts @@ -1,28 +1,7 @@ import merge from 'lodash/merge'; import { resolveColumnValues } from '../general/layoutUtils'; -import { - BaseVisConfig, - ColumnInfo, - EColumnTypes, - ECorrelationType, - EScaleType, - ESupportedPlotlyVis, - VisCategoricalValue, - VisColumn, - VisNumericalValue, -} from '../interfaces'; - -export interface ICorrelationConfig extends BaseVisConfig { - type: ESupportedPlotlyVis.CORRELATION; - correlationType: ECorrelationType; - numColumnsSelected: ColumnInfo[]; - pScaleType: EScaleType; - pDomain: [number, number]; -} - -export function isCorrelation(s: BaseVisConfig): s is ICorrelationConfig { - return s.type === ESupportedPlotlyVis.CORRELATION; -} +import { ColumnInfo, EColumnTypes, EScaleType, ESupportedPlotlyVis, VisCategoricalValue, VisColumn, VisNumericalValue } from '../interfaces'; +import { ECorrelationType, ICorrelationConfig } from './interfaces'; const defaultConfig: ICorrelationConfig = { type: ESupportedPlotlyVis.CORRELATION, diff --git a/src/vis/general/InvalidCols.tsx b/src/vis/general/InvalidCols.tsx index 30cc12a2e..356a6c11d 100644 --- a/src/vis/general/InvalidCols.tsx +++ b/src/vis/general/InvalidCols.tsx @@ -1,11 +1,11 @@ +import { Alert, Center, Stack, rem } from '@mantine/core'; import * as React from 'react'; -import { Alert, Center, Stack } from '@mantine/core'; export function InvalidCols({ headerMessage, bodyMessage }: { headerMessage: string; bodyMessage: string }) { return (
- + {bodyMessage}
diff --git a/src/vis/heatmap/AnimatedLine.tsx b/src/vis/heatmap/AnimatedLine.tsx index d46f536dc..ca84a230c 100644 --- a/src/vis/heatmap/AnimatedLine.tsx +++ b/src/vis/heatmap/AnimatedLine.tsx @@ -2,10 +2,24 @@ import * as React from 'react'; import { useMemo, useRef } from 'react'; import { useSpring, animated, easings } from 'react-spring'; -export function AnimatedLine({ x1, x2, y1, y2, order = 1 }: { y2: number; y1: number; x2: number; x1: number; order?: number }) { +export function AnimatedLine({ + x1, + x2, + y1, + y2, + order = 1, + setImmediate, +}: { + y2: number; + y1: number; + x2: number; + x1: number; + order?: number; + setImmediate: boolean; +}) { const myOrder = useRef(order); - const isImmediate = myOrder.current === order; + const isImmediate = setImmediate || myOrder.current === order; const spring = useSpring({ x1, y1, diff --git a/src/vis/heatmap/AnimatedText.tsx b/src/vis/heatmap/AnimatedText.tsx index 5f3f8a653..af1e74aa6 100644 --- a/src/vis/heatmap/AnimatedText.tsx +++ b/src/vis/heatmap/AnimatedText.tsx @@ -10,6 +10,7 @@ export function AnimatedText({ width, height, bold = false, + setImmediate = true, }: { x: number; y: number; @@ -18,10 +19,11 @@ export function AnimatedText({ bold?: boolean; width: number; height: number; + setImmediate?: boolean; }) { const myOrder = useRef(order); - const isImmediate = myOrder.current === order; + const isImmediate = setImmediate || myOrder.current === order; const spring = useSpring({ x, y, diff --git a/src/vis/heatmap/Heatmap.tsx b/src/vis/heatmap/Heatmap.tsx index 023f99466..dafe044b1 100644 --- a/src/vis/heatmap/Heatmap.tsx +++ b/src/vis/heatmap/Heatmap.tsx @@ -1,4 +1,4 @@ -import { faArrowUpWideShort, faArrowUpZA } from '@fortawesome/free-solid-svg-icons'; +import { faArrowDownShortWide, faArrowDownWideShort, faArrowDownAZ, faArrowDownZA } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Box, Container, Group, Stack, Text } from '@mantine/core'; import { useResizeObserver } from '@mantine/hooks'; @@ -6,12 +6,12 @@ import { desc, op, table } from 'arquero'; import * as d3 from 'd3v7'; import * as React from 'react'; import { useMemo } from 'react'; -import { rollupByAggregateType } from '../barGood/utils'; -import { ColumnInfo, EAggregateTypes, EColumnTypes, ENumericalColorScaleType, ESortTypes, VisCategoricalValue, VisNumericalValue } from '../interfaces'; +import { rollupByAggregateType } from '../bar/utils'; +import { ColumnInfo, EAggregateTypes, EColumnTypes, ENumericalColorScaleType, VisCategoricalValue, VisNumericalValue } from '../interfaces'; import { ColorLegendVert } from '../legend/ColorLegendVert'; import { HeatmapRect } from './HeatmapRect'; import { HeatmapText } from './HeatmapText'; -import { IHeatmapConfig } from './utils'; +import { ESortTypes, IHeatmapConfig } from './interfaces'; const interRectDistance = 1; @@ -42,19 +42,20 @@ export function Heatmap({ }) { const [ref, { width, height }] = useResizeObserver(); - const aggregatedTable = useMemo(() => { + const baseTable = useMemo(() => { if (!column1 || !column2) return null; - let valueTable = table({ + return table({ xVal: column1.resolvedValues.map(({ val }) => val), yVal: column2.resolvedValues.map(({ val }) => val), - aggregateValues: aggregateColumn?.resolvedValues.map(({ val }) => val) || [], + aggregateVal: aggregateColumn?.resolvedValues.map(({ val }) => val) || [], id: column1.resolvedValues.map(({ id }) => id), }); + }, [aggregateColumn?.resolvedValues, column1, column2]); + const aggregatedTable = useMemo(() => { + if (!baseTable) return null; - valueTable = valueTable.groupby('xVal', 'yVal'); - - valueTable = rollupByAggregateType(valueTable, config.aggregateType); + let valueTable = rollupByAggregateType(baseTable.groupby('xVal', 'yVal'), config.aggregateType); if (config.aggregateType === EAggregateTypes.COUNT) { valueTable = valueTable.impute({ aggregateVal: () => 0 }, { expand: ['xVal', 'yVal'] }); @@ -68,14 +69,43 @@ export function Heatmap({ .groupby('yVal') .derive({ rowTotal: op.sum('aggregateVal') }); - if (config.sortedBy === ESortTypes.COUNT_ASC) { - valueTable = valueTable.orderby('colTotal', desc('rowTotal')); - } else { - valueTable = valueTable.orderby('xVal', 'yVal'); + // default is ESortTypes.CAT_ASC + let xOrder: string | object; + switch (config.xSortedBy) { + case ESortTypes.VAL_ASC: + xOrder = 'colTotal'; + break; + case ESortTypes.CAT_DESC: + xOrder = desc('xVal'); + break; + case ESortTypes.VAL_DESC: + xOrder = desc('colTotal'); + break; + default: + xOrder = 'xVal'; + break; } + // default is ESortTypes.CAT_ASC + let yOrder: string | object; + switch (config.ySortedBy) { + case ESortTypes.VAL_ASC: + yOrder = 'rowTotal'; + break; + case ESortTypes.CAT_DESC: + yOrder = desc('yVal'); + break; + case ESortTypes.VAL_DESC: + yOrder = desc('rowTotal'); + break; + default: + yOrder = 'yVal'; + break; + } + valueTable = valueTable.orderby(xOrder, yOrder); + return valueTable; - }, [aggregateColumn?.resolvedValues, column1, column2, config.aggregateType, config.sortedBy]); + }, [baseTable, config.aggregateType, config.xSortedBy, config.ySortedBy]); const { groupedValues, rectHeight, rectWidth, yScale, xScale, colorScale } = React.useMemo(() => { const groupedVals = aggregatedTable.objects() as { xVal: string; yVal: string; aggregateVal: number; ids: string[] }[]; @@ -149,7 +179,13 @@ export function Heatmap({ const rects = useMemo(() => { if (width === 0 || height === 0) return null; return groupedValues.map((d, i) => { - const { aggregateVal, ids, x, y, xVal, yVal, color } = d; + const { aggregateVal, x, y, xVal, yVal, color } = d; + const ids: string[] = Array.from( + baseTable + .params({ x: xVal, y: yVal }) + .filter((b, $) => b.xVal === $.x && b.yVal === $.y) + .values('id'), + ); return ( selectionCallback(ids)} + isImmediate={!config.isAnimationEnabled} /> ); }); - }, [groupedValues, height, rectHeight, rectWidth, selected, selectionCallback, width, xScale, yScale]); + }, [baseTable, groupedValues, height, rectHeight, rectWidth, selected, selectionCallback, width, xScale, yScale, config.isAnimationEnabled]); const text = useMemo(() => { if (width === 0 || height === 0) return null; - return ; - }, [height, margin, rectHeight, rectWidth, width, xScale, yScale]); + return ( + + ); + }, [height, margin, rectHeight, rectWidth, width, xScale, yScale, config.isAnimationEnabled]); return ( @@ -188,13 +236,33 @@ export function Heatmap({ setExternalConfig({ ...config, sortedBy: config.sortedBy === ESortTypes.CAT_ASC ? ESortTypes.COUNT_ASC : ESortTypes.CAT_ASC })} + onClick={() => + setExternalConfig({ + ...config, + ySortedBy: + config.ySortedBy === ESortTypes.CAT_ASC + ? ESortTypes.CAT_DESC + : config.ySortedBy === ESortTypes.CAT_DESC + ? ESortTypes.VAL_ASC + : config.ySortedBy === ESortTypes.VAL_ASC + ? ESortTypes.VAL_DESC + : ESortTypes.CAT_ASC, + }) + } > {column2.info.name} @@ -219,9 +287,33 @@ export function Heatmap({ setExternalConfig({ ...config, sortedBy: config.sortedBy === ESortTypes.CAT_ASC ? ESortTypes.COUNT_ASC : ESortTypes.CAT_ASC })} + onClick={() => + setExternalConfig({ + ...config, + xSortedBy: + config.xSortedBy === ESortTypes.CAT_ASC + ? ESortTypes.CAT_DESC + : config.xSortedBy === ESortTypes.CAT_DESC + ? ESortTypes.VAL_ASC + : config.xSortedBy === ESortTypes.VAL_ASC + ? ESortTypes.VAL_DESC + : ESortTypes.CAT_ASC, + }) + } > - + {column1.info.name} diff --git a/src/vis/heatmap/HeatmapGrid.tsx b/src/vis/heatmap/HeatmapGrid.tsx index 2d6aae150..05af2e414 100644 --- a/src/vis/heatmap/HeatmapGrid.tsx +++ b/src/vis/heatmap/HeatmapGrid.tsx @@ -1,9 +1,11 @@ -import { Loader, Stack, Text } from '@mantine/core'; +import { Loader, Stack } from '@mantine/core'; import * as React from 'react'; import { useAsync } from '../../hooks/useAsync'; +import { InvalidCols } from '../general/InvalidCols'; import { VisColumn } from '../interfaces'; import { Heatmap } from './Heatmap'; -import { IHeatmapConfig, getHeatmapData } from './utils'; +import { IHeatmapConfig } from './interfaces'; +import { getHeatmapData } from './utils'; export function HeatmapGrid({ config, @@ -35,9 +37,7 @@ export function HeatmapGrid({ {status === 'pending' ? ( ) : !hasAtLeast2CatCols ? ( - - Select at least 2 categorical columns to display heatmap - + ) : ( null, }: { x: number; @@ -28,13 +29,14 @@ export function HeatmapRect({ xOrder?: number; yOrder?: number; isSelected?: boolean; + isImmediate?: boolean; onClick?: (e: any) => void; }) { const [isHovered, setIsHovered] = useState(); const currXOrder = useRef(xOrder); const currYOrder = useRef(yOrder); - const isImmediate = currXOrder.current === xOrder && currYOrder.current === yOrder; + isImmediate = isImmediate || (currXOrder.current === xOrder && currYOrder.current === yOrder); const colorSpring = useSpring({ fill: color, config: { duration: 750, easing: easings.easeInOutSine } }); diff --git a/src/vis/heatmap/HeatmapText.tsx b/src/vis/heatmap/HeatmapText.tsx index cdb26248e..37744f1e7 100644 --- a/src/vis/heatmap/HeatmapText.tsx +++ b/src/vis/heatmap/HeatmapText.tsx @@ -14,6 +14,7 @@ export function HeatmapText({ rectHeight, height, rectWidth, + isImmediate, }: { margin: { top: number; right: number; bottom: number; left: number }; yScale: d3.ScaleBand; @@ -22,6 +23,7 @@ export function HeatmapText({ height: number; rectHeight: number; rectWidth: number; + isImmediate: boolean; }) { const labelSpacing = useMemo(() => { const maxLabelLength = d3.max(yScale.domain().map((m) => m.length)); @@ -39,6 +41,7 @@ export function HeatmapText({ y1={margin.top} y2={height - margin.bottom} order={1 - i / xScale.domain().length} + setImmediate={isImmediate} /> @@ -70,6 +75,7 @@ export function HeatmapText({ y1={yScale(yVal) + rectHeight + margin.top} y2={yScale(yVal) + rectHeight + margin.top} order={i / yScale.domain().length} + setImmediate={isImmediate} /> - + diff --git a/src/vis/heatmap/HeatmapVis.tsx b/src/vis/heatmap/HeatmapVis.tsx index ae9fd1644..f9eb0b73e 100644 --- a/src/vis/heatmap/HeatmapVis.tsx +++ b/src/vis/heatmap/HeatmapVis.tsx @@ -1,9 +1,8 @@ import { Group } from '@mantine/core'; import * as React from 'react'; -import { VisSidebarOpenButton } from '../VisSidebarOpenButton'; import { ICommonVisProps } from '../interfaces'; import { HeatmapGrid } from './HeatmapGrid'; -import { IHeatmapConfig } from './utils'; +import { IHeatmapConfig } from './interfaces'; export function HeatmapVis({ config, @@ -17,7 +16,6 @@ export function HeatmapVis({ }: ICommonVisProps) { return ( - {enableSidebar ? setShowSidebar(!showSidebar)} isOpen={showSidebar} /> : null} ); diff --git a/src/vis/heatmap/HeatmapVisSidebar.tsx b/src/vis/heatmap/HeatmapVisSidebar.tsx index d7083df1f..87c668d13 100644 --- a/src/vis/heatmap/HeatmapVisSidebar.tsx +++ b/src/vis/heatmap/HeatmapVisSidebar.tsx @@ -1,11 +1,11 @@ -import { Container, Stack } from '@mantine/core'; import * as React from 'react'; -import { ColumnInfo, EAggregateTypes, EColumnTypes, ESupportedPlotlyVis, VisColumn } from '../interfaces'; +import { Switch } from '@mantine/core'; +import { ColumnInfo, EAggregateTypes, EColumnTypes, VisColumn } from '../interfaces'; import { AggregateTypeSelect } from '../sidebar/AggregateTypeSelect'; import { CategoricalColumnSelect } from '../sidebar/CategoricalColumnSelect'; import { NumericalColorButtons } from '../sidebar/NumericalColorButtons'; -import { VisTypeSelect } from '../sidebar/VisTypeSelect'; -import { IHeatmapConfig } from './utils'; +import { IHeatmapConfig } from './interfaces'; +import { i18n } from '../../i18n'; export function HeatmapVisSidebar({ config, @@ -17,35 +17,38 @@ export function HeatmapVisSidebar({ setConfig: (config: IHeatmapConfig) => void; }) { return ( - - - setConfig({ ...(config as any), type })} currentSelected={config.type} /> - setConfig({ ...config, catColumnsSelected })} - columns={columns} - currentSelected={config.catColumnsSelected || []} - /> - {config?.catColumnsSelected?.length > 1 ? ( - setConfig({ ...config, numColorScaleType })} currentSelected={config.numColorScaleType} /> - ) : null} - { - if (config.aggregateColumn === null) { - setConfig({ - ...config, - aggregateType, - aggregateColumn: columns.find((col) => col.type === EColumnTypes.NUMERICAL).info, - }); - } else { - setConfig({ ...config, aggregateType }); - } - }} - aggregateColumnSelectCallback={(aggregateColumn: ColumnInfo) => setConfig({ ...config, aggregateColumn })} - columns={columns} - currentSelected={config.aggregateType} - aggregateColumn={config.aggregateColumn} - /> - - + <> + setConfig({ ...config, catColumnsSelected })} + columns={columns} + currentSelected={config.catColumnsSelected || []} + /> + {config?.catColumnsSelected?.length > 1 ? ( + setConfig({ ...config, numColorScaleType })} currentSelected={config.numColorScaleType} /> + ) : null} + { + if (config.aggregateColumn === null) { + setConfig({ + ...config, + aggregateType, + aggregateColumn: columns.find((col) => col.type === EColumnTypes.NUMERICAL).info, + }); + } else { + setConfig({ ...config, aggregateType }); + } + }} + aggregateColumnSelectCallback={(aggregateColumn: ColumnInfo) => setConfig({ ...config, aggregateColumn })} + columns={columns} + currentSelected={config.aggregateType} + aggregateColumn={config.aggregateColumn} + /> + {/* Disabled until the animations are fixed. By default animations are disabled */} + {/* setConfig({ ...config, isAnimationEnabled: event.currentTarget.checked })} + label={i18n.t('visyn:vis.animation')} + /> */} + ); } diff --git a/src/vis/heatmap/interfaces.ts b/src/vis/heatmap/interfaces.ts new file mode 100644 index 000000000..586e2f738 --- /dev/null +++ b/src/vis/heatmap/interfaces.ts @@ -0,0 +1,24 @@ +import { BaseVisConfig, ColumnInfo, EAggregateTypes, ENumericalColorScaleType, ESupportedPlotlyVis } from '../interfaces'; + +export interface IHeatmapConfig { + type: ESupportedPlotlyVis.HEATMAP; + color: ColumnInfo | null; + catColumnsSelected: ColumnInfo[]; + numColorScaleType: ENumericalColorScaleType; + xSortedBy: ESortTypes; + ySortedBy: ESortTypes; + aggregateType: EAggregateTypes; + aggregateColumn: ColumnInfo | null; + isAnimationEnabled: boolean; +} + +export enum ESortTypes { + CAT_ASC = 'CAT_ASC', + CAT_DESC = 'CAT_DESC', + VAL_ASC = 'VAL_ASC', + VAL_DESC = 'VAL_DESC', +} + +export function isHeatmapConfig(vis: BaseVisConfig): vis is IHeatmapConfig { + return vis.type === ESupportedPlotlyVis.HEATMAP; +} diff --git a/src/vis/heatmap/utils.ts b/src/vis/heatmap/utils.ts index f62543690..3109564a3 100644 --- a/src/vis/heatmap/utils.ts +++ b/src/vis/heatmap/utils.ts @@ -1,40 +1,27 @@ import merge from 'lodash/merge'; import { resolveColumnValues, resolveSingleColumn } from '../general/layoutUtils'; import { - BaseVisConfig, ColumnInfo, EAggregateTypes, EColumnTypes, ENumericalColorScaleType, - ESortTypes, ESupportedPlotlyVis, VisCategoricalValue, VisColumn, VisNumericalValue, } from '../interfaces'; - -export interface IHeatmapConfig { - type: ESupportedPlotlyVis.HEATMAP; - color: ColumnInfo | null; - catColumnsSelected: ColumnInfo[]; - numColorScaleType: ENumericalColorScaleType; - sortedBy: ESortTypes; - aggregateType: EAggregateTypes; - aggregateColumn: ColumnInfo | null; -} - -export function isHeatmap(vis: BaseVisConfig): vis is IHeatmapConfig { - return vis.type === ESupportedPlotlyVis.HEATMAP; -} +import { ESortTypes, IHeatmapConfig } from './interfaces'; const defaultConfig: IHeatmapConfig = { type: ESupportedPlotlyVis.HEATMAP, color: null, catColumnsSelected: [], - numColorScaleType: null, - sortedBy: ESortTypes.CAT_ASC, + numColorScaleType: ENumericalColorScaleType.SEQUENTIAL, + xSortedBy: ESortTypes.CAT_ASC, + ySortedBy: ESortTypes.CAT_ASC, aggregateColumn: null, aggregateType: EAggregateTypes.COUNT, + isAnimationEnabled: false, }; export function heatmapMergeDefaultConfig(columns: VisColumn[], config: IHeatmapConfig): IHeatmapConfig { diff --git a/src/vis/sidebar/HexOpacitySwitch.tsx b/src/vis/hexbin/HexOpacitySwitch.tsx similarity index 100% rename from src/vis/sidebar/HexOpacitySwitch.tsx rename to src/vis/hexbin/HexOpacitySwitch.tsx diff --git a/src/vis/hexbin/HexSizeSlider.tsx b/src/vis/hexbin/HexSizeSlider.tsx new file mode 100644 index 000000000..ba0692af4 --- /dev/null +++ b/src/vis/hexbin/HexSizeSlider.tsx @@ -0,0 +1,37 @@ +import { Input, Slider } from '@mantine/core'; +import debounce from 'lodash/debounce'; +import * as React from 'react'; +import { useMemo } from 'react'; +import { useSyncedRef } from '../../hooks'; + +interface OpacitySliderProps { + callback: (n: number) => void; + currentValue: number; +} + +export function HexSizeSlider({ callback, currentValue }: OpacitySliderProps) { + const syncedCallback = useSyncedRef(callback); + + const debouncedCallback = useMemo(() => { + return debounce((n: number) => syncedCallback.current?.(n), 10); + }, [syncedCallback]); + + return ( + + { + debouncedCallback(n); + }} + /> + + ); +} diff --git a/src/vis/sidebar/HexSizeSwitch.tsx b/src/vis/hexbin/HexSizeSwitch.tsx similarity index 100% rename from src/vis/sidebar/HexSizeSwitch.tsx rename to src/vis/hexbin/HexSizeSwitch.tsx diff --git a/src/vis/sidebar/HexbinOptionSelect.tsx b/src/vis/hexbin/HexbinOptionSelect.tsx similarity index 93% rename from src/vis/sidebar/HexbinOptionSelect.tsx rename to src/vis/hexbin/HexbinOptionSelect.tsx index 5b3d52187..aa9bfeca9 100644 --- a/src/vis/sidebar/HexbinOptionSelect.tsx +++ b/src/vis/hexbin/HexbinOptionSelect.tsx @@ -1,7 +1,7 @@ import { Select } from '@mantine/core'; import * as React from 'react'; import { i18n } from '../../i18n'; -import { EHexbinOptions } from '../interfaces'; +import { EHexbinOptions } from './interfaces'; interface HexbinOptionSelectProps { callback: (c: EHexbinOptions) => void; diff --git a/src/vis/hexbin/HexbinVis.tsx b/src/vis/hexbin/HexbinVis.tsx index 7a37378ef..ddbaf2426 100644 --- a/src/vis/hexbin/HexbinVis.tsx +++ b/src/vis/hexbin/HexbinVis.tsx @@ -1,36 +1,102 @@ -import { Center, Group, SimpleGrid, Stack } from '@mantine/core'; -import merge from 'lodash/merge'; +import { Box, Center, Chip, Group, ScrollArea, Stack, Tooltip, rem } from '@mantine/core'; +import * as d3v7 from 'd3v7'; import * as React from 'react'; -import { useMemo } from 'react'; +import { useAsync } from '../../hooks/useAsync'; import { i18n } from '../../i18n'; import { InvalidCols } from '../general'; import { EScatterSelectSettings, ICommonVisProps } from '../interfaces'; import { BrushOptionButtons } from '../sidebar'; import { Hexplot } from './Hexplot'; -import { IHexbinConfig } from './utils'; +import { IHexbinConfig } from './interfaces'; +import { getHexData } from './utils'; -const defaultExtensions = { - prePlot: null, - postPlot: null, - preSidebar: null, - postSidebar: null, -}; +function Legend({ + categories, + filteredCategories, + colorScale, + onClick, + height, +}: { + categories: string[]; + filteredCategories: string[]; + colorScale: d3v7.ScaleOrdinal; + onClick: (string) => void; + height: number; +}) { + return ( + + + {categories.map((c) => { + return ( + + + onClick(c)} + checked={false} + styles={{ + label: { + width: '100%', + backgroundColor: filteredCategories.includes(c) ? 'lightgrey' : `${colorScale(c)} !important`, + textAlign: 'center', + paddingLeft: '10px', + paddingRight: '10px', + overflow: 'hidden', + color: filteredCategories.includes(c) ? 'black' : 'white', + textOverflow: 'ellipsis', + }, + }} + > + {c} + + + + ); + })} + + + ); +} export function HexbinVis({ config, - extensions, columns, + dimensions, setConfig, selectionCallback = () => null, selectedMap = {}, showDragModeOptions = true, }: ICommonVisProps) { - const mergedExtensions = useMemo(() => { - return merge({}, defaultExtensions, extensions); - }, [extensions]); + const { width, height } = dimensions; + const { value: allColumns, status: colsStatus } = useAsync(getHexData, [columns, config.numColumnsSelected, config.color]); + + const [filteredCategories, setFilteredCategories] = React.useState([]); + + const currentColorColumn = React.useMemo(() => { + if (config.color && allColumns?.colorColVals) { + return { + allValues: allColumns.colorColVals.resolvedValues, + filteredValues: allColumns.colorColVals.resolvedValues.filter((val) => !filteredCategories.includes(val.val as string)), + }; + } + + return null; + }, [allColumns?.colorColVals, config.color, filteredCategories]); + + const colorScale = React.useMemo(() => { + if (!currentColorColumn?.allValues) { + return null; + } + + const colorOptions = currentColorColumn.allValues.map((val) => val.val as string); + + return d3v7 + .scaleOrdinal(allColumns.colorColVals.color ? Object.keys(allColumns.colorColVals.color) : d3v7.schemeCategory10) + .domain(allColumns.colorColVals.color ? Object.values(allColumns.colorColVals.color) : Array.from(new Set(colorOptions))); + }, [currentColorColumn, allColumns]); return ( - + {showDragModeOptions ? (
@@ -42,13 +108,33 @@ export function HexbinVis({
) : null} - 2 ? config.numColumnsSelected.length : 1}> - {config.numColumnsSelected.length < 2 ? ( - - ) : ( - <> - {config.numColumnsSelected.length > 2 ? ( - config.numColumnsSelected.map((xCol) => { + + 2 + ? { gridTemplateColumns: 'repeat(3, minmax(0, 1fr))', gridTemplateRows: 'repeat(3, minmax(0, 1fr))', gap: '1rem 1rem' } + : { gridTemplateColumns: 'repeat(1, minmax(0, 1fr))', gridTemplateRows: 'repeat(1, minmax(0, 1fr))', gap: '1rem 1rem' }), + }} + > + {config.numColumnsSelected.length < 2 ? ( + + ) : null} + + {config.numColumnsSelected.length === 2 && allColumns?.numColVals.length === config.numColumnsSelected.length && colsStatus === 'success' ? ( + + ) : null} + {config.numColumnsSelected.length > 2 && allColumns?.numColVals.length === config.numColumnsSelected.length && colsStatus === 'success' + ? config.numColumnsSelected.map((xCol) => { return config.numColumnsSelected.map((yCol) => { if (xCol.id !== yCol.id) { return ( @@ -57,11 +143,14 @@ export function HexbinVis({ selectionCallback={selectionCallback} selected={selectedMap} config={config} - columns={[ - columns.find((col) => col.info.id === yCol.id), - columns.find((col) => col.info.id === xCol.id), - columns.find((col) => col.info.id === config.color?.id), - ]} + filteredCategories={filteredCategories} + allColumns={{ + numColVals: [ + allColumns.numColVals.find((col) => col.info.id === yCol.id), + allColumns.numColVals.find((col) => col.info.id === xCol.id), + ], + colorColVals: allColumns.colorColVals, + }} /> ); } @@ -69,22 +158,24 @@ export function HexbinVis({ return
; }); }) - ) : ( - col.info.id === config.numColumnsSelected[0].id), - columns.find((col) => col.info.id === config.numColumnsSelected[1].id), - columns.find((col) => col.info.id === config.color?.id), - ]} - /> - )} - {mergedExtensions.postPlot} - - )} - + : null} + + {currentColorColumn ? ( +
+ + filteredCategories.includes(s) + ? setFilteredCategories(filteredCategories.filter((f) => f !== s)) + : setFilteredCategories([...filteredCategories, s]) + } + height={height - 100} + /> +
+ ) : null} + ); } diff --git a/src/vis/hexbin/HexbinVisSidebar.tsx b/src/vis/hexbin/HexbinVisSidebar.tsx index 0f50be88f..6d973f726 100644 --- a/src/vis/hexbin/HexbinVisSidebar.tsx +++ b/src/vis/hexbin/HexbinVisSidebar.tsx @@ -1,45 +1,35 @@ -import { Container, Divider, Stack } from '@mantine/core'; import * as React from 'react'; -import { ColumnInfo, EColumnTypes, EHexbinOptions, ESupportedPlotlyVis, ICommonVisSideBarProps } from '../interfaces'; +import { ColumnInfo, EColumnTypes, ICommonVisSideBarProps } from '../interfaces'; import { NumericalColumnSelect } from '../sidebar'; -import { HexOpacitySwitch } from '../sidebar/HexOpacitySwitch'; -import { HexSizeSlider } from '../sidebar/HexSizeSlider'; -import { HexSizeSwitch } from '../sidebar/HexSizeSwitch'; -import { HexbinOptionSelect } from '../sidebar/HexbinOptionSelect'; import { SingleColumnSelect } from '../sidebar/SingleColumnSelect'; -import { VisTypeSelect } from '../sidebar/VisTypeSelect'; -import { IHexbinConfig } from './utils'; +import { HexOpacitySwitch } from './HexOpacitySwitch'; +import { HexSizeSlider } from './HexSizeSlider'; +import { HexSizeSwitch } from './HexSizeSwitch'; +import { HexbinOptionSelect } from './HexbinOptionSelect'; +import { EHexbinOptions, IHexbinConfig } from './interfaces'; export function HexbinVisSidebar({ config, columns, setConfig }: ICommonVisSideBarProps) { return ( - - - setConfig({ ...(config as any), type })} currentSelected={config.type} /> - - - setConfig({ ...config, numColumnsSelected })} - columns={columns} - currentSelected={config.numColumnsSelected || []} - /> - setConfig({ ...config, color })} - columns={columns} - currentSelected={config.color} - /> - {config.color ? ( - setConfig({ ...config, hexbinOptions })} currentSelected={config.hexbinOptions} /> - ) : null} - - - - setConfig({ ...config, hexRadius })} /> - setConfig({ ...config, isSizeScale })} /> - setConfig({ ...config, isOpacityScale })} /> - - - + <> + setConfig({ ...config, numColumnsSelected })} + columns={columns} + currentSelected={config.numColumnsSelected || []} + /> + setConfig({ ...config, color })} + columns={columns} + currentSelected={config.color} + /> + {config.color ? ( + setConfig({ ...config, hexbinOptions })} currentSelected={config.hexbinOptions} /> + ) : null} + + setConfig({ ...config, hexRadius })} /> + setConfig({ ...config, isSizeScale })} /> + setConfig({ ...config, isOpacityScale })} /> + ); } diff --git a/src/vis/hexbin/Hexplot.tsx b/src/vis/hexbin/Hexplot.tsx index 9100421a5..ed3bfe64b 100644 --- a/src/vis/hexbin/Hexplot.tsx +++ b/src/vis/hexbin/Hexplot.tsx @@ -1,4 +1,5 @@ import { Box, Chip, Container, ScrollArea, Stack, Tooltip } from '@mantine/core'; +import { useElementSize } from '@mantine/hooks'; import * as hex from 'd3-hexbin'; import { HexbinBin } from 'd3-hexbin'; import * as d3v7 from 'd3v7'; @@ -6,87 +7,35 @@ import { D3BrushEvent, D3ZoomEvent } from 'd3v7'; import uniqueId from 'lodash/uniqueId'; import * as React from 'react'; import { useEffect, useMemo, useRef, useState } from 'react'; -import { useAsync } from '../../hooks/useAsync'; -import { EScatterSelectSettings, VisColumn } from '../interfaces'; +import { EScatterSelectSettings } from '../interfaces'; import { SingleHex } from './SingleHex'; import { XAxis } from './XAxis'; import { YAxis } from './YAxis'; -import { IHexbinConfig, getHexData } from './utils'; +import { IHexbinConfig } from './interfaces'; +import { ResolvedHexValues } from './utils'; interface HexagonalBinProps { config: IHexbinConfig; - columns: VisColumn[]; + allColumns: ResolvedHexValues; selectionCallback?: (ids: string[]) => void; selected?: { [key: string]: boolean }; -} - -function Legend({ - categories, - filteredCategories, - colorScale, - onClick, - height, -}: { - categories: string[]; filteredCategories: string[]; - colorScale: d3v7.ScaleOrdinal; - onClick: (string) => void; - height: number; -}) { - return ( - - - {categories.map((c) => { - return ( - - - onClick(c)} - checked={false} - styles={{ - label: { - width: '100%', - backgroundColor: filteredCategories.includes(c) ? 'lightgrey' : `${colorScale(c)} !important`, - textAlign: 'center', - paddingLeft: '10px', - paddingRight: '10px', - overflow: 'hidden', - color: filteredCategories.includes(c) ? 'black' : 'white', - textOverflow: 'ellipsis', - }, - }} - > - {c} - - - - ); - })} - - - ); } -export function Hexplot({ config, columns, selectionCallback = () => null, selected = {} }: HexagonalBinProps) { - const ref = useRef(null); - const [height, setHeight] = useState(0); - const [width, setWidth] = useState(0); +export function Hexplot({ config, allColumns, selectionCallback = () => null, selected = {}, filteredCategories }: HexagonalBinProps) { + const { ref: hexRef, width: realWidth, height: realHeight } = useElementSize(); + const xZoomedScale = useRef>(null); const yZoomedScale = useRef>(null); const [xZoomTransform, setXZoomTransform] = useState(0); const [yZoomTransform, setYZoomTransform] = useState(0); const [zoomScale, setZoomScale] = useState(1); - const [filteredCategories, setFilteredCategories] = useState([]); - - const { value: allColumns, status: colsStatus } = useAsync(getHexData, [columns, config.numColumnsSelected, config.color]); - const id = React.useMemo(() => uniqueId('HexPlot'), []); // getting current categorical column values, original and filtered const currentColorColumn = useMemo(() => { - if (colsStatus === 'success' && config.color && allColumns.colorColVals) { + if (config.color && allColumns.colorColVals) { return { allValues: allColumns.colorColVals.resolvedValues, filteredValues: allColumns.colorColVals.resolvedValues.filter((val) => !filteredCategories.includes(val.val as string)), @@ -94,20 +43,23 @@ export function Hexplot({ config, columns, selectionCallback = () => null, selec } return null; - }, [allColumns?.colorColVals, config.color, colsStatus, filteredCategories]); + }, [allColumns?.colorColVals, config.color, filteredCategories]); const margin = useMemo(() => { return { - left: 52, - right: config.color ? 80 : 25, - top: 50, - bottom: 53, + left: 48, + right: 16, + top: 48, + bottom: 48, }; - }, [config.color]); + }, []); + + const height = realHeight - margin.top - margin.bottom; + const width = realWidth - margin.left - margin.right; // getting currentX data values, both original and filtered. const currentX = useMemo(() => { - if (colsStatus === 'success' && allColumns) { + if (allColumns) { if (config.color && allColumns.colorColVals) { return { allValues: allColumns.numColVals[0].resolvedValues, @@ -123,11 +75,11 @@ export function Hexplot({ config, columns, selectionCallback = () => null, selec } return null; - }, [allColumns, config.color, colsStatus, filteredCategories]); + }, [allColumns, config.color, filteredCategories]); // getting currentY data values, both original and filtered. const currentY = useMemo(() => { - if (colsStatus === 'success' && allColumns) { + if (allColumns) { if (config.color && allColumns.colorColVals) { return { allValues: allColumns.numColVals[1].resolvedValues, @@ -143,23 +95,7 @@ export function Hexplot({ config, columns, selectionCallback = () => null, selec } return null; - }, [allColumns, colsStatus, config.color, filteredCategories]); - - // resize observer for setting size of the svg and updating on size change - useEffect(() => { - const ro = new ResizeObserver((entries: ResizeObserverEntry[]) => { - setHeight(entries[0].contentRect.height - margin.top - margin.bottom); - setWidth(entries[0].contentRect.width - margin.left - margin.right); - }); - - if (ref) { - ro.observe(ref.current); - } - - return () => { - ro.disconnect(); - }; - }, [margin]); + }, [allColumns, config.color, filteredCategories]); // create x scale const xScale = useMemo(() => { @@ -230,32 +166,28 @@ export function Hexplot({ config, columns, selectionCallback = () => null, selec // simple radius scale for the hexes const radiusScale = useMemo(() => { - if (colsStatus === 'success') { - const [min, max] = d3v7.extent(hexes, (h) => h.length); + const [min, max] = d3v7.extent(hexes, (h) => h.length); - return d3v7 - .scaleLinear() - .domain([min, max]) - .range([config.hexRadius / 2, config.hexRadius]); - } + return d3v7 + .scaleLinear() + .domain([min, max]) + .range([config.hexRadius / 2, config.hexRadius]); return null; - }, [colsStatus, hexes, config.hexRadius]); + }, [hexes, config.hexRadius]); // simple opacity scale for the hexes const opacityScale = useMemo(() => { - if (colsStatus === 'success') { - const [min, max] = d3v7.extent(hexes, (h) => h.length); + const [min, max] = d3v7.extent(hexes, (h) => h.length); - return d3v7.scaleLinear().domain([min, max]).range([0.1, 1]); - } + return d3v7.scaleLinear().domain([min, max]).range([0.1, 1]); return null; - }, [colsStatus, hexes]); + }, [hexes]); // Create a default color scale const colorScale = useMemo(() => { - if (colsStatus !== 'success' || !currentColorColumn?.allValues) { + if (!currentColorColumn?.allValues) { return null; } @@ -264,7 +196,7 @@ export function Hexplot({ config, columns, selectionCallback = () => null, selec return d3v7 .scaleOrdinal(allColumns.colorColVals.color ? Object.keys(allColumns.colorColVals.color) : d3v7.schemeCategory10) .domain(allColumns.colorColVals.color ? Object.values(allColumns.colorColVals.color) : Array.from(new Set(colorOptions))); - }, [allColumns, colsStatus, currentColorColumn]); + }, [allColumns, currentColorColumn]); // memoize the actual hexes since they do not need to change on zoom/drag const hexObjects = React.useMemo(() => { @@ -381,7 +313,7 @@ export function Hexplot({ config, columns, selectionCallback = () => null, selec }, [width, height, id, hexes, selectionCallback, config.dragMode, xScale, yScale, margin]); return ( - + null, selec pointerEvents={config.dragMode === EScatterSelectSettings.PAN ? 'auto' : 'none'} /> -
- - filteredCategories.includes(s) - ? setFilteredCategories(filteredCategories.filter((f) => f !== s)) - : setFilteredCategories([...filteredCategories, s]) - } - height={200} - /> -
); diff --git a/src/vis/hexbin/SingleHex.tsx b/src/vis/hexbin/SingleHex.tsx index 1fc703023..2fe25fc7a 100644 --- a/src/vis/hexbin/SingleHex.tsx +++ b/src/vis/hexbin/SingleHex.tsx @@ -4,7 +4,7 @@ import * as d3v7 from 'd3v7'; import { useMemo } from 'react'; import { PieChart } from './PieChart'; import { cutHex } from './utils'; -import { EHexbinOptions } from '../interfaces'; +import { EHexbinOptions } from './interfaces'; export interface SingleHexProps { hexbinOption: EHexbinOptions; diff --git a/src/vis/hexbin/interfaces.ts b/src/vis/hexbin/interfaces.ts new file mode 100644 index 000000000..976d29154 --- /dev/null +++ b/src/vis/hexbin/interfaces.ts @@ -0,0 +1,22 @@ +import { BaseVisConfig, ColumnInfo, EScatterSelectSettings, ESupportedPlotlyVis } from '../interfaces'; + +export interface IHexbinConfig extends BaseVisConfig { + type: ESupportedPlotlyVis.HEXBIN; + numColumnsSelected: ColumnInfo[]; + color: ColumnInfo | null; + hexRadius: number; + isOpacityScale: boolean; + isSizeScale: boolean; + dragMode: EScatterSelectSettings; + hexbinOptions: EHexbinOptions; +} + +export enum EHexbinOptions { + COLOR = 'Color', + PIE = 'Pie', + BINS = 'Bins', +} + +export function isHexbinConfig(vis: BaseVisConfig): vis is IHexbinConfig { + return vis.type === ESupportedPlotlyVis.HEXBIN; +} diff --git a/src/vis/hexbin/utils.tsx b/src/vis/hexbin/utils.tsx index 606f9d738..32f73f8e1 100644 --- a/src/vis/hexbin/utils.tsx +++ b/src/vis/hexbin/utils.tsx @@ -1,10 +1,8 @@ import merge from 'lodash/merge'; import { resolveColumnValues, resolveSingleColumn } from '../general/layoutUtils'; import { - BaseVisConfig, ColumnInfo, EColumnTypes, - EHexbinOptions, EScatterSelectSettings, ESupportedPlotlyVis, VisCategoricalValue, @@ -12,17 +10,7 @@ import { VisNumericalColumn, VisNumericalValue, } from '../interfaces'; - -export interface IHexbinConfig extends BaseVisConfig { - type: ESupportedPlotlyVis.HEXBIN; - numColumnsSelected: ColumnInfo[]; - color: ColumnInfo | null; - hexRadius: number; - isOpacityScale: boolean; - isSizeScale: boolean; - dragMode: EScatterSelectSettings; - hexbinOptions: EHexbinOptions; -} +import { EHexbinOptions, IHexbinConfig } from './interfaces'; export const defaultDensityConfig: IHexbinConfig = { type: ESupportedPlotlyVis.HEXBIN, @@ -52,11 +40,7 @@ export function hexinbMergeDefaultConfig(columns: VisColumn[], config: IHexbinCo return merged; } -export async function getHexData( - columns: VisColumn[], - numColumnsSelected: ColumnInfo[], - colorColumn: ColumnInfo | null, -): Promise<{ +export type ResolvedHexValues = { numColVals: { resolvedValues: (VisNumericalValue | VisCategoricalValue)[]; type: EColumnTypes.NUMERICAL | EColumnTypes.CATEGORICAL; @@ -68,8 +52,10 @@ export async function getHexData( color?: Record; info: ColumnInfo; }; -}> { - const numCols: VisNumericalColumn[] = [columns[0] as VisNumericalColumn, columns[1] as VisNumericalColumn]; +}; + +export async function getHexData(columns: VisColumn[], numColumnsSelected: ColumnInfo[], colorColumn: ColumnInfo | null): Promise { + const numCols: VisNumericalColumn[] = columns.filter((col) => numColumnsSelected.find((e) => e.id === col.info.id)) as VisNumericalColumn[]; const numColVals = await resolveColumnValues(numCols); diff --git a/src/vis/index.ts b/src/vis/index.ts index 09f4efb4c..e967b592b 100644 --- a/src/vis/index.ts +++ b/src/vis/index.ts @@ -10,3 +10,13 @@ export * from './VisSidebar'; export * from './general'; export * from './interfaces'; export * from './sidebar'; + +// Export interfaces ONLY since else the lazy loading will break +export * from './bar/interfaces'; +export * from './correlation/interfaces'; +export * from './heatmap/interfaces'; +export * from './violin/interfaces'; +export * from './hexbin/interfaces'; +export * from './scatter/interfaces'; +export * from './raincloud/interfaces'; +export * from './sankey/interfaces'; diff --git a/src/vis/interfaces.ts b/src/vis/interfaces.ts index 35fb58f10..c42dd3be2 100644 --- a/src/vis/interfaces.ts +++ b/src/vis/interfaces.ts @@ -6,7 +6,6 @@ export enum ESupportedPlotlyVis { BAR = 'Bar chart', HEXBIN = 'Hexbin plot', HEATMAP = 'Heatmap plot', - PARALLEL_COORDINATES = 'Parallel plot', RAINCLOUD = 'Raincloud plot', SANKEY = 'Sankey', CORRELATION = 'Correlation plot', @@ -16,12 +15,6 @@ export interface BaseVisConfig { type: string; } -export enum EHexbinOptions { - COLOR = 'Color', - PIE = 'Pie', - BINS = 'Bins', -} - export enum EAggregateTypes { COUNT = 'Count', MIN = 'Minimum', @@ -35,12 +28,6 @@ export enum EColumnTypes { CATEGORICAL = 'Categorical', } -export enum EGeneralFormType { - DROPDOWN = 'Dropdown', - BUTTON = 'Button', - SLIDER = 'Slider', -} - export enum EFilterOptions { IN = 'Filter in', OUT = 'Filter out', @@ -59,49 +46,11 @@ export enum EScatterSelectSettings { PAN = 'pan', } -export enum ECorrelationPlotMode { - PVALUE = 'p-value', - CORRELATION = 'correlation', -} - -export enum ECorrelationType { - PEARSON = 'Pearson', - SPEARMAN = 'Spearman', -} - export enum EScaleType { LINEAR = 'Linear', LOG = 'Log', } -export enum ECloudType { - SPLIT_VIOLIN = 'Split violin', - HEATMAP = 'Heatmap', - HISTOGRAM = 'Histogram', -} - -export enum ELightningType { - MEAN_AND_DEV = 'Mean and deviation', - MEDIAN_AND_DEV = 'Median and deviation', - MEAN = 'Mean', - BOXPLOT = 'Boxplot', -} - -export enum ERainType { - DOTPLOT = 'Dot plot', - BEESWARM = 'Beeswarm', - WHEATPLOT = 'Wheat plot', - STRIPPLOT = 'Strip plot', -} - -export enum ESortTypes { - NONE = 'NONE', - CAT_ASC = 'CAT_ASC', - CAT_DESC = 'CAT_DESC', - COUNT_ASC = 'COUNT_ASC', - COUNT_DESC = 'COUNT_DESC', -} - type ValueGetter = () => T | Promise; export interface IVisCommonValue { diff --git a/src/vis/sidebar/AggregateRainSwitch.tsx b/src/vis/raincloud/AggregateRainSwitch.tsx similarity index 66% rename from src/vis/sidebar/AggregateRainSwitch.tsx rename to src/vis/raincloud/AggregateRainSwitch.tsx index 5820a8715..335e0d399 100644 --- a/src/vis/sidebar/AggregateRainSwitch.tsx +++ b/src/vis/raincloud/AggregateRainSwitch.tsx @@ -7,5 +7,5 @@ interface AggregateRainSwitchProps { } export function AggregateRainSwitch({ callback, currentValue }: AggregateRainSwitchProps) { - return callback(event.currentTarget.checked)} label="Aggregate rain" />; + return callback(event.currentTarget.checked)} label="Aggregate rain" />; } diff --git a/src/vis/raincloud/Raincloud.tsx b/src/vis/raincloud/Raincloud.tsx index ecc986135..6c06e3aa6 100644 --- a/src/vis/raincloud/Raincloud.tsx +++ b/src/vis/raincloud/Raincloud.tsx @@ -2,7 +2,7 @@ import { Box, Container } from '@mantine/core'; import { useResizeObserver } from '@mantine/hooks'; import { op, table } from 'arquero'; import React, { useCallback, useMemo, useState } from 'react'; -import { ColumnInfo, ECloudType, EColumnTypes, ELightningType, ERainType, VisCategoricalValue, VisNumericalValue } from '../interfaces'; +import { ColumnInfo, EColumnTypes, VisCategoricalValue, VisNumericalValue } from '../interfaces'; import { XAxis } from '../hexbin/XAxis'; import { Brush } from './Brush'; @@ -10,6 +10,7 @@ import { Heatmap } from './cloud/Heatmap'; import { Histogram } from './cloud/Histogram'; import { SplitViolin } from './cloud/SplitViolin'; import { useXScale } from './hooks/useXScale'; +import { ECloudType, ELightningType, ERainType, IRaincloudConfig, IRaindropCircle } from './interfaces'; import { Boxplot } from './lightning/Boxplot'; import { Mean } from './lightning/Mean'; import { MeanAndInterval } from './lightning/MeanAndInterval'; @@ -19,7 +20,6 @@ import { Circle } from './rain/Circle'; import { DotPlot } from './rain/DotPlot'; import { StripPlot } from './rain/StripPlot'; import { WheatPlot } from './rain/WheatPlot'; -import { IRaincloudConfig, IRaindropCircle } from './utils'; const margin = { top: 0, diff --git a/src/vis/sidebar/RaincloudCloudSelect.tsx b/src/vis/raincloud/RaincloudCloudSelect.tsx similarity index 89% rename from src/vis/sidebar/RaincloudCloudSelect.tsx rename to src/vis/raincloud/RaincloudCloudSelect.tsx index 9dd5fa1f0..1f31c3c80 100644 --- a/src/vis/sidebar/RaincloudCloudSelect.tsx +++ b/src/vis/raincloud/RaincloudCloudSelect.tsx @@ -1,7 +1,6 @@ import { Select } from '@mantine/core'; import * as React from 'react'; -import { i18n } from '../../i18n'; -import { ECloudType } from '../interfaces'; +import { ECloudType } from './interfaces'; interface HexbinOptionSelectProps { callback: (c: ECloudType) => void; diff --git a/src/vis/raincloud/RaincloudGrid.tsx b/src/vis/raincloud/RaincloudGrid.tsx index 178dd6709..e557af0cf 100644 --- a/src/vis/raincloud/RaincloudGrid.tsx +++ b/src/vis/raincloud/RaincloudGrid.tsx @@ -1,9 +1,11 @@ import { SimpleGrid } from '@mantine/core'; import React from 'react'; import { VisColumn } from '../interfaces'; -import { IRaincloudConfig, getRaincloudData } from './utils'; +import { IRaincloudConfig } from './interfaces'; +import { getRaincloudData } from './utils'; import { useAsync } from '../../hooks/useAsync'; +import { InvalidCols } from '../general/InvalidCols'; import { Raincloud } from './Raincloud'; export function RaincloudGrid({ @@ -21,10 +23,13 @@ export function RaincloudGrid({ return ( - {data && + {data && config.numColumnsSelected.length >= 1 ? ( data.numColVals.map((numCol) => { return ; - })} + }) + ) : ( + + )} ); } diff --git a/src/vis/sidebar/RaincloudLightningSelect.tsx b/src/vis/raincloud/RaincloudLightningSelect.tsx similarity index 90% rename from src/vis/sidebar/RaincloudLightningSelect.tsx rename to src/vis/raincloud/RaincloudLightningSelect.tsx index b3f73e56b..c0eeec828 100644 --- a/src/vis/sidebar/RaincloudLightningSelect.tsx +++ b/src/vis/raincloud/RaincloudLightningSelect.tsx @@ -1,7 +1,6 @@ import { Select } from '@mantine/core'; import * as React from 'react'; -import { i18n } from '../../i18n'; -import { ELightningType } from '../interfaces'; +import { ELightningType } from './interfaces'; interface HexbinOptionSelectProps { callback: (c: ELightningType) => void; diff --git a/src/vis/sidebar/RaincloudRainSelect.tsx b/src/vis/raincloud/RaincloudRainSelect.tsx similarity index 89% rename from src/vis/sidebar/RaincloudRainSelect.tsx rename to src/vis/raincloud/RaincloudRainSelect.tsx index ec116fd1d..cbba136a7 100644 --- a/src/vis/sidebar/RaincloudRainSelect.tsx +++ b/src/vis/raincloud/RaincloudRainSelect.tsx @@ -1,7 +1,6 @@ import { Select } from '@mantine/core'; import * as React from 'react'; -import { i18n } from '../../i18n'; -import { ERainType } from '../interfaces'; +import { ERainType } from './interfaces'; interface HexbinOptionSelectProps { callback: (c: ERainType) => void; diff --git a/src/vis/raincloud/RaincloudVis.tsx b/src/vis/raincloud/RaincloudVis.tsx index 2f1f9b572..04055d1ef 100644 --- a/src/vis/raincloud/RaincloudVis.tsx +++ b/src/vis/raincloud/RaincloudVis.tsx @@ -4,7 +4,7 @@ import { useRef } from 'react'; import { ICommonVisProps } from '../interfaces'; import { RaincloudGrid } from './RaincloudGrid'; -import { IRaincloudConfig } from './utils'; +import { IRaincloudConfig } from './interfaces'; export function RaincloudVis({ config, columns, selectionCallback = () => null, selectedMap = {} }: ICommonVisProps) { const ref = useRef(); diff --git a/src/vis/raincloud/RaincloudVisSidebar.tsx b/src/vis/raincloud/RaincloudVisSidebar.tsx index 74ccc0994..22e38e9f5 100644 --- a/src/vis/raincloud/RaincloudVisSidebar.tsx +++ b/src/vis/raincloud/RaincloudVisSidebar.tsx @@ -1,13 +1,11 @@ -import { Container, Divider, Stack } from '@mantine/core'; import * as React from 'react'; -import { ColumnInfo, ESupportedPlotlyVis, ICommonVisSideBarProps, VisColumn } from '../interfaces'; -import { AggregateRainSwitch } from '../sidebar/AggregateRainSwitch'; +import { ColumnInfo, ICommonVisSideBarProps, VisColumn } from '../interfaces'; import { NumericalColumnSelect } from '../sidebar/NumericalColumnSelect'; -import { RaincloudCloudSelect } from '../sidebar/RaincloudCloudSelect'; -import { RaincloudLightningSelect } from '../sidebar/RaincloudLightningSelect'; -import { RaincloudRainSelect } from '../sidebar/RaincloudRainSelect'; -import { VisTypeSelect } from '../sidebar/VisTypeSelect'; -import { IRaincloudConfig } from './utils'; +import { AggregateRainSwitch } from './AggregateRainSwitch'; +import { RaincloudCloudSelect } from './RaincloudCloudSelect'; +import { RaincloudLightningSelect } from './RaincloudLightningSelect'; +import { RaincloudRainSelect } from './RaincloudRainSelect'; +import { IRaincloudConfig } from './interfaces'; export function RaincloudVisSidebar({ config, @@ -19,20 +17,16 @@ export function RaincloudVisSidebar({ setConfig: (config: IRaincloudConfig) => void; } & ICommonVisSideBarProps) { return ( - - - setConfig({ ...(config as any), type })} currentSelected={config.type} /> - - setConfig({ ...config, numColumnsSelected })} - columns={columns} - currentSelected={config.numColumnsSelected || []} - /> - setConfig({ ...config, cloudType: cloud })} currentSelected={config.cloudType} /> - setConfig({ ...config, lightningType: lightning })} currentSelected={config.lightningType} /> - setConfig({ ...config, rainType: rain })} currentSelected={config.rainType} /> - setConfig({ ...config, aggregateRain })} currentValue={config.aggregateRain} /> - - + <> + setConfig({ ...config, numColumnsSelected })} + columns={columns} + currentSelected={config.numColumnsSelected || []} + /> + setConfig({ ...config, cloudType: cloud })} currentSelected={config.cloudType} /> + setConfig({ ...config, lightningType: lightning })} currentSelected={config.lightningType} /> + setConfig({ ...config, rainType: rain })} currentSelected={config.rainType} /> + setConfig({ ...config, aggregateRain })} currentValue={config.aggregateRain} /> + ); } diff --git a/src/vis/raincloud/cloud/Heatmap.tsx b/src/vis/raincloud/cloud/Heatmap.tsx index 54d92594c..ae9bd0d13 100644 --- a/src/vis/raincloud/cloud/Heatmap.tsx +++ b/src/vis/raincloud/cloud/Heatmap.tsx @@ -3,7 +3,7 @@ import React, { useMemo } from 'react'; import { ColumnInfo, EColumnTypes, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; import { useXScale } from '../hooks/useXScale'; -import { IRaincloudConfig } from '../utils'; +import { IRaincloudConfig } from '../interfaces'; import { useKdeCalc } from './useKdeCalc'; const margin = { diff --git a/src/vis/raincloud/cloud/Histogram.tsx b/src/vis/raincloud/cloud/Histogram.tsx index 2b9d6ee76..479f3da48 100644 --- a/src/vis/raincloud/cloud/Histogram.tsx +++ b/src/vis/raincloud/cloud/Histogram.tsx @@ -3,7 +3,7 @@ import React, { useMemo } from 'react'; import { ColumnInfo, EColumnTypes, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; import { useXScale } from '../hooks/useXScale'; -import { IRaincloudConfig } from '../utils'; +import { IRaincloudConfig } from '../interfaces'; import { useKdeCalc } from './useKdeCalc'; const margin = { diff --git a/src/vis/raincloud/cloud/SplitViolin.tsx b/src/vis/raincloud/cloud/SplitViolin.tsx index a39980c06..d8fb716fd 100644 --- a/src/vis/raincloud/cloud/SplitViolin.tsx +++ b/src/vis/raincloud/cloud/SplitViolin.tsx @@ -3,7 +3,7 @@ import React, { useMemo } from 'react'; import { ColumnInfo, EColumnTypes, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; import { useXScale } from '../hooks/useXScale'; -import { IRaincloudConfig } from '../utils'; +import { IRaincloudConfig } from '../interfaces'; import { useKdeCalc } from './useKdeCalc'; const margin = { diff --git a/src/vis/raincloud/interfaces.ts b/src/vis/raincloud/interfaces.ts new file mode 100644 index 000000000..817e0f10f --- /dev/null +++ b/src/vis/raincloud/interfaces.ts @@ -0,0 +1,40 @@ +import { BaseVisConfig, ColumnInfo, ESupportedPlotlyVis } from '../interfaces'; + +export interface IRaincloudConfig { + type: ESupportedPlotlyVis.RAINCLOUD; + numColumnsSelected: ColumnInfo[]; + cloudType: ECloudType; + rainType: ERainType; + lightningType: ELightningType; + aggregateRain: boolean; +} + +export interface IRaindropCircle { + id: string[]; + x: number; + y: number; +} + +export enum ERainType { + DOTPLOT = 'Dot plot', + BEESWARM = 'Beeswarm', + WHEATPLOT = 'Wheat plot', + STRIPPLOT = 'Strip plot', +} + +export enum ECloudType { + SPLIT_VIOLIN = 'Split violin', + HEATMAP = 'Heatmap', + HISTOGRAM = 'Histogram', +} + +export enum ELightningType { + MEAN_AND_DEV = 'Mean and deviation', + MEDIAN_AND_DEV = 'Median and deviation', + MEAN = 'Mean', + BOXPLOT = 'Boxplot', +} + +export function isRaincloudConfig(s: BaseVisConfig): s is IRaincloudConfig { + return s.type === ESupportedPlotlyVis.RAINCLOUD; +} diff --git a/src/vis/raincloud/lightning/Boxplot.tsx b/src/vis/raincloud/lightning/Boxplot.tsx index ef7760093..5a59bed5b 100644 --- a/src/vis/raincloud/lightning/Boxplot.tsx +++ b/src/vis/raincloud/lightning/Boxplot.tsx @@ -4,7 +4,7 @@ import React, { useMemo } from 'react'; import ColumnTable from 'arquero/dist/types/table/column-table'; import { ColumnInfo, EColumnTypes, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; import { useXScale } from '../hooks/useXScale'; -import { IRaincloudConfig } from '../utils'; +import { IRaincloudConfig } from '../interfaces'; const margin = { top: 0, diff --git a/src/vis/raincloud/lightning/Mean.tsx b/src/vis/raincloud/lightning/Mean.tsx index 7cd98494b..fd3e60b5c 100644 --- a/src/vis/raincloud/lightning/Mean.tsx +++ b/src/vis/raincloud/lightning/Mean.tsx @@ -4,7 +4,7 @@ import React, { useMemo } from 'react'; import ColumnTable from 'arquero/dist/types/table/column-table'; import { ColumnInfo, EColumnTypes, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; import { useXScale } from '../hooks/useXScale'; -import { IRaincloudConfig } from '../utils'; +import { IRaincloudConfig } from '../interfaces'; const margin = { top: 0, diff --git a/src/vis/raincloud/lightning/MeanAndInterval.tsx b/src/vis/raincloud/lightning/MeanAndInterval.tsx index d02864cc2..1db5e558f 100644 --- a/src/vis/raincloud/lightning/MeanAndInterval.tsx +++ b/src/vis/raincloud/lightning/MeanAndInterval.tsx @@ -4,7 +4,7 @@ import React, { useMemo } from 'react'; import ColumnTable from 'arquero/dist/types/table/column-table'; import { ColumnInfo, EColumnTypes, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; import { useXScale } from '../hooks/useXScale'; -import { IRaincloudConfig } from '../utils'; +import { IRaincloudConfig } from '../interfaces'; const margin = { top: 0, diff --git a/src/vis/raincloud/lightning/MedianAndInterval.tsx b/src/vis/raincloud/lightning/MedianAndInterval.tsx index c5ae05c7a..d727ea808 100644 --- a/src/vis/raincloud/lightning/MedianAndInterval.tsx +++ b/src/vis/raincloud/lightning/MedianAndInterval.tsx @@ -4,7 +4,7 @@ import React, { useMemo } from 'react'; import ColumnTable from 'arquero/dist/types/table/column-table'; import { ColumnInfo, EColumnTypes, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; import { useXScale } from '../hooks/useXScale'; -import { IRaincloudConfig } from '../utils'; +import { IRaincloudConfig } from '../interfaces'; const margin = { top: 0, diff --git a/src/vis/raincloud/rain/BeeSwarm.tsx b/src/vis/raincloud/rain/BeeSwarm.tsx index f45aac9ad..55ce5099f 100644 --- a/src/vis/raincloud/rain/BeeSwarm.tsx +++ b/src/vis/raincloud/rain/BeeSwarm.tsx @@ -5,7 +5,7 @@ import forceBoundary from 'd3-force-boundary'; import * as d3 from 'd3v7'; import { ColumnInfo, EColumnTypes, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; import { useXScale } from '../hooks/useXScale'; -import { IRaincloudConfig } from '../utils'; +import { IRaincloudConfig } from '../interfaces'; const margin = { top: 30, diff --git a/src/vis/raincloud/rain/Circle.tsx b/src/vis/raincloud/rain/Circle.tsx index 93821f5dd..987e332e5 100644 --- a/src/vis/raincloud/rain/Circle.tsx +++ b/src/vis/raincloud/rain/Circle.tsx @@ -1,7 +1,7 @@ import { Tooltip } from '@mantine/core'; import React, { useEffect, useMemo, useRef, useState } from 'react'; import { useSpring, easings, animated } from 'react-spring'; -import { ERainType } from '../../interfaces'; +import { ERainType } from '../interfaces'; export function Circle({ x, diff --git a/src/vis/raincloud/rain/DotPlot.tsx b/src/vis/raincloud/rain/DotPlot.tsx index 24425237a..26076eec1 100644 --- a/src/vis/raincloud/rain/DotPlot.tsx +++ b/src/vis/raincloud/rain/DotPlot.tsx @@ -4,7 +4,7 @@ import { bin, op } from 'arquero'; import ColumnTable from 'arquero/dist/types/table/column-table'; import { ColumnInfo, EColumnTypes, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; import { useXScale } from '../hooks/useXScale'; -import { IRaincloudConfig } from '../utils'; +import { IRaincloudConfig } from '../interfaces'; const margin = { top: 30, diff --git a/src/vis/raincloud/rain/StripPlot.tsx b/src/vis/raincloud/rain/StripPlot.tsx index ab5d860c3..7feb23c3f 100644 --- a/src/vis/raincloud/rain/StripPlot.tsx +++ b/src/vis/raincloud/rain/StripPlot.tsx @@ -3,7 +3,7 @@ import { useEffect } from 'react'; import ColumnTable from 'arquero/dist/types/table/column-table'; import { ColumnInfo, EColumnTypes, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; import { useXScale } from '../hooks/useXScale'; -import { IRaincloudConfig } from '../utils'; +import { IRaincloudConfig } from '../interfaces'; const margin = { top: 30, diff --git a/src/vis/raincloud/rain/WheatPlot.tsx b/src/vis/raincloud/rain/WheatPlot.tsx index 0565d4084..97334a31b 100644 --- a/src/vis/raincloud/rain/WheatPlot.tsx +++ b/src/vis/raincloud/rain/WheatPlot.tsx @@ -4,7 +4,7 @@ import { bin, op } from 'arquero'; import ColumnTable from 'arquero/dist/types/table/column-table'; import { ColumnInfo, EColumnTypes, VisCategoricalValue, VisNumericalValue } from '../../interfaces'; import { useXScale } from '../hooks/useXScale'; -import { IRaincloudConfig } from '../utils'; +import { IRaincloudConfig } from '../interfaces'; const margin = { top: 30, diff --git a/src/vis/raincloud/utils.ts b/src/vis/raincloud/utils.ts index f3a11390b..01dee6717 100644 --- a/src/vis/raincloud/utils.ts +++ b/src/vis/raincloud/utils.ts @@ -1,30 +1,7 @@ import { merge } from 'lodash'; import { resolveColumnValues } from '../general/layoutUtils'; -import { - BaseVisConfig, - ColumnInfo, - ECloudType, - EColumnTypes, - ELightningType, - ERainType, - ESupportedPlotlyVis, - VisCategoricalValue, - VisColumn, - VisNumericalValue, -} from '../interfaces'; - -export interface IRaincloudConfig { - type: ESupportedPlotlyVis.RAINCLOUD; - numColumnsSelected: ColumnInfo[]; - cloudType: ECloudType; - rainType: ERainType; - lightningType: ELightningType; - aggregateRain: boolean; -} - -export function isRaincloud(s: BaseVisConfig): s is IRaincloudConfig { - return s.type === ESupportedPlotlyVis.RAINCLOUD; -} +import { ColumnInfo, EColumnTypes, ESupportedPlotlyVis, VisCategoricalValue, VisColumn, VisNumericalValue } from '../interfaces'; +import { ECloudType, ELightningType, ERainType, IRaincloudConfig } from './interfaces'; const defaultConfig: IRaincloudConfig = { type: ESupportedPlotlyVis.RAINCLOUD, @@ -55,9 +32,3 @@ export async function getRaincloudData( return { numColVals }; } - -export interface IRaindropCircle { - id: string[]; - x: number; - y: number; -} diff --git a/src/vis/sankey/SankeyVis.tsx b/src/vis/sankey/SankeyVis.tsx index 1e2cf8484..ac5f1b3e2 100644 --- a/src/vis/sankey/SankeyVis.tsx +++ b/src/vis/sankey/SankeyVis.tsx @@ -2,9 +2,10 @@ import { Group, MantineTheme, Stack, useMantineTheme } from '@mantine/core'; import * as React from 'react'; import { useAsync } from '../../hooks/useAsync'; import { PlotlyComponent } from '../../plotly'; +import { InvalidCols } from '../general/InvalidCols'; import { resolveColumnValues } from '../general/layoutUtils'; import { ICommonVisProps, VisCategoricalColumn, VisColumn } from '../interfaces'; -import { ISankeyConfig } from './utils'; +import { ISankeyConfig } from './interfaces'; /** * Performs the data transformation that maps the fetched data to @@ -203,6 +204,7 @@ export function SankeyVis({ config, columns, selectedList, selectionCallback, di ) : ( -

Select at least 2 categorical attributes.

+ )} diff --git a/src/vis/sankey/SankeyVisSidebar.tsx b/src/vis/sankey/SankeyVisSidebar.tsx index d80be3cf3..c0f2e1be8 100644 --- a/src/vis/sankey/SankeyVisSidebar.tsx +++ b/src/vis/sankey/SankeyVisSidebar.tsx @@ -1,9 +1,7 @@ -import { Container, Stack } from '@mantine/core'; import * as React from 'react'; -import { ColumnInfo, ESupportedPlotlyVis, ICommonVisSideBarProps } from '../interfaces'; +import { ColumnInfo, ICommonVisSideBarProps } from '../interfaces'; import { CategoricalColumnSelect } from '../sidebar/CategoricalColumnSelect'; -import { VisTypeSelect } from '../sidebar/VisTypeSelect'; -import { ISankeyConfig } from './utils'; +import { ISankeyConfig } from './interfaces'; export function SankeyVisSidebar({ config, @@ -13,15 +11,10 @@ export function SankeyVisSidebar({ style: { width = '20em', ...style } = {}, }: ICommonVisSideBarProps) { return ( - - - setConfig({ ...(config as any), type })} currentSelected={config.type} /> - setConfig({ ...config, catColumnsSelected })} - columns={columns} - currentSelected={config.catColumnsSelected || []} - /> - - + setConfig({ ...config, catColumnsSelected })} + columns={columns} + currentSelected={config.catColumnsSelected || []} + /> ); } diff --git a/src/vis/sankey/interfaces.ts b/src/vis/sankey/interfaces.ts new file mode 100644 index 000000000..ceeb29578 --- /dev/null +++ b/src/vis/sankey/interfaces.ts @@ -0,0 +1,10 @@ +import { BaseVisConfig, ColumnInfo, ESupportedPlotlyVis } from '../interfaces'; + +export interface ISankeyConfig extends BaseVisConfig { + type: ESupportedPlotlyVis.SANKEY; + catColumnsSelected: ColumnInfo[]; +} + +export function isSankeyConfig(s: BaseVisConfig): s is ISankeyConfig { + return s.type === ESupportedPlotlyVis.SANKEY; +} diff --git a/src/vis/sankey/utils.ts b/src/vis/sankey/utils.ts index dac88ccf9..442d01ea1 100644 --- a/src/vis/sankey/utils.ts +++ b/src/vis/sankey/utils.ts @@ -1,10 +1,6 @@ import { merge } from 'lodash'; -import { BaseVisConfig, ColumnInfo, ESupportedPlotlyVis, VisColumn } from '../interfaces'; - -export interface ISankeyConfig extends BaseVisConfig { - type: ESupportedPlotlyVis.SANKEY; - catColumnsSelected: ColumnInfo[]; -} +import { ESupportedPlotlyVis, VisColumn } from '../interfaces'; +import { ISankeyConfig } from './interfaces'; const defaultConfig: ISankeyConfig = { type: ESupportedPlotlyVis.SANKEY, diff --git a/src/vis/sidebar/ColorSelect.tsx b/src/vis/scatter/ColorSelect.tsx similarity index 90% rename from src/vis/sidebar/ColorSelect.tsx rename to src/vis/scatter/ColorSelect.tsx index 6b2d88e5a..c112bb5e1 100644 --- a/src/vis/sidebar/ColorSelect.tsx +++ b/src/vis/scatter/ColorSelect.tsx @@ -1,8 +1,8 @@ import * as React from 'react'; import { Select, Stack } from '@mantine/core'; import { ColumnInfo, EColumnTypes, VisColumn, ENumericalColorScaleType } from '../interfaces'; -import { SelectDropdownItem, getCol } from './utils'; -import { NumericalColorButtons } from './NumericalColorButtons'; +import { SelectDropdownItem, getCol } from '../sidebar/utils'; +import { NumericalColorButtons } from '../sidebar/NumericalColorButtons'; interface ColorSelectProps { callback: (c: ColumnInfo) => void; diff --git a/src/vis/scatter/OpacitySlider.tsx b/src/vis/scatter/OpacitySlider.tsx new file mode 100644 index 000000000..1ad4fa79a --- /dev/null +++ b/src/vis/scatter/OpacitySlider.tsx @@ -0,0 +1,38 @@ +import { Input, Slider } from '@mantine/core'; +import debounce from 'lodash/debounce'; +import { useMemo } from 'react'; + +import * as React from 'react'; +import { useSyncedRef } from '../../hooks'; + +interface OpacitySliderProps { + callback: (n: number) => void; + currentValue: number; +} + +export function OpacitySlider({ callback, currentValue }: OpacitySliderProps) { + const syncedCallback = useSyncedRef(callback); + + const debouncedCallback = useMemo(() => { + return debounce((n: number) => syncedCallback.current?.(n), 10); + }, [syncedCallback]); + + return ( + + { + debouncedCallback(n); + }} + /> + + ); +} diff --git a/src/vis/scatter/ScatterVis.tsx b/src/vis/scatter/ScatterVis.tsx index b1cfa8a06..2c13b4227 100644 --- a/src/vis/scatter/ScatterVis.tsx +++ b/src/vis/scatter/ScatterVis.tsx @@ -10,7 +10,8 @@ import { InvalidCols } from '../general/InvalidCols'; import { beautifyLayout } from '../general/layoutUtils'; import { EScatterSelectSettings, ICommonVisProps } from '../interfaces'; import { BrushOptionButtons } from '../sidebar/BrushOptionButtons'; -import { IScatterConfig, createScatterTraces } from './utils'; +import { createScatterTraces } from './utils'; +import { IScatterConfig } from './interfaces'; export function ScatterVis({ config, diff --git a/src/vis/scatter/ScatterVisSidebar.tsx b/src/vis/scatter/ScatterVisSidebar.tsx index d5af431bf..49f2c36b2 100644 --- a/src/vis/scatter/ScatterVisSidebar.tsx +++ b/src/vis/scatter/ScatterVisSidebar.tsx @@ -1,15 +1,13 @@ -import { Container, Divider, Stack } from '@mantine/core'; import merge from 'lodash/merge'; import * as React from 'react'; import { useMemo } from 'react'; -import { ColumnInfo, EColumnTypes, ENumericalColorScaleType, ESupportedPlotlyVis, ICommonVisSideBarProps } from '../interfaces'; -import { ColorSelect } from '../sidebar/ColorSelect'; +import { ColumnInfo, EColumnTypes, ENumericalColorScaleType, ICommonVisSideBarProps } from '../interfaces'; import { FilterButtons } from '../sidebar/FilterButtons'; import { NumericalColumnSelect } from '../sidebar/NumericalColumnSelect'; -import { OpacitySlider } from '../sidebar/OpacitySlider'; import { SingleColumnSelect } from '../sidebar/SingleColumnSelect'; -import { VisTypeSelect } from '../sidebar/VisTypeSelect'; -import { IScatterConfig } from './utils'; +import { ColorSelect } from './ColorSelect'; +import { OpacitySlider } from './OpacitySlider'; +import { IScatterConfig } from './interfaces'; const defaultConfig = { color: { @@ -32,55 +30,44 @@ export function ScatterVisSidebar({ config, optionsConfig, columns, filterCallba }, [optionsConfig]); return ( - - - setConfig({ ...(config as any), type })} currentSelected={config.type} /> - - setConfig({ ...config, numColumnsSelected })} - columns={columns} - currentSelected={config.numColumnsSelected || []} - /> - + <> + setConfig({ ...config, numColumnsSelected })} + columns={columns} + currentSelected={config.numColumnsSelected || []} + /> - - {mergedOptionsConfig.color.enable - ? mergedOptionsConfig.color.customComponent || ( - setConfig({ ...config, color })} - numTypeCallback={(numColorScaleType: ENumericalColorScaleType) => setConfig({ ...config, numColorScaleType })} - currentNumType={config.numColorScaleType} - columns={columns} - currentSelected={config.color} - /> - ) - : null} - {mergedOptionsConfig.shape.enable - ? mergedOptionsConfig.shape.customComponent || ( - setConfig({ ...config, shape })} - columns={columns} - currentSelected={config.shape} - /> - ) - : null} - - - - { - if (config.alphaSliderVal !== e) { - setConfig({ ...config, alphaSliderVal: e }); - } - }} - currentValue={config.alphaSliderVal} - /> - - - {mergedOptionsConfig.filter.enable ? mergedOptionsConfig.filter.customComponent || : null} - - + {mergedOptionsConfig.color.enable + ? mergedOptionsConfig.color.customComponent || ( + setConfig({ ...config, color })} + numTypeCallback={(numColorScaleType: ENumericalColorScaleType) => setConfig({ ...config, numColorScaleType })} + currentNumType={config.numColorScaleType} + columns={columns} + currentSelected={config.color} + /> + ) + : null} + {mergedOptionsConfig.shape.enable + ? mergedOptionsConfig.shape.customComponent || ( + setConfig({ ...config, shape })} + columns={columns} + currentSelected={config.shape} + /> + ) + : null} + { + if (config.alphaSliderVal !== e) { + setConfig({ ...config, alphaSliderVal: e }); + } + }} + currentValue={config.alphaSliderVal} + /> + {mergedOptionsConfig.filter.enable ? mergedOptionsConfig.filter.customComponent || : null} + ); } diff --git a/src/vis/scatter/interfaces.ts b/src/vis/scatter/interfaces.ts new file mode 100644 index 000000000..7f495fe55 --- /dev/null +++ b/src/vis/scatter/interfaces.ts @@ -0,0 +1,16 @@ +import { BaseVisConfig, ColumnInfo, ENumericalColorScaleType, EScatterSelectSettings, ESupportedPlotlyVis } from '../interfaces'; + +export interface IScatterConfig extends BaseVisConfig { + type: ESupportedPlotlyVis.SCATTER; + numColumnsSelected: ColumnInfo[]; + color: ColumnInfo | null; + numColorScaleType: ENumericalColorScaleType; + shape: ColumnInfo | null; + dragMode: EScatterSelectSettings; + alphaSliderVal: number; + sizeSliderVal: number; +} + +export function isScatterConfig(s: BaseVisConfig): s is IScatterConfig { + return s.type === ESupportedPlotlyVis.SCATTER; +} diff --git a/src/vis/scatter/utils.ts b/src/vis/scatter/utils.ts index 5c5589a91..38d589472 100644 --- a/src/vis/scatter/utils.ts +++ b/src/vis/scatter/utils.ts @@ -5,7 +5,6 @@ import { getCssValue } from '../../utils'; import { DEFAULT_COLOR, SELECT_COLOR } from '../general/constants'; import { columnNameWithDescription, resolveColumnValues, resolveSingleColumn } from '../general/layoutUtils'; import { - BaseVisConfig, ColumnInfo, EColumnTypes, ENumericalColorScaleType, @@ -20,17 +19,7 @@ import { VisNumericalValue, } from '../interfaces'; import { getCol } from '../sidebar'; - -export interface IScatterConfig extends BaseVisConfig { - type: ESupportedPlotlyVis.SCATTER; - numColumnsSelected: ColumnInfo[]; - color: ColumnInfo | null; - numColorScaleType: ENumericalColorScaleType; - shape: ColumnInfo | null; - dragMode: EScatterSelectSettings; - alphaSliderVal: number; - sizeSliderVal: number; -} +import { IScatterConfig } from './interfaces'; function calculateDomain(domain: [number | undefined, number | undefined], vals: number[]): [number, number] { if (!domain) return null; @@ -179,9 +168,9 @@ export async function createScatterTraces( }, hovertext: validCols[0].resolvedValues.map( (v, i) => - `${v.id}
x: ${v.val}
y: ${validCols[1].resolvedValues[i].val}
${ - colorCol ? `${columnNameWithDescription(colorCol.info)}: ${colorCol.resolvedValues[i].val}` : '' - }`, + `${v.id}
x: ${v.val}
y: ${validCols[1].resolvedValues[i].val}${ + colorCol ? `
${columnNameWithDescription(colorCol.info)}: ${colorCol.resolvedValues[i].val}` : '' + }${shapeCol ? `
${columnNameWithDescription(shapeCol.info)}: ${shapeCol.resolvedValues[i].val}` : ''}`, ), hoverinfo: 'text', text: validCols[0].resolvedValues.map((v) => v.id.toString()), diff --git a/src/vis/sidebar/BarDirectionButtons.tsx b/src/vis/sidebar/BarDirectionButtons.tsx deleted file mode 100644 index 236977f66..000000000 --- a/src/vis/sidebar/BarDirectionButtons.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { Container, SegmentedControl, Stack, Text } from '@mantine/core'; -import * as React from 'react'; -import { EBarDirection } from '../barGood/utils'; - -interface BarDirectionProps { - callback: (s: EBarDirection) => void; - currentSelected: EBarDirection; -} - -export function BarDirectionButtons({ callback, currentSelected }: BarDirectionProps) { - return ( - - - - Direction - - - - - ); -} diff --git a/src/vis/sidebar/CategoricalColumnSelect.tsx b/src/vis/sidebar/CategoricalColumnSelect.tsx index eec786bef..56bee6aed 100644 --- a/src/vis/sidebar/CategoricalColumnSelect.tsx +++ b/src/vis/sidebar/CategoricalColumnSelect.tsx @@ -1,7 +1,7 @@ import { MultiSelect } from '@mantine/core'; import * as React from 'react'; import { ColumnInfo, EColumnTypes, VisColumn } from '../interfaces'; -import { SelectDropdownItem } from './utils'; +import { SelectDropdownItem, SelectLabelComponent } from './utils'; interface CategoricalColumnSelectProps { callback: (s: ColumnInfo[]) => void; @@ -17,6 +17,7 @@ export function CategoricalColumnSelect({ callback, columns, currentSelected }: return ( void }) { - return ( -
-
- ); -} diff --git a/src/vis/sidebar/FilterButtons.tsx b/src/vis/sidebar/FilterButtons.tsx index 35e001c46..b4cd20445 100644 --- a/src/vis/sidebar/FilterButtons.tsx +++ b/src/vis/sidebar/FilterButtons.tsx @@ -1,4 +1,4 @@ -import { Button, Stack, Tooltip, Text } from '@mantine/core'; +import { Button, Input, Tooltip } from '@mantine/core'; import * as React from 'react'; import { EFilterOptions } from '../interfaces'; @@ -8,11 +8,8 @@ interface FilterButtonsProps { export function FilterButtons({ callback }: FilterButtonsProps) { return ( - - - Filter - - + + - + ); } diff --git a/src/vis/sidebar/HexSizeSlider.tsx b/src/vis/sidebar/HexSizeSlider.tsx deleted file mode 100644 index c5cd90207..000000000 --- a/src/vis/sidebar/HexSizeSlider.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { Box, Slider, Stack, Text } from '@mantine/core'; -import debounce from 'lodash/debounce'; -import * as React from 'react'; -import { useMemo } from 'react'; -import { useSyncedRef } from '../../hooks'; - -interface OpacitySliderProps { - callback: (n: number) => void; - currentValue: number; -} - -export function HexSizeSlider({ callback, currentValue }: OpacitySliderProps) { - const syncedCallback = useSyncedRef(callback); - - const debouncedCallback = useMemo(() => { - return debounce((n: number) => syncedCallback.current?.(n), 10); - }, [syncedCallback]); - - return ( - - - Size - - - { - debouncedCallback(n); - }} - /> - - - ); -} diff --git a/src/vis/sidebar/NumericalColorButtons.tsx b/src/vis/sidebar/NumericalColorButtons.tsx index 015fa0cde..04acb5511 100644 --- a/src/vis/sidebar/NumericalColorButtons.tsx +++ b/src/vis/sidebar/NumericalColorButtons.tsx @@ -1,4 +1,4 @@ -import { Group, SegmentedControl } from '@mantine/core'; +import { Group, Input, SegmentedControl } from '@mantine/core'; import * as React from 'react'; import { ENumericalColorScaleType } from '../interfaces'; @@ -12,31 +12,35 @@ export function NumericalColorButtons({ callback, currentSelected }: NumericalCo const divergentColors = ['#337ab7', '#7496c1', '#a5b4ca', '#d3d3d3', '#e5b19d', '#ec8e6a', '#ec6836']; return ( - - {divergentColors.map((d) => { - return ; - })} - - ), - value: ENumericalColorScaleType.DIVERGENT, - }, - { - label: ( - - {sequentialColors.map((d) => { - return ; - })} - - ), - value: ENumericalColorScaleType.SEQUENTIAL, - }, - ]} - /> + + + {divergentColors.map((d) => { + return ; + })} + + ), + value: ENumericalColorScaleType.DIVERGENT, + }, + { + label: ( + + {sequentialColors.map((d) => { + return ; + })} + + ), + value: ENumericalColorScaleType.SEQUENTIAL, + }, + ]} + /> + ); } diff --git a/src/vis/sidebar/NumericalColumnSelect.tsx b/src/vis/sidebar/NumericalColumnSelect.tsx index f82919d13..d2fc61513 100644 --- a/src/vis/sidebar/NumericalColumnSelect.tsx +++ b/src/vis/sidebar/NumericalColumnSelect.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { MultiSelect } from '@mantine/core'; import { ColumnInfo, EColumnTypes, VisColumn } from '../interfaces'; -import { SelectDropdownItem } from './utils'; +import { SelectDropdownItem, SelectLabelComponent } from './utils'; interface NumericalColumnSelectProps { callback: (s: ColumnInfo[]) => void; @@ -20,6 +20,7 @@ export function NumericalColumnSelect({ callback, columns, currentSelected }: Nu { diff --git a/src/vis/sidebar/OpacitySlider.tsx b/src/vis/sidebar/OpacitySlider.tsx deleted file mode 100644 index ce031fd61..000000000 --- a/src/vis/sidebar/OpacitySlider.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { Box, Slider, Stack, Text } from '@mantine/core'; -import debounce from 'lodash/debounce'; -import { useMemo } from 'react'; - -import * as React from 'react'; -import { useSyncedRef } from '../../hooks'; - -interface OpacitySliderProps { - callback: (n: number) => void; - currentValue: number; -} - -export function OpacitySlider({ callback, currentValue }: OpacitySliderProps) { - const syncedCallback = useSyncedRef(callback); - - const debouncedCallback = useMemo(() => { - return debounce((n: number) => syncedCallback.current?.(n), 10); - }, [syncedCallback]); - - return ( - - - Opacity - - - { - debouncedCallback(n); - }} - /> - - - ); -} diff --git a/src/vis/sidebar/SingleValueSelect.tsx b/src/vis/sidebar/SingleValueSelect.tsx deleted file mode 100644 index f5e0715f4..000000000 --- a/src/vis/sidebar/SingleValueSelect.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Select } from '@mantine/core'; -import * as React from 'react'; -import { SelectDropdownItem } from './utils'; - -interface SingleValueSelectProps { - callback: (s: string) => void; - availableFilterValues: string[]; - currentSelected: string; - placeholder: string; -} - -export function SingleValueSelect({ callback, availableFilterValues, currentSelected, placeholder }: SingleValueSelectProps) { - return ( - + Visualization type + + } + content={{currentVis?.description}} + /> + } + styles={{ + label: { + width: '100%', + }, + }} // components={{Option: optionLayout}} onChange={(e) => callback(e as ESupportedPlotlyVis)} name="visTypes" + itemComponent={SelectItem} + maxDropdownHeight={380} data={visTypes.map((t) => { return { value: t.type, label: t.type, + description: t.description, }; })} value={currentSelected} diff --git a/src/vis/sidebar/index.ts b/src/vis/sidebar/index.ts index dee6a8e2b..80fd42d75 100644 --- a/src/vis/sidebar/index.ts +++ b/src/vis/sidebar/index.ts @@ -1,14 +1,14 @@ -export * from './BarDirectionButtons'; -export * from './BarDisplayTypeButtons'; -export * from './BarGroupTypeButtons'; +export * from '../bar/BarDirectionButtons'; +export * from '../bar/BarDisplayTypeButtons'; +export * from '../bar/BarGroupTypeButtons'; export * from './BrushOptionButtons'; export * from './CategoricalColumnSelect'; -export * from './ColorSelect'; +export * from '../scatter/ColorSelect'; export * from './FilterButtons'; -export * from './GroupSelect'; +export * from '../bar/GroupSelect'; export * from './NumericalColorButtons'; export * from './NumericalColumnSelect'; -export * from './OpacitySlider'; +export * from '../scatter/OpacitySlider'; export * from './utils'; -export * from './ViolinOverlayButtons'; +export * from '../violin/ViolinOverlayButtons'; export * from './VisTypeSelect'; diff --git a/src/vis/sidebar/utils.tsx b/src/vis/sidebar/utils.tsx index eb7c153f2..a76f27e39 100644 --- a/src/vis/sidebar/utils.tsx +++ b/src/vis/sidebar/utils.tsx @@ -37,3 +37,46 @@ export const SelectDropdownItem = forwardRef(({ value
)); + +export function SelectLabelComponent({ + value, + label, + description, + onRemove, + classNames, + ...others +}: MultiSelectValueProps & { value: string; description: string }) { + return ( +
+ + {label} + + {description} + + + } + > + ({ + display: 'flex', + cursor: 'default', + alignItems: 'center', + backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[7] : theme.colors.gray[1], + paddingLeft: theme.spacing.xs, + borderRadius: theme.radius.sm, + })} + > + + {label} + + + + +
+ ); +} diff --git a/src/vis/stories/Iris.stories.tsx b/src/vis/stories/Iris.stories.tsx index dee46f256..6afb1cff3 100644 --- a/src/vis/stories/Iris.stories.tsx +++ b/src/vis/stories/Iris.stories.tsx @@ -1,9 +1,9 @@ import { ComponentStory } from '@storybook/react'; import React, { useState } from 'react'; import { Vis } from '../LazyVis'; -import { EBarDirection, EBarDisplayType, EBarGroupingType } from '../barGood/utils'; +import { EBarDirection, EBarDisplayType, EBarGroupingType } from '../bar/interfaces'; import { BaseVisConfig, EAggregateTypes, EColumnTypes, ENumericalColorScaleType, EScatterSelectSettings, ESupportedPlotlyVis, VisColumn } from '../interfaces'; -import { EViolinOverlay } from '../violin/utils'; +import { EViolinOverlay } from '../violin/interfaces'; export function fetchIrisData(): VisColumn[] { const dataPromise = import('./irisData').then((m) => diff --git a/src/vis/stories/Vis/Bar/BarRandom.stories.tsx b/src/vis/stories/Vis/Bar/BarRandom.stories.tsx index de24a1a63..f73a9a880 100644 --- a/src/vis/stories/Vis/Bar/BarRandom.stories.tsx +++ b/src/vis/stories/Vis/Bar/BarRandom.stories.tsx @@ -1,7 +1,7 @@ import { ComponentStory } from '@storybook/react'; import React from 'react'; import { Vis } from '../../../LazyVis'; -import { EBarDirection, EBarDisplayType, EBarGroupingType } from '../../../barGood/utils'; +import { EBarDirection, EBarDisplayType, EBarGroupingType } from '../../../bar/interfaces'; import { BaseVisConfig, EAggregateTypes, EColumnTypes, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; function RNG(seed) { diff --git a/src/vis/stories/Vis/Correlation/CorrelationIris.stories.tsx b/src/vis/stories/Vis/Correlation/CorrelationIris.stories.tsx index bd8854410..5f3163c92 100644 --- a/src/vis/stories/Vis/Correlation/CorrelationIris.stories.tsx +++ b/src/vis/stories/Vis/Correlation/CorrelationIris.stories.tsx @@ -1,7 +1,8 @@ import { ComponentStory } from '@storybook/react'; import React, { useState } from 'react'; import { Vis } from '../../../LazyVis'; -import { BaseVisConfig, ECorrelationType, EScaleType, ESupportedPlotlyVis } from '../../../interfaces'; +import { ECorrelationType } from '../../../correlation/interfaces'; +import { BaseVisConfig, EScaleType, ESupportedPlotlyVis } from '../../../interfaces'; import { fetchIrisData } from '../../fetchIrisData'; // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export diff --git a/src/vis/stories/Vis/Heatmap/HeatmapRandom.stories.tsx b/src/vis/stories/Vis/Heatmap/HeatmapRandom.stories.tsx index 0b443e0a8..ba26f6463 100644 --- a/src/vis/stories/Vis/Heatmap/HeatmapRandom.stories.tsx +++ b/src/vis/stories/Vis/Heatmap/HeatmapRandom.stories.tsx @@ -2,7 +2,8 @@ import { ComponentStory } from '@storybook/react'; import * as d3 from 'd3v7'; import React from 'react'; import { Vis } from '../../../LazyVis'; -import { BaseVisConfig, EAggregateTypes, EColumnTypes, ENumericalColorScaleType, ESortTypes, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; +import { ESortTypes } from '../../../heatmap/interfaces'; +import { BaseVisConfig, EAggregateTypes, EColumnTypes, ENumericalColorScaleType, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; function RNG(seed) { const m = 2 ** 35 - 31; @@ -149,7 +150,8 @@ Basic.args = { name: 'category2', }, ], - sortedBy: ESortTypes.CAT_ASC, + xSortedBy: ESortTypes.CAT_ASC, + ySortedBy: ESortTypes.CAT_ASC, color: null, numColorScaleType: ENumericalColorScaleType.SEQUENTIAL, aggregateColumn: null, @@ -178,7 +180,8 @@ Multiples.args = { name: 'category3', }, ], - sortedBy: ESortTypes.CAT_ASC, + xSortedBy: ESortTypes.CAT_ASC, + ySortedBy: ESortTypes.CAT_ASC, color: null, numColorScaleType: ENumericalColorScaleType.SEQUENTIAL, aggregateColumn: null, diff --git a/src/vis/stories/Vis/Hexbin/HexbinRandom.stories.tsx b/src/vis/stories/Vis/Hexbin/HexbinRandom.stories.tsx index 5e74fd99d..44cf32f7c 100644 --- a/src/vis/stories/Vis/Hexbin/HexbinRandom.stories.tsx +++ b/src/vis/stories/Vis/Hexbin/HexbinRandom.stories.tsx @@ -1,7 +1,8 @@ import { ComponentStory } from '@storybook/react'; import React from 'react'; import { Vis } from '../../../LazyVis'; -import { BaseVisConfig, EColumnTypes, EHexbinOptions, EScatterSelectSettings, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; +import { EHexbinOptions } from '../../../hexbin/interfaces'; +import { BaseVisConfig, EColumnTypes, EScatterSelectSettings, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; function RNG(seed) { const m = 2 ** 35 - 31; diff --git a/src/vis/stories/Vis/Raincloud/RaincloudRandom.stories.tsx b/src/vis/stories/Vis/Raincloud/RaincloudRandom.stories.tsx index c0284fce9..f590ed0ee 100644 --- a/src/vis/stories/Vis/Raincloud/RaincloudRandom.stories.tsx +++ b/src/vis/stories/Vis/Raincloud/RaincloudRandom.stories.tsx @@ -1,7 +1,8 @@ import { ComponentStory } from '@storybook/react'; import React from 'react'; import { Vis } from '../../../LazyVis'; -import { BaseVisConfig, ECloudType, EColumnTypes, ELightningType, ERainType, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; +import { BaseVisConfig, EColumnTypes, ESupportedPlotlyVis, VisColumn } from '../../../interfaces'; +import { ECloudType, ELightningType, ERainType } from '../../../raincloud/interfaces'; function RNG(seed) { const m = 2 ** 35 - 31; diff --git a/src/vis/stories/Vis/Violin/ViolinIris.stories.tsx b/src/vis/stories/Vis/Violin/ViolinIris.stories.tsx index c0afc6a0d..db316fbae 100644 --- a/src/vis/stories/Vis/Violin/ViolinIris.stories.tsx +++ b/src/vis/stories/Vis/Violin/ViolinIris.stories.tsx @@ -2,7 +2,7 @@ import { ComponentStory } from '@storybook/react'; import React from 'react'; import { Vis } from '../../../LazyVis'; import { BaseVisConfig, ESupportedPlotlyVis } from '../../../interfaces'; -import { EViolinOverlay } from '../../../violin/utils'; +import { EViolinOverlay } from '../../../violin/interfaces'; import { fetchIrisData } from '../../fetchIrisData'; // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export diff --git a/src/vis/violin/ViolinOverlayButtons.tsx b/src/vis/violin/ViolinOverlayButtons.tsx new file mode 100644 index 000000000..adda8b7bd --- /dev/null +++ b/src/vis/violin/ViolinOverlayButtons.tsx @@ -0,0 +1,25 @@ +import { Input, SegmentedControl } from '@mantine/core'; +import * as React from 'react'; +import { EViolinOverlay } from './interfaces'; + +interface ViolinOverlayProps { + callback: (s: EViolinOverlay) => void; + currentSelected: EViolinOverlay; +} + +export function ViolinOverlayButtons({ callback, currentSelected }: ViolinOverlayProps) { + return ( + + + + ); +} diff --git a/src/vis/violin/ViolinVis.tsx b/src/vis/violin/ViolinVis.tsx index 00b465760..41760868d 100644 --- a/src/vis/violin/ViolinVis.tsx +++ b/src/vis/violin/ViolinVis.tsx @@ -9,7 +9,8 @@ import { Plotly } from '../../plotly/full'; import { InvalidCols } from '../general'; import { beautifyLayout } from '../general/layoutUtils'; import { ICommonVisProps } from '../interfaces'; -import { IViolinConfig, createViolinTraces } from './utils'; +import { createViolinTraces } from './utils'; +import { IViolinConfig } from './interfaces'; export function ViolinVis({ config, columns, scales, dimensions, selectedList, selectedMap, selectionCallback }: ICommonVisProps) { const { value: traces, status: traceStatus, error: traceError } = useAsync(createViolinTraces, [columns, config, scales, selectedList, selectedMap]); diff --git a/src/vis/violin/ViolinVisSidebar.tsx b/src/vis/violin/ViolinVisSidebar.tsx index 11f6fcb36..eeb52df25 100644 --- a/src/vis/violin/ViolinVisSidebar.tsx +++ b/src/vis/violin/ViolinVisSidebar.tsx @@ -1,14 +1,12 @@ -import { Container, Divider, Stack } from '@mantine/core'; import merge from 'lodash/merge'; import * as React from 'react'; import { useMemo } from 'react'; -import { ColumnInfo, ESupportedPlotlyVis, ICommonVisSideBarProps } from '../interfaces'; +import { ColumnInfo, ICommonVisSideBarProps } from '../interfaces'; import { CategoricalColumnSelect } from '../sidebar/CategoricalColumnSelect'; import { FilterButtons } from '../sidebar/FilterButtons'; import { NumericalColumnSelect } from '../sidebar/NumericalColumnSelect'; -import { ViolinOverlayButtons } from '../sidebar/ViolinOverlayButtons'; -import { VisTypeSelect } from '../sidebar/VisTypeSelect'; -import { EViolinOverlay, IViolinConfig } from './utils'; +import { ViolinOverlayButtons } from './ViolinOverlayButtons'; +import { EViolinOverlay, IViolinConfig } from './interfaces'; const defaultConfig = { overlay: { @@ -35,22 +33,17 @@ export function ViolinVisSidebar({ }, [optionsConfig]); return ( - - setConfig({ ...(config as any), type })} currentSelected={config.type} /> - - - setConfig({ ...config, numColumnsSelected })} - columns={columns} - currentSelected={config.numColumnsSelected || []} - /> - setConfig({ ...config, catColumnsSelected })} - columns={columns} - currentSelected={config.catColumnsSelected || []} - /> - - + <> + setConfig({ ...config, numColumnsSelected })} + columns={columns} + currentSelected={config.numColumnsSelected || []} + /> + setConfig({ ...config, catColumnsSelected })} + columns={columns} + currentSelected={config.catColumnsSelected || []} + /> {mergedOptionsConfig.overlay.enable ? mergedOptionsConfig.overlay.customComponent || ( @@ -62,6 +55,6 @@ export function ViolinVisSidebar({ : null} {mergedOptionsConfig.filter.enable ? mergedOptionsConfig.filter.customComponent || : null} - + ); } diff --git a/src/vis/violin/interfaces.ts b/src/vis/violin/interfaces.ts new file mode 100644 index 000000000..906bae180 --- /dev/null +++ b/src/vis/violin/interfaces.ts @@ -0,0 +1,17 @@ +import { BaseVisConfig, ColumnInfo, ESupportedPlotlyVis } from '../interfaces'; + +export enum EViolinOverlay { + NONE = 'None', + BOX = 'Box', +} + +export interface IViolinConfig extends BaseVisConfig { + type: ESupportedPlotlyVis.VIOLIN; + numColumnsSelected: ColumnInfo[]; + catColumnsSelected: ColumnInfo[]; + violinOverlay: EViolinOverlay; +} + +export function isViolinConfig(s: BaseVisConfig): s is IViolinConfig { + return s.type === ESupportedPlotlyVis.VIOLIN; +} diff --git a/src/vis/violin/utils.ts b/src/vis/violin/utils.ts index efa186bcf..4c6cb29e2 100644 --- a/src/vis/violin/utils.ts +++ b/src/vis/violin/utils.ts @@ -2,30 +2,8 @@ import merge from 'lodash/merge'; import { i18n } from '../../i18n'; import { SELECT_COLOR } from '../general/constants'; import { columnNameWithDescription, resolveColumnValues } from '../general/layoutUtils'; -import { - BaseVisConfig, - ColumnInfo, - EColumnTypes, - ESupportedPlotlyVis, - PlotlyData, - PlotlyInfo, - Scales, - VisCategoricalColumn, - VisColumn, - VisNumericalColumn, -} from '../interfaces'; - -export enum EViolinOverlay { - NONE = 'None', - BOX = 'Box', -} - -export interface IViolinConfig extends BaseVisConfig { - type: ESupportedPlotlyVis.VIOLIN; - numColumnsSelected: ColumnInfo[]; - catColumnsSelected: ColumnInfo[]; - violinOverlay: EViolinOverlay; -} +import { EColumnTypes, ESupportedPlotlyVis, PlotlyData, PlotlyInfo, Scales, VisCategoricalColumn, VisColumn, VisNumericalColumn } from '../interfaces'; +import { EViolinOverlay, IViolinConfig } from './interfaces'; const defaultConfig: IViolinConfig = { type: ESupportedPlotlyVis.VIOLIN, From d48134c8426cd24dadfe2c7fa795b8bd30fafefa Mon Sep 17 00:00:00 2001 From: Michael Puehringer Date: Wed, 25 Oct 2023 17:36:51 +0200 Subject: [PATCH 237/241] Pin @types/react to 18.2.31 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index df09ab8e7..22c843722 100644 --- a/package.json +++ b/package.json @@ -190,7 +190,7 @@ "storybook-addon-swc": "^1.1.9" }, "resolutions": { - "@types/react": "~18.2.0", + "@types/react": "18.2.31", "@types/react-dom": "~18.2.0", "react": "~18.2.0", "react-dom": "~18.2.0" From 9e62fd4ab48d97af4b97dc460e51545c9af777d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20P=C3=BChringer?= <51900829+puehringer@users.noreply.github.com> Date: Fri, 27 Oct 2023 09:08:38 +0200 Subject: [PATCH 238/241] Revert "deps: pin @types/react to 18.2.31" --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 22c843722..df09ab8e7 100644 --- a/package.json +++ b/package.json @@ -190,7 +190,7 @@ "storybook-addon-swc": "^1.1.9" }, "resolutions": { - "@types/react": "18.2.31", + "@types/react": "~18.2.0", "@types/react-dom": "~18.2.0", "react": "~18.2.0", "react-dom": "~18.2.0" From 2b686e8889fc6e847410b5e1bc88c3f7df1adf5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20P=C3=BChringer?= <51900829+puehringer@users.noreply.github.com> Date: Fri, 27 Oct 2023 09:09:09 +0200 Subject: [PATCH 239/241] Update package.json --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index df09ab8e7..f8a42d7f6 100644 --- a/package.json +++ b/package.json @@ -145,6 +145,7 @@ "@mantine/hooks": "~6.0.19", "@mantine/modals": "~6.0.19", "@mantine/notifications": "~6.0.19", + "@mantine/styles": "~6.0.19", "@types/d3-hexbin": "^0.2.3", "@types/d3v7": "npm:@types/d3@^7.4.0", "@types/plotly.js-dist-min": "^2.3.0", From 4b84a5283bcd8a5562987f53b573dc59415e5bc3 Mon Sep 17 00:00:00 2001 From: dvvanessastoiber Date: Tue, 31 Oct 2023 16:29:03 +0100 Subject: [PATCH 240/241] prepare release 5.0.0 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index f8a42d7f6..32237c06d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "visyn_core", "description": "Core repository for datavisyn applications.", - "version": "4.1.2-SNAPSHOT", + "version": "5.0.0", "author": { "name": "datavisyn GmbH", "email": "contact@datavisyn.io", @@ -167,7 +167,7 @@ "react-plotly.js": "^2.5.1", "react-spring": "^9.7.1", "use-deep-compare-effect": "^1.8.0", - "visyn_scripts": "git+ssh://git@github.com/datavisyn/visyn_scripts#develop" + "visyn_scripts": "^5.1.0" }, "devDependencies": { "@babel/core": "^7.17.7", From 1436d5ab2dff063c1524b730397df81dd598efb9 Mon Sep 17 00:00:00 2001 From: dvvanessastoiber Date: Tue, 31 Oct 2023 16:57:34 +0100 Subject: [PATCH 241/241] prepare next dev version --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 32237c06d..affc28bda 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "visyn_core", "description": "Core repository for datavisyn applications.", - "version": "5.0.0", + "version": "5.0.1-SNAPSHOT", "author": { "name": "datavisyn GmbH", "email": "contact@datavisyn.io", @@ -167,7 +167,7 @@ "react-plotly.js": "^2.5.1", "react-spring": "^9.7.1", "use-deep-compare-effect": "^1.8.0", - "visyn_scripts": "^5.1.0" + "visyn_scripts": "git+ssh://git@github.com/datavisyn/visyn_scripts#develop" }, "devDependencies": { "@babel/core": "^7.17.7",