Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add numerical column support to bar plot #272

Closed
wants to merge 33 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
7266c43
fix violin plot selection
dvmartinweigl Apr 23, 2024
5f5eb65
partial fix vis stories
dvmartinweigl Apr 23, 2024
1c964e9
move null value filtering to trace creation function
dvmartinweigl Apr 23, 2024
8615971
disable zoom for violin plot
dvmartinweigl Apr 23, 2024
48943a8
small refactor
dvmartinweigl Apr 23, 2024
7372eff
pin storybook/node-logger
dvmartinweigl Apr 23, 2024
c346ddc
remove resolution
dvmartinweigl Apr 24, 2024
31e4569
small useEffect dependency array fix
dvmartinweigl Apr 24, 2024
493c090
feat(wip): add numerical column selection to bar plot
dv-usama-ansari Apr 24, 2024
a6fd9a7
fix: domain and range for numerical scales
dv-usama-ansari Apr 25, 2024
8443522
fix: tooltip text
dv-usama-ansari Apr 25, 2024
9a7046a
refactor: update SingleSelect to support multiple column types
dv-usama-ansari Apr 25, 2024
a2d147f
refactor: use new SingleSelect implementation
dv-usama-ansari Apr 25, 2024
aed1b05
chore: update bar merge default config
dv-usama-ansari Apr 25, 2024
aafcb5d
style: use full size vis components
dv-usama-ansari Apr 25, 2024
9fa4ba4
feat: update sidebar to have column type aware options
dv-usama-ansari Apr 25, 2024
5038a42
fix: bar selection and sizing issues
dv-usama-ansari Apr 25, 2024
10f6ec5
fix: infinite rendering in sidebar
dv-usama-ansari Apr 25, 2024
5533969
chore: update x and y axes
dv-usama-ansari Apr 25, 2024
082aa5f
Merge remote-tracking branch 'origin/develop' into ua/89-bar-plot
dvchristianbors Apr 25, 2024
df1275d
refactor: set domain to [most-negative, 0], [0, most positive] and […
dv-usama-ansari Apr 25, 2024
4625ffe
style: rotate x axis labels
dv-usama-ansari Apr 25, 2024
ae205f4
fix: update axes to use the new ticks
dv-usama-ansari Apr 25, 2024
bcde224
chore(wip): update sorting logic for the axes
dv-usama-ansari Apr 25, 2024
6a6bc64
feat: smartly rotate axis text
dv-usama-ansari Apr 25, 2024
e7f53c9
style: make select consistent with others
dv-usama-ansari Apr 25, 2024
f201cf4
chore: set 20 items cap for categorical and 100 for numerical columns
dv-usama-ansari Apr 25, 2024
4f6135e
chore: rename multiples to facets
dv-usama-ansari Apr 25, 2024
92b5458
fix: adjust bar boundaries for negative as well as positive values
dv-usama-ansari Apr 26, 2024
47f7792
feat: change search criteria for columns to match id
dv-usama-ansari Apr 29, 2024
3437231
refactor: minor improvements related to scaling of string columns
dv-usama-ansari Apr 29, 2024
f4ef799
chore(wip): update axis for the bar chart
dv-usama-ansari Apr 29, 2024
afff379
refactor: improve prng function in the storybook
dv-usama-ansari Apr 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 11 additions & 15 deletions src/vis/EagerVis.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -324,26 +324,22 @@ export function EagerVis({

<Stack gap={0} style={{ width: '100%', height: '100%', overflow: 'hidden' }} align="stretch" ref={ref}>
<Renderer
closeButtonCallback={closeCallback}
columns={columns}
config={_visConfig}
dimensions={dimensions}
optionsConfig={{
color: {
enable: true,
},
}}
showDragModeOptions={showDragModeOptions}
shapes={shapes}
setConfig={setVisConfig}
filterCallback={filterCallback}
selectionCallback={selectionCallback}
selectedMap={selectedMap}
selectedList={selected}
columns={columns}
optionsConfig={{ color: { enable: true } }}
scales={scales}
showSidebar={showSidebar}
showCloseButton={showCloseButton}
closeButtonCallback={closeCallback}
scrollZoom={scrollZoom}
selectedList={selected}
selectedMap={selectedMap}
selectionCallback={selectionCallback}
setConfig={setVisConfig}
shapes={shapes}
showCloseButton={showCloseButton}
showDragModeOptions={showDragModeOptions}
showSidebar={showSidebar}
{...commonProps}
/>
</Stack>
Expand Down
43 changes: 23 additions & 20 deletions src/vis/bar/BarChart.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,36 @@
import { Box, Loader, SimpleGrid, Stack, Center } from '@mantine/core';
import { Box, Center, Loader, SimpleGrid, Stack } from '@mantine/core';
import { op } from 'arquero';
import React, { useCallback, useMemo } from 'react';
import { useAsync } from '../../hooks/useAsync';
import { EColumnTypes, VisColumn } from '../interfaces';
import { SingleBarChart } from './SingleBarChart';
import { Legend } from './barComponents/Legend';
import { useGetGroupedBarScales } from './hooks/useGetGroupedBarScales';
import { getBarData } from './utils';
import { IBarConfig, SortTypes } from './interfaces';
import { getBarData } from './utils';

export function BarChart({
config,
columns,
selectedMap,
config,
selectedList,
selectedMap,
selectionCallback,
}: {
config: IBarConfig;
columns: VisColumn[];
selectedMap: Record<string, boolean>;
config: IBarConfig;
selectedList: string[];
selectedMap: Record<string, boolean>;
selectionCallback?: (ids: string[]) => void;
}) {
const { value: allColumns, status: colsStatus } = useAsync(getBarData, [
columns,
config.catColumnSelected,
config.group,
config.multiples,
config.aggregateColumn,
{
columns,
catColumn: config.catColumnSelected,
numColumn: config.numColumnsSelected?.[0],
groupColumn: config.group,
multiplesColumn: config.multiples,
aggregateColumn: config.aggregateColumn,
},
]);

const [sortType, setSortType] = React.useState<SortTypes>(SortTypes.NONE);
Expand All @@ -36,18 +39,18 @@ export function BarChart({
return [...new Set(allColumns?.multiplesColVals?.resolvedValues.map((v) => v.val))] as string[];
}, [allColumns]);

const { groupColorScale, groupedTable } = useGetGroupedBarScales(
const { groupColorScale, groupedTable } = useGetGroupedBarScales({
aggregateType: config.aggregateType,
allColumns,
0,
0,
{ left: 0, top: 0, right: 0, bottom: 0 },
null,
true,
categoryFilter: null,
groupType: config.groupType,
height: 0,
isVertical: true,
margin: { left: 0, top: 0, right: 0, bottom: 0 },
selectedMap,
config.groupType,
sortType,
config.aggregateType,
);
width: 0,
});

const groupedIds = useMemo(() => {
if (!groupedTable) {
Expand Down
2 changes: 1 addition & 1 deletion src/vis/bar/BarVis.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { IBarConfig } from './interfaces';
export function BarVis({ config, columns, selectionCallback = () => null, selectedMap = {}, selectedList = [] }: ICommonVisProps<IBarConfig>) {
return (
<Stack p={0} style={{ height: '100%', overflow: 'hidden', width: '100%', position: 'relative' }}>
{config.catColumnSelected ? (
{config.catColumnSelected || config.numColumnsSelected.length > 0 ? (
<BarChart config={config} columns={columns} selectedMap={selectedMap} selectionCallback={selectionCallback} selectedList={selectedList} />
) : (
<InvalidCols headerMessage="Invalid settings" bodyMessage="To create a bar chart, please select at least 1 column." />
Expand Down
151 changes: 89 additions & 62 deletions src/vis/bar/BarVisSidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { useShallowEffect } from '@mantine/hooks';
import merge from 'lodash/merge';
import * as React from 'react';
import { useMemo } from 'react';
import React, { useEffect, useMemo, useState } from 'react';
import { ColumnInfo, EAggregateTypes, EColumnTypes, ICommonVisSideBarProps } from '../interfaces';
import { AggregateTypeSelect } from '../sidebar/AggregateTypeSelect';
import { FilterButtons } from '../sidebar/FilterButtons';
import { SingleSelect } from '../sidebar/SingleSelect';
import { BarDirectionButtons } from './BarDirectionButtons';
import { GroupSelect } from './GroupSelect';
import { EBarDirection, EBarDisplayType, EBarGroupingType, IBarConfig } from './interfaces';
import { SingleSelect } from '../sidebar/SingleSelect';

const defaultConfig = {
direction: { enable: true, customComponent: null },
Expand All @@ -31,73 +31,100 @@ export function BarVisSidebar({
return merge({}, defaultConfig, optionsConfig);
}, [optionsConfig]);

const [selectedColumn, setSelectedColumn] = useState<{ column: ColumnInfo; columnType: EColumnTypes }>(
config.catColumnSelected
? { column: config.catColumnSelected, columnType: EColumnTypes.CATEGORICAL }
: config.numColumnsSelected[0]
? { column: config.numColumnsSelected[0], columnType: EColumnTypes.NUMERICAL }
: null,
);

// NOTE: @dv-usama-ansari: useEffect causes an infinite loop here.
useShallowEffect(() => {
setConfig({
...config,
catColumnSelected: selectedColumn?.columnType === EColumnTypes.CATEGORICAL ? selectedColumn?.column : null,
numColumnsSelected: selectedColumn?.columnType === EColumnTypes.NUMERICAL ? [selectedColumn?.column] : [],
multiples: config.multiples && config.multiples.id === selectedColumn?.column?.id ? null : config.multiples,
group: config.group && config.group.id === selectedColumn?.column?.id ? null : config.group,
});
}, [selectedColumn?.column, selectedColumn?.columnType, setConfig]);

return (
<>
<SingleSelect
callback={(catColumnSelected: ColumnInfo) =>
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}
columnType={EColumnTypes.CATEGORICAL}
label="Categorical column"
/>
<AggregateTypeSelect
aggregateTypeSelectCallback={(aggregateType: EAggregateTypes) => {
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 });
}
callback={(column: ColumnInfo) => {
setSelectedColumn(() => {
const c = columns.find((col) => col.info.id === column?.id);
return !c ? null : { column: c.info, columnType: c.type };
});
}}
aggregateColumnSelectCallback={(aggregateColumn: ColumnInfo) => setConfig({ ...config, aggregateColumn })}
columns={columns}
currentSelected={config.aggregateType}
aggregateColumn={config.aggregateColumn}
currentSelected={selectedColumn?.column}
columnTypes={[EColumnTypes.CATEGORICAL, EColumnTypes.NUMERICAL]}
label="Select a column"
/>
{!selectedColumn ? null : (
<>
{selectedColumn?.columnType === EColumnTypes.CATEGORICAL ? (
<>
<AggregateTypeSelect
aggregateTypeSelectCallback={(aggregateType: EAggregateTypes) => {
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 || (
<GroupSelect
aggregateType={config.aggregateType}
groupColumnSelectCallback={(group: ColumnInfo) => 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 || (
<SingleSelect
callback={(multiples: ColumnInfo) => setConfig({ ...config, multiples })}
columns={columns.filter((c) => config.catColumnSelected && c.info.id !== config.catColumnSelected.id)}
currentSelected={config.multiples}
label="Multiples"
columnType={EColumnTypes.CATEGORICAL}
/>
)
: null}
{mergedOptionsConfig.direction.enable
? mergedOptionsConfig.direction.customComponent || (
<BarDirectionButtons callback={(direction: EBarDirection) => setConfig({ ...config, direction })} currentSelected={config.direction} />
)
: null}
{mergedOptionsConfig.group.enable
? mergedOptionsConfig.group.customComponent || (
<GroupSelect
aggregateType={config.aggregateType}
groupColumnSelectCallback={(group: ColumnInfo) => 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 || (
<SingleSelect
callback={(multiples: ColumnInfo) => setConfig({ ...config, multiples })}
columns={columns.filter((c) => config.catColumnSelected && c.info.id !== config.catColumnSelected.id)}
currentSelected={config.multiples}
label="Facets"
columnTypes={[EColumnTypes.CATEGORICAL]}
/>
)
: null}
</>
) : null}
{mergedOptionsConfig.direction.enable
? mergedOptionsConfig.direction.customComponent || (
<BarDirectionButtons callback={(direction: EBarDirection) => setConfig({ ...config, direction })} currentSelected={config.direction} />
)
: null}

{filterCallback && mergedOptionsConfig.filter.enable ? mergedOptionsConfig.filter.customComponent || <FilterButtons callback={filterCallback} /> : null}
{filterCallback && mergedOptionsConfig.filter.enable
? mergedOptionsConfig.filter.customComponent || <FilterButtons callback={filterCallback} />
: null}
</>
)}
</>
);
}
4 changes: 2 additions & 2 deletions src/vis/bar/GroupSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Stack } from '@mantine/core';
import * as React from 'react';
import { ColumnInfo, EAggregateTypes, VisColumn } from '../interfaces';
import { ColumnInfo, EAggregateTypes, EColumnTypes, VisColumn } from '../interfaces';
import { BarDisplayButtons } from './BarDisplayTypeButtons';
import { BarGroupTypeButtons } from './BarGroupTypeButtons';
import { EBarDisplayType, EBarGroupingType } from './interfaces';
Expand Down Expand Up @@ -34,7 +34,7 @@ export function GroupSelect({
callback={(e) => groupColumnSelectCallback(e ? columns.find((c) => c.info.id === e.id)?.info : null)}
columns={columns}
currentSelected={currentSelected}
columnType={null}
columnTypes={[EColumnTypes.CATEGORICAL, EColumnTypes.NUMERICAL]}
/>
{currentSelected ? (
<BarGroupTypeButtons callback={(newGroupType: EBarGroupingType) => groupTypeSelectCallback(newGroupType)} currentSelected={groupType} />
Expand Down
Loading
Loading