Skip to content

Commit a17a39b

Browse files
committed
Refactor CohortComparison: simplify props, enhance UI components, add error handling, and migrate reusable logic
1 parent 2221507 commit a17a39b

File tree

14 files changed

+226
-118
lines changed

14 files changed

+226
-118
lines changed

packages/core/src/features/cohortComparison/cohortFacetSlice.ts

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,25 @@ export const cohortFacetSlice = graphQLAPI.injectEndpoints({
2424
primaryCohort,
2525
comparisonCohort,
2626
continuousFacetsInterval = undefined,
27-
}) => ({
28-
url: `${GEN3_ANALYSIS_API}/compare/facets`,
29-
method: 'POST',
30-
body: {
31-
doc_type: index,
32-
cohort1: primaryCohort,
33-
cohort2: comparisonCohort,
34-
facets: facetFields,
35-
interval:
36-
continuousFacetsInterval ??
37-
continuousFacets.reduce((acc: Record<string, number>, x) => {
38-
acc[x] = DAYS_IN_DECADE;
39-
return acc;
40-
}, {}),
41-
},
42-
}),
27+
}) => {
28+
console.log('Fetching cohort facets for index:', index);
29+
return {
30+
url: `${GEN3_ANALYSIS_API}/compare/facets`,
31+
method: 'POST',
32+
body: {
33+
doc_type: index,
34+
cohort1: primaryCohort,
35+
cohort2: comparisonCohort,
36+
facets: facetFields,
37+
interval:
38+
continuousFacetsInterval ??
39+
continuousFacets.reduce((acc: Record<string, number>, x) => {
40+
acc[x] = DAYS_IN_DECADE;
41+
return acc;
42+
}, {}),
43+
},
44+
};
45+
},
4346
transformResponse: (response: any) => {
4447
const facets1 = response?.cohort1?.facets;
4548
const facets2 = response?.cohort2?.facets;

packages/frontend/src/components/charts/echarts/ComparisonBarChart.tsx

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@ import React, { useCallback, useMemo, useRef } from 'react';
22
import { ActionIcon, Menu, Tooltip } from '@mantine/core';
33
import { processLabel } from '../utils';
44
import { ChartProps } from '../types';
5-
import ReactECharts, {
6-
ReactEChartsHandle,
7-
ReactEChartsProps,
8-
} from './ReactECharts';
5+
import ReactECharts, { ReactEChartsHandle, ReactEChartsProps, } from './ReactECharts';
96
import { HistogramDataArray } from '@gen3/core';
107
import { CallbackDataParams } from 'echarts/types/dist/shared';
118
import { isArray } from 'lodash';
@@ -110,16 +107,18 @@ const ComparisonBarChart = ({
110107
return `${colorSquare}${p.name}: <b>${p.value}</b>`;
111108
},
112109
},
113-
...processAxis(
114-
data[0],
115-
maxBins,
116-
labelTruncation,
117-
xLabel,
118-
yLabel,
119-
showXTicks,
120-
showYTicks,
121-
xLabelRotation,
122-
),
110+
...(data.length > 0
111+
? processAxis(
112+
data[0],
113+
maxBins,
114+
labelTruncation,
115+
xLabel,
116+
yLabel,
117+
showXTicks,
118+
showYTicks,
119+
xLabelRotation,
120+
)
121+
: {}),
123122
series: data.map((d: HistogramDataArray, i: number) => ({
124123
name: labels[i],
125124
type: 'bar',
@@ -130,15 +129,16 @@ const ComparisonBarChart = ({
130129
})),
131130
};
132131
}, [
133-
colors,
134132
data,
135-
labelTruncation,
136133
maxBins,
137-
showXTicks,
138-
showYTicks,
134+
labelTruncation,
139135
xLabel,
140136
yLabel,
137+
showXTicks,
138+
showYTicks,
141139
xLabelRotation,
140+
labels,
141+
colors,
142142
]);
143143

144144
if (!data || data.length === 0)

