Skip to content

Commit

Permalink
fix: restrict heatmaps to only 2 categorical columns
Browse files Browse the repository at this point in the history
  • Loading branch information
dv-usama-ansari committed Nov 20, 2023
1 parent 92c3b49 commit c0ae437
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 68 deletions.
78 changes: 47 additions & 31 deletions src/vis/heatmap/HeatmapGrid.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Box, Loader, Stack } from '@mantine/core';
import { /* Box, */ Loader, Stack } from '@mantine/core';
import React, { useMemo } from 'react';
import { useAsync } from '../../hooks/useAsync';
import { InvalidCols } from '../general/InvalidCols';
import { VisColumn } from '../interfaces';
import { Heatmap } from './Heatmap';
import { IHeatmapConfig } from './interfaces';
import { getHeatmapData, setsOfTwo } from './utils';
import { getHeatmapData /* , setsOfTwo */ } from './utils';

export function HeatmapGrid({
config,
Expand All @@ -21,7 +21,10 @@ export function HeatmapGrid({
selected?: { [key: string]: boolean };
}) {
const { value: allColumns, status } = useAsync(getHeatmapData, [columns, config.catColumnsSelected, config.aggregateColumn]);
const hasAtLeast2CatCols = useMemo(() => allColumns?.catColumn && allColumns?.catColumn?.length > 1, [allColumns?.catColumn]);
const hasTwoCatCols = useMemo(() => allColumns?.catColumn && allColumns?.catColumn?.length === 2, [allColumns?.catColumn]);

// NOTE: @dv-usama-ansari: This flag is used when multiple heatmaps are rendered.
// const hasAtLeastTwoCatCols = useMemo(() => allColumns?.catColumn && allColumns?.catColumn?.length > 1, [allColumns?.catColumn]);

const margin = useMemo(() => {
return {
Expand All @@ -32,40 +35,53 @@ export function HeatmapGrid({
};
}, []);

const heatmapMultiples = useMemo(() => {
return setsOfTwo(hasAtLeast2CatCols ? allColumns?.catColumn : []) as Awaited<ReturnType<typeof getHeatmapData>>['catColumn'][];
}, [allColumns?.catColumn, hasAtLeast2CatCols]);
// NOTE: @dv-usama-ansari: This implementation for multiple heatmaps works, but it's not very performant.
// const heatmapMultiples = useMemo(() => {
// return setsOfTwo(hasTwoCatCols ? allColumns?.catColumn : []) as Awaited<ReturnType<typeof getHeatmapData>>['catColumn'][];
// }, [allColumns?.catColumn, hasTwoCatCols]);

return (
<Stack align="center" justify="center" sx={{ width: '100%', height: '100%' }} p="sm">
{status === 'pending' ? (
<Loader />
) : !hasAtLeast2CatCols ? (
<InvalidCols headerMessage="Invalid settings" bodyMessage="To create a heatmap chart, select at least 2 categorical columns." />
) : !hasTwoCatCols ? (
<InvalidCols headerMessage="Invalid settings" bodyMessage="To create a heatmap chart, select exactly 2 categorical columns." />
) : (
<Box
style={{
display: 'grid',
gridTemplateColumns: `repeat(${heatmapMultiples.length === 1 ? 1 : heatmapMultiples.length - 1}, 1fr)`,
gridTemplateRows: `repeat(${heatmapMultiples.length === 1 ? 1 : heatmapMultiples.length - 1}, 1fr)`,
width: '100%',
height: '100%',
}}
>
{heatmapMultiples.map(([column1, column2]) => (
<Heatmap
key={`${column1.info.id}-${column2.info.id}`}
column1={column1}
column2={column2}
aggregateColumn={allColumns.aggregateColumn}
margin={margin}
config={config}
selected={selected}
setExternalConfig={setExternalConfig}
selectionCallback={selectionCallback}
/>
))}
</Box>
<Heatmap
column1={allColumns.catColumn[0]}
column2={allColumns.catColumn[1]}
aggregateColumn={allColumns.aggregateColumn}
margin={margin}
config={config}
selected={selected}
setExternalConfig={setExternalConfig}
selectionCallback={selectionCallback}
/>

// NOTE: @dv-usama-ansari: This implementation for multiple heatmaps works, but it's not very performant.
// <Box
// style={{
// display: 'grid',
// gridTemplateColumns: `repeat(${heatmapMultiples.length === 1 ? 1 : heatmapMultiples.length - 1}, 1fr)`,
// gridTemplateRows: `repeat(${heatmapMultiples.length === 1 ? 1 : heatmapMultiples.length - 1}, 1fr)`,
// width: '100%',
// height: '100%',
// }}
// >
// {heatmapMultiples.map(([column1, column2]) => (
// <Heatmap
// key={`${column1.info.id}-${column2.info.id}`}
// column1={column1}
// column2={column2}
// aggregateColumn={allColumns.aggregateColumn}
// margin={margin}
// config={config}
// selected={selected}
// setExternalConfig={setExternalConfig}
// selectionCallback={selectionCallback}
// />
// ))}
// </Box>
)}
</Stack>
);
Expand Down
77 changes: 40 additions & 37 deletions src/vis/stories/Vis/Heatmap/HeatmapRandom.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ import { VisProvider } from '../../../Provider';
import { ESortTypes } from '../../../heatmap/interfaces';
import { BaseVisConfig, EAggregateTypes, EColumnTypes, ENumericalColorScaleType, ESupportedPlotlyVis, VisColumn } from '../../../interfaces';

function RNG(seed) {
const m = 2 ** 35 - 31;
const a = 185852;
let s = seed % m;
return function () {
return (s = (s * a) % m) / m;
};
}
// NOTE: @dv-usama-ansari: This function is not used anywhere, maybe it can be removed.
// function RNG(seed) {
// const m = 2 ** 35 - 31;
// const a = 185852;
// let s = seed % m;
// return function () {
// return (s = (s * a) % m) / m;
// };
// }

function fetchData(numberOfPoints: number): VisColumn[] {
const norm = d3.randomNormal.source(d3.randomLcg(0.5));
const rng = norm(0.5, 0.3);
Expand Down Expand Up @@ -162,32 +164,33 @@ Basic.args = {
} as BaseVisConfig,
};

export const Multiples: typeof Template = Template.bind({}) as typeof Template;
Multiples.args = {
externalConfig: {
type: ESupportedPlotlyVis.HEATMAP,
catColumnsSelected: [
{
description: '',
id: 'category',
name: 'category',
},
{
description: '',
id: 'category2',
name: 'category2',
},
{
description: '',
id: 'category3',
name: 'category3',
},
],
xSortedBy: ESortTypes.CAT_ASC,
ySortedBy: ESortTypes.CAT_ASC,
color: null,
numColorScaleType: ENumericalColorScaleType.SEQUENTIAL,
aggregateColumn: null,
aggregateType: EAggregateTypes.COUNT,
} as BaseVisConfig,
};
// NOTE: @dv-usama-ansari: This is the implementation for multiple heatmaps, but it's not very performant.
// export const Multiples: typeof Template = Template.bind({}) as typeof Template;
// Multiples.args = {
// externalConfig: {
// type: ESupportedPlotlyVis.HEATMAP,
// catColumnsSelected: [
// {
// description: '',
// id: 'category',
// name: 'category',
// },
// {
// description: '',
// id: 'category2',
// name: 'category2',
// },
// {
// description: '',
// id: 'category3',
// name: 'category3',
// },
// ],
// xSortedBy: ESortTypes.CAT_ASC,
// ySortedBy: ESortTypes.CAT_ASC,
// color: null,
// numColorScaleType: ENumericalColorScaleType.SEQUENTIAL,
// aggregateColumn: null,
// aggregateType: EAggregateTypes.COUNT,
// } as BaseVisConfig,
// };

0 comments on commit c0ae437

Please sign in to comment.