From 2ef898820d51419c60a20fbad2c00069b6bfad6f Mon Sep 17 00:00:00 2001 From: Riley Grant Date: Thu, 15 Aug 2024 17:03:01 -0500 Subject: [PATCH] feat(browser): adjust frontend for new gtex/pext schema --- browser/src/GenePage/GenePage.tsx | 58 ++- browser/src/GenePage/GenePageContainer.tsx | 167 +++---- browser/src/GenePage/GeneTranscriptsTrack.tsx | 82 ++-- .../src/GenePage/TissueExpressionTrack.tsx | 179 +++++--- .../GenePage/TranscriptsTissueExpression.tsx | 119 ++--- .../TranscriptsTissueExpressionPlot.tsx | 101 ++-- browser/src/GenePage/VariantsInGene.tsx | 14 +- browser/src/GenePage/sortedTranscripts.ts | 34 +- .../src/__factories__/TissueExpression.tsx | 172 +++---- browser/src/gtex.ts | 431 +++++++++++++----- 10 files changed, 739 insertions(+), 618 deletions(-) diff --git a/browser/src/GenePage/GenePage.tsx b/browser/src/GenePage/GenePage.tsx index 15be9baa8..e686aaecc 100644 --- a/browser/src/GenePage/GenePage.tsx +++ b/browser/src/GenePage/GenePage.tsx @@ -22,6 +22,7 @@ import { isExac, hasCopyNumberVariants, isV2, + getTopLevelDataset, } from '@gnomad/dataset-metadata/metadata' import ConstraintTable from '../ConstraintTable/ConstraintTable' import VariantCooccurrenceCountsTable, { @@ -50,7 +51,7 @@ import MitochondrialGeneCoverageTrack from './MitochondrialGeneCoverageTrack' import MitochondrialVariantsInGene from './MitochondrialVariantsInGene' import { getPreferredTranscript } from './preferredTranscript' import StructuralVariantsInGene from './StructuralVariantsInGene' -import TissueExpressionTrack from './TissueExpressionTrack' +import TissueExpressionTrack, { TranscriptWithTissueExpression } from './TissueExpressionTrack' import VariantsInGene from './VariantsInGene' import { GnomadConstraint } from '../ConstraintTable/GnomadConstraintTable' @@ -71,6 +72,8 @@ import { LegendSwatch, } from '../ChartStyles' import { logButtonClick } from '../analytics' +import { GtexTissueExpression } from './TranscriptsTissueExpression' +import { GTEX_TISSUES } from '../gtex' export type Strand = '+' | '-' @@ -88,6 +91,30 @@ export type GeneMetadata = { flags: string[] } +export type GeneTranscript = { + transcript_id: string + transcript_version: string + exons: { + feature_type: string + start: number + stop: number + }[] + gtex_tissue_expression: GtexTissueExpression | null +} + +export type Pext = { + regions: { + start: number + stop: number + mean: number + tissues: { + tissue: string + value: number + }[] + }[] + flags: string[] +} + export type Gene = GeneMetadata & { reference_genome: ReferenceGenome name?: string @@ -100,29 +127,11 @@ export type Gene = GeneMetadata & { start: number stop: number }[] - transcripts: { - transcript_id: string - transcript_version: string - exons: { - feature_type: string - start: number - stop: number - }[] - }[] + transcripts: GeneTranscript[] flags: string[] gnomad_constraint?: GnomadConstraint exac_constraint?: ExacConstraint - pext?: { - regions: { - start: number - stop: number - mean: number - tissues: { - [key: string]: number - } - }[] - flags: string[] - } + pext?: Pext short_tandem_repeats?: { id: string }[] @@ -517,6 +526,8 @@ const GenePage = ({ datasetId, gene, geneId }: Props) => { { {hasCodingExons && gene.chrom !== 'M' && gene.pext && ( @@ -563,7 +576,6 @@ const GenePage = ({ datasetId, gene, geneId }: Props) => { & { [key: string]: TissueDetail | undefined } gene: Gene includeNonCodingTranscripts: boolean includeUTRs: boolean @@ -43,27 +46,23 @@ type OwnProps = { preferredTranscriptDescription?: string | React.ReactNode } -// @ts-expect-error TS(2456) FIXME: Type alias 'Props' circularly references itself. -type Props = OwnProps & typeof GeneTranscriptsTrack.defaultProps - -// @ts-expect-error TS(7022) FIXME: 'GeneTranscriptsTrack' implicitly has type 'any' b... Remove this comment to see the full error message const GeneTranscriptsTrack = ({ datasetId, + isTissueExpressionAvailable, + gtexTissues, gene, includeNonCodingTranscripts, includeUTRs, preferredTranscriptId, preferredTranscriptDescription, -}: Props) => { +}: GeneTranscriptsTrack) => { const transcriptsTrack = useRef(null) - - const isTissueExpressionAvailable = gene.reference_genome === 'GRCh37' const [showTissueExpressionModal, setShowTissueExpressionModal] = useState(false) const maxMeanExpression = isTissueExpressionAvailable ? max( - gene.transcripts.map((transcript: any) => - mean(Object.values(transcript.gtex_tissue_expression)) + (gene.transcripts as TranscriptWithTissueExpression[]).map( + (transcript) => mean(transcript.gtex_tissue_expression.map((tissue) => tissue.value))! ) ) : undefined @@ -129,15 +128,36 @@ const GeneTranscriptsTrack = ({ renderTranscriptRightPanel={ !isTissueExpressionAvailable ? null - : ({ transcript, width }: any) => { + : ({ + transcript, + width, + }: { + transcript: TranscriptWithTissueExpression + width: number + }) => { if (width < 36) { return null } - const meanExpression = mean(Object.values(transcript.gtex_tissue_expression)) - const maxExpression = max(Object.values(transcript.gtex_tissue_expression)) - const tissueMostExpressedIn = Object.keys(transcript.gtex_tissue_expression).find( - (tissue: any) => transcript.gtex_tissue_expression[tissue] === maxExpression + const meanExpression = mean( + transcript.gtex_tissue_expression.map( + (tissueExpression) => tissueExpression.value + ) + )! + const maxExpression = max( + transcript.gtex_tissue_expression.map( + (tissueExpression) => tissueExpression.value + ) + )! + const tissueMostExpressedIn = transcript.gtex_tissue_expression.find( + (tissue) => tissue.value === maxExpression + )!.tissue + + const circleRadiusMeanContribution = meanExpression === 0 ? 0 : 0.25 + const circleRadiusMaxMeanContribution = + maxMeanExpression === 0 ? 0 : meanExpression / maxMeanExpression! // if the right panel render, maxMean is defined + const circleRadius = Math.sqrt( + circleRadiusMeanContribution + 23.75 * circleRadiusMaxMeanContribution ) return ( @@ -147,12 +167,8 @@ const GeneTranscriptsTrack = ({ tooltip={`Mean expression across all tissues = ${meanExpression.toFixed( 2 )} TPM\nMost expressed in ${ - // @ts-expect-error TS(2538) FIXME: Type 'undefined' cannot be used as an index type. - GTEX_TISSUE_NAMES[tissueMostExpressedIn] - } (${ - // @ts-expect-error TS(2532) FIXME: Object is possibly 'undefined'. - maxExpression.toFixed(2) - } TPM)`} + gtexTissues[tissueMostExpressedIn]!.fullName + } (${maxExpression.toFixed(2)} TPM)`} > - + ) } @@ -195,7 +198,8 @@ const GeneTranscriptsTrack = ({ }} > { const roundedRegions = expressionRegions.map((region: any) => ({ @@ -67,6 +68,8 @@ const TRACK_HEIGHT = 20 const heightScale = scaleLinear().domain([0, 1]).range([0, TRACK_HEIGHT]).clamp(true) type PextRegionsPlotProps = { + // datasetId: DatasetId + gtexTissues: Partial color: string regions: { start: number @@ -145,8 +148,14 @@ const NotExpressedMessage = styled.div` color: gray; font-size: 10px; ` +type ExpressedTissue = { + tissue: string + value: number +} -type OwnIndividualTissueTrackProps = { +type IndividualTissueTrackProps = { + // datasetId: DatasetId + gtexTissues: Partial exons: { start: number stop: number @@ -155,26 +164,20 @@ type OwnIndividualTissueTrackProps = { start: number stop: number mean?: number - tissues: { - [key: string]: number - } + tissues: ExpressedTissue[] }[] maxTranscriptExpressionInTissue: number maxMeanTranscriptExpressionInAnyTissue: number meanTranscriptExpressionInTissue: number tissue: string - transcriptWithMaxExpressionInTissue?: { + transcriptWithMaxExpressionInTissue: { transcript_id: string transcript_version: string - } + } | null } -// @ts-expect-error TS(2456) FIXME: Type alias 'IndividualTissueTrackProps' circularly... Remove this comment to see the full error message -type IndividualTissueTrackProps = OwnIndividualTissueTrackProps & - typeof IndividualTissueTrack.defaultProps - -// @ts-expect-error TS(7022) FIXME: 'IndividualTissueTrack' implicitly has type 'any' ... Remove this comment to see the full error message const IndividualTissueTrack = ({ + gtexTissues, exons, expressionRegions, maxTranscriptExpressionInTissue, @@ -183,11 +186,16 @@ const IndividualTissueTrack = ({ tissue, transcriptWithMaxExpressionInTissue, }: IndividualTissueTrackProps) => { - const isExpressed = expressionRegions.some((region: any) => region.tissues[tissue] !== 0) + const isExpressed = expressionRegions.some( + (region: any) => + region.tissues.find((tissueObject: ExpressedTissue) => tissueObject.tissue === tissue) + .value !== 0 + ) + return ( {GTEX_TISSUE_NAMES[tissue]}} + renderLeftPanel={() => {gtexTissuesForDataset[tissue].fullName}} renderRightPanel={({ width }: any) => width > 36 && ( @@ -212,11 +220,11 @@ const IndividualTissueTrack = ({ 2 )} TPM\nMax transcript expression in this tissue = ${maxTranscriptExpressionInTissue.toFixed( 2 - )} (${transcriptWithMaxExpressionInTissue.transcript_id}.${ - transcriptWithMaxExpressionInTissue.transcript_version + )} (${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 ${GTEX_TISSUE_NAMES[tissue]}` + `Gene is not expressed in ${gtexTissuesForDataset[tissue].fullName}` } > @@ -249,9 +257,15 @@ const IndividualTissueTrack = ({ return ( r.tissues[tissue])} + color={gtexTissues[tissue].color} + regions={getPlotRegions( + expressionRegions, + (r: any) => + r.tissues.find((tissueObject: ExpressedTissue) => tissueObject.tissue === tissue) + .value + )} scalePosition={scalePosition} width={width} /> @@ -310,7 +324,13 @@ const RightPanel = styled.div` margin-top: 1.25em; ` -type OwnTissueExpressionTrackProps = { +// Omit gtex then re-include to remove the possible null, as this component only renders if gtex and pext are non null +export type TranscriptWithTissueExpression = Omit & { + gtex_tissue_expression: GtexTissueExpression +} + +type TissueExpressionTrackProps = { + gtexTissues: Partial exons: { start: number stop: number @@ -320,29 +340,18 @@ type OwnTissueExpressionTrackProps = { stop: number mean?: number tissues: { - [key: string]: number - } - }[] - flags: string[] - transcripts: { - transcript_id: string - transcript_version: string - exons: { - feature_type: string - start: number - stop: number + tissue: string + value: number }[] }[] + flags: string[] + transcripts: TranscriptWithTissueExpression[] preferredTranscriptId?: string preferredTranscriptDescription?: string | React.ReactNode } -// @ts-expect-error TS(2456) FIXME: Type alias 'TissueExpressionTrackProps' circularly... Remove this comment to see the full error message -type TissueExpressionTrackProps = OwnTissueExpressionTrackProps & - typeof TissueExpressionTrack.defaultProps - -// @ts-expect-error TS(7022) FIXME: 'TissueExpressionTrack' implicitly has type 'any' ... Remove this comment to see the full error message const TissueExpressionTrack = ({ + gtexTissues, exons, expressionRegions, flags, @@ -355,56 +364,78 @@ const TissueExpressionTrack = ({ useState(false) const [tissueFilterText, setTissueFilterText] = useState('') const mainTrack = useRef() + const [sortTissuesBy, setSortTissuesBy] = useState<'alphabetical' | 'mean-expression'>( + 'alphabetical' + ) - const [sortTissuesBy, setSortTissuesBy] = useState('alphabetical') + type ExpressionByTissueDetails = { + maxTranscriptExpressionInTissue: number + meanTranscriptExpressionInTissue: number + transcriptWithMaxExpressionInTissue: { + transcript_id: string + transcript_version: string + } | null + } + type ExpressionByTissue = Record + + const expressionByTissue: ExpressionByTissue = Object.keys(gtexTissues).reduce( + (acc, tissueId) => { + let maxTranscriptExpressionInTissue = 0 + let transcriptWithMaxExpressionInTissue = null + + transcripts.forEach((transcript) => { + const expressionInTissue = transcript.gtex_tissue_expression.find( + (tissue) => tissue.tissue === tissueId + )!.value + + if (expressionInTissue > maxTranscriptExpressionInTissue) { + maxTranscriptExpressionInTissue = expressionInTissue! + transcriptWithMaxExpressionInTissue = { + transcript_id: transcript.transcript_id, + transcript_version: transcript.transcript_version, + } + } + }) - const expressionByTissue = Object.keys(GTEX_TISSUE_NAMES).reduce((acc, tissueId) => { - let maxTranscriptExpressionInTissue = 0 - let transcriptWithMaxExpressionInTissue = null - transcripts.forEach((transcript: any) => { - const expressionInTissue = transcript.gtex_tissue_expression[tissueId] - if (expressionInTissue > maxTranscriptExpressionInTissue) { - maxTranscriptExpressionInTissue = expressionInTissue - transcriptWithMaxExpressionInTissue = transcript + const meanTranscriptExpressionInTissue = mean( + transcripts.map( + (transcript) => + transcript.gtex_tissue_expression.find((tissue) => tissue.tissue === tissueId)!.value + ) + ) + + return { + ...acc, + [tissueId]: { + maxTranscriptExpressionInTissue, + meanTranscriptExpressionInTissue, + transcriptWithMaxExpressionInTissue, + }, } - }) - - const meanTranscriptExpressionInTissue = mean( - transcripts.map((transcript: any) => transcript.gtex_tissue_expression[tissueId]) - ) - - return { - ...acc, - [tissueId]: { - maxTranscriptExpressionInTissue, - meanTranscriptExpressionInTissue, - transcriptWithMaxExpressionInTissue, - }, - } - }, {}) + }, + {} + ) const maxMeanTranscriptExpressionInAnyTissue = max( - Object.values(expressionByTissue).map((v: any) => v.meanTranscriptExpressionInTissue) - ) + Object.values(expressionByTissue).map((v) => v.meanTranscriptExpressionInTissue) + )! let tissues if (sortTissuesBy === 'mean-expression') { - tissues = Object.entries(GTEX_TISSUE_NAMES) - .sort((t1: any, t2: any) => { - // @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message + tissues = Object.entries(gtexTissues) + .sort((t1, t2) => { const t1Expression = expressionByTissue[t1[0]].meanTranscriptExpressionInTissue - // @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message const t2Expression = expressionByTissue[t2[0]].meanTranscriptExpressionInTissue if (t1Expression === t2Expression) { - return t1[1].localeCompare(t2[1]) + return t1[1].fullName.localeCompare(t2[1].fullName) } return t2Expression - t1Expression }) .map((t: any) => t[0]) } else { - tissues = Object.entries(GTEX_TISSUE_NAMES) - .sort((t1: any, t2: any) => t1[1].localeCompare(t2[1])) - .map((t: any) => t[0]) + tissues = Object.entries(gtexTissues) + .sort((t1, t2) => t1[1].fullName.localeCompare(t2[1].fullName)) + .map((t) => t[0]) } const isExpressed = expressionRegions.some((region: any) => region.mean !== 0) @@ -471,6 +502,7 @@ const TissueExpressionTrack = ({ return ( r.mean)} scalePosition={scalePosition} @@ -549,20 +581,18 @@ const TissueExpressionTrack = ({ {(tissueFilterText ? tissues.filter(tissuePredicate(tissueFilterText)) : tissues).map( (tissue: any) => ( transcript.exons.some((exon: any) => exon.feature_type === 'CDS') -type OwnTranscriptsTissueExpressionProps = { - transcripts: { - transcript_id: string - transcript_version: string - exons: { - feature_type: string - start: number - stop: number - }[] - }[] +type TranscriptsTissueExpressionProps = { + gtexTissues: Partial + transcripts: TranscriptWithTissueExpression[] includeNonCodingTranscripts: boolean preferredTranscriptId?: string preferredTranscriptDescription?: string | React.ReactNode defaultSortTissuesBy?: 'alphabetical' | 'mean-expression' } -export type GtexTissueExpression = { - adipose_subcutaneous: number - adipose_visceral_omentum: number - adrenal_gland: number - artery_aorta: number - artery_coronary: number - artery_tibial: number - bladder: number - brain_amygdala: number - brain_anterior_cingulate_cortex_ba24: number - brain_caudate_basal_ganglia: number - brain_cerebellar_hemisphere: number - brain_cerebellum: number - brain_cortex: number - brain_frontal_cortex_ba9: number - brain_hippocampus: number - brain_hypothalamus: number - brain_nucleus_accumbens_basal_ganglia: number - brain_putamen_basal_ganglia: number - brain_spinal_cord_cervical_c_1: number - brain_substantia_nigra: number - breast_mammary_tissue: number - cells_ebv_transformed_lymphocytes: number - cells_transformed_fibroblasts: number - cervix_ectocervix: number - cervix_endocervix: number - colon_sigmoid: number - colon_transverse: number - esophagus_gastroesophageal_junction: number - esophagus_mucosa: number - esophagus_muscularis: number - fallopian_tube: number - heart_atrial_appendage: number - heart_left_ventricle: number - kidney_cortex: number - liver: number - lung: number - minor_salivary_gland: number - muscle_skeletal: number - nerve_tibial: number - ovary: number - pancreas: number - pituitary: number - prostate: number - skin_not_sun_exposed_suprapubic: number - skin_sun_exposed_lower_leg: number - small_intestine_terminal_ileum: number - spleen: number - stomach: number - testis: number - thyroid: number - uterus: number - vagina: number - whole_blood: number +export type TissueExpression = { + tissue: string + value: number } -// @ts-expect-error TS(2456) FIXME: Type alias 'TranscriptsTissueExpressionProps' circ... Remove this comment to see the full error message -type TranscriptsTissueExpressionProps = OwnTranscriptsTissueExpressionProps & - typeof TranscriptsTissueExpression.defaultProps +export type GtexTissueExpression = TissueExpression[] -// @ts-expect-error TS(7022) FIXME: 'TranscriptsTissueExpression' implicitly has type ... Remove this comment to see the full error message const TranscriptsTissueExpression = ({ + gtexTissues, transcripts, includeNonCodingTranscripts, preferredTranscriptId, @@ -109,8 +50,14 @@ const TranscriptsTissueExpression = ({ sortTranscriptsBy === 'default' ? sortedTranscripts(transcripts, preferredTranscriptId) : [...transcripts].sort((t1, t2) => { - const t1Expression = t1.gtex_tissue_expression[sortTranscriptsBy] || 0 - const t2Expression = t2.gtex_tissue_expression[sortTranscriptsBy] || 0 + const t1Expression = + t1.gtex_tissue_expression.find( + (tissue: TissueExpression) => tissue.tissue === sortTranscriptsBy + )!.value || 0 + const t2Expression = + t2.gtex_tissue_expression.find( + (tissue: TissueExpression) => tissue.tissue === sortTranscriptsBy + )!.value || 0 if (t1Expression === t2Expression) { return t1.transcript_id.localeCompare(t2.transcript_id) @@ -122,31 +69,34 @@ const TranscriptsTissueExpression = ({ const [sortTissuesBy, setSortTissuesBy] = useState(defaultSortTissuesBy) let tissues if (sortTissuesBy === 'mean-expression') { - const meanExpressionByTissue = Object.keys(GTEX_TISSUE_NAMES).reduce( + const meanExpressionByTissue: Record = Object.keys(gtexTissues).reduce( (acc, tissueId) => ({ ...acc, [tissueId]: mean( - transcripts.map((transcript: any) => transcript.gtex_tissue_expression[tissueId] || 0) + transcripts.map( + (transcript: any) => + transcript.gtex_tissue_expression.find( + (tissue: TissueExpression) => tissue.tissue === tissueId + ).value || 0 + ) ), }), {} ) - tissues = Object.entries(GTEX_TISSUE_NAMES) - .sort((t1: any, t2: any) => { - // @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message + tissues = Object.entries(gtexTissues) + .sort((t1, t2) => { const t1Expression = meanExpressionByTissue[t1[0]] - // @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message const t2Expression = meanExpressionByTissue[t2[0]] if (t1Expression === t2Expression) { - return t1[1].localeCompare(t2[1]) + return t1[1].fullName.localeCompare(t2[1].fullName) } return t2Expression - t1Expression }) .map((t: any) => t[0]) } else { - tissues = Object.entries(GTEX_TISSUE_NAMES) - .sort((t1: any, t2: any) => t1[1].localeCompare(t2[1])) - .map((t: any) => t[0]) + tissues = Object.entries(gtexTissues) + .sort((t1, t2) => t1[1].fullName.localeCompare(t2[1].fullName)) + .map((t) => t[0]) } if (!includeNonCodingTranscripts) { @@ -166,10 +116,10 @@ const TranscriptsTissueExpression = ({ > - {Object.entries(GTEX_TISSUE_NAMES).map(([tissueId, tissueName]) => { + {Object.entries(gtexTissues).map(([tissueId, tissueDetails]) => { return ( ) })} @@ -193,8 +143,9 @@ const TranscriptsTissueExpression = ({ {preferredTranscriptDescription &&

* {preferredTranscriptDescription}

} diff --git a/browser/src/GenePage/TranscriptsTissueExpressionPlot.tsx b/browser/src/GenePage/TranscriptsTissueExpressionPlot.tsx index d353e46a0..12c03c33b 100644 --- a/browser/src/GenePage/TranscriptsTissueExpressionPlot.tsx +++ b/browser/src/GenePage/TranscriptsTissueExpressionPlot.tsx @@ -4,8 +4,8 @@ import React from 'react' import { AxisBottom, AxisLeft } from '@visx/axis' import { TooltipAnchor } from '@gnomad/ui' - -import { GTEX_TISSUE_NAMES } from '../gtex' +import { AllGtexTissueNames, AllGtexTissues } from '../gtex' +import { TranscriptWithTissueExpression } from './TissueExpressionTrack' const mergeOverlappingRegions = (regions: any) => { if (regions.length === 0) { @@ -120,49 +120,47 @@ const margin = { top: 45, } -type OwnTranscriptsTissueExpressionPlotProps = { - tissues?: string[] - transcripts: { - transcript_id: string - transcript_version: string - gtex_tissue_expression: { - [key: string]: number - } - }[] +type TranscriptsTissueExpressionPlotProps = { + gtexTissues: Partial + tissues?: AllGtexTissueNames[] + transcripts: TranscriptWithTissueExpression[] starredTranscriptId?: string } -// @ts-expect-error TS(2456) FIXME: Type alias 'TranscriptsTissueExpressionPlotProps' ... Remove this comment to see the full error message -type TranscriptsTissueExpressionPlotProps = OwnTranscriptsTissueExpressionPlotProps & - typeof TranscriptsTissueExpressionPlot.defaultProps - -// @ts-expect-error TS(7022) FIXME: 'TranscriptsTissueExpressionPlot' implicitly has t... Remove this comment to see the full error message const TranscriptsTissueExpressionPlot = ({ + gtexTissues, tissues, transcripts, starredTranscriptId, }: TranscriptsTissueExpressionPlotProps) => { - const renderedTissues = ['Mean', 'Median', ...tissues] + type RenderedTissue = AllGtexTissueNames | 'Mean' | 'Median' + const renderedTissues: RenderedTissue[] = ['Mean', 'Median', ...tissues!] + + const transcriptsWithMeanAndMedianExpression = transcripts.map((transcript) => { + const gtexTissueExpressionObject: { [key: string]: number } = + transcript.gtex_tissue_expression.reduce((acc, tissue) => { + acc[tissue.tissue] = tissue.value + return acc + }, {} as Record) + + const expressionValues = transcript.gtex_tissue_expression.map((tissue) => tissue.value) - const transcriptsWithMeanAndMedianExpresion = transcripts.map((transcript: any) => { - const expressionValues = Object.values(transcript.gtex_tissue_expression) return { ...transcript, gtex_tissue_expression: { - ...transcript.gtex_tissue_expression, - // @ts-expect-error TS(2345) FIXME: Argument of type 'unknown[]' is not assignable to ... Remove this comment to see the full error message + ...(gtexTissueExpressionObject as Partial>), Mean: mean(expressionValues), - // @ts-expect-error TS(2345) FIXME: Argument of type 'unknown[]' is not assignable to ... Remove this comment to see the full error message Median: median(expressionValues), }, } }) const maxTissueExpression = max( - transcripts.flatMap((transcript: any) => Object.values(transcript.gtex_tissue_expression)) - ) + transcripts.flatMap((transcript) => + transcript.gtex_tissue_expression.map((tissue) => tissue.value) + ) + )! - // @ts-expect-error TS(2345) FIXME: Argument of type '(string | number | undefined)[]'... Remove this comment to see the full error message const opacityScale = scaleLinear().domain([0, maxTissueExpression]).range([0, 1]) const transcriptsWidth = 150 @@ -185,8 +183,7 @@ const TranscriptsTissueExpressionPlot = ({ .domain(renderedTissues) .range([ ...renderedTissues.slice(0, 2).map(baseXScale), - // @ts-expect-error TS(2532) FIXME: Object is possibly 'undefined'. - ...renderedTissues.slice(2).map((tissueId) => baseXScale(tissueId) + gutterWidth), + ...renderedTissues.slice(2).map((tissueId) => baseXScale(tissueId)! + gutterWidth), ]) const xAxisScale = scaleOrdinal() @@ -194,14 +191,12 @@ const TranscriptsTissueExpressionPlot = ({ .range( [ ...renderedTissues.slice(0, 2).map(baseXScale), - // @ts-expect-error TS(2532) FIXME: Object is possibly 'undefined'. - ...renderedTissues.slice(2).map((tissueId) => baseXScale(tissueId) + gutterWidth), - // @ts-expect-error TS(2532) FIXME: Object is possibly 'undefined'. - ].map((x) => x + xBandWidth / 2) + ...renderedTissues.slice(2).map((tissueId) => baseXScale(tissueId)! + gutterWidth), + ].map((x) => x! + xBandWidth / 2) ) const yScale = scaleBand() - .domain(transcriptsWithMeanAndMedianExpresion.map((t: any) => t.transcript_id)) + .domain(transcriptsWithMeanAndMedianExpression.map((transcript) => transcript.transcript_id)) .range([0, plotHeight]) .padding(padding) @@ -209,8 +204,7 @@ const TranscriptsTissueExpressionPlot = ({ const halfYPadding = (yScale.step() * yScale.paddingInner()) / 2 - const transcriptLabels = transcripts.reduce( - // @ts-expect-error TS(7006) FIXME: Parameter 'acc' implicitly has an 'any' type. + const transcriptLabels: { [key: string]: string } = transcripts.reduce( (acc, transcript) => ({ ...acc, [transcript.transcript_id]: `${transcript.transcript_id}.${transcript.transcript_version}`, @@ -236,14 +230,12 @@ const TranscriptsTissueExpressionPlot = ({ - {/* @ts-expect-error TS(2532) FIXME: Object is possibly 'undefined'. */} {maxTissueExpression.toPrecision(4)} - {transcripts.slice(1).map((transcript: any) => { - // @ts-expect-error TS(2532) FIXME: Object is possibly 'undefined'. - const y = margin.top + yScale(transcript.transcript_id) - halfYPadding + {transcripts.slice(1).map((transcript) => { + const y = margin.top + yScale(transcript.transcript_id)! - halfYPadding return ( ' is not... Remove this comment to see the full error message scale={xAxisScale} stroke="#333" - // @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message - tickFormat={(t) => GTEX_TISSUE_NAMES[t] || t} + tickFormat={(tissue: AllGtexTissueNames) => { + return gtexTissues[tissue] ? gtexTissues[tissue]!.fullName : tissue + }} tickLabelProps={(value) => ({ dx: '-0.25em', dy: '0.25em', fill: '#000', fontSize: 10, textAnchor: 'end', - // @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'. - transform: `translate(0, 0), rotate(-40 ${xScale(value) + xBandWidth / 2}, 0)`, + transform: `translate(0, 0), rotate(-40 ${ + (xScale(value) as number) + xBandWidth / 2 + }, 0)`, })} tickLength={3} /> - {transcriptsWithMeanAndMedianExpresion.map((transcript: any) => ( + {transcriptsWithMeanAndMedianExpression.map((transcript) => ( {/* @ts-expect-error TS(2322) FIXME: Type '{ children: Element; key: any; tooltip: stri... Remove this comment to see the full error message */} @@ -361,11 +354,11 @@ const TranscriptsTissueExpressionPlot = ({ ) } -TranscriptsTissueExpressionPlot.defaultProps = { - tissues: Object.entries(GTEX_TISSUE_NAMES) - .sort((t1: any, t2: any) => t1[1].localeCompare(t2[1])) - .map((t: any) => t[0]), - starredTranscriptId: null, -} +// TranscriptsTissueExpressionPlot.defaultProps = { +// tissues: Object.entries(GTEX_TISSUE_NAMES) +// .sort((t1: any, t2: any) => t1[1].localeCompare(t2[1])) +// .map((t: any) => t[0]), +// starredTranscriptId: null, +// } export default TranscriptsTissueExpressionPlot diff --git a/browser/src/GenePage/VariantsInGene.tsx b/browser/src/GenePage/VariantsInGene.tsx index 7a727aad4..da367cf91 100644 --- a/browser/src/GenePage/VariantsInGene.tsx +++ b/browser/src/GenePage/VariantsInGene.tsx @@ -11,6 +11,7 @@ import filterVariantsInZoomRegion from '../RegionViewer/filterVariantsInZoomRegi import { TrackPageSection } from '../TrackPage' import annotateVariantsWithClinvar from '../VariantList/annotateVariantsWithClinvar' import Variants from '../VariantList/Variants' +import { Pext } from './GenePage' type TranscriptsModalProps = { gene: { @@ -326,18 +327,9 @@ type ConnectedVariantsInGeneProps = { datasetId: DatasetId gene: { gene_id: string - pext?: { - regions: { - start: number - stop: number - mean: number - tissues: { - [key: string]: number - } - }[] - } + pext?: Pext } -} +} & VariantsInGeneProps const ConnectedVariantsInGene = ({ datasetId, diff --git a/browser/src/GenePage/sortedTranscripts.ts b/browser/src/GenePage/sortedTranscripts.ts index f0e825e8b..59ff69f7f 100644 --- a/browser/src/GenePage/sortedTranscripts.ts +++ b/browser/src/GenePage/sortedTranscripts.ts @@ -1,24 +1,38 @@ import { mean } from 'd3-array' -const sortedTranscripts = (transcripts: any, firstTranscriptId: any) => { +interface GenericTranscript { + transcript_id: string + gtex_tissue_expression: + | { + tissue: string + value: number + }[] + | null +} + +const sortedTranscripts = ( + transcripts: GenericTranscript[], + firstTranscriptId: string | undefined +) => { return [...transcripts].sort((t1, t2) => { // Sort specified transcript first // Then sort transcripts by mean expression and transcript ID - if (t1.transcript_id === firstTranscriptId) { - return -1 - } - if (t2.transcript_id === firstTranscriptId) { - return 1 + + if (firstTranscriptId) { + if (t1.transcript_id === firstTranscriptId) { + return -1 + } + if (t2.transcript_id === firstTranscriptId) { + return 1 + } } - const t1Mean = mean(Object.values(t1.gtex_tissue_expression || {})) - const t2Mean = mean(Object.values(t2.gtex_tissue_expression || {})) + const t1Mean = mean(t1.gtex_tissue_expression!.map((tissue) => tissue.value)) || 0 + const t2Mean = mean(t2.gtex_tissue_expression!.map((tissue) => tissue.value)) || 0 if (t1Mean === t2Mean) { return t1.transcript_id.localeCompare(t2.transcript_id) } - - // @ts-expect-error TS(2532) FIXME: Object is possibly 'undefined'. return t2Mean - t1Mean }) } diff --git a/browser/src/__factories__/TissueExpression.tsx b/browser/src/__factories__/TissueExpression.tsx index 128cd11bb..ea6eecaa0 100644 --- a/browser/src/__factories__/TissueExpression.tsx +++ b/browser/src/__factories__/TissueExpression.tsx @@ -2,114 +2,68 @@ import { Factory } from 'fishery' import { GtexTissueExpression } from '../GenePage/TranscriptsTissueExpression' export const gtexTissueExpressionFactory = Factory.define(({ params }) => { - const { - adipose_subcutaneous = 0, - adipose_visceral_omentum = 0, - adrenal_gland = 0, - artery_aorta = 0, - artery_coronary = 0, - artery_tibial = 0, - bladder = 0, - brain_amygdala = 0, - brain_anterior_cingulate_cortex_ba24 = 0, - brain_caudate_basal_ganglia = 0, - brain_cerebellar_hemisphere = 0, - brain_cerebellum = 0, - brain_cortex = 0, - brain_frontal_cortex_ba9 = 0, - brain_hippocampus = 0, - brain_hypothalamus = 0, - brain_nucleus_accumbens_basal_ganglia = 0, - brain_putamen_basal_ganglia = 0, - brain_spinal_cord_cervical_c_1 = 0, - brain_substantia_nigra = 0, - breast_mammary_tissue = 0, - cells_ebv_transformed_lymphocytes = 0, - cells_transformed_fibroblasts = 0, - cervix_ectocervix = 0, - cervix_endocervix = 0, - colon_sigmoid = 0, - colon_transverse = 0, - esophagus_gastroesophageal_junction = 0, - esophagus_mucosa = 0, - esophagus_muscularis = 0, - fallopian_tube = 0, - heart_atrial_appendage = 0, - heart_left_ventricle = 0, - kidney_cortex = 0, - liver = 0, - lung = 0, - minor_salivary_gland = 0, - muscle_skeletal = 0, - nerve_tibial = 0, - ovary = 0, - pancreas = 0, - pituitary = 0, - prostate = 0, - skin_not_sun_exposed_suprapubic = 0, - skin_sun_exposed_lower_leg = 0, - small_intestine_terminal_ileum = 0, - spleen = 0, - stomach = 0, - testis = 0, - thyroid = 0, - uterus = 0, - vagina = 0, - whole_blood = 0, - } = params - return { - adipose_subcutaneous, - adipose_visceral_omentum, - adrenal_gland, - artery_aorta, - artery_coronary, - artery_tibial, - bladder, - brain_amygdala, - brain_anterior_cingulate_cortex_ba24, - brain_caudate_basal_ganglia, - brain_cerebellar_hemisphere, - brain_cerebellum, - brain_cortex, - brain_frontal_cortex_ba9, - brain_hippocampus, - brain_hypothalamus, - brain_nucleus_accumbens_basal_ganglia, - brain_putamen_basal_ganglia, - brain_spinal_cord_cervical_c_1, - brain_substantia_nigra, - breast_mammary_tissue, - cells_ebv_transformed_lymphocytes, - cells_transformed_fibroblasts, - cervix_ectocervix, - cervix_endocervix, - colon_sigmoid, - colon_transverse, - esophagus_gastroesophageal_junction, - esophagus_mucosa, - esophagus_muscularis, - fallopian_tube, - heart_atrial_appendage, - heart_left_ventricle, - kidney_cortex, - liver, - lung, - minor_salivary_gland, - muscle_skeletal, - nerve_tibial, - ovary, - pancreas, - pituitary, - prostate, - skin_not_sun_exposed_suprapubic, - skin_sun_exposed_lower_leg, - small_intestine_terminal_ileum, - spleen, - stomach, - testis, - thyroid, - uterus, - vagina, - whole_blood, + const defaultTissues = { + adipose_subcutaneous: 0, + adipose_visceral_omentum: 0, + adrenal_gland: 0, + artery_aorta: 0, + artery_coronary: 0, + artery_tibial: 0, + bladder: 0, + brain_amygdala: 0, + brain_anterior_cingulate_cortex_ba24: 0, + brain_caudate_basal_ganglia: 0, + brain_cerebellar_hemisphere: 0, + brain_cerebellum: 0, + brain_cortex: 0, + brain_frontal_cortex_ba9: 0, + brain_hippocampus: 0, + brain_hypothalamus: 0, + brain_nucleus_accumbens_basal_ganglia: 0, + brain_putamen_basal_ganglia: 0, + brain_spinal_cord_cervical_c_1: 0, + brain_substantia_nigra: 0, + breast_mammary_tissue: 0, + cells_ebv_transformed_lymphocytes: 0, + cells_transformed_fibroblasts: 0, + cervix_ectocervix: 0, + cervix_endocervix: 0, + colon_sigmoid: 0, + colon_transverse: 0, + esophagus_gastroesophageal_junction: 0, + esophagus_mucosa: 0, + esophagus_muscularis: 0, + fallopian_tube: 0, + heart_atrial_appendage: 0, + heart_left_ventricle: 0, + kidney_cortex: 0, + liver: 0, + lung: 0, + minor_salivary_gland: 0, + muscle_skeletal: 0, + nerve_tibial: 0, + ovary: 0, + pancreas: 0, + pituitary: 0, + prostate: 0, + skin_not_sun_exposed_suprapubic: 0, + skin_sun_exposed_lower_leg: 0, + small_intestine_terminal_ileum: 0, + spleen: 0, + stomach: 0, + testis: 0, + thyroid: 0, + uterus: 0, + vagina: 0, + whole_blood: 0, } + + const tissueObject = { ...defaultTissues, ...params } as typeof defaultTissues + + const tissueArray: GtexTissueExpression = Object.entries(tissueObject).map((entry) => ({ + tissue: entry[0], + value: entry[1], + })) + + return tissueArray }) diff --git a/browser/src/gtex.ts b/browser/src/gtex.ts index c2e957dc2..e93a4faa6 100644 --- a/browser/src/gtex.ts +++ b/browser/src/gtex.ts @@ -1,111 +1,326 @@ -export const GTEX_TISSUE_NAMES = { - adipose_subcutaneous: 'Adipose - Subcutaneous', - adipose_visceral_omentum: 'Adipose - Visceral (Omentum)', - adrenal_gland: 'Adrenal Gland', - artery_aorta: 'Artery - Aorta', - artery_coronary: 'Artery - Coronary', - artery_tibial: 'Artery - Tibial', - bladder: 'Bladder', - brain_amygdala: 'Brain - Amygdala', - brain_anterior_cingulate_cortex_ba24: 'Brain - Anterior cingulate cortex (BA24)', - brain_caudate_basal_ganglia: 'Brain - Caudate (basal ganglia)', - brain_cerebellar_hemisphere: 'Brain - Cerebellar Hemisphere', - brain_cerebellum: 'Brain - Cerebellum', - brain_cortex: 'Brain - Cortex', - brain_frontal_cortex_ba9: 'Brain - Frontal Cortex (BA9)', - brain_hippocampus: 'Brain - Hippocampus', - brain_hypothalamus: 'Brain - Hypothalamus', - brain_nucleus_accumbens_basal_ganglia: 'Brain - Nucleus accumbens (basal ganglia)', - brain_putamen_basal_ganglia: 'Brain - Putamen (basal ganglia)', - brain_spinal_cord_cervical_c_1: 'Brain - Spinal cord (cervical c-1)', - brain_substantia_nigra: 'Brain - Substantia nigra', - breast_mammary_tissue: 'Breast - Mammary Tissue', - cells_ebv_transformed_lymphocytes: 'Cells - EBV-transformed lymphocytes', - cells_transformed_fibroblasts: 'Cells - Transformed fibroblasts', - cervix_ectocervix: 'Cervix - Ectocervix', - cervix_endocervix: 'Cervix - Endocervix', - colon_sigmoid: 'Colon - Sigmoid', - colon_transverse: 'Colon - Transverse', - esophagus_gastroesophageal_junction: 'Esophagus - Gastroesophageal Junction', - esophagus_mucosa: 'Esophagus - Mucosa', - esophagus_muscularis: 'Esophagus - Muscularis', - fallopian_tube: 'Fallopian Tube', - heart_atrial_appendage: 'Heart - Atrial Appendage', - heart_left_ventricle: 'Heart - Left Ventricle', - kidney_cortex: 'Kidney - Cortex', - liver: 'Liver', - lung: 'Lung', - minor_salivary_gland: 'Minor Salivary Gland', - muscle_skeletal: 'Muscle - Skeletal', - nerve_tibial: 'Nerve - Tibial', - ovary: 'Ovary', - pancreas: 'Pancreas', - pituitary: 'Pituitary', - prostate: 'Prostate', - skin_not_sun_exposed_suprapubic: 'Skin - Not Sun Exposed (Suprapubic)', - skin_sun_exposed_lower_leg: 'Skin - Sun Exposed (Lower leg)', - small_intestine_terminal_ileum: 'Small Intestine - Terminal Ileum', - spleen: 'Spleen', - stomach: 'Stomach', - testis: 'Testis', - thyroid: 'Thyroid', - uterus: 'Uterus', - vagina: 'Vagina', - whole_blood: 'Whole Blood', +const SHARED_GTEX_TISSUES = { + adipose_subcutaneous: { + fullName: 'Adipose - Subcutaneous', + color: '#FF6600', + }, + adipose_visceral_omentum: { + fullName: 'Adipose - Visceral (Omentum)', + color: '#FFAA00', + }, + adrenal_gland: { + fullName: 'Adrenal Gland', + color: '#33DD33', + }, + artery_aorta: { + fullName: 'Artery - Aorta', + color: '#FF5555', + }, + artery_coronary: { + fullName: 'Artery - Coronary', + color: '#FFAA99', + }, + artery_tibial: { + fullName: 'Artery - Tibial', + color: '#FF0000', + }, + bladder: { + fullName: 'Bladder', + color: '#AA0000', + }, + brain_amygdala: { + fullName: 'Brain - Amygdala', + color: '#EEEE00', + }, + brain_anterior_cingulate_cortex_ba24: { + fullName: 'Brain - Anterior cingulate cortex (BA24)', + color: '#EEEE00', + }, + brain_caudate_basal_ganglia: { + fullName: 'Brain - Caudate (basal ganglia)', + color: '#EEEE00', + }, + brain_cerebellar_hemisphere: { + fullName: 'Brain - Cerebellar Hemisphere', + color: '#EEEE00', + }, + brain_cerebellum: { + fullName: 'Brain - Cerebellum', + color: '#EEEE00', + }, + brain_cortex: { + fullName: 'Brain - Cortex', + color: '#EEEE00', + }, + brain_frontal_cortex_ba9: { + fullName: 'Brain - Frontal Cortex (BA9)', + color: '#EEEE00', + }, + brain_hippocampus: { + fullName: 'Brain - Hippocampus', + color: '#EEEE00', + }, + brain_hypothalamus: { + fullName: 'Brain - Hypothalamus', + color: '#EEEE00', + }, + brain_nucleus_accumbens_basal_ganglia: { + fullName: 'Brain - Nucleus accumbens (basal ganglia)', + color: '#EEEE00', + }, + brain_putamen_basal_ganglia: { + fullName: 'Brain - Putamen (basal ganglia)', + color: '#EEEE00', + }, + brain_spinal_cord_cervical_c_1: { + fullName: 'Brain - Spinal cord (cervical c-1)', + color: '#EEEE00', + }, + brain_substantia_nigra: { + fullName: 'Brain - Substantia nigra', + color: '#EEEE00', + }, + breast_mammary_tissue: { + fullName: 'Breast - Mammary Tissue', + color: '#33CCCC', + }, + cells_ebv_transformed_lymphocytes: { + fullName: 'Cells - EBV-transformed lymphocytes', + color: '#CC66FF', + }, + cervix_ectocervix: { + fullName: 'Cervix - Ectocervix', + color: '#FFCCCC', + }, + cervix_endocervix: { + fullName: 'Cervix - Endocervix', + color: '#CCAADD', + }, + colon_sigmoid: { + fullName: 'Colon - Sigmoid', + color: '#EEBB77', + }, + colon_transverse: { + fullName: 'Colon - Transverse', + color: '#CC9955', + }, + esophagus_gastroesophageal_junction: { + fullName: 'Esophagus - Gastroesophageal Junction', + color: '#8B7355', + }, + esophagus_mucosa: { + fullName: 'Esophagus - Mucosa', + color: '#552200', + }, + esophagus_muscularis: { + fullName: 'Esophagus - Muscularis', + color: '#BB9988', + }, + fallopian_tube: { + fullName: 'Fallopian Tube', + color: '#FFCCCC', + }, + heart_atrial_appendage: { + fullName: 'Heart - Atrial Appendage', + color: '#9900FF', + }, + heart_left_ventricle: { + fullName: 'Heart - Left Ventricle', + color: '#660099', + }, + kidney_cortex: { + fullName: 'Kidney - Cortex', + color: '#22FFDD', + }, + liver: { + fullName: 'Liver', + color: '#AABB66', + }, + lung: { + fullName: 'Lung', + color: '#99FF00', + }, + minor_salivary_gland: { + fullName: 'Minor Salivary Gland', + color: '#99BB88', + }, + muscle_skeletal: { + fullName: 'Muscle - Skeletal', + color: '#AAAAFF', + }, + nerve_tibial: { + fullName: 'Nerve - Tibial', + color: '#FFD700', + }, + ovary: { + fullName: 'Ovary', + color: '#FFAAFF', + }, + pancreas: { + fullName: 'Pancreas', + color: '#995522', + }, + pituitary: { + fullName: 'Pituitary', + color: '#AAFF99', + }, + prostate: { + fullName: 'Prostate', + color: '#DDDDDD', + }, + skin_not_sun_exposed_suprapubic: { + fullName: 'Skin - Not Sun Exposed (Suprapubic)', + color: '#0000FF', + }, + skin_sun_exposed_lower_leg: { + fullName: 'Skin - Sun Exposed (Lower leg)', + color: '#7777FF', + }, + small_intestine_terminal_ileum: { + fullName: 'Small Intestine - Terminal Ileum', + color: '#555522', + }, + spleen: { + fullName: 'Spleen', + color: '#778855', + }, + stomach: { + fullName: 'Stomach', + color: '#FFDD99', + }, + testis: { + fullName: 'Testis', + color: '#AAAAAA', + }, + thyroid: { + fullName: 'Thyroid', + color: '#006600', + }, + uterus: { + fullName: 'Uterus', + color: '#FF66FF', + }, + vagina: { + fullName: 'Vagina', + color: '#FF5599', + }, + whole_blood: { + fullName: 'Whole Blood', + color: '#FF00BB', + }, } -export const GTEX_TISSUE_COLORS = { - adipose_subcutaneous: '#FF6600', - adipose_visceral_omentum: '#FFAA00', - adrenal_gland: '#33DD33', - artery_aorta: '#FF5555', - artery_coronary: '#FFAA99', - artery_tibial: '#FF0000', - bladder: '#AA0000', - brain_amygdala: '#EEEE00', - brain_anterior_cingulate_cortex_ba24: '#EEEE00', - brain_caudate_basal_ganglia: '#EEEE00', - brain_cerebellar_hemisphere: '#EEEE00', - brain_cerebellum: '#EEEE00', - brain_cortex: '#EEEE00', - brain_frontal_cortex_ba9: '#EEEE00', - brain_hippocampus: '#EEEE00', - brain_hypothalamus: '#EEEE00', - brain_nucleus_accumbens_basal_ganglia: '#EEEE00', - brain_putamen_basal_ganglia: '#EEEE00', - brain_spinal_cord_cervical_c_1: '#EEEE00', - brain_substantia_nigra: '#EEEE00', - breast_mammary_tissue: '#33CCCC', - cells_ebv_transformed_lymphocytes: '#CC66FF', - cells_transformed_fibroblasts: '#AAEEFF', - cervix_ectocervix: '#FFCCCC', - cervix_endocervix: '#CCAADD', - colon_sigmoid: '#EEBB77', - colon_transverse: '#CC9955', - esophagus_gastroesophageal_junction: '#8B7355', - esophagus_mucosa: '#552200', - esophagus_muscularis: '#BB9988', - fallopian_tube: '#FFCCCC', - heart_atrial_appendage: '#9900FF', - heart_left_ventricle: '#660099', - kidney_cortex: '#22FFDD', - liver: '#AABB66', - lung: '#99FF00', - minor_salivary_gland: '#99BB88', - muscle_skeletal: '#AAAAFF', - nerve_tibial: '#FFD700', - ovary: '#FFAAFF', - pancreas: '#995522', - pituitary: '#AAFF99', - prostate: '#DDDDDD', - skin_not_sun_exposed_suprapubic: '#0000FF', - skin_sun_exposed_lower_leg: '#7777FF', - small_intestine_terminal_ileum: '#555522', - spleen: '#778855', - stomach: '#FFDD99', - testis: '#AAAAAA', - thyroid: '#006600', - uterus: '#FF66FF', - vagina: '#FF5599', - whole_blood: '#FF00BB', +type SharedGtexTissueNames = keyof typeof SHARED_GTEX_TISSUES + +export type TissueDetail = { + fullName: string + color: string +} + +const V2_SPECIFIC_GTEX_TISSUES = { + cells_transformed_fibroblasts: { + fullName: 'Cells - Transformed fibroblasts', + color: '#AAEEFF', + }, +} + +type V2GtexTissueNames = SharedGtexTissueNames | keyof typeof V2_SPECIFIC_GTEX_TISSUES + +const V2_GTEX_TISSUES: Record = { + ...SHARED_GTEX_TISSUES, + ...V2_SPECIFIC_GTEX_TISSUES, +} + +const V4_SPECIFIC_GTEX_TISSUES = { + cells_cultured_fibroblasts: { + fullName: 'Cells - Cultured fibroblasts', + color: '#AAEEFF', + }, + colon_transverse_mixed_cell: { + fullName: 'Colon - Transverse mixed cell', + color: '#CC9955', + }, + colon_transverse_mucosa: { + fullName: 'Colon - Transverse mucosa', + color: '#CC9955', + }, + colon_transverse_muscularis: { + fullName: 'Colon - Transverse muscularis', + color: '#CC9955', + }, + kidney_medulla: { + fullName: 'Kidney - Medulla', + color: '#33FFC2', + }, + liver_hepatocyte: { + fullName: 'Liver - Hepatocyte', + color: '#AABB66', + }, + liver_mixed_cell: { + fullName: 'Liver - Mixed cell', + color: '#AABB66', + }, + liver_portal_tract: { + fullName: 'Liver - Portal tract', + color: '#AABB66', + }, + pancreas_acini: { + fullName: 'Pancreas - Acini', + color: '#995522', + }, + pancreas_islets: { + fullName: 'Pancreas - Islets', + color: '#995522', + }, + pancreas_mixed_cell: { + fullName: 'Pancreas - Mixed cell', + color: '#995522', + }, + small_intestine_terminal_ileum_lymphoid_aggregate: { + fullName: 'Small Intestine - Terminal ileum lymphoid aggregate', + color: '#555522', + }, + small_intestine_terminal_ileum_mixed_cell: { + fullName: 'Small intestine - Terminal ileum mixed cell', + color: '#555522', + }, + stomach_mixed_cell: { + fullName: 'Stomach - Mixed cell', + color: '#FFDD99', + }, + stomach_mucosa: { + fullName: 'Stomach - Mucosa', + color: '#FFDD99', + }, + stomach_muscularis: { + fullName: 'Stomach - Muscularis', + color: '#FFDD99', + }, +} + +type V4GtexTissueNames = SharedGtexTissueNames | keyof typeof V4_SPECIFIC_GTEX_TISSUES + +export type AllGtexTissueNames = + | SharedGtexTissueNames + | keyof typeof V2_SPECIFIC_GTEX_TISSUES + | keyof typeof V4_SPECIFIC_GTEX_TISSUES + +export type AllGtexTissues = Record + +const V4_GTEX_TISSUES: Record = { + ...SHARED_GTEX_TISSUES, + ...V4_SPECIFIC_GTEX_TISSUES, +} + +export const GTEX_TISSUES: { + v2: Record + v4: Record + default: Record + v3: Record + ExAC: Record +} = { + v2: V2_GTEX_TISSUES, + v4: V4_GTEX_TISSUES, + default: SHARED_GTEX_TISSUES, + v3: SHARED_GTEX_TISSUES, + ExAC: SHARED_GTEX_TISSUES, }