Skip to content

Commit

Permalink
Add mitochondrial regional constraint visualizations
Browse files Browse the repository at this point in the history
  • Loading branch information
phildarnowsky-broad committed May 1, 2024
1 parent 50722d0 commit f0c671c
Show file tree
Hide file tree
Showing 11 changed files with 431 additions and 96 deletions.
1 change: 1 addition & 0 deletions browser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@gnomad/ui": "2.0.0",
"@hot-loader/react-dom": "^17.0.0",
"@visx/axis": "^3.0.0",
"@visx/group": "^3.0.0",
"core-js": "3.5.0",
"css-loader": "^6.7.3",
"d3-array": "^1.2.4",
Expand Down
134 changes: 86 additions & 48 deletions browser/src/ConstraintTrack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,45 @@ const TopPanel = styled.div`
margin-bottom: 5px;
`

const LegendWrapper = styled.div`
display: flex;
@media (max-width: 600px) {
flex-direction: column;
align-items: center;
}
`

export const RegionAttributeList = styled.dl`
margin: 0;
div {
margin-bottom: 0.25em;
}
dt {
display: inline;
font-weight: bold;
}
dd {
display: inline;
margin-left: 0.5em;
}
`

export interface GenericRegion {
start: number
stop: number
}

type Props<R extends GenericRegion> = {
trackTitle: string
allRegions: R[]
allRegions: R[] | null
constrainedRegions: R[]
infobuttonTopic: string
legend: ReactNode
tooltipComponent: any // TK any
tooltipComponent: React.ElementType
colorFn: (region: R) => string
valueFn: (region: R) => string
}
Expand Down Expand Up @@ -104,9 +131,12 @@ const ConstraintTrack = <R extends GenericRegion>({
>
{({ scalePosition, width }: TrackProps) => (
<>
<TopPanel>{legend}</TopPanel>
<TopPanel>
<LegendWrapper>{legend}</LegendWrapper>
</TopPanel>
<PlotWrapper>
<svg height={55} width={width}>
{!allRegions && <rect x={0} y={7.5} width={width} height={1} />}
{constrainedRegions.map((region: R) => {
const startX = scalePosition(region.start)
const stopX = scalePosition(region.stop)
Expand All @@ -117,13 +147,13 @@ const ConstraintTrack = <R extends GenericRegion>({
key={`${region.start}-${region.stop}`}
// @ts-expect-error need to redefine TooltipAnchor to allow arbitrary props for the children type-safely
region={region}
isTranscript={allRegions.length === 1}
isTranscript={allRegions && allRegions.length === 1}
tooltipComponent={tooltipComponent}
>
<g>
<rect
x={startX}
y={0}
y={1}
width={regionWidth}
height={15}
fill={colorFn(region)}
Expand All @@ -133,49 +163,57 @@ const ConstraintTrack = <R extends GenericRegion>({
</TooltipAnchor>
)
})}
<g transform="translate(0,20)">
{allRegions.map((region: R, index: number) => {
const startX = scalePosition(region.start)
const stopX = scalePosition(region.stop)
const regionWidth = stopX - startX
const midX = (startX + stopX) / 2
const offset = index * 0

return (
<g key={`${region.start}-${region.stop}`}>
<line
x1={startX}
y1={2 + offset}
x2={startX}
y2={11 + offset}
stroke="#424242"
/>
<line
x1={startX}
y1={7 + offset}
x2={stopX}
y2={7 + offset}
stroke="#424242"
/>
<line
x1={stopX}
y1={2 + offset}
x2={stopX}
y2={11 + offset}
stroke="#424242"
/>
{regionWidth > 40 && (
<>
<rect x={midX - 15} y={3 + offset} width={30} height={5} fill="#fafafa" />
<text x={midX} y={8 + offset} dy="0.33em" textAnchor="middle">
{valueFn(region)}
</text>
</>
)}
</g>
)
})}
</g>
{allRegions && (
<g transform="translate(0,20)">
{allRegions.map((region: R, index: number) => {
const startX = scalePosition(region.start)
const stopX = scalePosition(region.stop)
const regionWidth = stopX - startX
const midX = (startX + stopX) / 2
const offset = index * 0

return (
<g key={`${region.start}-${region.stop}`}>
<line
x1={startX}
y1={2 + offset}
x2={startX}
y2={11 + offset}
stroke="#424242"
/>
<line
x1={startX}
y1={7 + offset}
x2={stopX}
y2={7 + offset}
stroke="#424242"
/>
<line
x1={stopX}
y1={2 + offset}
x2={stopX}
y2={11 + offset}
stroke="#424242"
/>
{regionWidth > 40 && (
<>
<rect
x={midX - 15}
y={3 + offset}
width={30}
height={5}
fill="#fafafa"
/>
<text x={midX} y={8 + offset} dy="0.33em" textAnchor="middle">
{valueFn(region)}
</text>
</>
)}
</g>
)
})}
</g>
)}
</svg>
</PlotWrapper>
</>
Expand Down
46 changes: 46 additions & 0 deletions browser/src/GenePage/GenePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import { Track } from '@gnomad/region-viewer'
// @ts-expect-error TS(7016) FIXME: Could not find a declaration file for module '@gno... Remove this comment to see the full error message
import { TranscriptPlot } from '@gnomad/track-transcripts'
import { Badge, Button } from '@gnomad/ui'
import MitochondrialRegionConstraintTrack, {
MitochondrialConstraintRegion,
} from './MitochondrialRegionConstraintTrack'

import {
DatasetId,
Expand Down Expand Up @@ -72,6 +75,40 @@ import {
} from '../ChartStyles'
import { logButtonClick } from '../analytics'

type ProteinMitochondrialGeneConstraint = {
exp_lof: number
exp_mis: number
exp_syn: number

obs_lof: number
obs_mis: number
obs_syn: number

oe_lof: number
oe_lof_lower: number
oe_lof_upper: number

oe_mis: number
oe_mis_lower: number
oe_mis_upper: number

oe_syn: number
oe_syn_lower: number
oe_syn_upper: number
}

type RNAMitochondrialGeneConstraint = {
observed: number
expected: number
oe: number
oe_upper: number
oe_lower: number
}

type MitochondrialGeneConstraint =
| ProteinMitochondrialGeneConstraint
| RNAMitochondrialGeneConstraint

export type Strand = '+' | '-'

export type GeneMetadata = {
Expand Down Expand Up @@ -136,6 +173,8 @@ export type Gene = GeneMetadata & {
clinvar_variants: ClinvarVariant[]
homozygous_variant_cooccurrence_counts: HomozygousVariantCooccurrenceCountsPerSeverityAndAf
heterozygous_variant_cooccurrence_counts: HeterozygousVariantCooccurrenceCountsPerSeverityAndAf
mitochondrial_constraint: MitochondrialGeneConstraint | null
mitochondrial_missense_constraint_regions: MitochondrialConstraintRegion[] | null
}

const GeneName = styled.span`
Expand Down Expand Up @@ -528,6 +567,13 @@ const GenePage = ({ datasetId, gene, geneId }: Props) => {
</TrackWrapper>
)}

{gene.chrom.startsWith('M') && (
<MitochondrialRegionConstraintTrack
constraintRegions={gene.mitochondrial_missense_constraint_regions}
exons={gene.exons}
/>
)}

{hasCodingExons && gene.chrom !== 'M' && gene.pext && (
<TissueExpressionTrack
exons={cdsCompositeExons}
Expand Down
35 changes: 35 additions & 0 deletions browser/src/GenePage/GenePageContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,41 @@ query ${operationName}($geneId: String, $geneSymbol: String, $referenceGenome: R
hom_total
}
}
mitochondrial_constraint {
...on ProteinMitochondrialGeneConstraint {
exp_lof
exp_mis
exp_syn
obs_lof
obs_mis
obs_syn
oe_lof
oe_lof_lower
oe_lof_upper
oe_mis
oe_mis_lower
oe_mis_upper
oe_syn
oe_syn_lower
oe_syn_upper
}
...on RNAMitochondrialGeneConstraint {
observed
expected
oe
oe_upper
oe_lower
}
}
mitochondrial_missense_constraint_regions{
start
stop
oe
oe_upper
oe_lower
}
}
}
`
Expand Down
46 changes: 46 additions & 0 deletions browser/src/GenePage/MitochondrialRegionConstraintTrack.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react'
import renderer from 'react-test-renderer'
import { expect, test } from '@jest/globals'
import MitochondrialRegionConstraintTrack, {
MitochondrialConstraintRegion,
} from './MitochondrialRegionConstraintTrack'
import { Exon } from '../TranscriptPage/TranscriptPage'
// @ts-expect-error
import { RegionViewerContext } from '@gnomad/region-viewer'

const childProps = {
centerPanelWidth: 3,
isPositionDefined: true,
leftPanelWidth: 4,
regions: [],
rightPanelWidth: 5,
scalePosition: (i: number) => i,
}

const exons: Exon[] = [
{ feature_type: 'CDS', start: 123, stop: 234 },
{ feature_type: 'UTR', start: 235, stop: 999 },
{ feature_type: 'CDS', start: 1000, stop: 1999 },
]

test('track has no unexpected changes when gene has constraint', () => {
const constraintRegions: MitochondrialConstraintRegion[] = [
{ start: 555, stop: 666, oe: 0.45, oe_lower: 0.37, oe_upper: 0.47 },
{ start: 777, stop: 888, oe: 0.56, oe_lower: 0.52, oe_upper: 0.59 },
]
const tree = renderer.create(
<RegionViewerContext.Provider value={childProps}>
<MitochondrialRegionConstraintTrack constraintRegions={constraintRegions} exons={exons} />
</RegionViewerContext.Provider>
)
expect(tree).toMatchSnapshot()
})

test('track has no unexpected changes when no constraint for gene', () => {
const tree = renderer.create(
<RegionViewerContext.Provider value={childProps}>
<MitochondrialRegionConstraintTrack constraintRegions={null} exons={exons} />
</RegionViewerContext.Provider>
)
expect(tree).toMatchSnapshot()
})
Loading

0 comments on commit f0c671c

Please sign in to comment.