diff --git a/graphql-api/src/graphql/resolvers/va.spec.ts b/graphql-api/src/graphql/resolvers/va.spec.ts index 1df264fa4..b0eb11bcb 100644 --- a/graphql-api/src/graphql/resolvers/va.spec.ts +++ b/graphql-api/src/graphql/resolvers/va.spec.ts @@ -59,6 +59,13 @@ describe('resolveVACohortAlleleFrequency', () => { homozygote_count: 3, faf95: { popmax: 0.123, popmax_population: 'afr' }, ancestry_groups: [], + filters: ['AC0'], + flags: ['monoallelic'], + quality_metrics: { + allele_balance: { + alt: { bin_freq: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] }, + }, + }, } const genomeEsDocument = { @@ -67,7 +74,19 @@ describe('resolveVACohortAlleleFrequency', () => { hemizygote_count: 4, homozygote_count: 5, faf95: { popmax: 0.234, popmax_population: 'eas' }, + filters: ['AC0'], ancestry_groups: [], + flags: ['monoallelic'], + quality_metrics: { + allele_balance: { + alt: { + bin_freq: [ + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, + ], + }, + }, + }, } const variantESDocument = { @@ -76,6 +95,8 @@ describe('resolveVACohortAlleleFrequency', () => { exome: exomeEsDocument, genome: genomeEsDocument, joint: { fafmax: { faf95_max: 0.234, faf95_max_gen_anc: 'amr' } }, + coverage: { exome: { mean: 0.345, over_20: 0.456 }, genome: { mean: 0.111, over_20: 0.222 } }, + flags: ['lcr', 'lc_lof', 'lof_flag'], } test('parses a single CohortAlleleFrequency exome correctly', async () => { @@ -103,6 +124,16 @@ describe('resolveVACohortAlleleFrequency', () => { hemizygotes: 2, }, subcohortFrequency: [], + qualityMeasures: { + meanDepth: 0.345, + fractionCoverage20x: 0.456, + qcFilters: ['AC0'], + monoallelic: true, + lowComplexityRegion: true, + lowConfidenceLossOfFunctionError: true, + lossOfFunctionWarning: true, + heterozygousSkewedAlleleCount: 37, + }, }, ] @@ -134,6 +165,16 @@ describe('resolveVACohortAlleleFrequency', () => { hemizygotes: 4, }, subcohortFrequency: [], + qualityMeasures: { + meanDepth: 0.111, + fractionCoverage20x: 0.222, + monoallelic: true, + qcFilters: ['AC0'], + lowComplexityRegion: true, + lowConfidenceLossOfFunctionError: true, + lossOfFunctionWarning: true, + heterozygousSkewedAlleleCount: 237, + }, }, ] diff --git a/graphql-api/src/graphql/resolvers/va.ts b/graphql-api/src/graphql/resolvers/va.ts index 790c3d33e..0e8401d97 100644 --- a/graphql-api/src/graphql/resolvers/va.ts +++ b/graphql-api/src/graphql/resolvers/va.ts @@ -93,6 +93,17 @@ type AncillaryResults = { hemizygotes: number | null } +type QualityMeasures = { + meanDepth: number | null + fractionCoverage20x: number | null + qcFilters: string[] | null + monoallelic: boolean | null + lowComplexityRegion: boolean | null + lowConfidenceLossOfFunctionError: boolean | null + lossOfFunctionWarning: boolean | null + heterozygousSkewedAlleleCount: number | null +} + export type CohortAlleleFrequency = { id: string type: string @@ -104,6 +115,7 @@ export type CohortAlleleFrequency = { alleleFrequency: number cohort: Cohort ancillaryResults: AncillaryResults | null + qualityMeasures: QualityMeasures | null subcohortFrequency: CohortAlleleFrequency[] } @@ -187,6 +199,7 @@ type Subset = { homozygote_count: number grpMax?: GrpMaxFAF95 jointGrpMax?: GrpMaxFAF95 + qualityMeasures: QualityMeasures } const GNOMAD_V4_DERIVATION = { @@ -279,6 +292,7 @@ const resolveVACohortAlleleFrequency = ( alleleFrequency: subset.ac / subset.an, cohort, ancillaryResults, + qualityMeasures: subset.qualityMeasures, } } @@ -367,6 +381,25 @@ const addSubcohorts = ( return Object.values(subcohortMap) } +type ESFrequencies = { + quality_metrics: { + allele_balance: { + alt?: { + bin_freq: number[] + } + } + } +} + +const calculateHeterozygousSkewedAlleleCount = (frequencies: ESFrequencies): number | null => { + const { alt } = frequencies.quality_metrics.allele_balance + if (!alt) { + return null + } + + return alt.bin_freq[18] + alt.bin_freq[19] +} + const resolveVACohortAlleleFrequencies = async ( obj: any, args: any, @@ -382,6 +415,18 @@ const resolveVACohortAlleleFrequencies = async ( if (!frequencies) { return null } + const coverage = obj.coverage[frequencyField] + + const qualityMeasures = { + meanDepth: coverage && coverage.mean ? coverage.mean : null, + fractionCoverage20x: coverage && coverage.over_20 ? coverage.over_20 : null, + qcFilters: frequencies.filters, + monoallelic: frequencies.flags.includes('monoallelic'), + lowComplexityRegion: obj.flags.includes('lcr'), + lowConfidenceLossOfFunctionError: obj.flags.includes('lc_lof'), + lossOfFunctionWarning: obj.flags.includes('lof_flag'), + heterozygousSkewedAlleleCount: calculateHeterozygousSkewedAlleleCount(frequencies), + } const fullSet: Subset = { ac: frequencies.ac, @@ -401,6 +446,7 @@ const resolveVACohortAlleleFrequencies = async ( confidenceInterval: 0.95, } : undefined, + qualityMeasures, } const subsets = [fullSet, ...(frequencies.ancestry_groups as Subset[])] const cohortsWithoutSubcohorts = subsets.map((subset) => diff --git a/graphql-api/src/graphql/types/va.graphql b/graphql-api/src/graphql/types/va.graphql index 03017146d..9c1656746 100644 --- a/graphql-api/src/graphql/types/va.graphql +++ b/graphql-api/src/graphql/types/va.graphql @@ -96,7 +96,6 @@ type VAQualityMeasures { lowComplexityRegion: Boolean lowConfidenceLossOfFunctionError: Boolean lossOfFunctionWarning: Boolean - noncodingTranscriptError: Boolean heterozygousSkewedAlleleCount: Int } @@ -118,6 +117,8 @@ type VACohortAlleleFrequencyData { cohort: VACohort! "Ancillary results that may be associated with the CohortAlleleFrequency, providing additional context or information." ancillaryResults: VAAncillaryResults + "Metrics of quality of, or confidence in, the CohortAlleleFrequency." + qualityMeasures: VAQualityMeasures """ A list of CohortAlleleFrequency objects describing subcohorts of the cohort currently being described. This creates a recursive relationship and subcohorts can be further subdivided into more subcohorts.