Skip to content

Commit e87ccd9

Browse files
author
Shawn O'Connor
committed
Merge branch 'main' into vpodcqa
2 parents ecc2a12 + 53dd05d commit e87ccd9

File tree

19 files changed

+166
-19
lines changed

19 files changed

+166
-19
lines changed

.github/workflows/update_dependencies.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ on:
1010
jobs:
1111
update-package-dependencies:
1212
runs-on: ubuntu-latest
13-
if: github.event.pull_request.title contains 'bump @gen3/frontend'
13+
if: contains(github.event.pull_request.title, 'bump @gen3/frontend')
1414
steps:
1515
- uses: actions/checkout@v6
1616
- name: Set up Node

src/lib/AnalysisApps/PLP/Components/AttritionTableWrapper/AttritionTable/AttritionTable.stories.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,23 @@ const TestSourcesData = {
2323
}
2424

2525
const TestOverlapData = {
26-
cohort_overlap: { case_control_overlap: 111 }
26+
cohort_overlap: { case_control_overlap: 90 }
2727
}
2828

2929
const TestStatsData1 = {
3030
cohort_definition_and_stats: { size: 112 }
3131
}
3232

3333
const TestStatsData2 = {
34-
cohort_definition_and_stats: { size: 107 }
34+
cohort_definition_and_stats: { size: 87 }
3535
}
3636

3737
const TestStatsData3 = {
38-
cohort_definition_and_stats: { size: 105 }
38+
cohort_definition_and_stats: { size: 85 }
39+
}
40+
41+
const TestStatsData4 = {
42+
cohort_definition_and_stats: { size: 5 }
3943
}
4044

4145
interface cohort { // TODO - centralize this interface
@@ -65,6 +69,7 @@ const AttritionTableWithHooks = () => {
6569
datasetObservationWindow={365}
6670
selectedOutcomeCohort={selectedOutcomeCohort}
6771
outcomeObservationWindow={365}
72+
removeIndividualsWithPriorOutcome={true}
6873
percentageOfDataToUseAsTest={25}
6974
/>
7075
</SourceContextProvider>
@@ -92,6 +97,9 @@ export const AttritionTableMockedSuccess: Story = {
9297
http.get(CohortsEndpoint + '/:sourceId/by-cohort-definition-ids/:cohort1_definition_id/:cohort2_definition_id/by-observation-window-1st-cohort/:observationwindow/by-outcome-window-2nd-cohort/:outcomeWindow2ndCohort', async () => {
9398
return HttpResponse.json(TestStatsData3);
9499
}),
100+
http.get(CohortsEndpoint + '/:sourceId/by-cohort-definition-ids/:cohort1_definition_id/:cohort2_definition_id/by-observation-window-1st-cohort/:observationwindow/and-cohort2-entry-first', async () => {
101+
return HttpResponse.json(TestStatsData4);
102+
}),
95103
],
96104
},
97105
},

src/lib/AnalysisApps/PLP/Components/AttritionTableWrapper/AttritionTable/AttritionTable.tsx

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ interface AttritionTableProps {
1010
datasetObservationWindow: number;
1111
selectedOutcomeCohort: cohort;
1212
outcomeObservationWindow: number;
13+
removeIndividualsWithPriorOutcome: boolean;
1314
percentageOfDataToUseAsTest: number | null;
1415
}
1516

@@ -19,7 +20,7 @@ interface cohort { // TODO - centralize this interface
1920
size: number;
2021
}
2122

22-
type Key = 'A1' | 'B1' | 'C1' | 'D1' | 'A2' | 'B2' | 'C2' | 'D2' | 'A3' | 'B3' | 'C3' | 'D3' | 'A4' | 'B4' | 'C4'| 'D4' ;
23+
type Key = 'A1' | 'B1' | 'C1' | 'D1' | 'A2' | 'B2' | 'C2' | 'D2' | 'A3' | 'B3' | 'C3' | 'D3' | 'A4' | 'B4' | 'C4'| 'D4' | 'A5' | 'B5' | 'C5'| 'D5';
2324
type ValueMap = Record<Key, number | null>;
2425
type LoadingMap = Record<Key, boolean>;
2526
const ComputeError = 1;
@@ -29,6 +30,7 @@ const cellKeys: Key[][] = [
2930
['A2', 'B2', 'C2', 'D2'],
3031
['A3', 'B3', 'C3', 'D3'],
3132
['A4', 'B4', 'C4', 'D4'],
33+
['A5', 'B5', 'C5', 'D5'],
3234
];
3335