packages/frontend/src/features/CohortComparison/AdditionalCohortSelection.tsx

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,35 @@ const AdditionalCohortSelection: React.FC<AdditionalCohortSelectionProps> = ({
3838

3939
const [rowSelection, setRowSelection] = useState<MRT_RowSelectionState>({});
4040

41+
console.log('Available cohorts:', availableCohorts);
42+
console.log('index', index);
43+
console.log('dataTypename', dataTypename);
44+
4145
const cohorts = useDeepCompareMemo(
4246
() => availableCohorts.filter((cohort) => cohort.id !== primaryCohort.id),
4347
[primaryCohort, availableCohorts],
4448
);
4549

50+
console.log('Available cohorts:', cohorts);
51+
4652
const [selectedCohort, setSelectedCohort] = useState<Cohort | undefined>();
4753

4854
useEffect(() => {
4955
//do something when the row selection changes...
5056
console.info({ rowSelection });
5157
}, [rowSelection]);
5258

59+
const cohortList = useMemo(
60+
() =>
61+
cohorts.map((cohort) => ({
62+
id: cohort.id,
63+
name: cohort.name,
64+
counts: cohort.counts,
65+
select: false,
66+
})),
67+
[cohorts],
68+
);
69+
5370
const cohortListTableColumns = useMemo(
5471
() =>
5572
[
@@ -84,6 +101,7 @@ const AdditionalCohortSelection: React.FC<AdditionalCohortSelectionProps> = ({
84101
},
85102
{
86103
accessorKey: 'name',
104+
accessorFn: (cohort) => cohort.name,
87105
header: 'Name',
88106
Cell: ({ row }) => (
89107
<label
@@ -121,10 +139,10 @@ const AdditionalCohortSelection: React.FC<AdditionalCohortSelectionProps> = ({
121139
manualSorting: true,
122140
manualPagination: false,
123141
paginateExpandedRows: false,
124-
rowCount: cohorts.length,
142+
rowCount: cohortList.length,
125143
enableTopToolbar: false,
126144
layoutMode: 'semantic',
127-
enableRowSelection: true,
145+
enableRowSelection: false,
128146
getRowId: (row) => row.id,
129147
onRowSelectionChange: setRowSelection,
130148
mantineTableHeadCellProps: {

packages/frontend/src/features/CohortComparison/CohortCard/CohortCard.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import React from 'react';
22
import { Switch, useMantineTheme } from '@mantine/core';
33
import CohortVennDiagram from '../CohortVennDiagram';
44
import Link from 'next/link';
5-
import { CohortComparisonType, FIELD_LABELS } from '../types';
5+
import { CohortComparisonType } from '../types';
66
import CohortTable from './CohortTable';
7+
import { fieldNameToLabel } from '@gen3/core';
78

89
interface CohortCardProps {
910
selectedCards: Record<string, boolean>;
@@ -91,7 +92,7 @@ const CohortCard: React.FC<CohortCardProps> = ({
9192
})
9293
}
9394
disabled={value === 'survival' && !survivalPlotSelectable}
94-
label={value === 'survival' ? field : FIELD_LABELS[field]}
95+
label={value === 'survival' ? field : fieldNameToLabel(field)}
9596
/>
9697
</li>
9798
))}

packages/frontend/src/features/CohortComparison/CohortComparison.tsx

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import React, { useState } from 'react';
22
import { pickBy } from 'lodash';
33
import { LoadingOverlay } from '@mantine/core';
4-
import { convertFilterSetToGqlFilter, FilterSet, useCohortFacetsQuery, } from '@gen3/core';
4+
import {
5+
convertFilterSetToGqlFilter,
6+
FilterSet,
7+
useCohortFacetsQuery,
8+
} from '@gen3/core';
59

610
import CohortCard from './CohortCard/CohortCard';
711
import FacetCard from './FacetCard';
8-
import { CohortComparisonConfiguration, CohortComparisonFields } from './types';
12+
import { CohortComparisonConfiguration } from './types';
913
import { DemoText } from '../../components/tailwindComponents';
1014

1115
export interface CohortComparisonType {
@@ -23,27 +27,29 @@ export interface CohortComparisonType {
2327
};
2428
}
2529

26-
interface CohortComparisonProps {
27-
configuration: CohortComparisonConfiguration;
30+
interface CohortComparisonProps extends CohortComparisonConfiguration {
2831
cohorts: CohortComparisonType;
2932
demoMode: boolean;
3033
}
3134

3235
const CohortComparison: React.FC<CohortComparisonProps> = ({
33-
configuration,
36+
index,
37+
dataTypename,
38+
uniqueIdField,
39+
facets,
3440
cohorts,
3541
demoMode = false,
3642
}: CohortComparisonProps) => {
37-
const [selectedCards, setSelectedCards] = useState({
38-
survival: true,
39-
ethnicity: false,
40-
gender: true,
41-
race: true,
42-
vital_status: true,
43-
age_at_diagnosis: true,
44-
} as Record<string, boolean>);
43+
const facetCards = facets.reduce(
44+
(acc, facet) => {
45+
acc[facet.field] = true;
46+
return acc;
47+
},
48+
{} as Record<string, boolean>,
49+
);
4550

46-
const { index, dataTypename, uniqueIdField, facets } = configuration;
51+
const [selectedCards, setSelectedCards] =
52+
useState<Record<string, boolean>>(facetCards);
4753

4854
const [survivalPlotSelectable, setSurvivalPlotSelectable] = useState(true);
4955
const fieldsToQuery = facets.map((f) => f.field);
@@ -53,6 +59,7 @@ const CohortComparison: React.FC<CohortComparisonProps> = ({
5359
isFetching: cohortFacetsFetching,
5460
isLoading: cohortFacetsLoading,
5561
isUninitialized: cohortFacetsUninitialized,
62+
isError: cohortFacetsError,
5663
} = useCohortFacetsQuery({
5764
index,
5865
continuousFacets: ['diagnoses.age_at_diagnosis'],
@@ -63,6 +70,9 @@ const CohortComparison: React.FC<CohortComparisonProps> = ({
6370
),
6471
});
6572

73+
console.log('cohortFacetsData', cohortFacetsData);
74+
console.log('cohortFacetsError', cohortFacetsError);
75+
6676
const counts = [
6777
cohorts.primary_cohort.counts,
6878
cohorts.comparison_cohort.counts,
@@ -91,19 +101,14 @@ const CohortComparison: React.FC<CohortComparisonProps> = ({
91101
visible={
92102
cohortFacetsFetching ||
93103
cohortFacetsUninitialized ||
94-
cohortFacetsLoading
104+
cohortFacetsLoading ||
105+
cohortFacetsData === undefined
95106
}
96107
zIndex={1} // need z-index 1
97108
/>
98109
<FacetCard
99-
data={
100-
cohortFacetsData?.aggregations
101-
? cohortFacetsData.aggregations.map(
102-
(d: any) => d[CohortComparisonFields[selectedCard]],
103-
)
104-
: []
105-
}
106-
field={CohortComparisonFields[selectedCard]}
110+
data={[]}
111+
field={selectedCard}
107112
counts={counts}
108113
cohorts={cohorts}
109114
dataTypename={dataTypename}

packages/frontend/src/features/CohortComparison/CohortComparisonApp.tsx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,22 @@ import { SelectionScreenContext } from '../Analysis/context';
1313
import CohortComparison from './CohortComparison';
1414
import AdditionalCohortSelection from './AdditionalCohortSelection';
1515
import { CohortComparisonConfiguration } from './types';
16+
import { ErrorCard } from '../../index';
1617

1718
const VoidFunction = () => {};
1819

1920
const CohortComparisonApp = (configuration: CohortComparisonConfiguration) => {
20-
const { index: COHORT_FILTER_INDEX } = configuration;
21-
const { selectionScreenOpen, setSelectionScreenOpen, app, setActiveApp } =
21+
const { index: COHORT_FILTER_INDEX, dataTypename } = configuration;
22+
const { selectionScreenOpen, setSelectionScreenOpen, setActiveApp } =
2223
useContext(SelectionScreenContext);
2324

2425
const allCohortsIds = useCoreSelector(selectCohortIds);
2526

2627
const primaryCohort = useCoreSelector((state) => selectCurrentCohort(state));
2728

28-
const [comparisonCohort, setComparisonCohort] = useState<Cohort>();
29+
const [comparisonCohort, setComparisonCohort] = useState<Cohort | undefined>(
30+
undefined,
31+
);
2932
const comparisonCohortObj: Cohort | null = useCoreSelector((state) =>
3033
comparisonCohort?.id ? selectCohortById(state, comparisonCohort.id) : null,
3134
);
@@ -83,12 +86,10 @@ const CohortComparisonApp = (configuration: CohortComparisonConfiguration) => {
8386
index={COHORT_FILTER_INDEX}
8487
dataTypename={configuration.dataTypename}
8588
/>
89+
) : comparisonCohort ? (
90+
<CohortComparison cohorts={cohorts} demoMode={false} {...configuration} />
8691
) : (
87-
<CohortComparison
88-
cohorts={cohorts}
89-
demoMode={false}
90-
configuration={configuration}
91-
/>
92+
<ErrorCard message="No cohort available" />
9293
);
9394
};
9495

packages/frontend/src/features/CohortComparison/FacetCard/index.tsx

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,9 @@ import {
1010
} from '@gen3/core';
1111
import FunctionButton from '../../../components/FunctionButton';
1212
import CohortCreationButton from '../../../components/Buttons/CohortCreationButton';
13-
import {
14-
COHORT_A_COLOR,
15-
COHORT_B_COLOR,
16-
CohortComparisonType,
17-
UPPER_FIRST_FIELDS,
18-
} from '../types';
13+
import { COHORT_A_COLOR, COHORT_B_COLOR, CohortComparisonType } from '../types';
1914
import { useDeepCompareMemo } from 'use-deep-compare';
2015
import { createFilters, formatBucket } from './utils';
21-
import { upperFirst } from 'lodash';
2216
import { labelToPlural } from '../../../utils/labels';
2317
import ComparisonBarChart from '../../../components/charts/echarts/ComparisonBarChart';
2418

@@ -75,10 +69,6 @@ export const FacetCard: React.FC<FacetCardProps> = ({
7569
[formattedData],
7670
);
7771

78-
if (field === 'diagnoses.age_at_diagnosis') {
79-
uniqueValues.sort();
80-
}
81-
8272
formattedData = useMemo(
8373
() =>
8474
formattedData.map((cohort) =>
@@ -93,22 +83,6 @@ export const FacetCard: React.FC<FacetCardProps> = ({
9383
[formattedData, uniqueValues],
9484
);
9585

96-
const barChartData = formattedData.map((cohort, idx) => ({
97-
x: cohort.map((facet) =>
98-
UPPER_FIRST_FIELDS.includes(field)
99-
? upperFirst(facet.key)
100-
: fieldNameToLabel(facet.key),
101-
),
102-
y: cohort.map((facet) => (facet.count / counts[idx]) * 100),
103-
customdata: cohort.map((facet) => facet.count),
104-
hovertemplate: `<b>${
105-
cohorts[idx === 0 ? 'primary_cohort' : 'comparison_cohort']?.name
106-
}</b><br /> %{y:.0f}% Cases (%{customdata:,})<extra></extra>`,
107-
marker: {
108-
color: idx === 0 ? COHORT_A_COLOR : COHORT_B_COLOR,
109-
},
110-
}));
111-
11286
const downloadTSVFile = () => {
11387
const header = [
11488
`${fieldLabel}`,
@@ -140,6 +114,8 @@ export const FacetCard: React.FC<FacetCardProps> = ({
140114
);
141115
};
142116

117+
console.log('formattedData', formattedData);
118+
143119
return (
144120
<Paper
145121
data-testid={`card-${fieldLabel}-cohort-comparison`}
@@ -204,9 +180,7 @@ export const FacetCard: React.FC<FacetCardProps> = ({
204180
key={`${field}_${value}`}
205181
>
206182
<td data-testid={`text-analysis-${value}`} className="pl-2">
207-
{UPPER_FIRST_FIELDS.includes(field)
208-
? upperFirst(value)
209-
: fieldNameToLabel(value)}
183+
{fieldNameToLabel(value)}
210184
</td>
211185
<td>
212186
<CohortCreationButton

0 commit comments

Comments
 (0)