From b3830a6ac48ad95f7866b69a7dadb87d7a83347d Mon Sep 17 00:00:00 2001 From: Riley Grant Date: Tue, 7 May 2024 17:30:18 -0500 Subject: [PATCH] fix(frontend): always prefer joint freq data when merging --- .../mergeExomeAndGenomeData.spec.ts | 328 +++++++++++++++++- .../VariantList/mergeExomeAndGenomeData.ts | 28 +- browser/src/VariantPage/VariantPage.tsx | 1 + 3 files changed, 350 insertions(+), 7 deletions(-) diff --git a/browser/src/VariantList/mergeExomeAndGenomeData.spec.ts b/browser/src/VariantList/mergeExomeAndGenomeData.spec.ts index 7bef38bd1..5bb03ae12 100644 --- a/browser/src/VariantList/mergeExomeAndGenomeData.spec.ts +++ b/browser/src/VariantList/mergeExomeAndGenomeData.spec.ts @@ -3,7 +3,10 @@ import { describe, it, expect } from '@jest/globals' import { populationFactory, variantFactory } from '../__factories__/Variant' import { Population } from '../VariantPage/VariantPage' -import { mergeExomeAndGenomePopulationData } from './mergeExomeAndGenomeData' +import { + mergeExomeAndGenomePopulationData, + mergeExomeAndGenomeData, +} from './mergeExomeAndGenomeData' import { PopulationId } from '@gnomad/dataset-metadata/gnomadPopulations' type AncestryGroupShorthand = { @@ -144,3 +147,326 @@ describe('mergeExomeAndGenomePopulationData', () => { expect(result).toStrictEqual(expected) }) }) + +describe('mergeExomeAndGenomeData', () => { + it('returns expected values with just exome data', () => { + const exomeGeneticAncestryGroupObjects = createAncestryGroupObjects([ + { id: 'afr', value: 1 }, + { id: 'remaining', value: 2 }, + { id: 'eur', value: 4 }, + ]) + const testExomeOnlyVariant = variantFactory.build({ + variant_id: 'test_variant', + exome: { + ac: 1, + ac_hemi: 2, + ac_hom: 3, + an: 4, + af: 5, + faf95: undefined, + filters: ['RF'], + populations: exomeGeneticAncestryGroupObjects, + }, + }) + + const result = mergeExomeAndGenomeData([testExomeOnlyVariant]) + + const expected = [ + { + ...testExomeOnlyVariant, + ac: 1, + ac_hemi: 2, + ac_hom: 3, + an: 4, + af: 5, + allele_freq: 5, + faf95: undefined, + filters: ['RF'], + populations: exomeGeneticAncestryGroupObjects, + }, + ] + + expect(result).toStrictEqual(expected) + }) + it('returns expected values with just genome data', () => { + const genomeGeneticAncestryGroupObjects = createAncestryGroupObjects([ + { id: 'afr', value: 8 }, + { id: 'remaining', value: 16 }, + { id: 'eur', value: 32 }, + { id: 'mid', value: 64 }, + ]) + const testGenomeOnlyVariant = variantFactory.build({ + variant_id: 'test_variant', + genome: { + ac: 2, + ac_hemi: 3, + ac_hom: 4, + an: 5, + af: 6, + faf95: undefined, + filters: ['AC0'], + populations: genomeGeneticAncestryGroupObjects, + }, + }) + + const result = mergeExomeAndGenomeData([testGenomeOnlyVariant]) + + const expected = [ + { + ...testGenomeOnlyVariant, + ac: 2, + ac_hemi: 3, + ac_hom: 4, + an: 5, + af: 6, + allele_freq: 6, + faf95: undefined, + filters: ['AC0'], + populations: genomeGeneticAncestryGroupObjects, + }, + ] + + expect(result).toStrictEqual(expected) + }) + + it('returns expected values with exome and genome data', () => { + const exomeGeneticAncestryGroupObjects = createAncestryGroupObjects([ + { id: 'afr', value: 1 }, + { id: 'remaining', value: 2 }, + { id: 'eur', value: 4 }, + ]) + + const genomeGeneticAncestryGroupObjects = createAncestryGroupObjects([ + { id: 'afr', value: 8 }, + { id: 'remaining', value: 16 }, + { id: 'eur', value: 32 }, + { id: 'mid', value: 64 }, + ]) + + const testExomeAndGenomeVariant = variantFactory.build({ + variant_id: 'test_variant', + exome: { + ac: 1, + ac_hemi: 2, + ac_hom: 3, + an: 4, + faf95: undefined, + filters: ['RF'], + populations: exomeGeneticAncestryGroupObjects, + }, + genome: { + ac: 2, + ac_hemi: 3, + ac_hom: 4, + an: 6, + faf95: undefined, + filters: ['AC0'], + populations: genomeGeneticAncestryGroupObjects, + }, + }) + + const result = mergeExomeAndGenomeData([testExomeAndGenomeVariant]) + + const expected = [ + { + ...testExomeAndGenomeVariant, + ac: 3, + ac_hemi: 5, + ac_hom: 7, + an: 10, + af: 0.3, + allele_freq: 0.3, + filters: ['RF', 'AC0'], + populations: [ + { ac: 9, ac_hemi: 11, ac_hom: 13, an: 90, id: 'afr' }, + { ac: 18, ac_hemi: 20, ac_hom: 22, an: 180, id: 'remaining' }, + { ac: 36, ac_hemi: 38, ac_hom: 40, an: 360, id: 'eur' }, + { ac: 64, ac_hemi: 65, ac_hom: 66, an: 640, id: 'mid' }, + ], + }, + ] + + expect(result).toStrictEqual(expected) + }) + it('returns expected values with exome and joint data', () => { + const exomeGeneticAncestryGroupObjects = createAncestryGroupObjects([ + { id: 'afr', value: 1 }, + { id: 'remaining', value: 2 }, + { id: 'eur', value: 4 }, + ]) + const jointGeneticAncestryGroupObjects = createAncestryGroupObjects([ + { id: 'afr', value: 8 }, + { id: 'remaining', value: 16 }, + { id: 'eur', value: 32 }, + { id: 'mid', value: 64 }, + ]) + const testExomeAndJointVariant = variantFactory.build({ + variant_id: 'test_variant', + exome: { + ac: 1, + ac_hemi: 2, + ac_hom: 3, + an: 4, + af: 5, + faf95: undefined, + filters: ['RF'], + populations: exomeGeneticAncestryGroupObjects, + }, + joint: { + ac: 10, + hemizygote_count: 20, + homozygote_count: 30, + an: 40, + faf95: undefined, + filters: ['RF'], + populations: jointGeneticAncestryGroupObjects, + }, + }) + + const result = mergeExomeAndGenomeData([testExomeAndJointVariant]) + + const expected = [ + { + ...testExomeAndJointVariant, + ac: 10, + hemizygote_count: 20, + homozygote_count: 30, + an: 40, + allele_freq: 0.25, + faf95: undefined, + filters: ['RF'], + populations: jointGeneticAncestryGroupObjects, + }, + ] + + expect(result).toStrictEqual(expected) + }) + it('returns expected values with genome and joint data', () => { + const genomeGeneticAncestryGroupObjects = createAncestryGroupObjects([ + { id: 'afr', value: 8 }, + { id: 'remaining', value: 16 }, + { id: 'eur', value: 32 }, + { id: 'mid', value: 64 }, + ]) + const jointGeneticAncestryGroupObjects = createAncestryGroupObjects([ + { id: 'afr', value: 1 }, + { id: 'remaining', value: 2 }, + { id: 'eur', value: 4 }, + ]) + const testGenomeAndJointVariant = variantFactory.build({ + variant_id: 'test_variant', + genome: { + ac: 1, + ac_hemi: 2, + ac_hom: 3, + an: 4, + af: 5, + faf95: undefined, + filters: ['RF'], + populations: genomeGeneticAncestryGroupObjects, + }, + joint: { + ac: 10, + hemizygote_count: 20, + homozygote_count: 30, + an: 40, + faf95: undefined, + filters: ['RF'], + populations: jointGeneticAncestryGroupObjects, + }, + }) + + const result = mergeExomeAndGenomeData([testGenomeAndJointVariant]) + + const expected = [ + { + ...testGenomeAndJointVariant, + ac: 10, + hemizygote_count: 20, + homozygote_count: 30, + an: 40, + allele_freq: 0.25, + faf95: undefined, + filters: ['RF'], + populations: jointGeneticAncestryGroupObjects, + }, + ] + + expect(result).toStrictEqual(expected) + }) + it('returns expected values with exome, genome, and joint data', () => { + const exomeGeneticAncestryGroupObjects = createAncestryGroupObjects([ + { id: 'afr', value: 1 }, + { id: 'remaining', value: 2 }, + { id: 'eur', value: 4 }, + ]) + const genomeGeneticAncestryGroupObjects = createAncestryGroupObjects([ + { id: 'afr', value: 8 }, + { id: 'remaining', value: 16 }, + { id: 'eur', value: 32 }, + { id: 'mid', value: 64 }, + ]) + const jointGeneticAncestryGroupObjects = createAncestryGroupObjects([ + { id: 'afr', value: 10 }, + { id: 'remaining', value: 20 }, + { id: 'eur', value: 40 }, + { id: 'mid', value: 80 }, + { id: 'sas', value: 160 }, + ]) + const testExomeGenomeAndJointVariant = variantFactory.build({ + variant_id: 'test_variant', + exome: { + ac: 1, + ac_hemi: 2, + ac_hom: 3, + an: 4, + af: 5, + faf95: undefined, + filters: ['RF'], + populations: exomeGeneticAncestryGroupObjects, + }, + genome: { + ac: 2, + ac_hemi: 4, + ac_hom: 5, + an: 6, + af: 5, + faf95: undefined, + filters: ['AC0'], + populations: genomeGeneticAncestryGroupObjects, + }, + joint: { + ac: 10, + hemizygote_count: 20, + homozygote_count: 30, + an: 40, + faf95: undefined, + filters: ['discrepant_frequencies'], + populations: jointGeneticAncestryGroupObjects, + }, + }) + + const result = mergeExomeAndGenomeData([testExomeGenomeAndJointVariant]) + + const expected = [ + { + ...testExomeGenomeAndJointVariant, + ac: 10, + ac_hemi: 20, + ac_hom: 30, + an: 40, + af: 0.25, + allele_freq: 0.25, + filters: ['RF', 'AC0', 'discrepant_frequencies'], + populations: [ + { ac: 9, ac_hemi: 11, ac_hom: 13, an: 90, id: 'afr' }, + { ac: 18, ac_hemi: 20, ac_hom: 22, an: 180, id: 'remaining' }, + { ac: 36, ac_hemi: 38, ac_hom: 40, an: 360, id: 'eur' }, + { ac: 64, ac_hemi: 65, ac_hom: 66, an: 640, id: 'mid' }, + ], + }, + ] + + expect(result).toStrictEqual(expected) + }) +}) diff --git a/browser/src/VariantList/mergeExomeAndGenomeData.ts b/browser/src/VariantList/mergeExomeAndGenomeData.ts index de11f2aad..b793c9c40 100644 --- a/browser/src/VariantList/mergeExomeAndGenomeData.ts +++ b/browser/src/VariantList/mergeExomeAndGenomeData.ts @@ -43,21 +43,37 @@ export const mergeExomeAndGenomePopulationData = ( return Object.values(populations) } -const mergeExomeAndGenomeData = (variants: any) => +export const mergeExomeAndGenomeData = (variants: any) => variants.map((variant: any) => { - const { exome, genome } = variant + const { exome, genome, joint } = variant if (!exome) { + if (!joint) { + return { + ...variant, + ...variant.genome, + allele_freq: variant.genome.af, // hack for variant track which expects allele_freq field + } + } return { ...variant, - ...variant.genome, - allele_freq: variant.genome.af, // hack for variant track which expects allele_freq field + ...variant.joint, + filters: variant.genome.filters, + allele_freq: variant.joint.ac / variant.joint.an, } } if (!genome) { + if (!joint) { + return { + ...variant, + ...variant.exome, + allele_freq: variant.exome.af, // hack for variant track which expects allele_freq field + } + } return { ...variant, - ...variant.exome, - allele_freq: variant.exome.af, // hack for variant track which expects allele_freq field + ...variant.joint, + filters: variant.exome.filters, + allele_freq: variant.joint.ac / variant.joint.an, // hack for variant track which expects allele_freq field } } diff --git a/browser/src/VariantPage/VariantPage.tsx b/browser/src/VariantPage/VariantPage.tsx index 16fe0f147..542629185 100644 --- a/browser/src/VariantPage/VariantPage.tsx +++ b/browser/src/VariantPage/VariantPage.tsx @@ -202,6 +202,7 @@ export type SequencingType = BaseSequencingType & { local_ancestry_populations: LocalAncestryPopulation[] ac_hom: number ac_hemi: number + af?: number } export type JointSequencingType = BaseSequencingType & {