diff --git a/browser/src/GenePage/GenePage.tsx b/browser/src/GenePage/GenePage.tsx index e686aaecc..f93a8712b 100644 --- a/browser/src/GenePage/GenePage.tsx +++ b/browser/src/GenePage/GenePage.tsx @@ -22,7 +22,6 @@ import { isExac, hasCopyNumberVariants, isV2, - getTopLevelDataset, } from '@gnomad/dataset-metadata/metadata' import ConstraintTable from '../ConstraintTable/ConstraintTable' import VariantCooccurrenceCountsTable, { @@ -73,7 +72,6 @@ import { } from '../ChartStyles' import { logButtonClick } from '../analytics' import { GtexTissueExpression } from './TranscriptsTissueExpression' -import { GTEX_TISSUES } from '../gtex' export type Strand = '+' | '-' @@ -527,7 +525,6 @@ const GenePage = ({ datasetId, gene, geneId }: Props) => { { {hasCodingExons && gene.chrom !== 'M' && gene.pext && ( diff --git a/browser/src/GenePage/GeneTranscriptsTrack.tsx b/browser/src/GenePage/GeneTranscriptsTrack.tsx index 0116273d2..ef75a616f 100644 --- a/browser/src/GenePage/GeneTranscriptsTrack.tsx +++ b/browser/src/GenePage/GeneTranscriptsTrack.tsx @@ -8,14 +8,14 @@ import { Track } from '@gnomad/region-viewer' import TranscriptsTrack from '@gnomad/track-transcripts' import { Button, Modal, TooltipAnchor } from '@gnomad/ui' -import { AllGtexTissues, TissueDetail } from '../gtex' +import { ALL_GTEX_TISSUES, GtexTissueName } from '../gtex' import InfoButton from '../help/InfoButton' import Link from '../Link' import sortedTranscripts from './sortedTranscripts' import TranscriptsTissueExpression from './TranscriptsTissueExpression' import { Gene } from './GenePage' import { DatasetId, hasStructuralVariants } from '../../../dataset-metadata/metadata' -import { TranscriptWithTissueExpression } from './TissueExpressionTrack' +import { GtexTissueDetail, TranscriptWithTissueExpression } from './TissueExpressionTrack' const TranscriptsInfoWrapper = styled.div` display: flex; @@ -38,7 +38,6 @@ const RightPanel = styled.div` type GeneTranscriptsTrack = { datasetId: DatasetId isTissueExpressionAvailable: boolean - gtexTissues: Partial & { [key: string]: TissueDetail | undefined } gene: Gene includeNonCodingTranscripts: boolean includeUTRs: boolean @@ -49,7 +48,6 @@ type GeneTranscriptsTrack = { const GeneTranscriptsTrack = ({ datasetId, isTissueExpressionAvailable, - gtexTissues, gene, includeNonCodingTranscripts, includeUTRs, @@ -59,6 +57,20 @@ const GeneTranscriptsTrack = ({ const transcriptsTrack = useRef(null) const [showTissueExpressionModal, setShowTissueExpressionModal] = useState(false) + const gtexTissues: Partial> = {} + if (isTissueExpressionAvailable) { + const preferredTranscript = (gene.transcripts as TranscriptWithTissueExpression[]).find( + (transcript) => transcript.transcript_id === preferredTranscriptId + ) + preferredTranscript!.gtex_tissue_expression.forEach((tissue) => { + gtexTissues[tissue.tissue as GtexTissueName] = { + fullName: ALL_GTEX_TISSUES[tissue.tissue as GtexTissueName].fullName || tissue.tissue, + color: ALL_GTEX_TISSUES[tissue.tissue as GtexTissueName].color || '#888888', + value: tissue.value, + } + }) + } + const maxMeanExpression = isTissueExpressionAvailable ? max( (gene.transcripts as TranscriptWithTissueExpression[]).map( @@ -167,7 +179,7 @@ const GeneTranscriptsTrack = ({ tooltip={`Mean expression across all tissues = ${meanExpression.toFixed( 2 )} TPM\nMost expressed in ${ - gtexTissues[tissueMostExpressedIn]!.fullName + gtexTissues[tissueMostExpressedIn as GtexTissueName]!.fullName } (${maxExpression.toFixed(2)} TPM)`} > + gtexTissues: Partial color: string regions: { start: number @@ -154,8 +153,7 @@ type ExpressedTissue = { } type IndividualTissueTrackProps = { - // datasetId: DatasetId - gtexTissues: Partial + gtexTissues: Partial exons: { start: number stop: number @@ -169,7 +167,7 @@ type IndividualTissueTrackProps = { maxTranscriptExpressionInTissue: number maxMeanTranscriptExpressionInAnyTissue: number meanTranscriptExpressionInTissue: number - tissue: string + tissue: GtexTissueName transcriptWithMaxExpressionInTissue: { transcript_id: string transcript_version: string @@ -189,13 +187,13 @@ const IndividualTissueTrack = ({ const isExpressed = expressionRegions.some( (region: any) => region.tissues.find((tissueObject: ExpressedTissue) => tissueObject.tissue === tissue) - .value !== 0 + ?.value !== 0 ) return ( {gtexTissuesForDataset[tissue].fullName}} + renderLeftPanel={() => {gtexTissues[tissue].fullName}} renderRightPanel={({ width }: any) => width > 36 && ( @@ -223,8 +221,7 @@ const IndividualTissueTrack = ({ )} (${transcriptWithMaxExpressionInTissue!.transcript_id}.${ transcriptWithMaxExpressionInTissue!.transcript_version })` - : // @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message - `Gene is not expressed in ${gtexTissuesForDataset[tissue].fullName}` + : `Gene is not expressed in ${gtexTissues[tissue]!.fullName}` } > @@ -258,13 +255,12 @@ const IndividualTissueTrack = ({ r.tissues.find((tissueObject: ExpressedTissue) => tissueObject.tissue === tissue) - .value + ?.value || 0 )} scalePosition={scalePosition} width={width} @@ -330,7 +326,6 @@ export type TranscriptWithTissueExpression = Omit exons: { start: number stop: number @@ -350,8 +345,13 @@ type TissueExpressionTrackProps = { preferredTranscriptDescription?: string | React.ReactNode } +export type GtexTissueDetail = { + fullName: string + color: string + value: number +} + const TissueExpressionTrack = ({ - gtexTissues, exons, expressionRegions, flags, @@ -368,6 +368,17 @@ const TissueExpressionTrack = ({ 'alphabetical' ) + const gtexTissues: Partial> = {} + transcripts + .find((transcript) => transcript.transcript_id === preferredTranscriptId) + ?.gtex_tissue_expression.forEach((tissue) => { + gtexTissues[tissue.tissue as GtexTissueName] = { + fullName: ALL_GTEX_TISSUES[tissue.tissue as GtexTissueName].fullName || tissue.tissue, + color: ALL_GTEX_TISSUES[tissue.tissue as GtexTissueName].color || '#888888', + value: tissue.value, + } + }) + type ExpressionByTissueDetails = { maxTranscriptExpressionInTissue: number meanTranscriptExpressionInTissue: number @@ -386,10 +397,10 @@ const TissueExpressionTrack = ({ transcripts.forEach((transcript) => { const expressionInTissue = transcript.gtex_tissue_expression.find( (tissue) => tissue.tissue === tissueId - )!.value + ) - if (expressionInTissue > maxTranscriptExpressionInTissue) { - maxTranscriptExpressionInTissue = expressionInTissue! + if (expressionInTissue && expressionInTissue.value > maxTranscriptExpressionInTissue) { + maxTranscriptExpressionInTissue = expressionInTissue.value transcriptWithMaxExpressionInTissue = { transcript_id: transcript.transcript_id, transcript_version: transcript.transcript_version, @@ -398,10 +409,12 @@ const TissueExpressionTrack = ({ }) const meanTranscriptExpressionInTissue = mean( - transcripts.map( - (transcript) => - transcript.gtex_tissue_expression.find((tissue) => tissue.tissue === tissueId)!.value - ) + transcripts + .map( + (transcript) => + transcript.gtex_tissue_expression.find((tissue) => tissue.tissue === tissueId)?.value + ) + .filter((value): value is number => value !== undefined) ) return { @@ -420,23 +433,27 @@ const TissueExpressionTrack = ({ Object.values(expressionByTissue).map((v) => v.meanTranscriptExpressionInTissue) )! - let tissues - if (sortTissuesBy === 'mean-expression') { - tissues = Object.entries(gtexTissues) - .sort((t1, t2) => { - const t1Expression = expressionByTissue[t1[0]].meanTranscriptExpressionInTissue - const t2Expression = expressionByTissue[t2[0]].meanTranscriptExpressionInTissue - if (t1Expression === t2Expression) { - return t1[1].fullName.localeCompare(t2[1].fullName) - } - return t2Expression - t1Expression - }) - .map((t: any) => t[0]) - } else { - tissues = Object.entries(gtexTissues) - .sort((t1, t2) => t1[1].fullName.localeCompare(t2[1].fullName)) - .map((t) => t[0]) - } + const tissues = + sortTissuesBy === 'mean-expression' + ? Object.entries(gtexTissues) + .sort((t1, t2) => { + const t1Expression = expressionByTissue[t1[0]].meanTranscriptExpressionInTissue + const t2Expression = expressionByTissue[t2[0]].meanTranscriptExpressionInTissue + if (t1Expression === t2Expression) { + return ALL_GTEX_TISSUES[t1[0] as GtexTissueName].fullName.localeCompare( + ALL_GTEX_TISSUES[t2[0] as GtexTissueName].fullName + ) + } + return t2Expression - t1Expression + }) + .map((t: any) => t[0]) + : Object.entries(gtexTissues) + .sort((t1, t2) => + ALL_GTEX_TISSUES[t1[0] as GtexTissueName].fullName.localeCompare( + ALL_GTEX_TISSUES[t2[0] as GtexTissueName].fullName + ) + ) + .map((t) => t[0]) const isExpressed = expressionRegions.some((region: any) => region.mean !== 0) @@ -579,25 +596,27 @@ const TissueExpressionTrack = ({ }} {(tissueFilterText ? tissues.filter(tissuePredicate(tissueFilterText)) : tissues).map( - (tissue: any) => ( - - ) + (tissue: any) => { + return ( + + ) + } )}