Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Constraint for mitochondrial genes #1451

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
72 changes: 70 additions & 2 deletions browser/src/ConstraintTable/ConstraintTable.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import { BrowserRouter } from 'react-router-dom'
import ConstraintTable from './ConstraintTable'
import { ExacConstraint } from './ExacConstraintTable'
import { GnomadConstraint } from './GnomadConstraintTable'
import {
ProteinMitochondrialGeneConstraint,
RNAMitochondrialGeneConstraint,
} from '../GenePage/GenePage'

const exacConstraintFactory = Factory.define<ExacConstraint>(() => ({
exp_lof: 0.123,
Expand Down Expand Up @@ -42,6 +46,34 @@ const gnomadConstraintFactory = Factory.define<GnomadConstraint>(() => ({
oe_syn_upper: 0.95,
}))

const proteinMitochondrialConstraintFactory = Factory.define<ProteinMitochondrialGeneConstraint>(
() => ({
exp_lof: 0.123,
exp_syn: 0.234,
exp_mis: 0.345,
oe_lof: 0.789,
oe_lof_lower: 0.6,
oe_lof_upper: 0.9,
oe_mis: 0.891,
oe_mis_lower: 0.8,
oe_mis_upper: 0.99,
oe_syn: 0.912,
oe_syn_lower: 0.8,
oe_syn_upper: 0.95,
obs_lof: 0.111,
obs_syn: 0.222,
obs_mis: 0.333,
})
)

const rnaMitochondrialConstraintFactory = Factory.define<RNAMitochondrialGeneConstraint>(() => ({
observed: 1.1,
expected: 22.2,
oe: 0.33,
oe_lower: 0.31,
oe_upper: 0.35,
}))

forAllDatasets('ConstraintTable with "%s" dataset selected', (datasetId) => {
describe('with a minimal gene', () => {
test('has no unexpected changes', () => {
Expand All @@ -65,20 +97,56 @@ forAllDatasets('ConstraintTable with "%s" dataset selected', (datasetId) => {
})
})

describe('with a mitochondrial gene', () => {
describe('with a mitochondrial protein gene', () => {
test('has no unexpected changes', () => {
const constraint = proteinMitochondrialConstraintFactory.build()
const tree = renderer.create(
<BrowserRouter>
<ConstraintTable
datasetId={datasetId}
geneOrTranscript={geneFactory.build({
chrom: 'M',
mitochondrial_constraint: constraint,
})}
/>
</BrowserRouter>
)
expect(tree).toMatchSnapshot()
})
})

describe('with a mitochondrial RNA gene', () => {
test('has no unexpected changes', () => {
const constraint = rnaMitochondrialConstraintFactory.build()
const tree = renderer.create(
<BrowserRouter>
<ConstraintTable
datasetId={datasetId}
geneOrTranscript={geneFactory.build({ chrom: 'M' })}
geneOrTranscript={geneFactory.build({
chrom: 'M',
mitochondrial_constraint: constraint,
})}
/>
</BrowserRouter>
)
expect(tree).toMatchSnapshot()
})
})

describe('with a mitochondrial gene missing constraint data', () => {
const tree = renderer.create(
<BrowserRouter>
<ConstraintTable
datasetId={datasetId}
geneOrTranscript={geneFactory.build({
chrom: 'M',
})}
/>
</BrowserRouter>
)
expect(tree).toMatchSnapshot()
})

describe('with a mitochondrial transcript', () => {
test('has no unexpected changes', () => {
const tree = renderer.create(
Expand Down
17 changes: 8 additions & 9 deletions browser/src/ConstraintTable/ConstraintTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Link from '../Link'

import ExacConstraintTable from './ExacConstraintTable'
import GnomadConstraintTable from './GnomadConstraintTable'
import MitochondrialConstraintTable from './MitochondrialConstraintTable'

type Props = {
datasetId: DatasetId
Expand Down Expand Up @@ -65,18 +66,16 @@ const ConstraintTable = ({ datasetId, geneOrTranscript }: Props) => {
const { transcriptId, transcriptVersion, transcriptDescription } =
transcriptDetails(geneOrTranscript)

const gnomadConstraint = geneOrTranscript.gnomad_constraint
const exacConstraint = geneOrTranscript.exac_constraint

if (geneOrTranscript.chrom === 'M') {
return (
<p>
Constraint is not available for mitochondrial{' '}
{isGene(geneOrTranscript) ? 'genes' : 'transcripts'}
</p>
)
if (isGene(geneOrTranscript)) {
return <MitochondrialConstraintTable constraint={geneOrTranscript.mitochondrial_constraint} />
}
return <p>Constraint is not available for mitochondrial transcripts</p>
}

const gnomadConstraint = geneOrTranscript.gnomad_constraint
const exacConstraint = geneOrTranscript.exac_constraint

if (datasetId === 'exac') {
if (!exacConstraint) {
return (
Expand Down
136 changes: 136 additions & 0 deletions browser/src/ConstraintTable/MitochondrialConstraintTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import React from 'react'
import {
MitochondrialGeneConstraint,
ProteinMitochondrialGeneConstraint,
RNAMitochondrialGeneConstraint,
} from '../GenePage/GenePage'
import { BaseTable } from '@gnomad/ui'

const isProteinMitochondrialGeneConstraint = (
constraint: MitochondrialGeneConstraint
): constraint is ProteinMitochondrialGeneConstraint =>
Object.prototype.hasOwnProperty.call(constraint, 'exp_lof')

const ConstraintRow = ({
category,
expected,
observed,
oe,
oeLower,
oeUpper,
}: {
category: string
expected: number
observed: number
oe: number
oeLower: number
oeUpper: number
}) => (
<tr>
<th scope="row">{category}</th>
<td>{expected < 10 ? expected.toFixed(2) : expected.toFixed(1)}</td>
<td>{observed < 10 ? observed.toFixed(2) : observed.toFixed(1)}</td>
<td>
o/e = {oe.toFixed(2)} ({oeLower.toFixed(2)} - {oeUpper.toFixed(2)})
</td>
</tr>
)

const ProteinConstraintMetrics = ({
constraint,
}: {
constraint: ProteinMitochondrialGeneConstraint
}) => {
const {
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,
} = constraint
return (
<tbody>
<ConstraintRow
category="Synonymous"
expected={exp_syn}
observed={obs_syn}
oe={oe_syn}
oeLower={oe_syn_lower}
oeUpper={oe_syn_upper}
/>
<ConstraintRow
category="Missense"
expected={exp_mis}
observed={obs_mis}
oe={oe_mis}
oeLower={oe_mis_lower}
oeUpper={oe_mis_upper}
/>
<ConstraintRow
category="pLoF"
expected={exp_lof}
observed={obs_lof}
oe={oe_lof}
oeLower={oe_lof_lower}
oeUpper={oe_lof_upper}
/>
</tbody>
)
}

const RNAConstraintMetrics = ({ constraint }: { constraint: RNAMitochondrialGeneConstraint }) => {
const { expected, observed, oe, oe_lower, oe_upper } = constraint
return (
<tbody>
<ConstraintRow
category="RNA variant"
expected={expected}
observed={observed}
oe={oe}
oeLower={oe_lower}
oeUpper={oe_upper}
/>
</tbody>
)
}

const MitochondrialConstraintTable = ({
constraint,
}: {
constraint: MitochondrialGeneConstraint | null
}) => {
if (constraint === null) {
return <p>Constraint is not available on this gene</p>
}

return (
// @ts-expect-error
<BaseTable>
<thead>
<tr>
<th scope="col">Category</th>
<th scope="col">Expected SNVs</th>
<th scope="col">Observed SNVs</th>
<th scope="col">Constraint metrics</th>
</tr>
</thead>
{isProteinMitochondrialGeneConstraint(constraint) ? (
<ProteinConstraintMetrics constraint={constraint} />
) : (
<RNAConstraintMetrics constraint={constraint} />
)}
</BaseTable>
)
}

export default MitochondrialConstraintTable
Loading
Loading