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 transformation and filters to remaining frontend parts #1672

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const AttritionTable = ({
'Autogenerated variable for filtering out Case Population',
};
}
return {};
return null;
};

return (
Expand Down Expand Up @@ -106,9 +106,9 @@ const AttritionTable = ({
rowType='Outcome'
outcome={outcome}
rowObject={outcome}
currentCovariateAndCovariatesFromPrecedingRows={[
applyAutoGenFilters(),
]}
currentCovariateAndCovariatesFromPrecedingRows={
(applyAutoGenFilters() ? [applyAutoGenFilters()] : [])
}
modalInfo={modalInfo}
setModalInfo={setModalInfo}
/>
Expand All @@ -129,7 +129,7 @@ const AttritionTable = ({
rowType='Covariate'
currentCovariateAndCovariatesFromPrecedingRows={[
...item,
applyAutoGenFilters(),
...(applyAutoGenFilters() ? [applyAutoGenFilters()] : []),
]}
modalInfo={modalInfo}
setModalInfo={setModalInfo}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,29 @@
.attrition-table-modal .euler-loading {
text-align: center;
}

.attrition-table-modal .GWASUI-row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 100%;
}

.attrition-table-modal .GWASUI-column {
display: flex;
flex-direction: column;
flex-basis: 100%;
flex: 1;
}

.attrition-table-modal .outlier-inputs .GWASUI-column:nth-child(odd) {
min-width: 180px;
}

.attrition-table-modal .outlier-inputs .GWASUI-column:nth-child(3) {
margin-left: 35px;
}

.attrition-table-modal .outlier-inputs .GWASUI-column:nth-child(even) {
margin-left: -25px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,23 @@ const AttritionTableModal = ({ modalInfo, setModalInfo }) => {
<div data-testid='phenotype-histogram-diagram'>
<PhenotypeHistogram
selectedStudyPopulationCohort={modalInfo.selectedCohort}
selectedCovariates={
modalInfo.currentCovariateAndCovariatesFromPrecedingRows
}
outcome={modalInfo.outcome}
selectedCovariates={(() => {
// If row is outcome, we don't want covariates to be included in the filter.
// If not, we only want covariates from previous rows here. The current one will be in selectedContinuousItem below.
// Overall, the result of the logic below should be a histogram that reflects what was displayed in the "select covariate"
// step (i.e. not the data that remains *after* filtering, but what was displayed while selecting the covariate).
if (rowIsOutcome) return [];

if (modalInfo.outcome.variable_type === 'custom_dichotomous') {
// case/control... - here we also remove an extra item that is added on the fly (see applyAutoGenFilters() in AttritionTable)
return modalInfo.currentCovariateAndCovariatesFromPrecedingRows.slice(0, -2);
}

return modalInfo.currentCovariateAndCovariatesFromPrecedingRows.slice(0, -1);
})()}
outcome={rowIsOutcome ? null : modalInfo.outcome}
selectedContinuousItem={modalInfo.rowObject}
useAnimation={false}
readOnly
/>
</div>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
.GWASUI-column.transformation-dropdown-label {
max-width: 25%;
max-width: 30%;
padding-top: 10px;
padding-bottom: 5px;
}

.GWASUI-column.transformation-select {
max-width: 65%;
max-width: 60%;
padding-bottom: 10px;
}

label[for='input-minOutlierCutoff'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const PhenotypeHistogram = ({
selectedCovariates,
outcome,
selectedContinuousItem,
useAnimation,
readOnly,
handleChangeTransformation,
handleChangeMinOutlierCutoff,
handleChangeMaxOutlierCutoff,
Expand Down Expand Up @@ -49,6 +49,14 @@ const PhenotypeHistogram = ({
queryConfig,
);

const getMinCutoff = (continuousItem) => continuousItem?.filters?.find(
(filter) => filter.type === FILTERS.greaterThanOrEqualTo,
)?.value ?? null;

const getMaxCutoff = (continuousItem) => continuousItem?.filters?.find(
(filter) => filter.type === FILTERS.lessThanOrEqualTo,
)?.value ?? null;

useEffect(() => {
// Validate and give error message if there is no data:
if (
Expand All @@ -70,6 +78,9 @@ const PhenotypeHistogram = ({
payload: MESSAGES.NO_BINS_ERROR,
});
}
setMinOutlierCutoff(getMinCutoff(selectedContinuousItem));
setMaxOutlierCutoff(getMaxCutoff(selectedContinuousItem));
setSelectedTransformation(selectedContinuousItem.transformation);
}
}, [data]);

Expand All @@ -90,33 +101,31 @@ const PhenotypeHistogram = ({
barColor: 'darkblue',
xAxisLegend: selectedContinuousItem.concept_name,
yAxisLegend: 'Persons',
useAnimation,
minCutoff:
selectedContinuousItem.filters?.find(
(filter) => filter.type === FILTERS.greaterThanOrEqualTo,
)?.value ?? undefined,
maxCutoff:
selectedContinuousItem.filters?.find(
(filter) => filter.type === FILTERS.lessThanOrEqualTo,
)?.value ?? undefined,
useAnimation: !readOnly,
minCutoff: getMinCutoff(selectedContinuousItem),
maxCutoff: getMaxCutoff(selectedContinuousItem),
};
return (
<React.Fragment>
{inlineErrorMessage}
{data.bins !== null && (
<div>
<div>{(outcome?.variable_type === 'custom_dichotomous' && readOnly
? '\u2139\uFE0F histogram displaying data from both case and control groups'
: '')}
</div>
<div className='GWASUI-row'>
<div className='GWASUI-column transformation-dropdown-label'>
<label
id='transformation-dropdown-label'
htmlFor='transformation-select'
>
Select Transformation
>{(readOnly ? 'Selected Transformation' : 'Select Transformation')}
</label>
</div>
<div className='GWASUI-column transformation-select'>
<Select
id='transformation-select'
disabled={readOnly}
showSearch={false}
labelInValue
value={selectedTransformation}
Expand Down Expand Up @@ -145,17 +154,18 @@ const PhenotypeHistogram = ({
<div className='GWASUI-column'>
<InputNumber
id='input-minOutlierCutoff'
disabled={readOnly}
value={minOutlierCutoff}
onChange={(value) => {
setMinOutlierCutoff(value);
handleChangeMinOutlierCutoff(value);
}}
min={data.bins[0]?.start || 0}
max={
maxOutlierCutoff
|| data.bins[data.bins.length - 1]?.end
|| 100
}
min={(data.bins[0]?.start ?? 0) - 1}
max={(() => {
const lastBinEnd = data.bins[data.bins.length - 1]?.end;
const cutOffValue = maxOutlierCutoff ?? lastBinEnd ?? 100;
return cutOffValue + 1;
})()}
onKeyDown={(e) => {
const { key } = e;
// Allow only numeric keys, backspace, and delete, and one decimal point
Expand All @@ -165,6 +175,7 @@ const PhenotypeHistogram = ({
&& key !== 'Delete'
&& key !== 'ArrowLeft'
&& key !== 'ArrowRight'
&& (key !== '-' || e.target.value.includes('-'))
&& (key !== '.' || e.target.value.includes('.'))
) {
e.preventDefault();
Expand All @@ -180,13 +191,18 @@ const PhenotypeHistogram = ({
<div className='GWASUI-column'>
<InputNumber
id='input-maxOutlierCutoff'
disabled={readOnly}
value={maxOutlierCutoff}
onChange={(value) => {
setMaxOutlierCutoff(value);
handleChangeMaxOutlierCutoff(value);
}}
min={minOutlierCutoff || data.bins[0]?.start || 0}
max={data.bins[data.bins.length - 1]?.end || 100}
min={(() => {
const firstBinStart = data.bins[0]?.start;
const cutOffValue = minOutlierCutoff ?? firstBinStart ?? 0;
return cutOffValue - 1;
})()}
max={(data.bins[data.bins.length - 1]?.end ?? 100) + 1}
onKeyDown={(e) => {
const { key } = e;
// Allow only numeric keys, backspace, and delete, and one decimal point
Expand All @@ -196,6 +212,7 @@ const PhenotypeHistogram = ({
&& key !== 'Delete'
&& key !== 'ArrowLeft'
&& key !== 'ArrowRight'
&& (key !== '-' || e.target.value.includes('-'))
&& (key !== '.' || e.target.value.includes('.'))
) {
e.preventDefault();
Expand All @@ -216,7 +233,7 @@ PhenotypeHistogram.propTypes = {
selectedCovariates: PropTypes.array,
outcome: PropTypes.object,
selectedContinuousItem: PropTypes.object.isRequired,
useAnimation: PropTypes.bool,
readOnly: PropTypes.bool,
handleChangeTransformation: PropTypes.func,
handleChangeMinOutlierCutoff: PropTypes.func,
handleChangeMaxOutlierCutoff: PropTypes.func,
Expand All @@ -226,7 +243,7 @@ PhenotypeHistogram.defaultProps = {
dispatch: null,
selectedCovariates: [],
outcome: null,
useAnimation: true,
readOnly: false,
handleChangeTransformation: null,
handleChangeMinOutlierCutoff: null,
handleChangeMaxOutlierCutoff: null,
Expand Down
53 changes: 3 additions & 50 deletions src/Analysis/GWASApp/Utils/cohortMiddlewareApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const fetchSimpleOverlapInfo = async (
outcome,
) => {
const variablesPayload = {
variables: [...selectedCovariates, outcome,
variables: [outcome, ...selectedCovariates, // <- note: this order is important (outcome first, then covariates)
// add extra filter to make sure we only count persons that have a HARE group as well:
{
variable_type: 'concept',
Expand Down Expand Up @@ -45,7 +45,7 @@ export const fetchHistogramInfo = async (
transformationType,
) => {
const variablesPayload = {
variables: [...selectedCovariates, outcome,
variables: [outcome, ...selectedCovariates, // <- note: this order is important (outcome first, then covariates)
// add extra filter to make sure we only count persons that have a HARE group as well:
{
variable_type: 'concept',
Expand Down Expand Up @@ -81,7 +81,7 @@ export const fetchConceptStatsByHareSubset = async (
sourceId,
) => {
const variablesPayload = {
variables: [outcome, ...subsetCovariates],
variables: [...(outcome !== null ? [outcome] : []), ...subsetCovariates],
};
const conceptStatsEndPoint = `${cohortMiddlewarePath}concept-stats/by-source-id/${sourceId}/by-cohort-definition-id/${cohortDefinitionId}/breakdown-by-concept-id/${hareConceptId}`;
const reqBody = {
Expand Down Expand Up @@ -113,53 +113,6 @@ export const addCDFilter = (cohortId, otherCohortId, covariateArr) => {
return covariateRequest;
};

export const fetchConceptStatsByHareSubsetCC = async (
cohortDefinitionId,
otherCohortDefinitionId,
covariateSubset,
sourceId,
) => fetchConceptStatsByHareSubset(
cohortDefinitionId,
addCDFilter(cohortDefinitionId, otherCohortDefinitionId, covariateSubset),
sourceId,
);

export const fetchConceptStatsByHareForCaseControl = async (
queriedCohortDefinitionId,
otherCohortDefinitionId,
selectedCovariates,
selectedDichotomousCovariates,
sourceId,
) => fetchConceptStatsByHareSubset(
queriedCohortDefinitionId,
addCDFilter(queriedCohortDefinitionId, otherCohortDefinitionId, [
...selectedCovariates,
...selectedDichotomousCovariates,
]),
sourceId,
);

export const fetchCovariateStats = async (
cohortDefinitionId,
selectedCovariateIds,
sourceId,
) => {
const covariateIds = { ConceptIds: selectedCovariateIds };
const conceptStatsEndpoint = `${cohortMiddlewarePath}concept-stats/by-source-id/${sourceId}/by-cohort-definition-id/${cohortDefinitionId}`;
const reqBody = {
method: 'POST',
credentials: 'include',
headers,
body: JSON.stringify(covariateIds),
};
const response = await fetch(conceptStatsEndpoint, reqBody);
if (!response.ok) {
const message = `An error has occured: ${response.status}`;
throw new Error(message);
}
return response.json();
};

export const fetchCohortDefinitions = async (sourceId, selectedTeamProject) => {
const cohortEndPoint = `${cohortMiddlewarePath}cohortdefinition-stats/by-source-id/${sourceId}/by-team-project?team-project=${selectedTeamProject}`;
const response = await fetch(cohortEndPoint);
Expand Down
2 changes: 1 addition & 1 deletion src/Analysis/GWASApp/Utils/gwasWorkflowApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const jobSubmission = async (
const submitEndpoint = `${gwasWorkflowPath}submit`;
const requestBody = {
n_pcs: numOfPCs,
variables: [...selectedCovariates, outcome],
variables: [outcome, ...selectedCovariates], // <- note: this order is important (outcome first, then covariates)
out_prefix: Date.now().toString(),
outcome,
hare_population: selectedHare.concept_value_name,
Expand Down
Loading