diff --git a/src/pages/resultsView/ResultsViewPage.tsx b/src/pages/resultsView/ResultsViewPage.tsx index 09423eeade7..62a0868d13a 100644 --- a/src/pages/resultsView/ResultsViewPage.tsx +++ b/src/pages/resultsView/ResultsViewPage.tsx @@ -265,7 +265,10 @@ export default class ResultsViewPage extends React.Component< entrezGeneIdToGene={store.entrezGeneIdToGene} sampleKeyToSample={store.sampleKeyToSample} genes={store.genes} - clinicalAttributes={store.clinicalAttributes} + clinicalAttributes={ + store.plotClinicalAttributes + } + customAttributes={store.customAttributes} genesets={store.genesets} genericAssayEntitiesGroupByMolecularProfileId={ store.genericAssayEntitiesGroupByMolecularProfileId diff --git a/src/pages/resultsView/ResultsViewPageStore.ts b/src/pages/resultsView/ResultsViewPageStore.ts index ea50031be8e..adef8acb186 100644 --- a/src/pages/resultsView/ResultsViewPageStore.ts +++ b/src/pages/resultsView/ResultsViewPageStore.ts @@ -1093,7 +1093,7 @@ export class ResultsViewPageStore extends AnalysisStore this.studyIds, this.clinicalAttributes_profiledIn, this.clinicalAttributes_comparisonGroupMembership, - this.clinicalAttributes_customCharts, + this.customAttributes, this.samples, this.patients, ], @@ -1142,7 +1142,7 @@ export class ResultsViewPageStore extends AnalysisStore ...specialAttributes, ...this.clinicalAttributes_profiledIn.result!, ...this.clinicalAttributes_comparisonGroupMembership.result!, - ...this.clinicalAttributes_customCharts.result!, + ...this.customAttributes.result!, ]; }, }); @@ -1187,7 +1187,7 @@ export class ResultsViewPageStore extends AnalysisStore this.studyToDataQueryFilter, this.clinicalAttributes_profiledIn, this.clinicalAttributes_comparisonGroupMembership, - this.clinicalAttributes_customCharts, + this.customAttributes, ], invoke: async () => { let clinicalAttributeCountFilter: ClinicalAttributeCountFilter; @@ -1270,7 +1270,7 @@ export class ResultsViewPageStore extends AnalysisStore ); } // add counts for custom chart clinical attributes - for (const attr of this.clinicalAttributes_customCharts.result!) { + for (const attr of this.customAttributes.result!) { ret[attr.clinicalAttributeId] = attr.data!.filter( d => d.value !== 'NA' ).length; @@ -2723,7 +2723,17 @@ export class ResultsViewPageStore extends AnalysisStore default: [], }); - readonly clinicalAttributes_customCharts = remoteData({ + readonly plotClinicalAttributes = remoteData({ + await: () => [this.clinicalAttributes, this.customAttributes], + invoke: async () => { + return _.filter( + this.clinicalAttributes.result!, + attr => !this.customAttributes.result!.includes(attr) + ); + }, + }); + + readonly customAttributes = remoteData({ await: () => [this.sampleMap], invoke: async () => { let ret: ExtendedClinicalAttribute[] = []; @@ -5693,7 +5703,7 @@ export class ResultsViewPageStore extends AnalysisStore this.coverageInformation, this.filteredSampleKeyToSample, this.filteredPatientKeyToPatient, - this.clinicalAttributes_customCharts + this.customAttributes ); public mutationCache = new MobxPromiseCache< diff --git a/src/pages/resultsView/oncoprint/TracksMenu.tsx b/src/pages/resultsView/oncoprint/TracksMenu.tsx index 839eb7aa698..a8910a227ba 100644 --- a/src/pages/resultsView/oncoprint/TracksMenu.tsx +++ b/src/pages/resultsView/oncoprint/TracksMenu.tsx @@ -151,7 +151,7 @@ export default class TracksMenu extends React.Component { await: () => [ this.props.store.clinicalAttributes, this.clinicalAttributeIdToAvailableFrequency, - this.props.store.clinicalAttributes_customCharts, + this.props.store.customAttributes, ], invoke: () => { const uniqueAttributes = _.uniqBy( @@ -167,7 +167,7 @@ export default class TracksMenu extends React.Component { }; const customChartClinicalAttributeIds = _.keyBy( - this.props.store.clinicalAttributes_customCharts.result!, + this.props.store.customAttributes.result!, a => a.clinicalAttributeId ); diff --git a/src/pages/studyView/StudyViewPage.tsx b/src/pages/studyView/StudyViewPage.tsx index 508fe36e461..59c918103c8 100644 --- a/src/pages/studyView/StudyViewPage.tsx +++ b/src/pages/studyView/StudyViewPage.tsx @@ -772,6 +772,9 @@ export default class StudyViewPage extends React.Component< clinicalAttributes={ this.store.clinicalAttributes } + customAttributes={ + this.store.customAttributes + } genesets={this.store.genesets} genericAssayEntitiesGroupByMolecularProfileId={ this.store diff --git a/src/pages/studyView/StudyViewPageStore.ts b/src/pages/studyView/StudyViewPageStore.ts index 98d9da7d788..bca05fbfe11 100644 --- a/src/pages/studyView/StudyViewPageStore.ts +++ b/src/pages/studyView/StudyViewPageStore.ts @@ -11439,7 +11439,7 @@ export class StudyViewPageStore ), }); - readonly clinicalAttributes_customCharts = remoteData({ + readonly customAttributes = remoteData({ await: () => [this.sampleMap], invoke: async () => { let ret: ExtendedClinicalAttribute[] = []; @@ -11485,7 +11485,7 @@ export class StudyViewPageStore this.coverageInformation, this.filteredSampleKeyToSample, this.filteredPatientKeyToPatient, - this.clinicalAttributes_customCharts + this.customAttributes ); private _numericGeneMolecularDataCache = new MobxPromiseCache< diff --git a/src/shared/components/plots/PlotsTab.tsx b/src/shared/components/plots/PlotsTab.tsx index 814df5b16f7..d1890336965 100644 --- a/src/shared/components/plots/PlotsTab.tsx +++ b/src/shared/components/plots/PlotsTab.tsx @@ -18,6 +18,7 @@ import _ from 'lodash'; import { axisHasNegativeNumbers, boxPlotTooltip, + CUSTOM_ATTR_DATA_TYPE, CLIN_ATTR_DATA_TYPE, CNA_STROKE_WIDTH, dataTypeDisplayOrder, @@ -277,6 +278,7 @@ export interface IPlotsTabProps { sampleKeyToSample: MobxPromise<_.Dictionary>; genes: MobxPromise; clinicalAttributes: MobxPromise; + customAttributes: MobxPromise; genesets: MobxPromise; genericAssayEntitiesGroupByMolecularProfileId: MobxPromise<{ [profileId: string]: GenericAssayMeta[]; @@ -696,6 +698,31 @@ export default class PlotsTab extends React.Component { ); } break; + case CUSTOM_ATTR_DATA_TYPE: + if ( + this.horzSelection.dataSourceId !== undefined && + this.customAttributesGroupByclinicalAttributeId.isComplete + ) { + const attributes = this + .customAttributesGroupByclinicalAttributeId.result![ + this.horzSelection.dataSourceId + ]; + const studyIds = attributes.map( + attribute => attribute.studyId + ); + horzAxisStudies = this.props.studies.result.filter(study => + studyIds.includes(study.studyId) + ); + components.push( +
+ Horizontal Axis: + {`${horzAxisDataSampleCount} samples from ${ + horzAxisStudies.length + } ${Pluralize('study', horzAxisStudies.length)}`} +
+ ); + } + break; default: // molecular profile if ( @@ -731,6 +758,31 @@ export default class PlotsTab extends React.Component { case NONE_SELECTED_OPTION_STRING_VALUE: isVertAxisNoneOptionSelected = true; break; + case CUSTOM_ATTR_DATA_TYPE: + if ( + this.vertSelection.dataSourceId !== undefined && + this.customAttributesGroupByclinicalAttributeId.isComplete + ) { + const attributes = this + .customAttributesGroupByclinicalAttributeId.result![ + this.vertSelection.dataSourceId + ]; + const studyIds = attributes.map( + attribute => attribute.studyId + ); + vertAxisStudies = this.props.studies.result.filter(study => + studyIds.includes(study.studyId) + ); + components.push( +
+ Vertical Axis: + {`${vertAxisDataSampleCount} samples from ${ + vertAxisStudies.length + } ${Pluralize('study', vertAxisStudies.length)}`} +
+ ); + } + break; case CLIN_ATTR_DATA_TYPE: if ( this.vertSelection.dataSourceId !== undefined && @@ -1121,9 +1173,10 @@ export default class PlotsTab extends React.Component { this._selectedGenesetOption && this._selectedGenesetOption.value === SAME_SELECTED_OPTION_STRING_VALUE && - self.horzSelection.dataType === CLIN_ATTR_DATA_TYPE + (self.horzSelection.dataType === CLIN_ATTR_DATA_TYPE || + self.horzSelection.dataType === CUSTOM_ATTR_DATA_TYPE) ) { - // if vertical gene set option is "same as horizontal", and horizontal is clinical, then use the actual + // if vertical gene set option is "same as horizontal", and horizontal is clinical or custom, then use the actual // gene set option value instead of "Same gene" option value, because that would be slightly weird UX return self.horzSelection.selectedGenesetOption; } else { @@ -1195,9 +1248,10 @@ export default class PlotsTab extends React.Component { this._selectedGenericAssayOption && this._selectedGenericAssayOption.value === SAME_SELECTED_OPTION_STRING_VALUE && - self.horzSelection.dataType === CLIN_ATTR_DATA_TYPE + (self.horzSelection.dataType === CLIN_ATTR_DATA_TYPE || + self.horzSelection.dataType === CUSTOM_ATTR_DATA_TYPE) ) { - // if vertical gene set option is "same as horizontal", and horizontal is clinical, then use the actual + // if vertical gene set option is "same as horizontal", and horizontal is clinical or custom, then use the actual // gene set option value instead of "Same gene" option value, because that would be slightly weird UX return self.horzSelection.selectedGenericAssayOption; } else { @@ -2063,10 +2117,45 @@ export default class PlotsTab extends React.Component { }, }); + readonly clinicalAndCustomAttributes = remoteData< + ExtendedClinicalAttribute[] + >({ + await: () => [ + this.props.clinicalAttributes, + this.props.customAttributes, + ], + invoke: () => { + return Promise.resolve([ + ...this.props.clinicalAttributes.result!, + ...this.props.customAttributes.result!, + ]); + }, + }); + + readonly clinicalAttributeOptions = remoteData({ + await: () => [this.props.clinicalAttributes], + invoke: () => + Promise.resolve( + makeClinicalAttributeOptions( + this.props.clinicalAttributes.result! + ) + ), + }); + + readonly customAttributeOptions = remoteData({ + await: () => [this.props.customAttributes], + invoke: () => + Promise.resolve( + makeClinicalAttributeOptions( + this.props.customAttributes.result! + ) + ), + }); + readonly coloringMenuOmnibarOptions = remoteData< (ColoringMenuOmnibarOption | ColoringMenuOmnibarGroup)[] >({ - await: () => [this.props.genes, this.props.clinicalAttributes], + await: () => [this.props.genes, this.clinicalAndCustomAttributes], invoke: () => { const allOptions: ( | Omit @@ -2088,7 +2177,7 @@ export default class PlotsTab extends React.Component { allOptions.push({ label: 'Clinical Attributes', - options: this.props.clinicalAttributes + options: this.clinicalAndCustomAttributes .result!.filter(a => { return ( a.clinicalAttributeId !== @@ -2104,7 +2193,6 @@ export default class PlotsTab extends React.Component { }; }), }); - if (allOptions.length > 0) { // add 'None' option to the top of the list to allow removing coloring of samples allOptions.unshift({ @@ -2365,6 +2453,7 @@ export default class PlotsTab extends React.Component { dataType !== NONE_SELECTED_OPTION_STRING_VALUE && dataType !== GENESET_DATA_TYPE && dataType !== CLIN_ATTR_DATA_TYPE && + dataType !== CUSTOM_ATTR_DATA_TYPE && !isGenericAssaySelected ); } @@ -2408,12 +2497,27 @@ export default class PlotsTab extends React.Component { readonly clinicalAttributeIdToClinicalAttribute = remoteData<{ [clinicalAttributeId: string]: ClinicalAttribute; }>({ - await: () => [this.props.clinicalAttributes, this.props.studyIds], + await: () => [this.props.studyIds, this.props.clinicalAttributes], invoke: () => { let _map: { [clinicalAttributeId: string]: ClinicalAttribute; } = _.keyBy( - this.props.clinicalAttributes.result, + this.props.clinicalAttributes.result!, + c => c.clinicalAttributeId + ); + return Promise.resolve(_map); + }, + }); + + readonly customAttributeIdToClinicalAttribute = remoteData<{ + [clinicalAttributeId: string]: ClinicalAttribute; + }>({ + await: () => [this.props.studyIds, this.props.customAttributes], + invoke: () => { + let _map: { + [clinicalAttributeId: string]: ClinicalAttribute; + } = _.keyBy( + this.props.customAttributes.result!, c => c.clinicalAttributeId ); return Promise.resolve(_map); @@ -2427,21 +2531,25 @@ export default class PlotsTab extends React.Component { invoke: () => { return Promise.resolve( _.groupBy( - this.props.clinicalAttributes.result, + this.props.clinicalAttributes.result!, c => c.clinicalAttributeId ) ); }, }); - readonly clinicalAttributeOptions = remoteData({ - await: () => [this.props.clinicalAttributes], - invoke: () => - Promise.resolve( - makeClinicalAttributeOptions( - this.props.clinicalAttributes.result! + readonly customAttributesGroupByclinicalAttributeId = remoteData<{ + [clinicalAttributeId: string]: ClinicalAttribute[]; + }>({ + await: () => [this.props.customAttributes], + invoke: () => { + return Promise.resolve( + _.groupBy( + this.props.customAttributes.result!, + c => c.clinicalAttributeId ) - ), + ); + }, }); readonly dataTypeOptions = remoteData({ @@ -2450,6 +2558,7 @@ export default class PlotsTab extends React.Component { this.clinicalAttributeOptions, this.props.molecularProfilesInStudies, this.props.genesets, + this.customAttributeOptions, ], invoke: () => { const profiles = this.props.molecularProfilesWithData.result!; @@ -2476,6 +2585,10 @@ export default class PlotsTab extends React.Component { dataTypeIds.push(CLIN_ATTR_DATA_TYPE); } + if (!_.isEmpty(this.customAttributeOptions.result)) { + dataTypeIds.push(CUSTOM_ATTR_DATA_TYPE); + } + if ( this.props.molecularProfilesInStudies.result!.length && this.horzGenesetOptions.result && @@ -2532,6 +2645,7 @@ export default class PlotsTab extends React.Component { await: () => [ this.props.molecularProfilesInStudies, this.clinicalAttributeOptions, + this.customAttributeOptions, ], invoke: () => { const profiles = this.props.molecularProfilesInStudies.result!; @@ -2584,6 +2698,13 @@ export default class PlotsTab extends React.Component { CLIN_ATTR_DATA_TYPE ] = this.clinicalAttributeOptions.result!; } + + if (!_.isEmpty(this.customAttributeOptions.result)) { + // add custom attributes + map[ + CUSTOM_ATTR_DATA_TYPE + ] = this.customAttributeOptions.result!; + } return Promise.resolve(map); }, }); @@ -2686,6 +2807,7 @@ export default class PlotsTab extends React.Component { @computed get hasMolecularProfile() { return (dataType: string | undefined) => dataType !== CLIN_ATTR_DATA_TYPE && + dataType !== CUSTOM_ATTR_DATA_TYPE && dataType !== AlterationTypeConstants.GENERIC_ASSAY; } @@ -2822,6 +2944,7 @@ export default class PlotsTab extends React.Component { selection.dataType !== undefined && selection.dataType !== NONE_SELECTED_OPTION_STRING_VALUE && selection.dataType !== CLIN_ATTR_DATA_TYPE && + selection.dataType !== CUSTOM_ATTR_DATA_TYPE && selection.dataType !== GENESET_DATA_TYPE && !isGenericAssaySelected(selection) ); @@ -3048,6 +3171,7 @@ export default class PlotsTab extends React.Component { return makeAxisDataPromise( this.horzSelection, this.clinicalAttributeIdToClinicalAttribute, + this.customAttributeIdToClinicalAttribute, this.props.molecularProfileIdSuffixToMolecularProfiles, this.props.patientKeyToFilteredSamples, this.props.entrezGeneIdToGene, @@ -3075,6 +3199,7 @@ export default class PlotsTab extends React.Component { return makeAxisDataPromise( this.vertSelection, this.clinicalAttributeIdToClinicalAttribute, + this.customAttributeIdToClinicalAttribute, this.props.molecularProfileIdSuffixToMolecularProfiles, this.props.patientKeyToFilteredSamples, this.props.entrezGeneIdToGene, @@ -3154,6 +3279,7 @@ export default class PlotsTab extends React.Component { this.props.molecularProfileIdSuffixToMolecularProfiles, this.props.entrezGeneIdToGene, this.clinicalAttributeIdToClinicalAttribute, + this.customAttributeIdToClinicalAttribute, this.plotType, ], invoke: () => { @@ -3164,6 +3290,7 @@ export default class PlotsTab extends React.Component { .result!, this.props.entrezGeneIdToGene.result!, this.clinicalAttributeIdToClinicalAttribute.result!, + this.customAttributeIdToClinicalAttribute.result!, this.horzLogScaleFunction ) ); @@ -3175,6 +3302,7 @@ export default class PlotsTab extends React.Component { this.props.molecularProfileIdSuffixToMolecularProfiles, this.props.entrezGeneIdToGene, this.clinicalAttributeIdToClinicalAttribute, + this.customAttributeIdToClinicalAttribute, ], invoke: () => { return Promise.resolve( @@ -3184,6 +3312,7 @@ export default class PlotsTab extends React.Component { .result!, this.props.entrezGeneIdToGene.result!, this.clinicalAttributeIdToClinicalAttribute.result!, + this.customAttributeIdToClinicalAttribute.result!, this.vertLogScaleFunction ) ); @@ -3195,6 +3324,7 @@ export default class PlotsTab extends React.Component { this.props.molecularProfileIdSuffixToMolecularProfiles, this.props.entrezGeneIdToGene, this.clinicalAttributeIdToClinicalAttribute, + this.customAttributeIdToClinicalAttribute, this.plotType, ], invoke: () => { @@ -3212,6 +3342,7 @@ export default class PlotsTab extends React.Component { .result!, this.props.entrezGeneIdToGene.result!, this.clinicalAttributeIdToClinicalAttribute.result!, + this.customAttributeIdToClinicalAttribute.result!, logScaleFunc ) ); @@ -3564,6 +3695,9 @@ export default class PlotsTab extends React.Component { : structuralVariantCountByOptions; switch (axisSelection.dataType) { + case CUSTOM_ATTR_DATA_TYPE: + dataSourceLabel = 'Custom Attribute'; + break; case CLIN_ATTR_DATA_TYPE: dataSourceLabel = 'Clinical Attribute'; break; @@ -3609,6 +3743,11 @@ export default class PlotsTab extends React.Component { .clinicalAttributeIdToClinicalAttribute.result![ dataSourceValue ].description; + } else if (axisSelection.dataType === CUSTOM_ATTR_DATA_TYPE) { + dataSourceDescription = this + .customAttributeIdToClinicalAttribute.result![ + dataSourceValue + ].description; } else { dataSourceDescription = this.props .molecularProfileIdSuffixToMolecularProfiles.result![ @@ -3939,7 +4078,9 @@ export default class PlotsTab extends React.Component { style={{ display: axisSelection.dataType === - CLIN_ATTR_DATA_TYPE + CLIN_ATTR_DATA_TYPE || + axisSelection.dataType === + CUSTOM_ATTR_DATA_TYPE ? 'none' : 'block', }} @@ -3979,7 +4120,9 @@ export default class PlotsTab extends React.Component { axisSelection.dataType === CLIN_ATTR_DATA_TYPE || axisSelection.dataType === - GENESET_DATA_TYPE + GENESET_DATA_TYPE || + axisSelection.dataType === + CUSTOM_ATTR_DATA_TYPE } loadOptions={loadOptions} cacheOptions={true} @@ -4017,7 +4160,9 @@ export default class PlotsTab extends React.Component { axisSelection.dataType === CLIN_ATTR_DATA_TYPE || axisSelection.dataType === - GENESET_DATA_TYPE + GENESET_DATA_TYPE || + axisSelection.dataType === + CUSTOM_ATTR_DATA_TYPE } /> @@ -4125,6 +4270,8 @@ export default class PlotsTab extends React.Component { undefined || axisSelection.dataType === CLIN_ATTR_DATA_TYPE || + axisSelection.dataType === + CUSTOM_ATTR_DATA_TYPE || !isGenericAssaySelected( axisSelection ) diff --git a/src/shared/components/plots/PlotsTabUtils.tsx b/src/shared/components/plots/PlotsTabUtils.tsx index 97ba12da992..23af98bf8ef 100644 --- a/src/shared/components/plots/PlotsTabUtils.tsx +++ b/src/shared/components/plots/PlotsTabUtils.tsx @@ -85,6 +85,7 @@ import { AnnotatedNumericGeneMolecularData } from 'shared/model/AnnotatedNumeric import { CustomDriverNumericGeneMolecularData } from 'shared/model/CustomDriverNumericGeneMolecularData'; export const CLIN_ATTR_DATA_TYPE = 'clinical_attribute'; +export const CUSTOM_ATTR_DATA_TYPE = 'custom_attribute'; export const GENESET_DATA_TYPE = 'GENESET_SCORE'; export const dataTypeToDisplayType: { [s: string]: string } = { [AlterationTypeConstants.MUTATION_EXTENDED]: 'Mutation', @@ -95,6 +96,7 @@ export const dataTypeToDisplayType: { [s: string]: string } = { [AlterationTypeConstants.METHYLATION]: 'DNA Methylation', [CLIN_ATTR_DATA_TYPE]: 'Clinical Attribute', [GENESET_DATA_TYPE]: 'Gene Sets', + [CUSTOM_ATTR_DATA_TYPE]: 'Custom Data', }; export const NO_GENE_OPTION = { @@ -115,6 +117,7 @@ export const mutationTypeToDisplayName: { export const dataTypeDisplayOrder = [ CLIN_ATTR_DATA_TYPE, + CUSTOM_ATTR_DATA_TYPE, AlterationTypeConstants.MUTATION_EXTENDED, AlterationTypeConstants.STRUCTURAL_VARIANT, AlterationTypeConstants.COPY_NUMBER_ALTERATION, @@ -1423,6 +1426,9 @@ export function makeAxisDataPromise( clinicalAttributeIdToClinicalAttribute: MobxPromise<{ [clinicalAttributeId: string]: ClinicalAttribute; }>, + customAttributeIdToClinicalAttribute: MobxPromise<{ + [clinicalAttributeId: string]: ClinicalAttribute; + }>, molecularProfileIdSuffixToMolecularProfiles: MobxPromise<{ [molecularProfileIdSuffix: string]: MolecularProfile[]; }>, @@ -1495,6 +1501,21 @@ export function makeAxisDataPromise( ); } break; + case CUSTOM_ATTR_DATA_TYPE: + if ( + selection.dataSourceId !== undefined && + customAttributeIdToClinicalAttribute.isComplete + ) { + const attribute = customAttributeIdToClinicalAttribute.result![ + selection.dataSourceId + ]; + ret = makeAxisDataPromise_Clinical( + attribute, + clinicalDataCache, + patientKeyToSamples + ); + } + break; case GENESET_DATA_TYPE: if ( selection.genesetId !== undefined && @@ -1553,6 +1574,9 @@ export function getAxisLabel( clinicalAttributeIdToClinicalAttribute: { [clinicalAttributeId: string]: ClinicalAttribute; }, + customAttributeIdToClinicalAttribute: { + [clinicalAttributeId: string]: ClinicalAttribute; + }, logScaleFunc: IAxisLogScaleParams | undefined ) { let label = ''; @@ -1570,6 +1594,13 @@ export function getAxisLabel( switch (selection.dataType) { case NONE_SELECTED_OPTION_STRING_VALUE: break; + case CUSTOM_ATTR_DATA_TYPE: + const customAttr = + customAttributeIdToClinicalAttribute[selection.dataSourceId!]; + if (customAttr) { + label = customAttr.displayName; + } + break; case CLIN_ATTR_DATA_TYPE: const attribute = clinicalAttributeIdToClinicalAttribute[selection.dataSourceId!]; @@ -1623,10 +1654,20 @@ export function getAxisDescription( }, clinicalAttributeIdToClinicalAttribute: { [clinicalAttributeId: string]: ClinicalAttribute; + }, + customAttributeIdToClinicalAttribute: { + [clinicalAttributeId: string]: ClinicalAttribute; } ) { let ret = ''; switch (selection.dataType) { + case CUSTOM_ATTR_DATA_TYPE: + const customAttr = + customAttributeIdToClinicalAttribute[selection.dataSourceId!]; + if (customAttr) { + ret = customAttr.description; + } + break; case CLIN_ATTR_DATA_TYPE: const attribute = clinicalAttributeIdToClinicalAttribute[selection.dataSourceId!]; @@ -3169,6 +3210,7 @@ export function bothAxesNoMolecularProfile( vertSelection: AxisMenuSelection ): boolean { const noMolecularProfileDataTypes = [ + CUSTOM_ATTR_DATA_TYPE, CLIN_ATTR_DATA_TYPE, NONE_SELECTED_OPTION_STRING_VALUE, ];