Skip to content

Commit

Permalink
refactor(browser): update merge ancestry to prefer joint data
Browse files Browse the repository at this point in the history
  • Loading branch information
rileyhgrant committed May 8, 2024
1 parent 4d8c6f9 commit 9998780
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 60 deletions.
83 changes: 75 additions & 8 deletions browser/src/VariantList/mergeExomeAndGenomeData.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import { populationFactory, variantFactory } from '../__factories__/Variant'
import { Population } from '../VariantPage/VariantPage'

import {
mergeExomeAndGenomePopulationData,
mergeExomeGenomeAndJointPopulationData,
mergeExomeAndGenomeData,
} from './mergeExomeAndGenomeData'
import { PopulationId } from '@gnomad/dataset-metadata/gnomadPopulations'

type AncestryGroupShorthand = {
id: PopulationId
id: string
value: number
}

Expand All @@ -37,7 +36,7 @@ const createAncestryGroupObjects = (
return geneticAncestryGroupObjects
}

describe('mergeExomeAndGenomePopulationData', () => {
describe('mergeExomeGenomeAndJointPopulationData', () => {
it('returns expected values when exomes and genomes have the same populations', () => {
const geneticAncestryGroupObjects = createAncestryGroupObjects(
[
Expand All @@ -54,7 +53,10 @@ describe('mergeExomeAndGenomePopulationData', () => {
genome: { populations: geneticAncestryGroupObjects },
})

const result = mergeExomeAndGenomePopulationData(testVariant.exome!, testVariant.genome!)
const result = mergeExomeGenomeAndJointPopulationData({
exomePopulations: testVariant.exome!.populations,
genomePopulations: testVariant.genome!.populations,
})

const expected = [
{ ac: 2, ac_hemi: 4, ac_hom: 6, an: 20, id: 'afr' },
Expand Down Expand Up @@ -91,7 +93,10 @@ describe('mergeExomeAndGenomePopulationData', () => {
genome: { populations: genomeGeneticAncestryGroupObjects },
})

const result = mergeExomeAndGenomePopulationData(testVariant.exome!, testVariant.genome!)
const result = mergeExomeGenomeAndJointPopulationData({
exomePopulations: testVariant.exome!.populations,
genomePopulations: testVariant.genome!.populations,
})

const expected = [
{ ac: 9, ac_hemi: 11, ac_hom: 13, an: 90, id: 'afr' },
Expand Down Expand Up @@ -129,7 +134,10 @@ describe('mergeExomeAndGenomePopulationData', () => {
genome: { populations: genomeGeneticAncestryGroupObjects },
})

const result = mergeExomeAndGenomePopulationData(testVariant.exome!, testVariant.genome!)
const result = mergeExomeGenomeAndJointPopulationData({
exomePopulations: testVariant.exome!.populations,
genomePopulations: testVariant.genome!.populations,
})

const expected = [
{ ac: 17, ac_hemi: 19, ac_hom: 21, an: 170, id: 'afr' },
Expand Down Expand Up @@ -166,7 +174,10 @@ describe('mergeExomeAndGenomePopulationData', () => {
genome: { populations: genomeGeneticAncestryGroupObjects },
})

const result = mergeExomeAndGenomePopulationData(testVariant.exome!, testVariant.genome!)
const result = mergeExomeGenomeAndJointPopulationData({
exomePopulations: testVariant.exome!.populations,
genomePopulations: testVariant.genome!.populations,
})

const expected = [
{ ac: 33, ac_hemi: 35, ac_hom: 37, an: 330, id: 'eur' },
Expand All @@ -176,6 +187,62 @@ describe('mergeExomeAndGenomePopulationData', () => {

expect(result).toStrictEqual(expected)
})

it('returns expected values when joint values are present', () => {
const exomeGeneticAncestryGroupObjects = createAncestryGroupObjects(
[
{ id: 'eur', value: 1 },
{ id: 'afr', value: 2 },
{ id: 'remaining', value: 4 },
],
false
)

const genomeGeneticAncestryGroupObjects = createAncestryGroupObjects(
[
{ id: 'afr', value: 8 },
{ id: 'remaining', value: 16 },
{ id: 'eur', value: 32 },
],
false
)

const jointGeneticAncestryGroupObjects = [
{ ac: 16, hemizygote_count: 17, homozygote_count: 18, an: 160, id: 'afr' },
{ ac: 16, hemizygote_count: 17, homozygote_count: 18, an: 160, id: 'afr_XX' },
{ ac: 16, hemizygote_count: 17, homozygote_count: 18, an: 160, id: 'afr_YY' },
{ ac: 32, hemizygote_count: 33, homozygote_count: 34, an: 320, id: 'remaining' },
{ ac: 64, hemizygote_count: 65, homozygote_count: 66, an: 640, id: 'eur' },
{ ac: 128, hemizygote_count: 129, homozygote_count: 130, an: 1280, id: 'mid' },
]

const testVariant = variantFactory.build({
variant_id: 'test_variant',
exome: { populations: exomeGeneticAncestryGroupObjects },
genome: { populations: genomeGeneticAncestryGroupObjects },
joint: { populations: jointGeneticAncestryGroupObjects as Population[] },
})

const result = mergeExomeGenomeAndJointPopulationData({
exomePopulations: testVariant.exome!.populations,
genomePopulations: testVariant.genome!.populations,
jointPopulations: testVariant.joint!.populations,
})

const expectedJointGeneticAncestryGroupObjects = createAncestryGroupObjects(
[
{ id: 'afr', value: 16 },
{ id: 'afr_XX', value: 16 },
{ id: 'afr_YY', value: 16 },
{ id: 'remaining', value: 32 },
{ id: 'eur', value: 64 },
{ id: 'mid', value: 128 },
],
true
)

expect(result).toStrictEqual(expectedJointGeneticAncestryGroupObjects)
})
})

describe('mergeExomeAndGenomeData', () => {
Expand Down
40 changes: 29 additions & 11 deletions browser/src/VariantList/mergeExomeAndGenomeData.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,34 @@
import { Filter } from '../QCFilter'
import { Population, SequencingType, Variant } from '../VariantPage/VariantPage'
import { Population, Variant } from '../VariantPage/VariantPage'

// safe math on possibly null values
const add = (n1: any, n2: any) => (n1 || 0) + (n2 || 0)

export const mergeExomeAndGenomePopulationData = (
exome: SequencingType,
genome: SequencingType
) => {
export const mergeExomeGenomeAndJointPopulationData = ({
exomePopulations = [],
genomePopulations = [],
jointPopulations = null,
}: {
exomePopulations: Population[]
genomePopulations: Population[]
jointPopulations?: Population[] | null
}) => {
if (jointPopulations) {
return (
jointPopulations
// filter to remove duplicate XX an XY keys from joint populations array
.filter((item, index, self) => index === self.findIndex((t) => t.id === item.id))
.map((jointPopulation) => ({
...jointPopulation,
ac_hemi: jointPopulation.hemizygote_count,
ac_hom: jointPopulation.homozygote_count,
}))
)
}

const populations: { [key: string]: Population } = {}

exome.populations.forEach((exomePopulation: Population) => {
exomePopulations.forEach((exomePopulation: Population) => {
populations[exomePopulation.id] = {
id: exomePopulation.id,
ac: exomePopulation.ac,
Expand All @@ -20,7 +38,7 @@ export const mergeExomeAndGenomePopulationData = (
}
})

genome.populations.forEach((genomePopulation: Population) => {
genomePopulations.forEach((genomePopulation: Population) => {
if (genomePopulation.id in populations) {
const entry = populations[genomePopulation.id]
populations[genomePopulation.id] = {
Expand Down Expand Up @@ -108,10 +126,10 @@ export const mergeExomeAndGenomeData = (variants: Variant[]): MergedVariant[] =>
const genomeFilters: Filter[] = genomeOrNone.filters
const combinedFilters = exomeFilters.concat(genomeFilters)

const combinedPopulations = mergeExomeAndGenomePopulationData(
exomeOrNone as SequencingType,
genomeOrNone as SequencingType
)
const combinedPopulations = mergeExomeGenomeAndJointPopulationData({
exomePopulations: exomeOrNone.populations,
genomePopulations: genomeOrNone.populations,
})

return {
...variant,
Expand Down
49 changes: 9 additions & 40 deletions browser/src/VariantPage/GnomadPopulationsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { GNOMAD_POPULATION_NAMES } from '@gnomad/dataset-metadata/gnomadPopulati
import { DatasetId, hasV2Genome } from '@gnomad/dataset-metadata/metadata'
import { PopulationsTable } from './PopulationsTable'
import { Population } from './VariantPage'
import { mergeExomeGenomeAndJointPopulationData } from '../VariantList/mergeExomeAndGenomeData'

const ControlSection = styled.div`
margin-top: 1em;
Expand All @@ -16,38 +17,6 @@ const ControlSection = styled.div`
}
`

/**
* Merge frequency information for multiple populations with the same ID.
* This is used to add exome and genome population frequencies.
*
* @param {Object[]} populations Array of populations.
*/
const mergePopulations = (populations: any) => {
const indices = {}
const merged = []

for (let i = 0; i < populations.length; i += 1) {
const pop = populations[i]

// @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
const popIndex = indices[pop.id]
if (popIndex === undefined) {
merged.push({ ...pop })
// @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
indices[pop.id] = merged.length - 1
} else {
merged[popIndex].ac += pop.ac
merged[popIndex].an += pop.an
if (pop.ac_hemi !== null) {
merged[popIndex].ac_hemi += pop.ac_hemi
}
merged[popIndex].ac_hom += pop.ac_hom
}
}

return merged
}

const addPopulationNames = (populations: any) => {
return populations.map((pop: any) => {
let name
Expand Down Expand Up @@ -137,15 +106,15 @@ export class GnomadPopulationsTable extends Component<
this.props
const { includeExomes, includeGenomes } = this.state

let includedPopulations: any = []
if (includeExomes) {
includedPopulations = includedPopulations.concat(exomePopulations)
}
if (includeGenomes) {
includedPopulations = includedPopulations.concat(genomePopulations)
}
const mergedPopulations = mergeExomeGenomeAndJointPopulationData({
exomePopulations: includeExomes ? exomePopulations : [],
genomePopulations: includeGenomes ? genomePopulations : [],
})

const mergedPopulationsWithNames = addPopulationNames(mergedPopulations)
const mergedNestedPopulationsWithNames = nestPopulations(mergedPopulationsWithNames)
let populations = mergedNestedPopulationsWithNames

let populations = nestPopulations(addPopulationNames(mergePopulations(includedPopulations)))
if (hasV2Genome(datasetId) && includeGenomes) {
populations = populations.map((pop) => {
if (pop.id === 'eas') {
Expand Down
2 changes: 1 addition & 1 deletion browser/src/VariantPage/VariantPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ export type Population = {
ac_hemi?: number | null
ac_hom?: number
hemizygote_count?: number | null
homozygote_count?: number | null
homozygote_count?: number
}

export type LocalAncestryPopulation = {
Expand Down

0 comments on commit 9998780

Please sign in to comment.