diff --git a/browser/src/CoverageTrack.tsx b/browser/src/CoverageTrack.tsx
index d0f7b6983..29c9fdb0c 100644
--- a/browser/src/CoverageTrack.tsx
+++ b/browser/src/CoverageTrack.tsx
@@ -16,7 +16,7 @@ const TopPanel = styled.div`
width: 100%;
`
-const LegendWrapper = styled.ul`
+export const LegendWrapper = styled.ul`
display: flex;
flex-direction: row;
padding: 0;
@@ -24,12 +24,12 @@ const LegendWrapper = styled.ul`
list-style-type: none;
`
-const LegendItem = styled.li`
+export const LegendItem = styled.li`
display: flex;
margin-left: 1em;
`
-const LegendSwatch = styled.span`
+export const LegendSwatch = styled.span`
display: inline-block;
width: 1em;
height: 1em;
@@ -46,7 +46,7 @@ const LegendSwatch = styled.span`
}
`
-type LegendProps = {
+export type LegendProps = {
datasets: {
color: string
name: string
diff --git a/browser/src/DiscreteBarPlot.tsx b/browser/src/DiscreteBarPlot.tsx
new file mode 100644
index 000000000..01aed239c
--- /dev/null
+++ b/browser/src/DiscreteBarPlot.tsx
@@ -0,0 +1,172 @@
+import React, { useRef } from 'react'
+import styled from 'styled-components'
+import { scaleLinear } from 'd3-scale'
+import { LegendWrapper, LegendItem, LegendSwatch, LegendProps } from './CoverageTrack'
+
+// @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 { Track } from '@gnomad/region-viewer'
+import { Button } from '@gnomad/ui'
+import { AxisLeft } from '@vx/axis'
+
+const TopPanel = styled.div`
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ width: 100%;
+`
+const TitlePanel = styled.div`
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ height: 100%;
+ padding-right: 40px;
+`
+type PercentCallableValues = {
+ pos: number
+ percent_callable: number
+ xpos: number
+}
+
+type GroupedData = {
+ startPos: number
+ endPos: number
+ percent_callable: number
+}
+
+const Legend = ({ datasets }: LegendProps) => (
+
+ {datasets.map((dataset) => (
+
+ {/* @ts-expect-error TS(2769) FIXME: No overload matches this call. */}
+
+ {dataset.name}
+
+ ))}
+
+)
+
+const groupDiscreteData = (buckets: PercentCallableValues[]): GroupedData[] => {
+ const groupedData: GroupedData[] = []
+
+ buckets.forEach((entry) => {
+ const prevEntry = groupedData.length > 0 ? groupedData[groupedData.length - 1] : null
+
+ if (prevEntry && prevEntry.percent_callable === entry.percent_callable) {
+ prevEntry.endPos = entry.pos + 1
+ } else {
+ groupedData.push({
+ startPos: entry.pos,
+ endPos: entry.pos,
+ percent_callable: entry.percent_callable,
+ })
+ }
+ })
+ return groupedData
+}
+
+const margin = {
+ top: 7,
+ left: 60,
+}
+
+const DiscreteBarPlot = ({
+ datasets,
+ height,
+ regionStart,
+ regionStop,
+ chrom,
+}: {
+ datasets: { color: string; buckets: PercentCallableValues[]; name: string; opacity: number }[]
+ height: number
+ regionStart: number
+ regionStop: number
+ chrom: number
+}) => {
+ const groupedData = groupDiscreteData(datasets[0].buckets)
+
+ const plotHeight = height + margin.top
+ const yScale = scaleLinear().domain([0, 1]).range([plotHeight, margin.top])
+
+ const plotRef = useRef(null)
+
+ const exportPlot = () => {
+ if (plotRef.current) {
+ const serializer = new XMLSerializer()
+ const data = serializer.serializeToString(plotRef.current)
+ const blob = new Blob(['\r\n', data], {
+ type: 'image/svg+xml;charset=utf-8',
+ })
+
+ const url = URL.createObjectURL(blob)
+ const link = document.createElement('a')
+ link.href = url
+ link.download = `${chrom}-${regionStart}-${regionStop}_percent_callable.svg`
+
+ document.body.appendChild(link)
+ link.click()
+ document.body.removeChild(link)
+
+ URL.revokeObjectURL(url)
+ }
+ }
+
+ return (
+
+ )
+}
+export default DiscreteBarPlot
diff --git a/browser/src/GenePage/CopyNumberVariantsGenePercentCallableTrack.spec.tsx b/browser/src/GenePage/CopyNumberVariantsGenePercentCallableTrack.spec.tsx
new file mode 100644
index 000000000..032160c60
--- /dev/null
+++ b/browser/src/GenePage/CopyNumberVariantsGenePercentCallableTrack.spec.tsx
@@ -0,0 +1,73 @@
+import React from 'react'
+import { createRenderer } from 'react-test-renderer/shallow'
+
+import { jest, describe, expect, test } from '@jest/globals'
+import { mockQueries } from '../../../tests/__helpers__/queries'
+import Query, { BaseQuery } from '../Query'
+
+import CopyNumberVariantsGenePercentCallableTrack from './CopyNumberVariantsGenePercentCallableTrack'
+
+import { allDatasetIds, hasCopyNumberVariantCoverage } from '@gnomad/dataset-metadata/metadata'
+import geneFactory from '../__factories__/Gene'
+
+jest.mock('../Query', () => {
+ const originalModule = jest.requireActual('../Query')
+
+ return {
+ __esModule: true,
+ ...(originalModule as object),
+ default: jest.fn(),
+ BaseQuery: jest.fn(),
+ }
+})
+
+const { resetMockApiCalls, resetMockApiResponses, simulateApiResponse, setMockApiResponses } =
+ mockQueries()
+
+beforeEach(() => {
+ Query.mockImplementation(
+ jest.fn(({ query, children, operationName, variables }) =>
+ simulateApiResponse('Query', query, children, operationName, variables)
+ )
+ )
+ ;(BaseQuery as any).mockImplementation(
+ jest.fn(({ query, children, operationName, variables }) =>
+ simulateApiResponse('BaseQuery', query, children, operationName, variables)
+ )
+ )
+})
+
+afterEach(() => {
+ resetMockApiCalls()
+ resetMockApiResponses()
+})
+
+const datasetsWithCoverage = allDatasetIds.filter((datasetId) =>
+ hasCopyNumberVariantCoverage(datasetId)
+)
+
+describe.each(datasetsWithCoverage)(
+ 'CopyNumberVariantsGenePercentCallableTrack with dataset %s',
+ (datasetId) => {
+ test('queries with appropriate params', () => {
+ const gene = geneFactory.build()
+ setMockApiResponses({
+ CopyNumberVariantsGenePercentCallableTrack: () => ({
+ gene: {
+ cnv_track_callable_coverage: [],
+ },
+ }),
+ })
+
+ const shallowRenderer = createRenderer()
+ shallowRenderer.render(
+
+ )
+
+ expect(shallowRenderer.getRenderOutput()).toMatchSnapshot()
+ })
+ }
+)
diff --git a/browser/src/GenePage/CopyNumberVariantsGenePercentCallableTrack.tsx b/browser/src/GenePage/CopyNumberVariantsGenePercentCallableTrack.tsx
new file mode 100644
index 000000000..914a00c23
--- /dev/null
+++ b/browser/src/GenePage/CopyNumberVariantsGenePercentCallableTrack.tsx
@@ -0,0 +1,85 @@
+import React from 'react'
+
+import { referenceGenome } from '@gnomad/dataset-metadata/metadata'
+// import CoverageTrack from '../CoverageTrack'
+import Query from '../Query'
+import DiscreteBarPlot from '../DiscreteBarPlot'
+
+type OwnProps = {
+ datasetId: string
+ chrom: string
+ start: number
+ stop: number
+}
+
+// @ts-expect-error TS(2456) FIXME: Type alias 'Props' circularly references itself.
+type Props = OwnProps & typeof CopyNumberVariantsGenePercentCallableTrack.defaultProps
+
+// @ts-expect-error TS(7022) FIXME: 'CopyNumberVariantsGenePercentCallableTrack' implicitly has type '... Remove this comment to see the full error message
+const CopyNumberVariantsGenePercentCallableTrack = ({ datasetId, geneId }: Props) => {
+ const operationName = 'CopyNumberVariantsGenePercentCallableTrack'
+ const query = `
+ query ${operationName}($geneId: String!, $datasetId: CopyNumberVariantDatasetId!, $referenceGenome: ReferenceGenomeId!) {
+ gene(gene_id: $geneId, reference_genome: $referenceGenome) {
+ cnv_track_callable_coverage(dataset: $datasetId) {
+ xpos
+ percent_callable
+ position
+ contig
+ }
+ start
+ stop
+ chrom
+ }
+ }
+`
+ return (
+ {
+ if (!data.gene || !data.gene.cnv_track_callable_coverage) {
+ return false
+ }
+ return data.gene && data.gene.cnv_track_callable_coverage
+ }}
+ >
+ {({ data }: any) => {
+ const transformedArray = data.gene.cnv_track_callable_coverage.map((item: any) => ({
+ pos: item.position,
+ percent_callable: item.percent_callable,
+ xpos: item.xpos,
+ }))
+ transformedArray.sort((a: any, b: any) => a.xpos - b.xpos)
+
+ const coverage = [
+ {
+ color: 'rgb(70, 130, 180)',
+ buckets: transformedArray,
+ name: 'percent callable',
+ opacity: 0.7,
+ },
+ ]
+ const geneStart = data.gene.start
+ const geneStop = data.gene.stop
+ const geneChrom = Number(data.gene.chrom)
+
+ return (
+
+ )
+ }}
+
+ )
+}
+
+export default CopyNumberVariantsGenePercentCallableTrack
diff --git a/browser/src/GenePage/GenePage.spec.tsx b/browser/src/GenePage/GenePage.spec.tsx
index f4ace7de3..ff62fe628 100644
--- a/browser/src/GenePage/GenePage.spec.tsx
+++ b/browser/src/GenePage/GenePage.spec.tsx
@@ -74,6 +74,9 @@ forDatasetsNotMatching(svRegexp, 'GenePage with non-SV dataset "%s"', (datasetId
CopyNumberVariantsInGene: () => ({
gene: { copy_number_variants: [] },
}),
+ CopyNumberVariantsGenePercentCallableTrack: () => ({
+ gene: { cnv_track_callable_coverage: [] },
+ }),
})
)
@@ -146,6 +149,9 @@ forDatasetsMatching(cnvRegexp, 'GenePage with CNV dataset "%s"', (datasetId) =>
coverage: {},
},
}),
+ CopyNumberVariantsGenePercentCallableTrack: () => ({
+ gene: { cnv_track_callable_coverage: [] },
+ }),
})
const tree = renderer.create(
withDummyRouter()
@@ -164,6 +170,9 @@ forDatasetsMatching(cnvRegexp, 'GenePage with CNV dataset "%s"', (datasetId) =>
coverage: {},
},
}),
+ CopyNumberVariantsGenePercentCallableTrack: () => ({
+ gene: { cnv_track_callable_coverage: [] },
+ }),
})
renderer.create(
withDummyRouter()
@@ -208,6 +217,9 @@ describe.each([
CopyNumberVariantsInGene: () => ({
gene: { copy_number_variants: [] },
}),
+ CopyNumberVariantsGenePercentCallableTrack: () => ({
+ gene: { cnv_track_callable_coverage: [] },
+ }),
})
renderer.create(
withDummyRouter()
diff --git a/browser/src/GenePage/GenePage.tsx b/browser/src/GenePage/GenePage.tsx
index 96dc44b6c..b7a733f74 100644
--- a/browser/src/GenePage/GenePage.tsx
+++ b/browser/src/GenePage/GenePage.tsx
@@ -62,6 +62,7 @@ import {
CopyNumberVariant,
} from '../VariantPage/VariantPage'
import CopyNumberVariantsInGene from './CopyNumberVariantsInGene'
+import CopyNumberVariantsGenePercentCallableTrack from './CopyNumberVariantsGenePercentCallableTrack'
export type Strand = '+' | '-'
@@ -609,6 +610,10 @@ const GenePage = ({ datasetId, gene, geneId }: Props) => {
zoomRegion={zoomRegion}
/>
)}
+
+ {hasCopyNumberVariants(datasetId) && (
+
+ )}
)
diff --git a/browser/src/GenePage/__snapshots__/CopyNumberVariantsGenePercentCallableTrack.spec.tsx.snap b/browser/src/GenePage/__snapshots__/CopyNumberVariantsGenePercentCallableTrack.spec.tsx.snap
new file mode 100644
index 000000000..877944ee1
--- /dev/null
+++ b/browser/src/GenePage/__snapshots__/CopyNumberVariantsGenePercentCallableTrack.spec.tsx.snap
@@ -0,0 +1,35 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`CopyNumberVariantsGenePercentCallableTrack with dataset gnomad_cnv_r4 queries with appropriate params 1`] = `
+
+ [Function]
+
+`;
diff --git a/browser/src/GenePage/__snapshots__/GenePage.spec.tsx.snap b/browser/src/GenePage/__snapshots__/GenePage.spec.tsx.snap
index fe8936c5c..9bc2fa9ec 100644
--- a/browser/src/GenePage/__snapshots__/GenePage.spec.tsx.snap
+++ b/browser/src/GenePage/__snapshots__/GenePage.spec.tsx.snap
@@ -1465,275 +1465,787 @@ exports[`GenePage with CNV dataset "gnomad_cnv_r4" has no unexpected changes 1`]
>
No variants found
-
-
-
-`;
-
-exports[`GenePage with SV dataset "gnomad_sv_r2_1" has no unexpected changes 1`] = `
-
-
-
-
-
+
+ 0.5
+
+
+
+
+
- gnomAD v3.1.2 (controls/biobanks)
-
+
-
-
-
-
- GRCh37
-
-
-
+
+ 0.6
+
+
+
+
+
- gnomAD v2.1.1
-
+
-
-
-
- gnomAD v2.1.1 (non-TOPMed)
-
+
+ 0.7
+
+
+
+
+
+
+
-
-
+
+
+ 0.8
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`GenePage with SV dataset "gnomad_sv_r2_1" has no unexpected changes 1`] = `
+
+
+
+
+
+ FAKEGENE
+
+
+
+
+
+
+ Variant co-occurrence
+
+
+
+
+ Constraint not available for this
+ gene
+
+
+
+
+ Viewing full
+ gene
+ .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Fraction of individuals with coverage over 20
+
+
+
+
+
+
+
+
+
+
+ Include:
+
+ -
+
-
+
+
+
- Variant co-occurrence
-
-
-
-
- Constraint not available for this
- gene
-
+ className="GenePage__LegendSwatch-sc-rcxzgc-9 gUeepi"
+ color="#424242"
+ height={4}
+ />
+
+
+
+
+
+
-
-
- Viewing full
- gene
- .
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+ No variants found
+
+
+
+
+
+ -
+
+ percent callable
+
+
@@ -10106,8 +11279,8 @@ exports[`GenePage with non-SV dataset "gnomad_cnv_r4" has no unexpected changes
stroke="#333"
x1={0}
x2={799}
- y1={190}
- y2={190}
+ y1={207}
+ y2={207}
/>
@@ -10115,155 +11288,6 @@ exports[`GenePage with non-SV dataset "gnomad_cnv_r4" has no unexpected changes
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- No variants found
-
diff --git a/browser/src/RegionPage/CopyNumberVariantsRegionCoverageTrack.tsx b/browser/src/RegionPage/CopyNumberVariantsRegionCoverageTrack.tsx
deleted file mode 100644
index 1aab97f70..000000000
--- a/browser/src/RegionPage/CopyNumberVariantsRegionCoverageTrack.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-import React from 'react'
-
-import {
- DatasetId,
- labelForDataset,
- referenceGenome,
- hasMitochondrialGenomeCoverage,
-} from '@gnomad/dataset-metadata/metadata'
-import CoverageTrack from '../CoverageTrack'
-import Query from '../Query'
-import StatusMessage from '../StatusMessage'
-
-const operationName = 'CopyNumberVariantsCoverageInRegion'
-const query = `
-query ${operationName}($start: Int!, $stop: Int!, $datasetId: DatasetId!, $referenceGenome: ReferenceGenomeId!) {
- region(chrom: $chrom, start: $start, stop: $stop, reference_genome: $referenceGenome) {
- copy_number_variants_coverage(dataset: $datasetId) {
- xpos
- percent_callable
- }
- }
-}
-`
-
-type Props = {
- datasetId: DatasetId
- chrom: number
- start: number
- stop: number
-}
-
-const CopyNumberVariantsRegionCoverageTrack = ({ datasetId, chrom, start, stop }: Props) => {
- if (!hasMitochondrialGenomeCoverage(datasetId)) {
- return (
-
- Copy Number Variant exome coverage is not available in {labelForDataset(datasetId)}
-
- )
- }
-
- return (
- {
- return data.region && data.region.copy_number_variant_coverage
- }}
- >
- {({ data }: any) => {
- const coverage = [
- {
- color: 'rgb(115, 171, 61)',
- buckets: data.region.copy_number_variant_coverage,
- name: 'copy number variant coverage', // TODO
- opacity: 0.7,
- },
- ]
-
- return (
- `${chrom}-${start}-${stop}_coverage`}
- height={190}
- maxCoverage={3000}
- datasetId={datasetId}
- />
- )
- }}
-
- )
-}
-
-export default CopyNumberVariantsRegionCoverageTrack
diff --git a/browser/src/RegionPage/CopyNumberVariantsRegionPercentCallableTrack.spec.tsx b/browser/src/RegionPage/CopyNumberVariantsRegionPercentCallableTrack.spec.tsx
new file mode 100644
index 000000000..03d398b76
--- /dev/null
+++ b/browser/src/RegionPage/CopyNumberVariantsRegionPercentCallableTrack.spec.tsx
@@ -0,0 +1,73 @@
+import React from 'react'
+import { createRenderer } from 'react-test-renderer/shallow'
+
+import { jest, describe, expect, test } from '@jest/globals'
+import { mockQueries } from '../../../tests/__helpers__/queries'
+import Query, { BaseQuery } from '../Query'
+
+import CopyNumberVariantsRegionPercentCallableTrack from './CopyNumberVariantsRegionPercentCallableTrack'
+
+import { allDatasetIds, hasCopyNumberVariantCoverage } from '@gnomad/dataset-metadata/metadata'
+
+jest.mock('../Query', () => {
+ const originalModule = jest.requireActual('../Query')
+
+ return {
+ __esModule: true,
+ ...(originalModule as object),
+ default: jest.fn(),
+ BaseQuery: jest.fn(),
+ }
+})
+
+const { resetMockApiCalls, resetMockApiResponses, simulateApiResponse, setMockApiResponses } =
+ mockQueries()
+
+beforeEach(() => {
+ Query.mockImplementation(
+ jest.fn(({ query, children, operationName, variables }) =>
+ simulateApiResponse('Query', query, children, operationName, variables)
+ )
+ )
+ ;(BaseQuery as any).mockImplementation(
+ jest.fn(({ query, children, operationName, variables }) =>
+ simulateApiResponse('BaseQuery', query, children, operationName, variables)
+ )
+ )
+})
+
+afterEach(() => {
+ resetMockApiCalls()
+ resetMockApiResponses()
+})
+
+const datasetsWithCoverage = allDatasetIds.filter((datasetId) =>
+ hasCopyNumberVariantCoverage(datasetId)
+)
+
+describe.each(datasetsWithCoverage)(
+ 'CopyNumberVariantsRegionPercentCallableTrack with dataset %s',
+ (datasetId) => {
+ test('queries with appropriate params', () => {
+ setMockApiResponses({
+ CopyNumberVariantsRegionPercentCallableTrack: () => ({
+ region: {
+ cnv_track_callable_coverage: [],
+ },
+ }),
+ })
+
+ const shallowRenderer = createRenderer()
+ shallowRenderer.render(
+
+ )
+
+ expect(shallowRenderer.getRenderOutput()).toMatchSnapshot()
+ })
+ }
+)
diff --git a/browser/src/RegionPage/CopyNumberVariantsRegionPercentCallableTrack.tsx b/browser/src/RegionPage/CopyNumberVariantsRegionPercentCallableTrack.tsx
new file mode 100644
index 000000000..a6f84a17b
--- /dev/null
+++ b/browser/src/RegionPage/CopyNumberVariantsRegionPercentCallableTrack.tsx
@@ -0,0 +1,75 @@
+import React from 'react'
+
+import { referenceGenome } from '@gnomad/dataset-metadata/metadata'
+import Query from '../Query'
+import DiscreteBarPlot from '../DiscreteBarPlot'
+
+type OwnProps = {
+ datasetId: string
+ chrom: string
+ start: number
+ stop: number
+}
+
+// @ts-expect-error TS(2456) FIXME: Type alias 'Props' circularly references itself.
+type Props = OwnProps & typeof CopyNumberVariantsRegionPercentCallableTrack.defaultProps
+
+// @ts-expect-error TS(7022) FIXME: 'CopyNumberVariantsRegionPercentCallableTrack' implicitly has type '... Remove this comment to see the full error message
+const CopyNumberVariantsRegionPercentCallableTrack = ({ datasetId, chrom, start, stop }: Props) => {
+ const operationName = 'CopyNumberVariantsRegionPercentCallableTrack'
+ const query = `
+ query ${operationName}($datasetId: CopyNumberVariantDatasetId!, $chrom: String!, $start: Int!, $stop: Int!, $referenceGenome: ReferenceGenomeId!) {
+ region(chrom: $chrom, start: $start, stop: $stop, reference_genome: $referenceGenome) {
+ cnv_track_callable_coverage(dataset: $datasetId) {
+ xpos
+ percent_callable
+ position
+ contig
+ }
+ }
+ }
+`
+ return (
+ {
+ return data.region && data.region.cnv_track_callable_coverage
+ }}
+ >
+ {({ data }: any) => {
+ const transformedArray = data.region.cnv_track_callable_coverage.map((item: any) => ({
+ pos: item.position,
+ percent_callable: item.percent_callable,
+ xpos: item.xpos,
+ }))
+ transformedArray.sort((a: any, b: any) => a.xpos - b.xpos)
+
+ const coverage = [
+ {
+ color: 'rgb(70, 130, 180)',
+ buckets: transformedArray,
+ name: 'percent callable',
+ opacity: 0.7,
+ },
+ ]
+
+ return (
+
+ )
+ }}
+
+ )
+}
+
+export default CopyNumberVariantsRegionPercentCallableTrack
diff --git a/browser/src/RegionPage/RegionPage.tsx b/browser/src/RegionPage/RegionPage.tsx
index 534cd5260..5fae551bf 100644
--- a/browser/src/RegionPage/RegionPage.tsx
+++ b/browser/src/RegionPage/RegionPage.tsx
@@ -30,6 +30,7 @@ import RegionInfo from './RegionInfo'
import RegularVariantsInRegion from './VariantsInRegion'
import StructuralVariantsInRegion from './StructuralVariantsInRegion'
import CopyNumberVariantsInRegion from './CopyNumberVariantsInRegion'
+import CopyNumberVariantsRegionTrackCallable from './CopyNumberVariantsRegionPercentCallableTrack'
const RegionInfoColumnWrapper = styled.div`
display: flex;
@@ -188,6 +189,12 @@ const RegionPage = ({ datasetId, region }: RegionPageProps) => {
>
)}
{variantsInRegion(datasetId, region)}
+
)
diff --git a/browser/src/RegionPage/__snapshots__/CopyNumberVariantsRegionPercentCallableTrack.spec.tsx.snap b/browser/src/RegionPage/__snapshots__/CopyNumberVariantsRegionPercentCallableTrack.spec.tsx.snap
new file mode 100644
index 000000000..ecb173174
--- /dev/null
+++ b/browser/src/RegionPage/__snapshots__/CopyNumberVariantsRegionPercentCallableTrack.spec.tsx.snap
@@ -0,0 +1,34 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`CopyNumberVariantsRegionPercentCallableTrack with dataset gnomad_cnv_r4 queries with appropriate params 1`] = `
+
+ [Function]
+
+`;
diff --git a/browser/src/RegionPage/__snapshots__/RegionPage.spec.tsx.snap b/browser/src/RegionPage/__snapshots__/RegionPage.spec.tsx.snap
index 45a4967ff..0fddd8c8f 100644
--- a/browser/src/RegionPage/__snapshots__/RegionPage.spec.tsx.snap
+++ b/browser/src/RegionPage/__snapshots__/RegionPage.spec.tsx.snap
@@ -137,6 +137,12 @@ exports[`RegionPage with "exac" dataset has no unexpected changes for a mitochon
}
}
/>
+
`;
@@ -270,6 +276,12 @@ exports[`RegionPage with "exac" dataset has no unexpected changes for a non-mito
}
}
/>
+
`;
@@ -411,6 +423,12 @@ exports[`RegionPage with "gnomad_cnv_r4" dataset has no unexpected changes for a
}
}
/>
+
`;
@@ -555,6 +573,12 @@ exports[`RegionPage with "gnomad_cnv_r4" dataset has no unexpected changes for a
}
}
/>
+
`;
@@ -696,6 +720,12 @@ exports[`RegionPage with "gnomad_r2_1" dataset has no unexpected changes for a m
}
}
/>
+
`;
@@ -829,6 +859,12 @@ exports[`RegionPage with "gnomad_r2_1" dataset has no unexpected changes for a n
}
}
/>
+
`;
@@ -970,6 +1006,12 @@ exports[`RegionPage with "gnomad_r2_1_controls" dataset has no unexpected change
}
}
/>
+
`;
@@ -1103,6 +1145,12 @@ exports[`RegionPage with "gnomad_r2_1_controls" dataset has no unexpected change
}
}
/>
+
`;
@@ -1244,6 +1292,12 @@ exports[`RegionPage with "gnomad_r2_1_non_cancer" dataset has no unexpected chan
}
}
/>
+
`;
@@ -1377,6 +1431,12 @@ exports[`RegionPage with "gnomad_r2_1_non_cancer" dataset has no unexpected chan
}
}
/>
+
`;
@@ -1518,6 +1578,12 @@ exports[`RegionPage with "gnomad_r2_1_non_neuro" dataset has no unexpected chang
}
}
/>
+
`;
@@ -1651,6 +1717,12 @@ exports[`RegionPage with "gnomad_r2_1_non_neuro" dataset has no unexpected chang
}
}
/>
+
`;
@@ -1792,6 +1864,12 @@ exports[`RegionPage with "gnomad_r2_1_non_topmed" dataset has no unexpected chan
}
}
/>
+
`;
@@ -1925,6 +2003,12 @@ exports[`RegionPage with "gnomad_r2_1_non_topmed" dataset has no unexpected chan
}
}
/>
+
`;
@@ -2074,6 +2158,12 @@ exports[`RegionPage with "gnomad_r3" dataset has no unexpected changes for a mit
}
}
/>
+
`;
@@ -2215,6 +2305,12 @@ exports[`RegionPage with "gnomad_r3" dataset has no unexpected changes for a non
}
}
/>
+
`;
@@ -2364,6 +2460,12 @@ exports[`RegionPage with "gnomad_r3_controls_and_biobanks" dataset has no unexpe
}
}
/>
+
`;
@@ -2505,6 +2607,12 @@ exports[`RegionPage with "gnomad_r3_controls_and_biobanks" dataset has no unexpe
}
}
/>
+
`;
@@ -2654,6 +2762,12 @@ exports[`RegionPage with "gnomad_r3_non_cancer" dataset has no unexpected change
}
}
/>
+
`;
@@ -2795,6 +2909,12 @@ exports[`RegionPage with "gnomad_r3_non_cancer" dataset has no unexpected change
}
}
/>
+
`;
@@ -2944,6 +3064,12 @@ exports[`RegionPage with "gnomad_r3_non_neuro" dataset has no unexpected changes
}
}
/>
+
`;
@@ -3085,6 +3211,12 @@ exports[`RegionPage with "gnomad_r3_non_neuro" dataset has no unexpected changes
}
}
/>
+
`;
@@ -3234,6 +3366,12 @@ exports[`RegionPage with "gnomad_r3_non_topmed" dataset has no unexpected change
}
}
/>
+
`;
@@ -3375,6 +3513,12 @@ exports[`RegionPage with "gnomad_r3_non_topmed" dataset has no unexpected change
}
}
/>
+
`;
@@ -3524,6 +3668,12 @@ exports[`RegionPage with "gnomad_r3_non_v2" dataset has no unexpected changes fo
}
}
/>
+
`;
@@ -3665,6 +3815,12 @@ exports[`RegionPage with "gnomad_r3_non_v2" dataset has no unexpected changes fo
}
}
/>
+
`;
@@ -3806,6 +3962,12 @@ exports[`RegionPage with "gnomad_r4" dataset has no unexpected changes for a mit
}
}
/>
+
`;
@@ -3939,6 +4101,12 @@ exports[`RegionPage with "gnomad_r4" dataset has no unexpected changes for a non
}
}
/>
+
`;
@@ -4080,6 +4248,12 @@ exports[`RegionPage with "gnomad_sv_r2_1" dataset has no unexpected changes for
}
}
/>
+
`;
@@ -4224,6 +4398,12 @@ exports[`RegionPage with "gnomad_sv_r2_1" dataset has no unexpected changes for
}
}
/>
+
`;
@@ -4365,6 +4545,12 @@ exports[`RegionPage with "gnomad_sv_r2_1_controls" dataset has no unexpected cha
}
}
/>
+
`;
@@ -4509,6 +4695,12 @@ exports[`RegionPage with "gnomad_sv_r2_1_controls" dataset has no unexpected cha
}
}
/>
+
`;
@@ -4650,6 +4842,12 @@ exports[`RegionPage with "gnomad_sv_r2_1_non_neuro" dataset has no unexpected ch
}
}
/>
+
`;
@@ -4794,6 +4992,12 @@ exports[`RegionPage with "gnomad_sv_r2_1_non_neuro" dataset has no unexpected ch
}
}
/>
+
`;
@@ -4943,6 +5147,12 @@ exports[`RegionPage with "gnomad_sv_r4" dataset has no unexpected changes for a
}
}
/>
+
`;
@@ -5095,6 +5305,12 @@ exports[`RegionPage with "gnomad_sv_r4" dataset has no unexpected changes for a
}
}
/>
+
`;
diff --git a/data-pipeline/src/data_pipeline/datasets/gnomad_v4/gnomad_v4_cnv_del_burden.py b/data-pipeline/src/data_pipeline/datasets/gnomad_v4/gnomad_v4_cnv_del_burden.py
index c5ca244fd..21dd3a310 100644
--- a/data-pipeline/src/data_pipeline/datasets/gnomad_v4/gnomad_v4_cnv_del_burden.py
+++ b/data-pipeline/src/data_pipeline/datasets/gnomad_v4/gnomad_v4_cnv_del_burden.py
@@ -1,9 +1,34 @@
import hail as hl
-def prepare_cnv_del_burden(burden_path):
- del_burden = hl.import_table(burden_path, force_bgz=True, types={"xpos": hl.tfloat64, "burden_del": hl.tfloat64})
+def extract_contig_and_position(xpos: hl.expr.Int64Expression) -> (hl.expr.StringExpression, hl.expr.Float64Expression):
+ value_str = hl.str(xpos)
+ contig_number_length = 1
- del_burden = del_burden.select("xpos", "burden_del")
+ is_double_digit = (hl.len(value_str) == 11) & (value_str[:2] != "00")
+ contig_number_length = hl.if_else(is_double_digit, 2, contig_number_length)
+
+ contig_number = value_str[:contig_number_length]
+ position = hl.float64(value_str[contig_number_length:])
+
+ return contig_number, position
+
+
+def get_contig(xpos: hl.expr.StringExpression) -> hl.expr.StringExpression:
+ contig_number, _ = extract_contig_and_position(xpos)
+ return hl.str(contig_number)
+
+
+def get_position(xpos: hl.expr.Int64Expression) -> hl.expr.Float64Expression:
+ _, position = extract_contig_and_position(xpos)
+ return position
+
+
+def prepare_cnv_del_burden(del_burden_path):
+ del_burden = hl.import_table(del_burden_path, force_bgz=True, types={"xpos": hl.tint64, "burden_del": hl.tfloat64})
+
+ del_burden = del_burden.annotate(contig=get_contig(del_burden.xpos), position=get_position(del_burden.xpos))
+
+ del_burden = del_burden.select("xpos", "burden_del", "contig", "position")
return del_burden
diff --git a/data-pipeline/src/data_pipeline/datasets/gnomad_v4/gnomad_v4_cnv_dup_burden.py b/data-pipeline/src/data_pipeline/datasets/gnomad_v4/gnomad_v4_cnv_dup_burden.py
index 1a7d3aade..f4a6d9561 100644
--- a/data-pipeline/src/data_pipeline/datasets/gnomad_v4/gnomad_v4_cnv_dup_burden.py
+++ b/data-pipeline/src/data_pipeline/datasets/gnomad_v4/gnomad_v4_cnv_dup_burden.py
@@ -1,9 +1,34 @@
import hail as hl
-def prepare_cnv_dup_burden(burden_path):
- dup_burden = hl.import_table(burden_path, force_bgz=True, types={"xpos": hl.tfloat64, "burden_dup": hl.tfloat64})
+def extract_contig_and_position(xpos: hl.expr.Int64Expression) -> (hl.expr.StringExpression, hl.expr.Float64Expression):
+ value_str = hl.str(xpos)
+ contig_number_length = 1
- dup_burden = dup_burden.select("xpos", "burden_dup")
+ is_double_digit = (hl.len(value_str) == 11) & (value_str[:2] != "00")
+ contig_number_length = hl.if_else(is_double_digit, 2, contig_number_length)
+
+ contig_number = value_str[:contig_number_length]
+ position = hl.float64(value_str[contig_number_length:])
+
+ return contig_number, position
+
+
+def get_contig(xpos: hl.expr.StringExpression) -> hl.expr.StringExpression:
+ contig_number, _ = extract_contig_and_position(xpos)
+ return hl.str(contig_number)
+
+
+def get_position(xpos: hl.expr.Int64Expression) -> hl.expr.Float64Expression:
+ _, position = extract_contig_and_position(xpos)
+ return position
+
+
+def prepare_cnv_dup_burden(dup_burden_path):
+ dup_burden = hl.import_table(dup_burden_path, force_bgz=True, types={"xpos": hl.tint64, "burden_dup": hl.tfloat64})
+
+ dup_burden = dup_burden.annotate(contig=get_contig(dup_burden.xpos), position=get_position(dup_burden.xpos))
+
+ dup_burden = dup_burden.select("xpos", "burden_dup", "contig", "position")
return dup_burden
diff --git a/data-pipeline/src/data_pipeline/datasets/gnomad_v4/gnomad_v4_cnv_track_percent_callable.py b/data-pipeline/src/data_pipeline/datasets/gnomad_v4/gnomad_v4_cnv_track_percent_callable.py
index a2febc302..35bddc7fa 100644
--- a/data-pipeline/src/data_pipeline/datasets/gnomad_v4/gnomad_v4_cnv_track_percent_callable.py
+++ b/data-pipeline/src/data_pipeline/datasets/gnomad_v4/gnomad_v4_cnv_track_percent_callable.py
@@ -1,11 +1,36 @@
import hail as hl
+def extract_contig_and_position(xpos: hl.expr.Int64Expression) -> (hl.expr.StringExpression, hl.expr.Float64Expression):
+ value_str = hl.str(xpos)
+ contig_number_length = 1
+
+ is_double_digit = (hl.len(value_str) == 11) & (value_str[:2] != "00")
+ contig_number_length = hl.if_else(is_double_digit, 2, contig_number_length)
+
+ contig_number = value_str[:contig_number_length]
+ position = hl.float64(value_str[contig_number_length:])
+
+ return contig_number, position
+
+
+def get_contig(xpos: hl.expr.StringExpression) -> hl.expr.StringExpression:
+ contig_number, _ = extract_contig_and_position(xpos)
+ return hl.str(contig_number)
+
+
+def get_position(xpos: hl.expr.Int64Expression) -> hl.expr.Float64Expression:
+ _, position = extract_contig_and_position(xpos)
+ return position
+
+
def prepare_cnv_track_callable(coverage_path):
coverage = hl.import_table(
- coverage_path, force_bgz=True, types={"xpos": hl.tfloat64, "percent_callable": hl.tfloat64}
+ coverage_path, force_bgz=True, types={"xpos": hl.tint64, "percent_callable": hl.tfloat64}
)
- coverage = coverage.select("xpos", "percent_callable")
+ coverage = coverage.annotate(contig=get_contig(coverage.xpos), position=get_position(coverage.xpos))
+
+ coverage = coverage.select("xpos", "percent_callable", "contig", "position")
return coverage
diff --git a/data-pipeline/src/data_pipeline/pipelines/gnomad_v4_cnv_del_burden.py b/data-pipeline/src/data_pipeline/pipelines/gnomad_v4_cnv_del_burden.py
index 5b717656a..8e5e57f34 100644
--- a/data-pipeline/src/data_pipeline/pipelines/gnomad_v4_cnv_del_burden.py
+++ b/data-pipeline/src/data_pipeline/pipelines/gnomad_v4_cnv_del_burden.py
@@ -9,7 +9,7 @@
"prepare_gnomad_v4_cnv_del_burden",
prepare_cnv_del_burden,
"/gnomad_v4/gnomad_v4_cnvs/cnv_tracks/del_burden.ht",
- {"burden_path": "gs://gnomad-v4-cnvs/2023-10-24jfu/burden_del_1.0.txt.gz"},
+ {"burden_path": "gs://gnomad-v4-cnvs/2023-10-24-jfu/burden_del_1.0.txt.gz"},
)
###############################################
diff --git a/data-pipeline/src/data_pipeline/pipelines/gnomad_v4_cnv_dup_burden.py b/data-pipeline/src/data_pipeline/pipelines/gnomad_v4_cnv_dup_burden.py
index 3c82b16f0..2007ee028 100644
--- a/data-pipeline/src/data_pipeline/pipelines/gnomad_v4_cnv_dup_burden.py
+++ b/data-pipeline/src/data_pipeline/pipelines/gnomad_v4_cnv_dup_burden.py
@@ -9,7 +9,7 @@
"prepare_gnomad_v4_cnv_dup_burden",
prepare_cnv_dup_burden,
"/gnomad_v4/gnomad_v4_cnvs/cnv_tracks/dup_burden.ht",
- {"burden_path": "gs://gnomad-v4-cnvs/2023-10-24jfu/burden_dup_1.0.txt.gz"},
+ {"dup_burden_path": "gs://gnomad-v4-cnvs/2023-10-24-jfu/burden_dup_1.0.txt.gz"},
)
###############################################
diff --git a/data-pipeline/src/data_pipeline/pipelines/gnomad_v4_cnv_track_percent_callable.py b/data-pipeline/src/data_pipeline/pipelines/gnomad_v4_cnv_track_percent_callable.py
index 7cd44dcf9..a6c9e0a54 100644
--- a/data-pipeline/src/data_pipeline/pipelines/gnomad_v4_cnv_track_percent_callable.py
+++ b/data-pipeline/src/data_pipeline/pipelines/gnomad_v4_cnv_track_percent_callable.py
@@ -9,7 +9,7 @@
"prepare_gnomad_v4_cnvs_track_percent_callable",
prepare_cnv_track_callable,
"/gnomad_v4/gnomad_v4_cnvs/cnv_tracks/track_percent_callable.ht",
- {"coverage_path": "gs://gnomad-v4-cnvs/2023-10-24jfu/track_percent_callable.tsv.gz"},
+ {"coverage_path": "gs://gnomad-v4-cnvs/2023-10-24-jfu/track_percent_callable.tsv.gz"},
)
###############################################
diff --git a/graphql-api/src/graphql/resolvers/cnv-coverage.ts b/graphql-api/src/graphql/resolvers/cnv-coverage.ts
index 8c68b5ef7..4fbb11658 100644
--- a/graphql-api/src/graphql/resolvers/cnv-coverage.ts
+++ b/graphql-api/src/graphql/resolvers/cnv-coverage.ts
@@ -1,12 +1,33 @@
-import { fetchTrackCallableCoverageForGene } from '../../queries/cnv-coverage-queries'
+import {
+ fetchDelBurdenCoverageForGene,
+ fetchDelBurdenCoverageForRegion,
+ fetchDupBurdenCoverageForGene,
+ fetchDupBurdenCoverageForRegion,
+ fetchTrackCallableCoverageForGene,
+ fetchTrackCallableCoverageForRegion,
+} from '../../queries/cnv-coverage-queries'
-const resolveTrackCallableCoverageInGene = async (obj: any, args: any, ctx: any) => {
- return fetchTrackCallableCoverageForGene(ctx.esClient, args.dataset, obj)
+const createResolver = (fetchCoverage: any) => async (obj: any, args: any, ctx: any) => {
+ return fetchCoverage(ctx.esClient, args.dataset, obj)
}
+const resolveTrackCallableCoverageInGene = createResolver(fetchTrackCallableCoverageForGene)
+const resolveDelBurdenCoverageInGene = createResolver(fetchDelBurdenCoverageForGene)
+const resolveDupBurdenCoverageInGene = createResolver(fetchDupBurdenCoverageForGene)
+const resolveTrackCallableCoverageInRegion = createResolver(fetchTrackCallableCoverageForRegion)
+const resolveDelBurdenCoverageInRegion = createResolver(fetchDelBurdenCoverageForRegion)
+const resolveDupBurdenCoverageInRegion = createResolver(fetchDupBurdenCoverageForRegion)
+
const resolvers = {
Gene: {
cnv_track_callable_coverage: resolveTrackCallableCoverageInGene,
+ cnv_del_burden_coverage: resolveDelBurdenCoverageInGene,
+ cnv_dup_burden_coverage: resolveDupBurdenCoverageInGene,
+ },
+ Region: {
+ cnv_track_callable_coverage: resolveTrackCallableCoverageInRegion,
+ cnv_del_burden_coverage: resolveDelBurdenCoverageInRegion,
+ cnv_dup_burden_coverage: resolveDupBurdenCoverageInRegion,
},
}
diff --git a/graphql-api/src/graphql/types/copy-number-variant.graphql b/graphql-api/src/graphql/types/copy-number-variant.graphql
index f9fe1af07..0d7b2779b 100644
--- a/graphql-api/src/graphql/types/copy-number-variant.graphql
+++ b/graphql-api/src/graphql/types/copy-number-variant.graphql
@@ -48,4 +48,16 @@ type CopyNumberVariantDetails {
type CNVTrackCallableCoverageBin {
xpos: Float!
percent_callable: Float
+ position: Float
+ contig: String
+}
+
+type CNVDelBurdenCoverageBin{
+ xpos: Float!
+ burden_del: Float
+}
+
+type CNVDupBurdenCoverageBin{
+ xpos: Float!
+ burden_dup: Float
}
\ No newline at end of file
diff --git a/graphql-api/src/graphql/types/gene.graphql b/graphql-api/src/graphql/types/gene.graphql
index dfd7bd187..3592d90d5 100644
--- a/graphql-api/src/graphql/types/gene.graphql
+++ b/graphql-api/src/graphql/types/gene.graphql
@@ -79,6 +79,8 @@ type Gene {
coverage(dataset: DatasetId): FeatureCoverage! @cost(value: 5)
mitochondrial_coverage(dataset: DatasetId!): [MitochondrialCoverageBin!] @cost(value: 5)
cnv_track_callable_coverage(dataset: CopyNumberVariantDatasetId!): [CNVTrackCallableCoverageBin!] @cost(value: 5)
+ cnv_del_burden_coverage(dataset: CopyNumberVariantDatasetId!): [CNVDelBurdenCoverageBin!] @cost(value: 5)
+ cnv_dup_burden_coverage(dataset: CopyNumberVariantDatasetId!): [CNVDupBurdenCoverageBin!] @cost(value: 5)
short_tandem_repeats(dataset: DatasetId!): [ShortTandemRepeat!]! @cost(value: 5)
heterozygous_variant_cooccurrence_counts: [HeterozygousVariantCooccurrenceCounts!]!
diff --git a/graphql-api/src/graphql/types/region.graphql b/graphql-api/src/graphql/types/region.graphql
index 91fce5bac..0cb30d812 100644
--- a/graphql-api/src/graphql/types/region.graphql
+++ b/graphql-api/src/graphql/types/region.graphql
@@ -32,11 +32,14 @@ type Region {
structural_variants(dataset: StructuralVariantDatasetId!): [StructuralVariant!]! @cost(value: 10)
mitochondrial_variants(dataset: DatasetId!): [MitochondrialVariant!]! @cost(value: 10)
copy_number_variants(dataset: CopyNumberVariantDatasetId!): [CopyNumberVariant!]! @cost(value: 10)
+ cnv_del_burden_coverage(dataset: CopyNumberVariantDatasetId!): [CNVDelBurdenCoverageBin!] @cost(value: 5)
+ cnv_dup_burden_coverage(dataset: CopyNumberVariantDatasetId!): [CNVDupBurdenCoverageBin!] @cost(value: 5)
clinvar_variants: [ClinVarVariant!] @cost(value: 10)
coverage(dataset: DatasetId!): RegionCoverage!
mitochondrial_coverage(dataset: DatasetId!): [MitochondrialCoverageBin!] @cost(value: 5)
+ cnv_track_callable_coverage(dataset: CopyNumberVariantDatasetId!): [CNVTrackCallableCoverageBin!] @cost(value: 5)
short_tandem_repeats(dataset: DatasetId!): [ShortTandemRepeat!]! @cost(value: 5)
}
diff --git a/graphql-api/src/queries/cnv-coverage-queries.ts b/graphql-api/src/queries/cnv-coverage-queries.ts
index df63f93e9..da72a812c 100644
--- a/graphql-api/src/queries/cnv-coverage-queries.ts
+++ b/graphql-api/src/queries/cnv-coverage-queries.ts
@@ -7,6 +7,8 @@ import { assertDatasetAndReferenceGenomeMatch } from './helpers/validation-helpe
const COVERAGE_INDICES = {
gnomad_cnv_r4: {
track_callable: 'gnomad_v4_cnv_track_callable_coverage',
+ del_burden: 'gnomad_v4_cnv_del_burden',
+ dup_burden: 'gnomad_v4_cnv_dup_burden',
},
}
@@ -14,44 +16,122 @@ const COVERAGE_INDICES = {
// Base query
// ================================================================================================
-const fetchTrackCallableCoverage = async (esClient: any, { regions }: any) => {
- const requestBody = {
- query: {
- bool: {
- filter: [
- {
- bool: {
- should: regions.map(({ xstart, xstop }: any) => ({
- range: { xpos: { gte: xstart, lte: xstop } },
- })),
- },
+const fetchTrackCallableCoverage = async (esClient: any, { index, contig, regions }: any) => {
+ try {
+ const response = await esClient.search({
+ index,
+ type: '_doc',
+ size: 10000,
+ body: {
+ query: {
+ bool: {
+ filter: [
+ { term: { contig } },
+ {
+ bool: {
+ should: regions.map(({ start, stop }: any) => ({
+ range: { position: { gte: start, lte: stop } },
+ })),
+ },
+ },
+ ],
},
- ],
+ },
},
- },
+ })
+ return response.body.hits.hits.map((hit: any) => ({
+ xpos: hit._source.xpos,
+ percent_callable: Math.ceil(parseFloat(hit._source.percent_callable || 0) * 100) / 100,
+ position: hit._source.position,
+ contig: hit._source.contig
+ }))
+ } catch (error) {
+ throw new Error(`Couldn't fetch coverage, ${error}`)
}
+}
- const response = await esClient.search({
- index: 'gnomad_v4_cnv_track_callable_coverage',
- type: '_doc',
- size: 2,
- body: requestBody,
- })
- return response.body.hits.hits.map((hit: any) => ({
- xpos: parseFloat(hit._source.xpos),
- percent_callable: Math.ceil((hit._source.percent_callable || 0) * 100) / 100,
- }))
+
+const fetchDelBurdenCoverage = async (esClient: any, { index, contig, regions }: any) => {
+ try {
+ const response = await esClient.search({
+ index,
+ type: '_doc',
+ size: 10000,
+ body: {
+ query: {
+ bool: {
+ filter: [
+ { term: { contig } },
+ {
+ bool: {
+ should: regions.map(({ start, stop }: any) => ({
+ range: { position: { gte: start, lte: stop } },
+ })),
+ },
+ },
+ ],
+ },
+ },
+ },
+ })
+ return response.body.hits.hits.map((hit: any) => ({
+ xpos: hit._source.xpos,
+ burden_del: parseFloat(hit._source.burden_del) ,
+ position: hit._source.position,
+ contig: hit._source.contig
+ }))
+ } catch (error) {
+ throw new Error(`Couldn't fetch coverage, ${error}`)
+ }
+}
+
+const fetchDupBurdenCoverage = async (esClient: any, { index, contig, regions }: any) => {
+ try {
+ const response = await esClient.search({
+ index,
+ type: '_doc',
+ size: 10000,
+ body: {
+ query: {
+ bool: {
+ filter: [
+ { term: { contig } },
+ {
+ bool: {
+ should: regions.map(({ start, stop }: any) => ({
+ range: { position: { gte: start, lte: stop } },
+ })),
+ },
+ },
+ ],
+ },
+ },
+ },
+ })
+ return response.body.hits.hits.map((hit: any) => ({
+ xpos: hit._source.xpos,
+ burden_dup: parseFloat(hit._source.burden_dup) ,
+ position: hit._source.position,
+ contig: hit._source.contig
+ }))
+ } catch (error) {
+ throw new Error(`Couldn't fetch coverage, ${error}`)
+ }
}
// ================================================================================================
// Region queries
// ================================================================================================
-export const fetchTrackCallableCoverageForRegion = (esClient: any, datasetId: any, region: any) => {
+export const fetchTrackCallableCoverageForRegion = async (
+ esClient: any,
+ datasetId: any,
+ region: any
+) => {
assertDatasetAndReferenceGenomeMatch(datasetId, region.reference_genome)
- if (!datasetId.startsWith('gnomad_cnv_')) {
- throw new UserVisibleError('Track callabe coverage is not available for non-CNVs')
+ if (!datasetId.startsWith('gnomad_cnv')) {
+ throw new UserVisibleError('Track callable coverage is not available for non-CNVs')
}
// @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
@@ -60,11 +140,67 @@ export const fetchTrackCallableCoverageForRegion = (esClient: any, datasetId: an
const regionSize = region.stop - region.start + 150
const bucketSize = Math.max(Math.floor(regionSize / 500), 1)
- return fetchTrackCallableCoverage(esClient, {
+ const trackCallableCoverage = await fetchTrackCallableCoverage(esClient, {
index: trackCallableCoverageIndex,
+ contig: region.chrom,
+ regions: [{ start: region.start - 75, stop: region.stop + 75 }],
+ bucketSize,
+ })
+
+ return trackCallableCoverage
+}
+
+export const fetchDelBurdenCoverageForRegion = async (
+ esClient: any,
+ datasetId: any,
+ region: any
+) => {
+ assertDatasetAndReferenceGenomeMatch(datasetId, region.reference_genome)
+
+ if (!datasetId.startsWith('gnomad_cnv')) {
+ throw new UserVisibleError('Deletion burden track coverage is not available for non-CNVs')
+ }
+
+ // @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
+ const delBurdenCoverageIndex = COVERAGE_INDICES[datasetId]
+
+ const regionSize = region.stop - region.start + 150
+ const bucketSize = Math.max(Math.floor(regionSize / 500), 1)
+
+ const delBurdenCoverage = await fetchDelBurdenCoverage(esClient, {
+ index: delBurdenCoverageIndex,
+ contig: region.chrom,
regions: [{ start: region.start - 75, stop: region.stop + 75 }],
bucketSize,
})
+
+ return delBurdenCoverage
+}
+
+export const fetchDupBurdenCoverageForRegion = async (
+ esClient: any,
+ datasetId: any,
+ region: any
+) => {
+ assertDatasetAndReferenceGenomeMatch(datasetId, region.reference_genome)
+
+ if (!datasetId.startsWith('gnomad_cnv')) {
+ throw new UserVisibleError('Duplication burden track coverage is not available for non-CNVs')
+ }
+
+ // @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
+ const dupBurdenCoverageIndex = COVERAGE_INDICES[datasetId]
+
+ const regionSize = region.stop - region.start + 150
+ const bucketSize = Math.max(Math.floor(regionSize / 500), 1)
+
+ const dupBurdenCoverage = await fetchDupBurdenCoverage(esClient, {
+ index: dupBurdenCoverageIndex,
+ regions: [{ start: region.start - 75, stop: region.stop + 75 }],
+ bucketSize,
+ })
+
+ return dupBurdenCoverage
}
// ================================================================================================
@@ -78,8 +214,8 @@ export const _fetchTrackCallableCoverageForGene = async (
) => {
assertDatasetAndReferenceGenomeMatch(datasetId, gene.reference_genome)
- if (!datasetId.startsWith('gnomad_cnv_')) {
- throw new UserVisibleError('Track callabe coverage is not available for non-CNVs')
+ if (!datasetId.startsWith('gnomad_cnv')) {
+ throw new UserVisibleError('Track callable coverage is not available for non-CNVs')
}
const paddedExons = extendRegions(75, gene.exons)
@@ -95,13 +231,71 @@ export const _fetchTrackCallableCoverageForGene = async (
const trackCallableCoverageIndex = COVERAGE_INDICES[datasetId]
const trackCallableCoverage = await fetchTrackCallableCoverage(esClient, {
index: trackCallableCoverageIndex,
+ contig: gene.chrom,
regions: mergedExons,
bucketSize,
})
- return {
- cnv_track_callable_coverage: trackCallableCoverage || [],
- }
+ return trackCallableCoverage
}
export const fetchTrackCallableCoverageForGene = _fetchTrackCallableCoverageForGene
+
+export const _fetchDelBurdenCoverageForGene = async (esClient: any, datasetId: any, gene: any) => {
+ assertDatasetAndReferenceGenomeMatch(datasetId, gene.reference_genome)
+
+ if (!datasetId.startsWith('gnomad_cnv')) {
+ throw new UserVisibleError('Deletion burden track coverage is not available for non-CNVs')
+ }
+
+ const paddedExons = extendRegions(75, gene.exons)
+
+ const mergedExons = mergeOverlappingRegions(
+ paddedExons.sort((a: any, b: any) => a.start - b.start)
+ )
+
+ const totalIntervalSize = totalRegionSize(mergedExons)
+ const bucketSize = Math.max(Math.floor(totalIntervalSize / 500), 1)
+
+ // @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
+ const delBurdenCoverageIndex = COVERAGE_INDICES[datasetId]
+ const delBurdenCoverage = await fetchDelBurdenCoverage(esClient, {
+ index: delBurdenCoverageIndex,
+ contig: gene.chrom,
+ regions: mergedExons,
+ bucketSize,
+ })
+
+ return delBurdenCoverage
+}
+
+export const fetchDelBurdenCoverageForGene = _fetchDelBurdenCoverageForGene
+
+export const _fetchDupBurdenCoverageForGene = async (esClient: any, datasetId: any, gene: any) => {
+ assertDatasetAndReferenceGenomeMatch(datasetId, gene.reference_genome)
+
+ if (!datasetId.startsWith('gnomad_cnv')) {
+ throw new UserVisibleError('Duplication burden track coverage is not available for non-CNVs')
+ }
+
+ const paddedExons = extendRegions(75, gene.exons)
+
+ const mergedExons = mergeOverlappingRegions(
+ paddedExons.sort((a: any, b: any) => a.start - b.start)
+ )
+
+ const totalIntervalSize = totalRegionSize(mergedExons)
+ const bucketSize = Math.max(Math.floor(totalIntervalSize / 500), 1)
+
+ // @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
+ const dupBurdenCoverageIndex = COVERAGE_INDICES[datasetId]
+ const dupBurdenCoverage = await fetchDupBurdenCoverage(esClient, {
+ index: dupBurdenCoverageIndex,
+ regions: mergedExons,
+ bucketSize,
+ })
+
+ return dupBurdenCoverage
+}
+
+export const fetchDupBurdenCoverageForGene = _fetchDupBurdenCoverageForGene