import * as React from 'react';
import { computed, makeObservable } from 'mobx';
import {
default as MutationTable,
IMutationTableProps,
MutationTableColumn,
MutationTableColumnType,
} from 'shared/components/mutationTable/MutationTable';
import SampleManager from '../SampleManager';
import { Mutation } from 'cbioportal-ts-api-client';
import AlleleCountColumnFormatter from 'shared/components/mutationTable/column/AlleleCountColumnFormatter';
import AlleleFreqColumnFormatter from './column/AlleleFreqColumnFormatter';
import TumorColumnFormatter from './column/TumorColumnFormatter';
import PanelColumnFormatter from 'shared/components/mutationTable/column/PanelColumnFormatter';
import { isUncalled } from 'shared/lib/MutationUtils';
import ExonColumnFormatter from 'shared/components/mutationTable/column/ExonColumnFormatter';
import HeaderIconMenu from './HeaderIconMenu';
import GeneFilterMenu, { GeneFilterOption } from './GeneFilterMenu';
import { getDefaultASCNCopyNumberColumnDefinition } from 'shared/components/mutationTable/column/ascnCopyNumber/ASCNCopyNumberColumnFormatter';
import { getDefaultCancerCellFractionColumnDefinition } from 'shared/components/mutationTable/column/cancerCellFraction/CancerCellFractionColumnFormatter';
import { getDefaultClonalColumnDefinition } from 'shared/components/mutationTable/column/clonal/ClonalColumnFormatter';
import { getDefaultExpectedAltCopiesColumnDefinition } from 'shared/components/mutationTable/column/expectedAltCopies/ExpectedAltCopiesColumnFormatter';
import { ASCNAttributes } from 'shared/enums/ASCNEnums';
import AnnotationHeader from 'shared/components/mutationTable/column/annotation/AnnotationHeader';
import _ from 'lodash';
import { createMutationNamespaceColumns } from 'shared/components/mutationTable/MutationTableUtils';
import { getServerConfig } from 'config/config';
import { adjustVisibility } from 'shared/components/alterationsTableUtils';
export interface IPatientViewMutationTableProps extends IMutationTableProps {
sampleManager: SampleManager | null;
sampleToGenePanelId: { [sampleId: string]: string | undefined };
genePanelIdToEntrezGeneIds: { [genePanelId: string]: number[] };
sampleIds?: string[];
showGeneFilterMenu?: boolean;
currentGeneFilter: GeneFilterOption;
onFilterGenes?: (option: GeneFilterOption) => void;
onSelectGenePanel?: (name: string) => void;
disableTooltip?: boolean;
existsSomeMutationWithAscnProperty: { [property: string]: boolean };
alleleFreqHeaderRender?: (name: string) => JSX.Element;
}
export const defaultAlleleFrequencyHeaderTooltip = (
Variant allele frequency in the tumor sample
);
export default class PatientViewMutationTable extends MutationTable<
IPatientViewMutationTableProps
> {
constructor(props: IPatientViewMutationTableProps) {
super(props);
makeObservable(this);
}
public static defaultProps = {
...MutationTable.defaultProps,
initialItemsPerPage: 10,
paginationProps: { itemsPerPageOptions: [10, 25, 50, 100] },
showGeneFilterMenu: true,
columns: [
MutationTableColumnType.COHORT,
MutationTableColumnType.MRNA_EXPR,
MutationTableColumnType.COPY_NUM,
MutationTableColumnType.ASCN_METHOD,
MutationTableColumnType.ASCN_COPY_NUM,
MutationTableColumnType.ANNOTATION,
MutationTableColumnType.HGVSG,
MutationTableColumnType.REF_READS_N,
MutationTableColumnType.VAR_READS_N,
MutationTableColumnType.REF_READS,
MutationTableColumnType.VAR_READS,
MutationTableColumnType.START_POS,
MutationTableColumnType.END_POS,
MutationTableColumnType.REF_ALLELE,
MutationTableColumnType.VAR_ALLELE,
MutationTableColumnType.MUTATION_STATUS,
MutationTableColumnType.VALIDATION_STATUS,
MutationTableColumnType.CENTER,
MutationTableColumnType.GENE,
MutationTableColumnType.CHROMOSOME,
MutationTableColumnType.PROTEIN_CHANGE,
MutationTableColumnType.MUTATION_TYPE,
MutationTableColumnType.VARIANT_TYPE,
MutationTableColumnType.CLONAL,
MutationTableColumnType.CANCER_CELL_FRACTION,
MutationTableColumnType.EXPECTED_ALT_COPIES,
MutationTableColumnType.FUNCTIONAL_IMPACT,
MutationTableColumnType.COSMIC,
MutationTableColumnType.TUMOR_ALLELE_FREQ,
MutationTableColumnType.SAMPLES,
MutationTableColumnType.EXON,
MutationTableColumnType.HGVSC,
MutationTableColumnType.GNOMAD,
MutationTableColumnType.CLINVAR,
MutationTableColumnType.DBSNP,
MutationTableColumnType.GENE_PANEL,
MutationTableColumnType.SIGNAL,
],
};
protected getSamples(): string[] {
if (this.props.sampleIds) {
return this.props.sampleIds;
} else {
return [];
}
}
protected generateColumns() {
super.generateColumns();
this._columns[MutationTableColumnType.TUMOR_ALLELE_FREQ] = {
name: 'Allele Freq',
headerRender: this.props.alleleFreqHeaderRender,
render: (d: Mutation[]) =>
AlleleFreqColumnFormatter.renderFunction(
d,
this.props.sampleManager
),
sortBy: (d: Mutation[]) =>
AlleleFreqColumnFormatter.getSortValue(
d,
this.props.sampleManager
),
download: (d: Mutation[]) =>
AlleleFreqColumnFormatter.getFrequency(d),
tooltip: this.props.alleleFreqHeaderRender
? undefined
: defaultAlleleFrequencyHeaderTooltip,
visible: AlleleFreqColumnFormatter.isVisible(
this.props.sampleManager,
this.props.dataStore
? this.props.dataStore.allData
: this.props.data
),
};
this._columns[MutationTableColumnType.SAMPLES] = {
name: 'Samples',
render: (d: Mutation[]) =>
TumorColumnFormatter.renderFunction(
d,
this.props.sampleManager,
this.props.sampleToGenePanelId,
this.props.genePanelIdToEntrezGeneIds,
this.props.onSelectGenePanel,
this.props.disableTooltip
),
sortBy: (d: Mutation[]) =>
TumorColumnFormatter.getSortValue(d, this.props.sampleManager),
download: (d: Mutation[]) => TumorColumnFormatter.getSample(d),
resizable: true,
};
const GenePanelProps = (d: Mutation[]) => ({
data: d,
sampleToGenePanelId: this.props.sampleToGenePanelId,
sampleManager: this.props.sampleManager,
genePanelIdToGene: this.props.genePanelIdToEntrezGeneIds,
onSelectGenePanel: this.props.onSelectGenePanel,
});
this._columns[MutationTableColumnType.GENE_PANEL] = {
name: 'Gene panel',
render: (d: Mutation[]) =>
PanelColumnFormatter.renderFunction(GenePanelProps(d)),
download: (d: Mutation[]) =>
PanelColumnFormatter.download(GenePanelProps(d)),
visible: false,
sortBy: (d: Mutation[]) =>
PanelColumnFormatter.getGenePanelIds(GenePanelProps(d)),
};
// customization for ASCN-related columns
// Patient view differs from default/results view because multiple samples can appear in a row
// due to same variant in multiple samples
// This can lead to cases where there are multiple icons/tooltips in a single cell
// therefore patient view needs sampleManager to indicate which values match which samples
this._columns[
MutationTableColumnType.CANCER_CELL_FRACTION
] = getDefaultCancerCellFractionColumnDefinition(
this.getSamples(),
this.props.sampleManager
);
this._columns[
MutationTableColumnType.CLONAL
] = getDefaultClonalColumnDefinition(
this.getSamples(),
this.props.sampleManager
);
this._columns[
MutationTableColumnType.EXPECTED_ALT_COPIES
] = getDefaultExpectedAltCopiesColumnDefinition(
this.getSamples(),
this.props.sampleManager
);
this._columns[
MutationTableColumnType.ASCN_COPY_NUM
] = getDefaultASCNCopyNumberColumnDefinition(
this.getSamples(),
this.props.sampleIdToClinicalDataMap,
this.props.sampleManager
);
// customization for allele count columns
this._columns[MutationTableColumnType.REF_READS_N].render = (
d: Mutation[]
) =>
AlleleCountColumnFormatter.renderFunction(
d,
this.getSamples(),
'normalRefCount'
);
this._columns[MutationTableColumnType.REF_READS_N].download = (
d: Mutation[]
) => AlleleCountColumnFormatter.getReads(d, 'normalRefCount');
this._columns[MutationTableColumnType.VAR_READS_N].render = (
d: Mutation[]
) =>
AlleleCountColumnFormatter.renderFunction(
d,
this.getSamples(),
'normalAltCount'
);
this._columns[MutationTableColumnType.VAR_READS_N].download = (
d: Mutation[]
) => AlleleCountColumnFormatter.getReads(d, 'normalAltCount');
this._columns[MutationTableColumnType.REF_READS].render = (
d: Mutation[]
) =>
AlleleCountColumnFormatter.renderFunction(
d,
this.getSamples(),
'tumorRefCount'
);
this._columns[MutationTableColumnType.REF_READS].download = (
d: Mutation[]
) => AlleleCountColumnFormatter.getReads(d, 'tumorRefCount');
this._columns[MutationTableColumnType.VAR_READS].render = (
d: Mutation[]
) =>
AlleleCountColumnFormatter.renderFunction(
d,
this.getSamples(),
'tumorAltCount'
);
this._columns[MutationTableColumnType.VAR_READS].download = (
d: Mutation[]
) => AlleleCountColumnFormatter.getReads(d, 'tumorAltCount');
// customization for columns
this._columns[MutationTableColumnType.EXON].sortBy = undefined;
this._columns[MutationTableColumnType.EXON].render = (d: Mutation[]) =>
ExonColumnFormatter.renderFunction(
d,
this.props.genomeNexusCache,
true
);
this._columns[MutationTableColumnType.GENE].headerRender = (
name: string
) => {
return (
);
};
this._columns[MutationTableColumnType.ANNOTATION].headerRender = (
name: string
) => {
return (
);
};
// order columns
this._columns[MutationTableColumnType.SAMPLES].order = 5;
this._columns[MutationTableColumnType.GENE].order = 20;
this._columns[MutationTableColumnType.GENE_PANEL].order = 25;
this._columns[MutationTableColumnType.PROTEIN_CHANGE].order = 30;
this._columns[MutationTableColumnType.ANNOTATION].order = 35;
this._columns[MutationTableColumnType.FUNCTIONAL_IMPACT].order = 38;
this._columns[MutationTableColumnType.CHROMOSOME].order = 40;
this._columns[MutationTableColumnType.START_POS].order = 50;
this._columns[MutationTableColumnType.END_POS].order = 60;
this._columns[MutationTableColumnType.REF_ALLELE].order = 70;
this._columns[MutationTableColumnType.VAR_ALLELE].order = 80;
this._columns[MutationTableColumnType.HGVSG].order = 81;
this._columns[MutationTableColumnType.HGVSC].order = 82;
this._columns[MutationTableColumnType.MUTATION_STATUS].order = 90;
this._columns[MutationTableColumnType.VALIDATION_STATUS].order = 100;
this._columns[MutationTableColumnType.MUTATION_TYPE].order = 110;
this._columns[MutationTableColumnType.VARIANT_TYPE].order = 114;
this._columns[MutationTableColumnType.ASCN_METHOD].order = 115;
this._columns[MutationTableColumnType.CLONAL].order = 116;
this._columns[MutationTableColumnType.CANCER_CELL_FRACTION].order = 117;
this._columns[MutationTableColumnType.EXPECTED_ALT_COPIES].order = 118;
this._columns[MutationTableColumnType.ASCN_COPY_NUM].order = 119;
this._columns[MutationTableColumnType.CENTER].order = 120;
this._columns[MutationTableColumnType.TUMOR_ALLELE_FREQ].order = 130;
this._columns[MutationTableColumnType.VAR_READS].order = 140;
this._columns[MutationTableColumnType.REF_READS].order = 150;
this._columns[MutationTableColumnType.VAR_READS_N].order = 170;
this._columns[MutationTableColumnType.REF_READS_N].order = 175;
this._columns[MutationTableColumnType.COPY_NUM].order = 177;
this._columns[MutationTableColumnType.MRNA_EXPR].order = 182;
this._columns[MutationTableColumnType.COHORT].order = 183;
this._columns[MutationTableColumnType.COSMIC].order = 184;
this._columns[MutationTableColumnType.EXON].order = 185;
this._columns[MutationTableColumnType.GNOMAD].order = 187;
this._columns[MutationTableColumnType.CLINVAR].order = 188;
this._columns[MutationTableColumnType.DBSNP].order = 189;
this._columns[MutationTableColumnType.SIGNAL].order = 190;
// exclusions
this._columns[MutationTableColumnType.MRNA_EXPR].shouldExclude = () => {
return (
!this.props.mrnaExprRankMolecularProfileId ||
this.getSamples().length > 1
);
};
this._columns[MutationTableColumnType.CLONAL].shouldExclude = () => {
return !this.props.existsSomeMutationWithAscnProperty[
ASCNAttributes.CCF_EXPECTED_COPIES_STRING
];
};
this._columns[
MutationTableColumnType.ASCN_METHOD
].shouldExclude = () => {
return !this.props.existsSomeMutationWithAscnProperty[
ASCNAttributes.ASCN_METHOD_STRING
];
};
this._columns[
MutationTableColumnType.CANCER_CELL_FRACTION
].shouldExclude = () => {
return !this.props.existsSomeMutationWithAscnProperty[
ASCNAttributes.CCF_EXPECTED_COPIES_STRING
];
};
this._columns[
MutationTableColumnType.EXPECTED_ALT_COPIES
].shouldExclude = () => {
return !this.props.existsSomeMutationWithAscnProperty[
ASCNAttributes.EXPECTED_ALT_COPIES_STRING
];
};
this._columns[
MutationTableColumnType.ASCN_COPY_NUM
].shouldExclude = () => {
return (
!this.props.existsSomeMutationWithAscnProperty[
ASCNAttributes.ASCN_INTEGER_COPY_NUMBER_STRING
] ||
!this.props.existsSomeMutationWithAscnProperty[
ASCNAttributes.TOTAL_COPY_NUMBER_STRING
] ||
!this.props.existsSomeMutationWithAscnProperty[
ASCNAttributes.MINOR_COPY_NUMBER_STRING
]
);
};
// only hide tumor column if there is one sample and no uncalled
// mutations (there is no information added in that case by the sample
// label)
this._columns[MutationTableColumnType.SAMPLES].shouldExclude = () => {
return this.getSamples().length < 2 && !this.hasUncalledMutations;
};
this._columns[MutationTableColumnType.COPY_NUM].shouldExclude = () => {
return (
!this.props.discreteCNAMolecularProfileId ||
this.getSamples().length > 1
);
};
// generate namespace columns
const namespaceColumns = createMutationNamespaceColumns(
this.props.namespaceColumns
);
_.forIn(
namespaceColumns,
(column: MutationTableColumn, columnName: string) => {
this._columns[columnName] = column;
}
);
//Adjust column visibility according to portal.properties
adjustVisibility(
this._columns,
Object.keys(namespaceColumns),
getServerConfig()
.skin_patient_view_mutation_table_columns_show_on_init,
getServerConfig()
.skin_mutation_table_namespace_column_show_by_default
);
}
@computed private get hasUncalledMutations(): boolean {
let data: Mutation[][] = [];
if (this.props.data) {
data = this.props.data;
} else if (this.props.dataStore) {
data = this.props.dataStore.allData;
}
return data.some((row: Mutation[]) => {
return row.some((m: Mutation) => {
return isUncalled(m.molecularProfileId);
});
});
}
}