3436
export const AttritionTable: React.FC<AttritionTableProps> = ({
@@ -37,14 +39,16 @@ export const AttritionTable: React.FC<AttritionTableProps> = ({
3739
datasetObservationWindow,
3840
selectedOutcomeCohort,
3941
outcomeObservationWindow,
42+
removeIndividualsWithPriorOutcome,
4043
percentageOfDataToUseAsTest,
4144
}) => {
4245
const { sourceId } = useSourceContext();
43-
const steps = [ 1, 2, 4, 6 ]; // the workflow step related to each description below
46+
const steps = [ 1, 2, '4a', '4b', 6 ]; // the workflow step related to each description below
4447
const descriptions = [
4548
'Initial data cohort',
4649
`Observation window (${datasetObservationWindow} days)`,
47-
`Time-at-risk (${outcomeObservationWindow} days)`,
50+
`Time-at-risk (${outcomeObservationWindow} days), `,
51+
`Remove prior (${removeIndividualsWithPriorOutcome ? 'yes' : 'no'})`,
4852
`Training set (${percentageOfDataToUseAsTest? 100-percentageOfDataToUseAsTest : '...'}%)`,
4953
];
5054

@@ -98,11 +102,14 @@ export const AttritionTable: React.FC<AttritionTableProps> = ({
98102
const responseData = await response.json();
99103
return responseData.cohort_definition_and_stats?.size;
100104
};
101-
const getInObservationWindowAndOverlapWithOutcome = async () => {
105+
const getInObservationWindowAndOverlapWithOutcome = async (outcomeCohortEntryFirst: boolean = false) => {
102106
if (! (selectedStudyPopulationCohort && selectedOutcomeCohort && datasetObservationWindow) ) {
103107
return null;
104108
}
105-
const endpoint = CohortsEndpoint + `/${sourceId}/by-cohort-definition-ids/${selectedStudyPopulationCohort.cohort_definition_id}/${selectedOutcomeCohort.cohort_definition_id}/by-observation-window-1st-cohort/${datasetObservationWindow}`;
109+
let endpoint = CohortsEndpoint + `/${sourceId}/by-cohort-definition-ids/${selectedStudyPopulationCohort.cohort_definition_id}/${selectedOutcomeCohort.cohort_definition_id}/by-observation-window-1st-cohort/${datasetObservationWindow}`;
110+
if (outcomeCohortEntryFirst) {
111+
endpoint += '/and-cohort2-entry-first'
112+
}
106113
const response = await fetch(endpoint, {
107114
method: 'GET',
108115
});
@@ -128,25 +135,36 @@ export const AttritionTable: React.FC<AttritionTableProps> = ({
128135
return responseData.cohort_definition_and_stats?.size;
129136
};
130137

138+
const getNewDatasetSize = async (size: number, removeIndividualsWithPriorOutcome: boolean) => {
139+
if (removeIndividualsWithPriorOutcome) {
140+
return size - await getInObservationWindowAndOverlapWithOutcome(true);
141+
} else {
142+
return size;
143+
}
144+
};
145+
131146
const [values, setValues] = useState<ValueMap>({
132147
A1: null, B1: null, C1: null, D1: null,
133148
A2: null, B2: null, C2: null, D2: null,
134149
A3: null, B3: null, C3: null, D3: null,
135150
A4: null, B4: null, C4: null, D4: null,
151+
A5: null, B5: null, C5: null, D5: null,
136152
});
137153

138154
const [errors] = useState<ValueMap>({
139155
A1: null, B1: null, C1: null, D1: null,
140156
A2: null, B2: null, C2: null, D2: null,
141157
A3: null, B3: null, C3: null, D3: null,
142158
A4: null, B4: null, C4: null, D4: null,
159+
A5: null, B5: null, C5: null, D5: null,
143160
});
144161

145162
const [loading, setLoading] = useState<LoadingMap>({
146163
A1: false, B1: false, C1: false, D1: false,
147164
A2: false, B2: false, C2: false, D2: false,
148165
A3: false, B3: false, C3: false, D3: false,
149166
A4: false, B4: false, C4: false, D4: false,
167+
A5: false, B5: false, C5: false, D5: false,
150168
});
151169

152170
const valueFns: ((vals: ValueMap) => Promise<number | null>)[][] = [
@@ -163,24 +181,30 @@ export const AttritionTable: React.FC<AttritionTableProps> = ({
163181
async (v) => (v.A2 == null || v.C2 == null ? null : (v.A2 - v.C2)), // D2
164182
],
165183
[
166-
async (v) => (v.C3 == null || v.D3 == null ? null : (v.C3 + v.D3)), // A3
184+
async (v) => (v.A2 == null ? null : (v.A2 )), // A3
167185
async () => null, // B3
168186
async () => getInObservationWindowAndOverlapWithOutcomeAndInOutcomeWindow(), // C3
169187
async (v) => (v.D2 == null || v.C2 == null || v.C3 == null ? null : (v.D2 +(v.C2 - v.C3))), // D3
170188
],
171189
[
172-
async (v) => getAndSetRemaningSize(v.A3), // A4
173-
async (v) => getTraininSetSize(v.A3), // B4
174-
async (v) => getTraininSetSize(v.C3), // C4
175-
async (v) => getTraininSetSize(v.D3), // D4
190+
async (v) => (v.A3 == null ? null : getNewDatasetSize(v.A3, removeIndividualsWithPriorOutcome)), // A4
191+
async (v) => null, // B4
192+
async (v) => (v.C3 == null ? null : (v.C3 )), // C4
193+
async (v) => (v.A4 == null || v.C4 == null ? null : (v.A4 - v.C4)), // D4
194+
],
195+
[
196+
async (v) => getAndSetRemaningSize(v.A4), // A5
197+
async (v) => getTraininSetSize(v.A4), // B5
198+
async (v) => getTraininSetSize(v.C4), // C5
199+
async (v) => getTraininSetSize(v.D4), // D5
176200
],
177201
];
178202

179203
useEffect(() => {
180204
const compute = async (initialValues: ValueMap, recalculateAll: boolean) => {
181205
const result: ValueMap = { ...initialValues };
182-
for (let row = 0; row < 4; row++) {
183-
for (let col = 0; col < 4; col++) {
206+
for (let row = 0; row < 5; row++) {
207+
for (let col = 0; col < 5; col++) {
184208
const key = cellKeys[row][col];
185209
const fn = valueFns[row][col];
186210
// only compute if (still) null:
@@ -211,6 +235,7 @@ export const AttritionTable: React.FC<AttritionTableProps> = ({
211235
datasetObservationWindow,
212236
selectedOutcomeCohort,
213237
outcomeObservationWindow,
238+
removeIndividualsWithPriorOutcome,
214239
percentageOfDataToUseAsTest,
215240
]);
216241

src/lib/AnalysisApps/PLP/Components/AttritionTableWrapper/AttritionTableWrapper.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ interface AttritionTableWrapperProps {
88
datasetObservationWindow: number;
99
selectedOutcomeCohort: cohort;
1010
outcomeObservationWindow: number;
11+
removeIndividualsWithPriorOutcome: boolean;
1112
percentageOfDataToUseAsTest: number | null;
1213
}
1314

@@ -23,6 +24,7 @@ const AttritionTableWrapper: React.FC<AttritionTableWrapperProps> = ({
2324
datasetObservationWindow,
2425
selectedOutcomeCohort,
2526
outcomeObservationWindow,
27+
removeIndividualsWithPriorOutcome,
2628
percentageOfDataToUseAsTest,
2729
}) => {
2830
const [isOpen, setIsOpen] = useState(false);
@@ -56,6 +58,7 @@ const AttritionTableWrapper: React.FC<AttritionTableWrapperProps> = ({
5658
datasetObservationWindow={datasetObservationWindow}
5759
selectedOutcomeCohort={selectedOutcomeCohort}
5860
outcomeObservationWindow={outcomeObservationWindow}
61+
removeIndividualsWithPriorOutcome={removeIndividualsWithPriorOutcome}
5962
percentageOfDataToUseAsTest={percentageOfDataToUseAsTest}
6063
/>
6164
</div> : null}

src/lib/AnalysisApps/PLP/Components/JobSubmitModal/JobSubmitModal.stories.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ const AttritionTableWithHooks = () => {
4141
datasetObservationWindow={state.datasetObservationWindow}
4242
selectedOutcomeCohort={state.selectedOutcomeCohort}
4343
outcomeObservationWindow={state.outcomeObservationWindow}
44+
removeIndividualsWithPriorOutcome={state.removeIndividualsWithPriorOutcome}
4445
selectedTeamProject={state.selectedTeamProject}
4546
minimumCovariateOccurrence={state.minimumCovariateOccurrence}
4647
percentageOfDataToUseAsTest={25}

src/lib/AnalysisApps/PLP/Components/JobSubmitModal/JobSubmitModal.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ interface Props {
1212
datasetObservationWindow: number;
1313
selectedOutcomeCohort: cohort;
1414
outcomeObservationWindow: number;
15+
removeIndividualsWithPriorOutcome: boolean;
1516
selectedTeamProject: string;
1617
minimumCovariateOccurrence: number;
1718
percentageOfDataToUseAsTest: number;
@@ -34,6 +35,7 @@ const JobSubmitModal: React.FC<Props> = ({
3435
datasetObservationWindow,
3536
selectedOutcomeCohort,
3637
outcomeObservationWindow,
38+
removeIndividualsWithPriorOutcome,
3739
selectedTeamProject,
3840
minimumCovariateOccurrence,
3941
percentageOfDataToUseAsTest,
@@ -91,7 +93,7 @@ const JobSubmitModal: React.FC<Props> = ({
9193
min_time_at_risk: 364, // TODO - advanced option
9294
include_all_outcomes: true, // TODO - advanced option
9395
first_exposure_only: false, // TODO - advanced option
94-
remove_subjects_with_prior_outcome: false, // TODO - advanced option
96+
remove_subjects_with_prior_outcome: removeIndividualsWithPriorOutcome,
9597
source_id: sourceId,
9698
covariate_min_fraction: minimumCovariateOccurrence,
9799
test_fraction: percentageOfDataToUseAsTest/100,
@@ -208,6 +210,14 @@ const JobSubmitModal: React.FC<Props> = ({
208210
{outcomeObservationWindow} days
209211
</td>
210212
</tr>
213+
<tr>
214+
<td className="font-semibold pr-4 text-right align-top whitespace-nowrap">
215+
Remove indiv. with prior outcome:
216+
</td>
217+
<td className="align-top">
218+
{removeIndividualsWithPriorOutcome ? 'Yes' : 'No'}
219+
</td>
220+
</tr>
211221
<tr>
212222
<td className="font-semibold pr-4 text-right align-top whitespace-nowrap">
213223
Dataset size (after time window filters):

src/lib/AnalysisApps/PLP/PLPContainer.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,13 @@ const PLPContainer = () => {
7979
<div>
8080
In this step, you can define an outcome period in days. This period specifies how many days to look for the outcome
8181
of interest to occur for each patient relative to their cohort entry date in the initial dataset.
82-
This is also known as the time-at-risk window.
82+
This is also known as the outcome window or time-at-risk window.
83+
Here you can also choose remove any individuals that have any record of the outcome in the period <i>before</i> the outcome window.
8384
</div>
8485
<br/>
8586
<DefineOutcomeObservationWindow
8687
outcomeObservationWindow={state.outcomeObservationWindow}
88+
removeIndividualsWithPriorOutcome={state.removeIndividualsWithPriorOutcome}
8789
dispatch={dispatch}
8890
/>
8991
<br/>
@@ -157,6 +159,7 @@ const PLPContainer = () => {
157159
datasetObservationWindow={state.datasetObservationWindow}
158160
selectedOutcomeCohort={state.selectedOutcomeCohort}
159161
outcomeObservationWindow={state.outcomeObservationWindow}
162+
removeIndividualsWithPriorOutcome={state.removeIndividualsWithPriorOutcome}
160163
selectedTeamProject={state.selectedTeamProject}
161164
minimumCovariateOccurrence={state.minimumCovariateOccurrence}
162165
percentageOfDataToUseAsTest={state.percentageOfDataToUseAsTest}
@@ -210,6 +213,7 @@ const PLPContainer = () => {
210213
datasetObservationWindow={state.datasetObservationWindow}
211214
selectedOutcomeCohort={state.selectedOutcomeCohort}
212215
outcomeObservationWindow={state.outcomeObservationWindow}
216+
removeIndividualsWithPriorOutcome={state.removeIndividualsWithPriorOutcome}
213217
percentageOfDataToUseAsTest={state.percentageOfDataToUseAsTest}
214218
/>
215219
<div data-testid="GWASApp" className="p-4">

src/lib/AnalysisApps/PLP/Steps/AddCovariates/AddCovariates.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ const AddCovariates = ({
2727
min={0.1}
2828
step={0.1}
2929
defaultValue={0.1}
30+
classNames={{
31+
section: 'text-gray-500'
32+
}}
3033
rightSection="%"
3134
value={minimumCovariateOccurrence * 100} // Convert decimal to percentage
3235
onChange={(value) => {

src/lib/AnalysisApps/PLP/Steps/DefineDatasetObservationWindow/DefineDatasetObservationWindow.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ const DefineDatasetObservationWindow = ({
2525
<NumberInput
2626
label="Dataset observation window "
2727
placeholder="Enter number of days"
28+
classNames={{
29+
section: 'text-gray-500'
30+
}}
2831
w={400}
2932
min={0}
3033
value={datasetObservationWindow}

0 commit comments

Comments
 (0)