From 488c6e4ef392a3362038be16b849dd9c30d844c7 Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Mon, 10 Apr 2023 10:40:24 -0400 Subject: [PATCH 01/24] Add pipeline to build v3 SVs Most of the key transformations in this new pipeline are taken from the v2 SV pipeline in `gnomad_sv_v2.py`. --- .../data_pipeline/datasets/gnomad_sv_v3.py | 295 ++++++++++++++++++ .../data_pipeline/pipelines/gnomad_sv_v3.py | 82 +++++ 2 files changed, 377 insertions(+) create mode 100644 data-pipeline/src/data_pipeline/datasets/gnomad_sv_v3.py create mode 100644 data-pipeline/src/data_pipeline/pipelines/gnomad_sv_v3.py diff --git a/data-pipeline/src/data_pipeline/datasets/gnomad_sv_v3.py b/data-pipeline/src/data_pipeline/datasets/gnomad_sv_v3.py new file mode 100644 index 000000000..f8655f5b4 --- /dev/null +++ b/data-pipeline/src/data_pipeline/datasets/gnomad_sv_v3.py @@ -0,0 +1,295 @@ +import itertools + +import hail as hl + + +def x_position(chrom, position): + contig_number = ( + hl.case().when(chrom == "X", 23).when(chrom == "Y", 24).when(chrom[0] == "M", 25).default(hl.int(chrom)) + ) + return hl.int64(contig_number) * 1_000_000_000 + position + + +TOP_LEVEL_INFO_FIELDS = [ + "ALGORITHMS", + "BOTHSIDES_SUPPORT", + "CPX_INTERVALS", + "CPX_TYPE", + "EVIDENCE", + "PESR_GT_OVERDISPERSION", + "SOURCE", + "STRANDS", + "UNRESOLVED_TYPE", +] + +RANKED_CONSEQUENCES = [ + "LOF", + "INTRAGENIC_EXON_DUP", + "PARTIAL_EXON_DUP", + "COPY_GAIN", + "TSS_DUP", + "MSV_EXON_OVERLAP", + "DUP_PARTIAL", + "BREAKEND_EXONIC", + "UTR", + "PROMOTER", + "INTRONIC", + "INV_SPAN", + "INTERGENIC", + "NEAREST_TSS", +] + +FREQ_FIELDS = [ + "AC", + "AN", + "AF", + "N_HOMALT", +] + +POPULATIONS = ["afr", "ami", "amr", "asj", "eas", "fin", "mid", "nfe", "oth", "sas"] + +DIVISIONS = list( + itertools.chain.from_iterable( + [(pop, pop), (f"{pop}_XX", f"{pop}_FEMALE"), (f"{pop}_XY", f"{pop}_MALE")] for pop in POPULATIONS + ) +) + [("XX", "FEMALE"), ("XY", "MALE")] + +# For MCNVs, sum AC/AF for all alt alleles except CN=2 +def sum_mcnv_ac_or_af(alts, values): + return hl.bind( + lambda cn2_index: hl.bind( + lambda values_to_sum: values_to_sum.fold(lambda acc, n: acc + n, 0), + hl.if_else(hl.is_defined(cn2_index), values[0:cn2_index].extend(values[cn2_index + 1 :]), values), + ), + hl.zip_with_index(alts).find(lambda t: t[1] == "")[0], + ) + + +def import_svs_from_vcfs(vcf_paths, preserve_par): + ds = hl.import_vcf(vcf_paths, force_bgz=True, min_partitions=32, reference_genome="GRCh38").rows() + ds = ds.annotate(**{field.lower(): ds.info[field] for field in TOP_LEVEL_INFO_FIELDS}) + + if preserve_par: + ds = ds.annotate(par=ds.info.PAR) + else: + ds = ds.annotate(par=hl.missing(hl.tbool)) + + ds = ds.annotate( + variant_id=ds.rsid.replace("^gnomAD-SV_v3_", ""), + reference_genome="GRCh38", + # Start + chrom=ds.locus.contig.replace("chr", ""), + pos=ds.locus.position, + # End + end=ds.info.END, + # Start 2 + chrom2=ds.info.CHR2.replace("chr", ""), + pos2=ds.info.POS2, + # End 2 + end2=ds.info.END2, + # Other + length=ds.info.SVLEN, + type=ds.info.SVTYPE, + alts=ds.alleles[1:], + ) + + ds = ds.annotate( + xpos=x_position(ds.chrom, ds.pos), + xend=x_position(ds.chrom, ds.end), + xpos2=x_position(ds.chrom2, ds.pos2), + xend2=x_position(ds.chrom2, ds.end2), + ) + + # MULTIALLELIC should not be used as a quality filter in the browser + ds = ds.annotate(filters=ds.filters.difference(hl.set(["MULTIALLELIC"]))) + + # Group gene lists for all consequences in one field + ds = ds.annotate( + consequences=hl.array( + [ + hl.struct( + consequence=csq.lower(), + genes=hl.or_else(ds.info[f"PREDICTED_{csq}"], hl.empty_array(hl.tstr)), + ) + for csq in RANKED_CONSEQUENCES + if csq not in ("INTERGENIC", "NEAREST_TSS") + ] + ).filter(lambda csq: hl.len(csq.genes) > 0) + ) + ds = ds.annotate(intergenic=ds.info.PREDICTED_INTERGENIC) + + ds = ds.annotate( + major_consequence=hl.rbind( + ds.consequences.find(lambda csq: hl.len(csq.genes) > 0), + lambda csq: hl.or_else(csq.consequence, hl.or_missing(ds.intergenic, "intergenic")), + ) + ) + + # Collect set of all genes for which a variant has a consequence + ds = ds.annotate(genes=hl.set(ds.consequences.flatmap(lambda c: c.genes))) + + # Group per-population frequency values + ds = ds.annotate( + freq=hl.struct( + **{field.lower(): ds.info[field] for field in FREQ_FIELDS}, + populations=[ + hl.struct(id=pop_id, **{field.lower(): ds.info[f"{pop_key}_{field}"] for field in FREQ_FIELDS}) + for (pop_id, pop_key) in DIVISIONS + ], + ) + ) + + # For MCNVs, store per-copy number allele counts + ds = ds.annotate( + freq=ds.freq.annotate( + copy_numbers=hl.or_missing( + ds.type == "MCNV", + hl.zip_with_index(ds.alts).map( + lambda pair: hl.rbind( + pair[0], + pair[1], + lambda index, alt: hl.struct( + # Extract copy number. Example, get 2 from "CN=<2>" + copy_number=hl.int(alt[4:-1]), + ac=ds.freq.ac[index], + ), + ) + ), + ) + ) + ) + + # For MCNVs, sum AC/AF for all alt alleles except CN=2 + ds = ds.annotate( + freq=ds.freq.annotate( + ac=hl.if_else(ds.type == "MCNV", sum_mcnv_ac_or_af(ds.alts, ds.freq.ac), ds.freq.ac[0]), + af=hl.if_else(ds.type == "MCNV", sum_mcnv_ac_or_af(ds.alts, ds.freq.af), ds.freq.af[0]), + populations=hl.if_else( + ds.type == "MCNV", + ds.freq.populations.map( + lambda pop: pop.annotate( + ac=sum_mcnv_ac_or_af(ds.alts, pop.ac), + af=sum_mcnv_ac_or_af(ds.alts, pop.af), + ) + ), + ds.freq.populations.map(lambda pop: pop.annotate(ac=pop.ac[0], af=pop.af[0])), + ), + ) + ) + + # Add hemizygous frequencies + ds = ds.annotate( + hemizygote_count=hl.dict( + [ + ( + pop_id, + hl.if_else( + ((ds.chrom == "X") | (ds.chrom == "Y")) & (ds.par == False), + ds.info[f"{pop_id}_MALE_N_HEMIALT"], + 0, + ), + ) + for pop_id in POPULATIONS + ] + + [(f"{pop_id}_XX", 0) for pop_id in POPULATIONS] + + [ + ( + f"{pop_id}_XY", + hl.if_else( + ((ds.chrom == "X") | (ds.chrom == "Y")) & (ds.par == False), + ds.info[f"{pop_id}_MALE_N_HEMIALT"], + 0, + ), + ) + for pop_id in POPULATIONS + ] + + [("XX", 0)] + + [ + ( + "XY", + hl.if_else(((ds.chrom == "X") | (ds.chrom == "Y")) & (ds.par == False), ds.info.MALE_N_HEMIALT, 0), + ) + ] + ) + ) + + ds = ds.annotate( + freq=ds.freq.annotate( + hemizygote_count=hl.or_missing( + ds.type != "MCNV", + hl.if_else(((ds.chrom == "X") | (ds.chrom == "Y")) & (ds.par == False), ds.info.MALE_N_HEMIALT, 0), + ), + populations=hl.if_else( + ds.type != "MCNV", + ds.freq.populations.map(lambda pop: pop.annotate(hemizygote_count=ds.hemizygote_count[pop.id])), + ds.freq.populations.map(lambda pop: pop.annotate(hemizygote_count=hl.null(hl.tint))), + ), + ) + ) + + ds = ds.drop("hemizygote_count") + + # Rename n_homalt + ds = ds.annotate( + freq=ds.freq.annotate( + homozygote_count=ds.freq.n_homalt, + populations=ds.freq.populations.map( + lambda pop: pop.annotate(homozygote_count=pop.n_homalt).drop("n_homalt") + ), + ).drop("n_homalt") + ) + + # Re-key + ds = ds.key_by("variant_id") + + ds = ds.drop("locus", "alleles", "info", "rsid") + + return ds + + +# Add uppercase ID to support case-insensitive searching +def add_variant_id_upper_case(svs_path): + ds = hl.read_table(svs_path) + ds = ds.annotate(variant_id_upper_case=ds.variant_id.upper()) + return ds + + +def annotate_with_histograms(svs_path, histograms_path): + ds = hl.read_table(svs_path) + histograms = hl.read_table(histograms_path) + + histograms = histograms.transmute( + **{ + field: hl.struct( + bin_freq=histograms[f"{field}_bin_freq"].split(r"\|").map(hl.float), + bin_edges=histograms[f"{field}_bin_edges"].split(r"\|").map(hl.float), + n_smaller=histograms[f"{field}_n_smaller"], + n_larger=histograms[f"{field}_n_larger"], + ) + for field in ["age_hist_het", "age_hist_hom", "gq_hist_alt", "gq_hist_all"] + } + ) + + histograms = histograms.transmute( + age_distribution=hl.struct( + het=histograms.age_hist_het, + hom=histograms.age_hist_hom, + ), + genotype_quality=hl.struct(all=histograms.gq_hist_all, alt=histograms.gq_hist_alt), + ) + + histograms = histograms.transmute(variant_id=histograms.rsid.replace("^gnomAD-SV_v3_", "")) + + histograms = histograms.key_by(histograms.variant_id).drop("locus", "alleles") + ds = ds.annotate(**hl.or_missing(ds.type != "MCNV", histograms[ds.variant_id])) + return ds + + +def import_all_svs_from_vcfs(autosome_vcf_paths, allosome_vcf_paths): + autosome_svs = import_svs_from_vcfs(autosome_vcf_paths, False) + autosome_svs = autosome_svs.annotate(freq=hl.struct(all=autosome_svs.freq)) + allosome_svs = import_svs_from_vcfs(allosome_vcf_paths, True) + allosome_svs = allosome_svs.annotate(freq=hl.struct(all=allosome_svs.freq)) + + svs = autosome_svs.union(allosome_svs) + return svs diff --git a/data-pipeline/src/data_pipeline/pipelines/gnomad_sv_v3.py b/data-pipeline/src/data_pipeline/pipelines/gnomad_sv_v3.py new file mode 100644 index 000000000..884af0980 --- /dev/null +++ b/data-pipeline/src/data_pipeline/pipelines/gnomad_sv_v3.py @@ -0,0 +1,82 @@ +from data_pipeline.pipeline import Pipeline, run_pipeline + +from data_pipeline.datasets.gnomad_sv_v3 import ( + import_all_svs_from_vcfs, + annotate_with_histograms, + add_variant_id_upper_case, +) + + +pipeline = Pipeline() + +# TK permanent home for these +vcf_path_template = ( + "gs://gnomadev-data-pipeline-output/pwd-2022-12-06/external_sources/gnomad_v3_SV_2/gnomAD.v3.SV.chr{id}.vcf.gz" +) + +autosome_ids = list(range(1, 23)) +allosome_ids = ["X", "Y"] + +autosome_vcf_paths = list( + map( + lambda id: vcf_path_template.format(id=id), + autosome_ids, + ) +) + +allosome_vcf_paths = list( + map( + lambda id: vcf_path_template.format(id=id), + allosome_ids, + ) +) +############################################### +# Variants +############################################### + +pipeline.add_task( + "import_all_svs_from_vcfs", + import_all_svs_from_vcfs, + "/gnomad_sv_v3/structural_variants_step_1.ht", + {}, + { + "autosome_vcf_paths": autosome_vcf_paths, + "allosome_vcf_paths": allosome_vcf_paths, + }, +) + +pipeline.add_task( + "add_histograms", + annotate_with_histograms, + "/gnomad_sv_v3/structural_variants_step_2.ht", + { + "svs_path": pipeline.get_task("import_all_svs_from_vcfs"), + "histograms_path": "gs://gnomadev-data-pipeline-output/pwd-2022-12-06/external_sources/gnomad_sv_v3.age_and_gq_hists.ht", + }, +) + +pipeline.add_task( + "add_variant_id_upper_case", + add_variant_id_upper_case, + "/gnomad_sv_v3/structural_variants_step_3.ht", + { + "svs_path": pipeline.get_task("add_histograms"), + }, +) + +############################################### +# Outputs +############################################### + +pipeline.set_outputs( + { + "structural_variants": "add_variant_id_upper_case", + } +) + +############################################### +# Run +############################################### + +if __name__ == "__main__": + run_pipeline(pipeline) From 9d5786f9626a3ca4a0993a43b6d19caec35a68b0 Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Thu, 4 May 2023 13:23:02 -0400 Subject: [PATCH 02/24] Add configuration to allow export of v3 SVs to Elasticsearch --- .../pipelines/export_to_elasticsearch.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/data-pipeline/src/data_pipeline/pipelines/export_to_elasticsearch.py b/data-pipeline/src/data_pipeline/pipelines/export_to_elasticsearch.py index 18ae890ea..b6d7e5619 100644 --- a/data-pipeline/src/data_pipeline/pipelines/export_to_elasticsearch.py +++ b/data-pipeline/src/data_pipeline/pipelines/export_to_elasticsearch.py @@ -17,6 +17,7 @@ from data_pipeline.pipelines.exac_variants import pipeline as exac_variants_pipeline from data_pipeline.pipelines.genes import pipeline as genes_pipeline from data_pipeline.pipelines.gnomad_sv_v2 import pipeline as gnomad_sv_v2_pipeline +from data_pipeline.pipelines.gnomad_sv_v3 import pipeline as gnomad_sv_v3_pipeline from data_pipeline.pipelines.gnomad_v2_coverage import pipeline as gnomad_v2_coverage_pipeline from data_pipeline.pipelines.gnomad_v2_lof_curation_results import pipeline as gnomad_v2_lof_curation_results_pipeline from data_pipeline.pipelines.gnomad_v2_variants import pipeline as gnomad_v2_variants_pipeline @@ -197,7 +198,7 @@ def add_liftover_document_id(ds): }, }, ############################################################################################################## - # gnomAD SV v2 + # gnomAD SV v2 and v3 ############################################################################################################## "gnomad_structural_variants_v2": { "get_table": lambda: hl.read_table(gnomad_sv_v2_pipeline.get_output("structural_variants").get_output_path()), @@ -209,6 +210,16 @@ def add_liftover_document_id(ds): "block_size": 1_000, }, }, + "gnomad_structural_variants_v3": { + "get_table": lambda: hl.read_table(gnomad_sv_v3_pipeline.get_output("structural_variants").get_output_path()), + "args": { + "index": "gnomad_structural_variants_v3", + "index_fields": ["variant_id", "xpos", "xend", "xpos2", "xend2", "genes", "variant_id_upper_case"], + "id_field": "variant_id_upper_case", + "num_shards": 2, + "block_size": 1_000, + }, + }, ############################################################################################################## # gnomAD v2 ############################################################################################################## From 677a3385efcf5f012e60bb8534f1f1f525a6dc8e Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Thu, 8 Jun 2023 13:41:04 -0400 Subject: [PATCH 03/24] Characterize v2 SV GraphQL queries --- .../gnomad-sv-v2-queries.ts | 2 +- .../structural-variant-queries.spec.ts | 544 ++++++++++++++++++ .../src/queries/structural-variant-queries.ts | 33 +- 3 files changed, 570 insertions(+), 9 deletions(-) create mode 100644 graphql-api/src/queries/structural-variant-queries.spec.ts diff --git a/graphql-api/src/queries/structural-variant-datasets/gnomad-sv-v2-queries.ts b/graphql-api/src/queries/structural-variant-datasets/gnomad-sv-v2-queries.ts index 8f0f69046..975c6f11e 100644 --- a/graphql-api/src/queries/structural-variant-datasets/gnomad-sv-v2-queries.ts +++ b/graphql-api/src/queries/structural-variant-datasets/gnomad-sv-v2-queries.ts @@ -7,7 +7,7 @@ const GNOMAD_STRUCTURAL_VARIANTS_V2_INDEX = 'gnomad_structural_variants_v2' // Variant query // ================================================================================================ -const fetchStructuralVariantById = async (esClient: any, variantId: any, subset: any) => { +const fetchStructuralVariantById = async (esClient: any, variantId: string, subset: string) => { const response = await esClient.search({ index: GNOMAD_STRUCTURAL_VARIANTS_V2_INDEX, type: '_doc', diff --git a/graphql-api/src/queries/structural-variant-queries.spec.ts b/graphql-api/src/queries/structural-variant-queries.spec.ts new file mode 100644 index 000000000..f47600d9b --- /dev/null +++ b/graphql-api/src/queries/structural-variant-queries.spec.ts @@ -0,0 +1,544 @@ +import { describe, expect, test } from '@jest/globals' + +import { + fetchStructuralVariantById, + fetchStructuralVariantsByGene, + fetchStructuralVariantsByRegion, +} from './structural-variant-queries' + +const datasetIds = [ + 'gnomad_sv_r2_1', + 'gnomad_sv_r2_1_controls', + 'gnomad_sv_r2_1_non_neuro', +] as const + +const subsets: Record<(typeof datasetIds)[number], string> = { + gnomad_sv_r2_1: 'all', + gnomad_sv_r2_1_controls: 'controls', + gnomad_sv_r2_1_non_neuro: 'non_neuro', +} + +const responseWithHits = (hits: any[]) => { + const formattedHits = hits.map((hit) => ({ _source: { value: hit } })) + return { + body: { + hits: { + hits: formattedHits, + total: { + value: hits.length, + }, + }, + }, + } +} + +const minimalResponse = responseWithHits([]) + +const minimalHit = (freq: any) => ({ + freq, + age_distribution: {}, + genotype_quality: { + alt: {}, + all: {}, + }, + consequences: [], +}) + +const makeMockClient = (response: any) => { + const mockSearch = jest.fn() + mockSearch.mockReturnValue(response) + return { search: mockSearch, clearScroll: () => {}, scroll: () => minimalResponse } +} + +describe('fetchStructuralVariantById', () => { + const variantId = 'dummy-variant' + + describe.each(datasetIds)('with datasetId %s', (datasetId) => { + test('constructs the correct ES query', async () => { + const mockClient = makeMockClient(minimalResponse) + await fetchStructuralVariantById(mockClient, datasetId, variantId) + + expect(mockClient.search).toHaveBeenCalledWith({ + index: 'gnomad_structural_variants_v2', + type: '_doc', + body: { + query: { + bool: { + filter: { term: { variant_id: variantId } }, + }, + }, + }, + size: 1, + }) + }) + + test('returns null if no hits', async () => { + const mockClient = makeMockClient(minimalResponse) + expect(await fetchStructuralVariantById(mockClient, datasetId, variantId)).toBeNull() + }) + + test('returns null if no frequencies in the subset for the variant', async () => { + const response = responseWithHits([ + { + freq: { + [subsets[datasetId]]: {}, + [`${subsets[datasetId]}_but_wrong`]: { + ac: 10000, + }, + }, + }, + ]) + const mockClient = makeMockClient(response) + expect(await fetchStructuralVariantById(mockClient, datasetId, variantId)).toBeNull() + }) + + test('age_distribution translates empty hom to null if het set', async () => { + const hit = { + ...minimalHit({ + [subsets[datasetId]]: { + ac: 100, + }, + }), + age_distribution: { + het: 'dummy het value', + hom: {}, + }, + } + const response = responseWithHits([hit]) + const mockClient = makeMockClient(response) + const processedResponse = await fetchStructuralVariantById(mockClient, datasetId, variantId) + expect(processedResponse.age_distribution['het']).toEqual('dummy het value') + expect(processedResponse.age_distribution['hom']).toBeNull() + }) + + test('age_distribution translates empty het to null if hom set', async () => { + const hit = { + ...minimalHit({ + [subsets[datasetId]]: { + ac: 100, + }, + }), + age_distribution: { + het: {}, + hom: 'dummy hom value', + }, + } + const response = responseWithHits([hit]) + const mockClient = makeMockClient(response) + const processedResponse = await fetchStructuralVariantById(mockClient, datasetId, variantId) + expect(processedResponse.age_distribution['het']).toBeNull() + expect(processedResponse.age_distribution['hom']).toEqual('dummy hom value') + }) + + test('age_distribution is null if neither het nor hom set', async () => { + const hit = minimalHit({ + [subsets[datasetId]]: { + ac: 100, + }, + }) + const response = responseWithHits([hit]) + const mockClient = makeMockClient(response) + const processedResponse = await fetchStructuralVariantById(mockClient, datasetId, variantId) + expect(processedResponse.age_distribution).toBeNull() + }) + + test('genotype_quality translates empty alt to null if all set', async () => { + const hit = { + ...minimalHit({ + [subsets[datasetId]]: { + ac: 100, + }, + }), + + genotype_quality: { + alt: {}, + all: 'dummy-all', + }, + } + + const response = responseWithHits([hit]) + const mockClient = makeMockClient(response) + const processedResponse = await fetchStructuralVariantById(mockClient, datasetId, variantId) + expect(processedResponse.genotype_quality.alt).toBeNull() + expect(processedResponse.genotype_quality.all).toEqual('dummy-all') + }) + + test('genotype_quality translates empty all to null if alt set', async () => { + const hit = { + ...minimalHit({ + [subsets[datasetId]]: { + ac: 100, + }, + }), + genotype_quality: { + alt: 'dummy-alt', + all: {}, + }, + } + + const response = responseWithHits([hit]) + const mockClient = makeMockClient(response) + const processedResponse = await fetchStructuralVariantById(mockClient, datasetId, variantId) + expect(processedResponse.genotype_quality.alt).toEqual('dummy-alt') + expect(processedResponse.genotype_quality.all).toBeNull() + }) + + test('genotype_quality is null if neither alt nor all set', async () => { + const response = responseWithHits([ + minimalHit({ + [subsets[datasetId]]: { + ac: 100, + }, + }), + ]) + const mockClient = makeMockClient(response) + const processedResponse = await fetchStructuralVariantById(mockClient, datasetId, variantId) + expect(processedResponse.genotype_quality).toBeNull() + }) + }) +}) + +describe('fetchStructuralVariantsByGene', () => { + const gene = { symbol: 'dummy-gene', reference_genome: 'GRCh37' } + + describe.each(datasetIds)('with dataset %s', (datasetId) => { + test('constructs the correct ES query', async () => { + const mockClient = makeMockClient(responseWithHits([])) + const subset = subsets[datasetId] + await fetchStructuralVariantsByGene(mockClient, datasetId, gene) + + expect(mockClient.search).toHaveBeenCalledWith({ + index: 'gnomad_structural_variants_v2', + type: '_doc', + size: 10000, + scroll: '30s', + _source: [ + 'value.chrom', + 'value.chrom2', + 'value.consequences', + 'value.end', + 'value.end2', + 'value.filters', + `value.freq.${subset}`, + 'value.intergenic', + 'value.length', + 'value.pos', + 'value.pos2', + 'value.reference_genome', + 'value.type', + 'value.variant_id', + ], + body: { + query: { + bool: { + filter: { + term: { genes: 'dummy-gene' }, + }, + }, + }, + sort: [{ xpos: { order: 'asc' } }], + }, + }) + }) + + test('rejects variants with AC of 0', async () => { + const hitWithNonzeroAc = minimalHit({ + [subsets[datasetId]]: { + ac: 100, + }, + }) + const hitWithZeroAc = { + ...hitWithNonzeroAc, + freq: { + [subsets[datasetId]]: { + ac: 0, + }, + }, + } + + const response = responseWithHits([hitWithNonzeroAc, hitWithZeroAc]) + const mockClient = makeMockClient(response) + const processedResponse = await fetchStructuralVariantsByGene(mockClient, datasetId, gene) + expect(processedResponse.length).toEqual(1) + expect(processedResponse[0].ac).toEqual(100) + }) + + test('uses first consequence in gene as major consequence, when present', async () => { + const hit = { + ...minimalHit({ + [subsets[datasetId]]: { + ac: 100, + }, + }), + consequences: [ + { consequence: 'csq-a', genes: [gene.symbol + 'NOTME'] }, + { consequence: 'csq-b', genes: [gene.symbol] }, + { consequence: 'csq-c', genes: [gene.symbol] }, + ], + } + + const response = responseWithHits([hit]) + const mockClient = makeMockClient(response) + const processedResponse = await fetchStructuralVariantsByGene(mockClient, datasetId, gene) + expect(processedResponse[0].major_consequence).toEqual('csq-b') + }) + + test('uses "intergenic" for major consequence if no consequences but variant is intergenic', async () => { + const hit = { + ...minimalHit({ + [subsets[datasetId]]: { + ac: 100, + }, + }), + intergenic: true, + } + + const response = responseWithHits([hit]) + const mockClient = makeMockClient(response) + const processedResponse = await fetchStructuralVariantsByGene(mockClient, datasetId, gene) + expect(processedResponse[0].major_consequence).toEqual('intergenic') + }) + }) +}) + +describe('fetchStructuralVariantsByRegion', () => { + describe.each(datasetIds)('with dataset %s', (datasetId) => { + const region = { + chrom: 12, + start: 123, + xstart: 126, + stop: 456, + xstop: 453, + reference_genome: 'GRCh37', + } + + describe.each(datasetIds)('with datasetId %s', () => { + const subset = subsets[datasetId] + + test('constructs the proper ES query', async () => { + const mockClient = makeMockClient(minimalResponse) + await fetchStructuralVariantsByRegion(mockClient, datasetId, region) + + expect(mockClient.search).toHaveBeenCalledWith({ + index: 'gnomad_structural_variants_v2', + type: '_doc', + size: 10000, + scroll: '30s', + _source: [ + 'value.chrom', + 'value.chrom2', + 'value.consequences', + 'value.end', + 'value.end2', + 'value.filters', + `value.freq.${subset}`, + 'value.intergenic', + 'value.length', + 'value.pos', + 'value.pos2', + 'value.reference_genome', + 'value.type', + 'value.variant_id', + ], + body: { + query: { + bool: { + should: [ + { + bool: { + must: [{ range: { xpos: { lte: 453 } } }, { range: { xend: { gte: 126 } } }], + }, + }, + { + bool: { + must: [ + { range: { xpos2: { lte: 453 } } }, + { range: { xend2: { gte: 126 } } }, + ], + }, + }, + ], + }, + }, + sort: [{ xpos: { order: 'asc' } }], + }, + }) + }) + test('rejects variants with AC of 0', async () => { + const hitWithNonzeroAc = minimalHit({ + [subsets[datasetId]]: { + ac: 100, + }, + }) + + const hitWithZeroAc = minimalHit({ + [subsets[datasetId]]: { + ac: 0, + }, + }) + + const response = responseWithHits([hitWithNonzeroAc, hitWithZeroAc]) + const mockClient = makeMockClient(response) + const processedResponse = await fetchStructuralVariantsByRegion( + mockClient, + datasetId, + region + ) + expect(processedResponse.length).toEqual(1) + expect(processedResponse[0].ac).toEqual(100) + }) + + test('includes insertions only if start point within region', async () => { + const insertionWithValidStartPoint1 = { + ...minimalHit({ + [subsets[datasetId]]: { + ac: 100, + }, + }), + type: 'INS', + chrom: region.chrom, + pos: region.start, + } + const insertionWithValidStartPoint2 = { ...insertionWithValidStartPoint1, pos: region.stop } + const insertionWithInvalidStartPoint1 = { + ...insertionWithValidStartPoint1, + pos: region.start - 1, + } + const insertionWithInvalidStartPoint2 = { + ...insertionWithValidStartPoint1, + pos: region.stop + 1, + } + + const response = responseWithHits([ + insertionWithValidStartPoint1, + insertionWithInvalidStartPoint1, + insertionWithValidStartPoint2, + insertionWithInvalidStartPoint2, + ]) + const mockClient = makeMockClient(response) + const processedResponse = await fetchStructuralVariantsByRegion( + mockClient, + datasetId, + region + ) + expect(processedResponse.length).toEqual(2) + expect(processedResponse[0].pos).toEqual(region.start) + expect(processedResponse[1].pos).toEqual(region.stop) + }) + + describe.each(['BND', 'CTX'])('and interchromosomal variant type "%s"', (type) => { + test(`include ${type} only if one endpoint within region`, async () => { + const variantWithQualifyingStart1 = { + ...minimalHit({ + [subsets[datasetId]]: { + ac: 100, + }, + }), + type, + chrom: region.chrom, + chrom2: region.chrom + 1, + pos: region.start, + pos2: region.start, + } + const variantWithQualifyingStart2 = { + ...variantWithQualifyingStart1, + pos: region.stop, + } + const variantWithQualifyingEnd1 = { + ...variantWithQualifyingStart1, + chrom: region.chrom - 1, + chrom2: region.chrom, + pos2: region.start, + } + const variantWithQualifyingEnd2 = { + ...variantWithQualifyingEnd1, + pos2: region.stop, + } + const variantBeforeRegion = { + ...variantWithQualifyingEnd1, + pos2: region.start - 1, + } + const variantAfterRegion = { + ...variantWithQualifyingStart1, + pos: region.stop + 1, + } + + const response = responseWithHits([ + variantWithQualifyingStart1, + variantWithQualifyingEnd1, + variantBeforeRegion, + variantAfterRegion, + variantWithQualifyingStart2, + variantWithQualifyingEnd2, + ]) + const mockClient = makeMockClient(response) + const processedResponse = await fetchStructuralVariantsByRegion( + mockClient, + datasetId, + region + ) + + const expectedEndpoints = [ + variantWithQualifyingStart1, + variantWithQualifyingEnd1, + variantWithQualifyingStart2, + variantWithQualifyingEnd2, + ].map((variant) => [variant.chrom, variant.pos, variant.chrom2, variant.pos2]) + const actualEndpoints = processedResponse.map((variant: any) => [ + variant.chrom, + variant.pos, + variant.chrom2, + variant.pos2, + ]) + expect(actualEndpoints).toEqual(expectedEndpoints) + }) + }) + + test('uses first consequence as major consequence, when present', async () => { + const hit = { + ...minimalHit({ + [subsets[datasetId]]: { + ac: 100, + }, + }), + consequences: [ + { consequence: 'csq-a' }, + { consequence: 'csq-b' }, + { consequence: 'csq-c' }, + ], + } + + const response = responseWithHits([hit]) + const mockClient = makeMockClient(response) + const processedResponse = await fetchStructuralVariantsByRegion( + mockClient, + datasetId, + region + ) + expect(processedResponse.length).toEqual(1) + expect(processedResponse[0].major_consequence).toEqual('csq-a') + }) + + test('uses "intergenic" for major consequence if no consequences but variant is intergenic', async () => { + const hit = { + ...minimalHit({ + [subsets[datasetId]]: { + ac: 100, + }, + }), + intergenic: true, + } + + const response = responseWithHits([hit]) + const mockClient = makeMockClient(response) + const processedResponse = await fetchStructuralVariantsByRegion( + mockClient, + datasetId, + region + ) + expect(processedResponse.length).toEqual(1) + expect(processedResponse[0].major_consequence).toEqual('intergenic') + }) + }) + }) +}) diff --git a/graphql-api/src/queries/structural-variant-queries.ts b/graphql-api/src/queries/structural-variant-queries.ts index f54962577..8534d2ac8 100644 --- a/graphql-api/src/queries/structural-variant-queries.ts +++ b/graphql-api/src/queries/structural-variant-queries.ts @@ -2,9 +2,21 @@ import { UserVisibleError } from '../errors' import gnomadSvV2Queries from './structural-variant-datasets/gnomad-sv-v2-queries' +import { DatasetId } from '@gnomad/dataset-metadata/metadata' + type QueryArgs = [any, any] -const datasetQueries = { +const subsets = ['controls', 'non_neuro'] as const +export type V2Subset = 'all' | (typeof subsets)[number] +type SvDatasetId = 'gnomad_sv_r2_1' | 'gnomad_sv_r2_1_controls' | 'gnomad_sv_r2_1_non_neuro' + +type QueriesForDataset = { + fetchStructuralVariantById: any + fetchStructuralVariantsByGene: any + fetchStructuralVariantsByRegion: any +} + +const datasetQueries: Record = { gnomad_sv_r2_1: { fetchStructuralVariantById: (...args: QueryArgs) => gnomadSvV2Queries.fetchStructuralVariantById(...args, 'all'), @@ -13,11 +25,9 @@ const datasetQueries = { fetchStructuralVariantsByRegion: (...args: QueryArgs) => gnomadSvV2Queries.fetchStructuralVariantsByRegion(...args, 'all'), }, -} +} as Record -const subsets = ['controls', 'non_neuro'] subsets.forEach((subset) => { - // @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message datasetQueries[`gnomad_sv_r2_1_${subset}`] = { fetchStructuralVariantById: (...args: QueryArgs) => gnomadSvV2Queries.fetchStructuralVariantById(...args, subset), @@ -28,13 +38,16 @@ subsets.forEach((subset) => { } }) -export const fetchStructuralVariantById = (esClient: any, datasetId: any, variantId: any) => { - // @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message +export const fetchStructuralVariantById = ( + esClient: any, + datasetId: SvDatasetId, + variantId: any +) => { const query = datasetQueries[datasetId].fetchStructuralVariantById return query(esClient, variantId) } -export const fetchStructuralVariantsByGene = (esClient: any, datasetId: any, gene: any) => { +export const fetchStructuralVariantsByGene = (esClient: any, datasetId: DatasetId, gene: any) => { if (gene.reference_genome !== 'GRCh37') { throw new UserVisibleError( `gnomAD v2 structural variants are not available on ${gene.reference_genome}` @@ -46,7 +59,11 @@ export const fetchStructuralVariantsByGene = (esClient: any, datasetId: any, gen return query(esClient, gene) } -export const fetchStructuralVariantsByRegion = (esClient: any, datasetId: any, region: any) => { +export const fetchStructuralVariantsByRegion = ( + esClient: any, + datasetId: DatasetId, + region: any +) => { if (region.reference_genome !== 'GRCh37') { throw new UserVisibleError( `gnomAD v2 structural variants are not available on ${region.reference_genome}` From 10184801a2c6974e3f23cdfacb8d765b666fdec8 Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Tue, 13 Jun 2023 10:24:38 -0400 Subject: [PATCH 04/24] Refactor SV queries to make it easier to add v3 SVs The only difference (at least in this first iteration) between v2 and v3 SV queries is the index they use. Here we refactor so that we'll be able to re-use the existing SV queries, largely by folding two separate modules into one. --- .../gnomad-sv-v2-queries.ts | 201 -------------- .../src/queries/structural-variant-queries.ts | 246 ++++++++++++++---- 2 files changed, 199 insertions(+), 248 deletions(-) delete mode 100644 graphql-api/src/queries/structural-variant-datasets/gnomad-sv-v2-queries.ts diff --git a/graphql-api/src/queries/structural-variant-datasets/gnomad-sv-v2-queries.ts b/graphql-api/src/queries/structural-variant-datasets/gnomad-sv-v2-queries.ts deleted file mode 100644 index 975c6f11e..000000000 --- a/graphql-api/src/queries/structural-variant-datasets/gnomad-sv-v2-queries.ts +++ /dev/null @@ -1,201 +0,0 @@ -import { isEmpty } from 'lodash' -import { fetchAllSearchResults } from '../helpers/elasticsearch-helpers' - -const GNOMAD_STRUCTURAL_VARIANTS_V2_INDEX = 'gnomad_structural_variants_v2' - -// ================================================================================================ -// Variant query -// ================================================================================================ - -const fetchStructuralVariantById = async (esClient: any, variantId: string, subset: string) => { - const response = await esClient.search({ - index: GNOMAD_STRUCTURAL_VARIANTS_V2_INDEX, - type: '_doc', - body: { - query: { - bool: { - filter: { term: { variant_id: variantId } }, - }, - }, - }, - size: 1, - }) - - if (response.body.hits.total.value === 0) { - return null - } - - const variant = response.body.hits.hits[0]._source.value - - // If the variant is not in the subset, then variant.freq[subset] will be an empty object. - if (!variant.freq[subset].ac) { - return null - } - - return { - ...variant, - ...variant.freq[subset], - age_distribution: - !isEmpty(variant.age_distribution.het) || !isEmpty(variant.age_distribution.hom) - ? { - het: isEmpty(variant.age_distribution.het) ? null : variant.age_distribution.het, - hom: isEmpty(variant.age_distribution.hom) ? null : variant.age_distribution.hom, - } - : null, - genotype_quality: - !isEmpty(variant.genotype_quality.all) || !isEmpty(variant.genotype_quality.alt) - ? { - all: isEmpty(variant.genotype_quality.all) ? null : variant.genotype_quality.all, - alt: isEmpty(variant.genotype_quality.alt) ? null : variant.genotype_quality.alt, - } - : null, - } -} - -// ================================================================================================ -// Gene query -// ================================================================================================ - -const esFieldsToFetch = (subset: any) => [ - 'value.chrom', - 'value.chrom2', - 'value.consequences', - 'value.end', - 'value.end2', - 'value.filters', - `value.freq.${subset}`, - 'value.intergenic', - 'value.length', - 'value.pos', - 'value.pos2', - 'value.reference_genome', - 'value.type', - 'value.variant_id', -] - -const fetchStructuralVariantsByGene = async (esClient: any, gene: any, subset: any) => { - const hits = await fetchAllSearchResults(esClient, { - index: GNOMAD_STRUCTURAL_VARIANTS_V2_INDEX, - type: '_doc', - size: 10000, - _source: esFieldsToFetch(subset), - body: { - query: { - bool: { - filter: { - term: { genes: gene.symbol }, - }, - }, - }, - sort: [{ xpos: { order: 'asc' } }], - }, - }) - - return hits - .map((hit: any) => hit._source.value) - .filter((variant: any) => variant.freq[subset].ac > 0) - .map((variant: any) => { - let majorConsequence = variant.consequences.find((csq: any) => - csq.genes.includes(gene.symbol) - ) - if (majorConsequence) { - majorConsequence = majorConsequence.consequence - } else if (variant.intergenic) { - majorConsequence = 'intergenic' - } - - return { - ...variant, - ...variant.freq[subset], - major_consequence: majorConsequence, - } - }) -} - -// ================================================================================================ -// Region query -// ================================================================================================ - -const fetchStructuralVariantsByRegion = async (esClient: any, region: any, subset: any) => { - const hits = await fetchAllSearchResults(esClient, { - index: GNOMAD_STRUCTURAL_VARIANTS_V2_INDEX, - type: '_doc', - size: 10000, - _source: esFieldsToFetch(subset), - body: { - query: { - bool: { - should: [ - { - bool: { - must: [ - { range: { xpos: { lte: region.xstop } } }, - { range: { xend: { gte: region.xstart } } }, - ], - }, - }, - { - bool: { - must: [ - { range: { xpos2: { lte: region.xstop } } }, - { range: { xend2: { gte: region.xstart } } }, - ], - }, - }, - ], - }, - }, - sort: [{ xpos: { order: 'asc' } }], - }, - }) - - return hits - .map((hit: any) => hit._source.value) - .filter((variant: any) => variant.freq[subset].ac > 0) - .filter((variant: any) => { - // Only include insertions if the start point falls within the requested region. - if (variant.type === 'INS') { - return ( - variant.chrom === region.chrom && - variant.pos >= region.start && - variant.pos <= region.stop - ) - } - - // Only include interchromosomal variants (CTX, BND) if one of the endpoints falls within the requested region. - // Some INS and CPX variants are also interchromosomal, but those can only be queried on their first position. - if (variant.type === 'BND' || variant.type === 'CTX') { - return ( - (variant.chrom === region.chrom && - variant.pos >= region.start && - variant.pos <= region.stop) || - (variant.chrom2 === region.chrom && - variant.pos2 >= region.start && - variant.pos2 <= region.stop) - ) - } - - return true - }) - .map((variant: any) => { - let majorConsequence = null - if (variant.consequences.length) { - majorConsequence = variant.consequences[0].consequence - } else if (variant.intergenic) { - majorConsequence = 'intergenic' - } - - return { - ...variant, - ...variant.freq[subset], - major_consequence: majorConsequence, - } - }) -} - -const queries = { - fetchStructuralVariantById, - fetchStructuralVariantsByGene, - fetchStructuralVariantsByRegion, -} -export default queries diff --git a/graphql-api/src/queries/structural-variant-queries.ts b/graphql-api/src/queries/structural-variant-queries.ts index 8534d2ac8..cef9acbe3 100644 --- a/graphql-api/src/queries/structural-variant-queries.ts +++ b/graphql-api/src/queries/structural-variant-queries.ts @@ -1,76 +1,228 @@ -import { UserVisibleError } from '../errors' - -import gnomadSvV2Queries from './structural-variant-datasets/gnomad-sv-v2-queries' +import { isEmpty } from 'lodash' -import { DatasetId } from '@gnomad/dataset-metadata/metadata' +import { UserVisibleError } from '../errors' +import { fetchAllSearchResults } from './helpers/elasticsearch-helpers' -type QueryArgs = [any, any] +const GNOMAD_STRUCTURAL_VARIANTS_V2_INDEX = 'gnomad_structural_variants_v2' -const subsets = ['controls', 'non_neuro'] as const -export type V2Subset = 'all' | (typeof subsets)[number] type SvDatasetId = 'gnomad_sv_r2_1' | 'gnomad_sv_r2_1_controls' | 'gnomad_sv_r2_1_non_neuro' +type Subset = 'all' | 'controls' | 'non_neuro' +type QuerySpecifier = { index: string; subset: Subset } -type QueriesForDataset = { - fetchStructuralVariantById: any - fetchStructuralVariantsByGene: any - fetchStructuralVariantsByRegion: any -} +const querySpecifiers: Record = { + gnomad_sv_r2_1: { index: GNOMAD_STRUCTURAL_VARIANTS_V2_INDEX, subset: 'all' }, + gnomad_sv_r2_1_controls: { index: GNOMAD_STRUCTURAL_VARIANTS_V2_INDEX, subset: 'controls' }, + gnomad_sv_r2_1_non_neuro: { index: GNOMAD_STRUCTURAL_VARIANTS_V2_INDEX, subset: 'non_neuro' }, +} as const -const datasetQueries: Record = { - gnomad_sv_r2_1: { - fetchStructuralVariantById: (...args: QueryArgs) => - gnomadSvV2Queries.fetchStructuralVariantById(...args, 'all'), - fetchStructuralVariantsByGene: (...args: QueryArgs) => - gnomadSvV2Queries.fetchStructuralVariantsByGene(...args, 'all'), - fetchStructuralVariantsByRegion: (...args: QueryArgs) => - gnomadSvV2Queries.fetchStructuralVariantsByRegion(...args, 'all'), - }, -} as Record - -subsets.forEach((subset) => { - datasetQueries[`gnomad_sv_r2_1_${subset}`] = { - fetchStructuralVariantById: (...args: QueryArgs) => - gnomadSvV2Queries.fetchStructuralVariantById(...args, subset), - fetchStructuralVariantsByGene: (...args: QueryArgs) => - gnomadSvV2Queries.fetchStructuralVariantsByGene(...args, subset), - fetchStructuralVariantsByRegion: (...args: QueryArgs) => - gnomadSvV2Queries.fetchStructuralVariantsByRegion(...args, subset), - } -}) +export type GeneQueryParams = { symbol: string; reference_genome: string } +export type RegionQueryParams = { + reference_genome: string + chrom: number + start: number + stop: number + xstart: number + xstop: number +} -export const fetchStructuralVariantById = ( +export const fetchStructuralVariantById = async ( esClient: any, datasetId: SvDatasetId, - variantId: any + variantId: string ) => { - const query = datasetQueries[datasetId].fetchStructuralVariantById - return query(esClient, variantId) + const { index, subset } = querySpecifiers[datasetId] + const response = await esClient.search({ + index, + type: '_doc', + body: { + query: { + bool: { + filter: { term: { variant_id: variantId } }, + }, + }, + }, + size: 1, + }) + + if (response.body.hits.total.value === 0) { + return null + } + + const variant = response.body.hits.hits[0]._source.value + + // If the variant is not in the subset, then variant.freq[subset] will be an empty object. + if (!variant.freq[subset].ac) { + return null + } + + return { + ...variant, + ...variant.freq[subset], + age_distribution: + !isEmpty(variant.age_distribution.het) || !isEmpty(variant.age_distribution.hom) + ? { + het: isEmpty(variant.age_distribution.het) ? null : variant.age_distribution.het, + hom: isEmpty(variant.age_distribution.hom) ? null : variant.age_distribution.hom, + } + : null, + genotype_quality: + !isEmpty(variant.genotype_quality.all) || !isEmpty(variant.genotype_quality.alt) + ? { + all: isEmpty(variant.genotype_quality.all) ? null : variant.genotype_quality.all, + alt: isEmpty(variant.genotype_quality.alt) ? null : variant.genotype_quality.alt, + } + : null, + } } -export const fetchStructuralVariantsByGene = (esClient: any, datasetId: DatasetId, gene: any) => { +const esFieldsToFetch = (subset: any) => [ + 'value.chrom', + 'value.chrom2', + 'value.consequences', + 'value.end', + 'value.end2', + 'value.filters', + `value.freq.${subset}`, + 'value.intergenic', + 'value.length', + 'value.pos', + 'value.pos2', + 'value.reference_genome', + 'value.type', + 'value.variant_id', +] +export const fetchStructuralVariantsByGene = async ( + esClient: any, + datasetId: SvDatasetId, + gene: GeneQueryParams +) => { if (gene.reference_genome !== 'GRCh37') { throw new UserVisibleError( `gnomAD v2 structural variants are not available on ${gene.reference_genome}` ) } + const { index, subset } = querySpecifiers[datasetId] + const hits = await fetchAllSearchResults(esClient, { + index, + type: '_doc', + size: 10000, + _source: esFieldsToFetch(subset), + body: { + query: { + bool: { + filter: { + term: { genes: gene.symbol }, + }, + }, + }, + sort: [{ xpos: { order: 'asc' } }], + }, + }) - // @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message - const query = datasetQueries[datasetId].fetchStructuralVariantsByGene - return query(esClient, gene) + return hits + .map((hit: any) => hit._source.value) + .filter((variant: any) => variant.freq[subset].ac > 0) + .map((variant: any) => { + let majorConsequence = variant.consequences.find((csq: any) => + csq.genes.includes(gene.symbol) + ) + if (majorConsequence) { + majorConsequence = majorConsequence.consequence + } else if (variant.intergenic) { + majorConsequence = 'intergenic' + } + + return { + ...variant, + ...variant.freq[subset], + major_consequence: majorConsequence, + } + }) } -export const fetchStructuralVariantsByRegion = ( +export const fetchStructuralVariantsByRegion = async ( esClient: any, - datasetId: DatasetId, - region: any + datasetId: SvDatasetId, + region: RegionQueryParams ) => { if (region.reference_genome !== 'GRCh37') { throw new UserVisibleError( `gnomAD v2 structural variants are not available on ${region.reference_genome}` ) } + const { index, subset } = querySpecifiers[datasetId] + const hits = await fetchAllSearchResults(esClient, { + index, + type: '_doc', + size: 10000, + _source: esFieldsToFetch(subset), + body: { + query: { + bool: { + should: [ + { + bool: { + must: [ + { range: { xpos: { lte: region.xstop } } }, + { range: { xend: { gte: region.xstart } } }, + ], + }, + }, + { + bool: { + must: [ + { range: { xpos2: { lte: region.xstop } } }, + { range: { xend2: { gte: region.xstart } } }, + ], + }, + }, + ], + }, + }, + sort: [{ xpos: { order: 'asc' } }], + }, + }) + + return hits + .map((hit: any) => hit._source.value) + .filter((variant: any) => variant.freq[subset].ac > 0) + .filter((variant: any) => { + // Only include insertions if the start point falls within the requested region. + if (variant.type === 'INS') { + return ( + variant.chrom === region.chrom && + variant.pos >= region.start && + variant.pos <= region.stop + ) + } + + // Only include interchromosomal variants (CTX, BND) if one of the endpoints falls within the requested region. + // Some INS and CPX variants are also interchromosomal, but those can only be queried on their first position. + if (variant.type === 'BND' || variant.type === 'CTX') { + return ( + (variant.chrom === region.chrom && + variant.pos >= region.start && + variant.pos <= region.stop) || + (variant.chrom2 === region.chrom && + variant.pos2 >= region.start && + variant.pos2 <= region.stop) + ) + } + + return true + }) + .map((variant: any) => { + let majorConsequence = null + if (variant.consequences.length) { + majorConsequence = variant.consequences[0].consequence + } else if (variant.intergenic) { + majorConsequence = 'intergenic' + } - // @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message - const query = datasetQueries[datasetId].fetchStructuralVariantsByRegion - return query(esClient, region) + return { + ...variant, + ...variant.freq[subset], + major_consequence: majorConsequence, + } + }) } From d1c50917ea56120fb9439c147fc9c79c9f731d2e Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Wed, 14 Jun 2023 11:22:15 -0400 Subject: [PATCH 05/24] Add support for v3 SVs to GraphQL API --- .../src/graphql/types/dataset-id.graphql | 1 + .../structural-variant-queries.spec.ts | 24 +++++-- .../src/queries/structural-variant-queries.ts | 65 ++++++++++++------- 3 files changed, 60 insertions(+), 30 deletions(-) diff --git a/graphql-api/src/graphql/types/dataset-id.graphql b/graphql-api/src/graphql/types/dataset-id.graphql index aaecab657..328e215aa 100644 --- a/graphql-api/src/graphql/types/dataset-id.graphql +++ b/graphql-api/src/graphql/types/dataset-id.graphql @@ -17,4 +17,5 @@ enum StructuralVariantDatasetId { gnomad_sv_r2_1 gnomad_sv_r2_1_controls gnomad_sv_r2_1_non_neuro + gnomad_sv_r3 } diff --git a/graphql-api/src/queries/structural-variant-queries.spec.ts b/graphql-api/src/queries/structural-variant-queries.spec.ts index f47600d9b..dc30b16ab 100644 --- a/graphql-api/src/queries/structural-variant-queries.spec.ts +++ b/graphql-api/src/queries/structural-variant-queries.spec.ts @@ -10,12 +10,15 @@ const datasetIds = [ 'gnomad_sv_r2_1', 'gnomad_sv_r2_1_controls', 'gnomad_sv_r2_1_non_neuro', + 'gnomad_sv_r3', ] as const +type SvDatasetId = (typeof datasetIds)[number] -const subsets: Record<(typeof datasetIds)[number], string> = { +const subsets: Record = { gnomad_sv_r2_1: 'all', gnomad_sv_r2_1_controls: 'controls', gnomad_sv_r2_1_non_neuro: 'non_neuro', + gnomad_sv_r3: 'all', } const responseWithHits = (hits: any[]) => { @@ -50,21 +53,29 @@ const makeMockClient = (response: any) => { return { search: mockSearch, clearScroll: () => {}, scroll: () => minimalResponse } } +const expectedIndex = (datasetId: SvDatasetId) => + datasetId === 'gnomad_sv_r3' ? 'gnomad_structural_variants_v3' : 'gnomad_structural_variants_v2' + describe('fetchStructuralVariantById', () => { const variantId = 'dummy-variant' describe.each(datasetIds)('with datasetId %s', (datasetId) => { test('constructs the correct ES query', async () => { + const expectedVariantIdParams = + datasetId === 'gnomad_sv_r3' + ? { variant_id_upper_case: 'DUMMY-VARIANT' } + : { variant_id: 'dummy-variant' } + const mockClient = makeMockClient(minimalResponse) await fetchStructuralVariantById(mockClient, datasetId, variantId) expect(mockClient.search).toHaveBeenCalledWith({ - index: 'gnomad_structural_variants_v2', + index: expectedIndex(datasetId), type: '_doc', body: { query: { bool: { - filter: { term: { variant_id: variantId } }, + filter: { term: expectedVariantIdParams }, }, }, }, @@ -199,7 +210,7 @@ describe('fetchStructuralVariantById', () => { }) describe('fetchStructuralVariantsByGene', () => { - const gene = { symbol: 'dummy-gene', reference_genome: 'GRCh37' } + const gene = { symbol: 'dummy-gene' } describe.each(datasetIds)('with dataset %s', (datasetId) => { test('constructs the correct ES query', async () => { @@ -208,7 +219,7 @@ describe('fetchStructuralVariantsByGene', () => { await fetchStructuralVariantsByGene(mockClient, datasetId, gene) expect(mockClient.search).toHaveBeenCalledWith({ - index: 'gnomad_structural_variants_v2', + index: expectedIndex(datasetId), type: '_doc', size: 10000, scroll: '30s', @@ -309,7 +320,6 @@ describe('fetchStructuralVariantsByRegion', () => { xstart: 126, stop: 456, xstop: 453, - reference_genome: 'GRCh37', } describe.each(datasetIds)('with datasetId %s', () => { @@ -320,7 +330,7 @@ describe('fetchStructuralVariantsByRegion', () => { await fetchStructuralVariantsByRegion(mockClient, datasetId, region) expect(mockClient.search).toHaveBeenCalledWith({ - index: 'gnomad_structural_variants_v2', + index: expectedIndex(datasetId), type: '_doc', size: 10000, scroll: '30s', diff --git a/graphql-api/src/queries/structural-variant-queries.ts b/graphql-api/src/queries/structural-variant-queries.ts index cef9acbe3..9694a8b2e 100644 --- a/graphql-api/src/queries/structural-variant-queries.ts +++ b/graphql-api/src/queries/structural-variant-queries.ts @@ -1,23 +1,52 @@ import { isEmpty } from 'lodash' -import { UserVisibleError } from '../errors' import { fetchAllSearchResults } from './helpers/elasticsearch-helpers' const GNOMAD_STRUCTURAL_VARIANTS_V2_INDEX = 'gnomad_structural_variants_v2' +const GNOMAD_STRUCTURAL_VARIANTS_V3_INDEX = 'gnomad_structural_variants_v3' -type SvDatasetId = 'gnomad_sv_r2_1' | 'gnomad_sv_r2_1_controls' | 'gnomad_sv_r2_1_non_neuro' +type SvDatasetId = + | 'gnomad_sv_r2_1' + | 'gnomad_sv_r2_1_controls' + | 'gnomad_sv_r2_1_non_neuro' + | 'gnomad_sv_r3' type Subset = 'all' | 'controls' | 'non_neuro' -type QuerySpecifier = { index: string; subset: Subset } +type DatasetDependentQueryParams = { + index: string + subset: Subset + variantIdParams: (variantId: string) => any +} -const querySpecifiers: Record = { - gnomad_sv_r2_1: { index: GNOMAD_STRUCTURAL_VARIANTS_V2_INDEX, subset: 'all' }, - gnomad_sv_r2_1_controls: { index: GNOMAD_STRUCTURAL_VARIANTS_V2_INDEX, subset: 'controls' }, - gnomad_sv_r2_1_non_neuro: { index: GNOMAD_STRUCTURAL_VARIANTS_V2_INDEX, subset: 'non_neuro' }, +const v2VariantIdParams = (variantId: string) => ({ variant_id: variantId }) +const v3VariantIdParams = (variantId: string) => ({ + variant_id_upper_case: variantId.toUpperCase(), +}) + +const datasetDependentQueryParams: Record = { + gnomad_sv_r2_1: { + index: GNOMAD_STRUCTURAL_VARIANTS_V2_INDEX, + subset: 'all', + variantIdParams: v2VariantIdParams, + }, + gnomad_sv_r2_1_controls: { + index: GNOMAD_STRUCTURAL_VARIANTS_V2_INDEX, + subset: 'controls', + variantIdParams: v2VariantIdParams, + }, + gnomad_sv_r2_1_non_neuro: { + index: GNOMAD_STRUCTURAL_VARIANTS_V2_INDEX, + subset: 'non_neuro', + variantIdParams: v2VariantIdParams, + }, + gnomad_sv_r3: { + index: GNOMAD_STRUCTURAL_VARIANTS_V3_INDEX, + subset: 'all', + variantIdParams: v3VariantIdParams, + }, } as const -export type GeneQueryParams = { symbol: string; reference_genome: string } +export type GeneQueryParams = { symbol: string } export type RegionQueryParams = { - reference_genome: string chrom: number start: number stop: number @@ -30,14 +59,14 @@ export const fetchStructuralVariantById = async ( datasetId: SvDatasetId, variantId: string ) => { - const { index, subset } = querySpecifiers[datasetId] + const { index, subset, variantIdParams } = datasetDependentQueryParams[datasetId] const response = await esClient.search({ index, type: '_doc', body: { query: { bool: { - filter: { term: { variant_id: variantId } }, + filter: { term: variantIdParams(variantId) }, }, }, }, @@ -96,12 +125,7 @@ export const fetchStructuralVariantsByGene = async ( datasetId: SvDatasetId, gene: GeneQueryParams ) => { - if (gene.reference_genome !== 'GRCh37') { - throw new UserVisibleError( - `gnomAD v2 structural variants are not available on ${gene.reference_genome}` - ) - } - const { index, subset } = querySpecifiers[datasetId] + const { index, subset } = datasetDependentQueryParams[datasetId] const hits = await fetchAllSearchResults(esClient, { index, type: '_doc', @@ -145,12 +169,7 @@ export const fetchStructuralVariantsByRegion = async ( datasetId: SvDatasetId, region: RegionQueryParams ) => { - if (region.reference_genome !== 'GRCh37') { - throw new UserVisibleError( - `gnomAD v2 structural variants are not available on ${region.reference_genome}` - ) - } - const { index, subset } = querySpecifiers[datasetId] + const { index, subset } = datasetDependentQueryParams[datasetId] const hits = await fetchAllSearchResults(esClient, { index, type: '_doc', From e79dd0df9a68ebaaf2e4db164dc659d0217e3f46 Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Fri, 16 Jun 2023 16:59:28 -0400 Subject: [PATCH 06/24] Add gnomad_sv_r3 as a valid dataset ID to metadata --- .../ConstraintTable.spec.tsx.snap | 36 + .../__snapshots__/GenePage.spec.tsx.snap | 1400 +++ ...riantCooccurrenceCountsTable.spec.tsx.snap | 8 + .../MitochondrialVariantPage.spec.tsx.snap | 8061 +++++++++++++++++ .../__snapshots__/ReadData.spec.tsx.snap | 205 + ...chondrialRegionCoverageTrack.spec.tsx.snap | 33 + ...itochondrialVariantsInRegion.spec.tsx.snap | 33 + .../__snapshots__/RegionPage.spec.tsx.snap | 299 + .../RegionPageContainer.spec.tsx.snap | 56 + ...drialTranscriptCoverageTrack.spec.tsx.snap | 32 + ...hondrialVariantsInTranscript.spec.tsx.snap | 33 + .../TranscriptPage.spec.tsx.snap | 647 ++ .../TranscriptPageContainer.spec.tsx.snap | 2 + .../DatasetSelector.spec.tsx.snap | 534 ++ browser/src/variantFeedback.spec.ts | 2 + dataset-metadata/metadata.spec.ts | 1 + dataset-metadata/metadata.ts | 33 +- 17 files changed, 11402 insertions(+), 13 deletions(-) diff --git a/browser/src/ConstraintTable/__snapshots__/ConstraintTable.spec.tsx.snap b/browser/src/ConstraintTable/__snapshots__/ConstraintTable.spec.tsx.snap index 1ade947c9..06240663f 100644 --- a/browser/src/ConstraintTable/__snapshots__/ConstraintTable.spec.tsx.snap +++ b/browser/src/ConstraintTable/__snapshots__/ConstraintTable.spec.tsx.snap @@ -6510,6 +6510,42 @@ exports[`ConstraintTable with "gnomad_sv_r2_1_non_neuro" dataset selected with a

`; +exports[`ConstraintTable with "gnomad_sv_r3" dataset selected and gene with available constraint has no unexpected changes 1`] = ` +

+ Constraint not yet available for gnomAD v3. +

+`; + +exports[`ConstraintTable with "gnomad_sv_r3" dataset selected and transcript with available constraint has no unexpected changes 1`] = ` +

+ Constraint not yet available for gnomAD v3. +

+`; + +exports[`ConstraintTable with "gnomad_sv_r3" dataset selected with a minimal gene has no unexpected changes 1`] = ` +

+ Constraint not yet available for gnomAD v3. +

+`; + +exports[`ConstraintTable with "gnomad_sv_r3" dataset selected with a minimal transcript has no unexpected changes 1`] = ` +

+ Constraint not yet available for gnomAD v3. +

+`; + +exports[`ConstraintTable with "gnomad_sv_r3" dataset selected with a mitochondrial gene has no unexpected changes 1`] = ` +

+ Constraint not yet available for gnomAD v3. +

+`; + +exports[`ConstraintTable with "gnomad_sv_r3" dataset selected with a mitochondrial transcript has no unexpected changes 1`] = ` +

+ Constraint not yet available for gnomAD v3. +

+`; + exports[`ConstraintTable with exac dataset and gene with available constraints has no unexpected changes 1`] = ` [ `; +exports[`GenePage with SV dataset "gnomad_sv_r3" has no unexpected changes 1`] = ` +
+
+
+
+

+ FAKEGENE + + +

+
+
+ + Dataset + + + + + +
+
+
+
+
+
+
+ Genome build +
+
+ GRCh37 + / + hg19 +
+
+
+
+ Ensembl gene ID +
+
+ dummy_gene-1 + . + 5.6.7.8 +
+
+
+
+ Symbol in GENCODE v19 +
+
+
+
+
+ Ensembl canonical transcript + +
+
+ + transcript-999 + . + 12.34.5 + +
+
+
+
+ Region +
+
+ + 13 + : + 123 + - + 321 + +
+
+
+
+ External resources +
+
+ + Ensembl + + , + + + UCSC Browser + + , + + +
+
+
+
+
+
+
+ Constraint + +
+
+ Variant co-occurrence + +
+
+

+ Constraint not yet available for gnomAD v3. +

+
+
+
+
+
+
+
+
+
    + + +
+
+
+
+
+ Per-base mean depth of coverage +
+
+
+
+ + + + + + + + 10 + + + + + + + + + + 20 + + + + + + + + + + 30 + + + + + + + + + + 40 + + + + + + + + + + 50 + + + + + + + + + + 60 + + + + + + + + + + 70 + + + + + + + + + + 80 + + + + + + + + + + 90 + + + + + + + + + + 100 + + + + + + + + + + + +
+
+
+
+
+ Include: +
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+
+
+
+
+
+ + Positive strand +
+
+
+
+ + + +
+
+
+
+
+
+ No variants found +
+
+
+
+`; + exports[`GenePage with non-SV dataset "exac" has no unexpected changes 1`] = `
`; +exports[`VariantCoocurrenceCountsTable with non v2 dataset "gnomad_sv_r3" has no unexpected changes and renders as placeholder text 1`] = ` + +

+ Variant co-occurrence is only available for gnomAD v2. +

+
+`; + exports[`VariantCoocurrenceCountsTable with v2 dataset "gnomad_r2_1" has no unexpected changes and renders as a table 1`] = `
diff --git a/browser/src/MitochondrialVariantPage/__snapshots__/MitochondrialVariantPage.spec.tsx.snap b/browser/src/MitochondrialVariantPage/__snapshots__/MitochondrialVariantPage.spec.tsx.snap index e0343e993..f0af820e0 100644 --- a/browser/src/MitochondrialVariantPage/__snapshots__/MitochondrialVariantPage.spec.tsx.snap +++ b/browser/src/MitochondrialVariantPage/__snapshots__/MitochondrialVariantPage.spec.tsx.snap @@ -72656,3 +72656,8064 @@ exports[`MitochondrialVariantPage with dataset gnomad_sv_r2_1_non_neuro has no u
`; + +exports[`MitochondrialVariantPage with dataset gnomad_sv_r3 has no unexpected changes 1`] = ` +
+
+
+

+ Single nucleotide variant + : + + M-123-A-C + (GRCh38) + +

+
+
+ + Dataset + + + + + +
+
+
+
+
+
+
+ + Filters + +
+
+ + Pass + +
+
+
+
+ + Allele Number + +
+
+ 0 +
+
+
+
+ + Homoplasmic AC + +
+
+ 0 +
+
+
+
+ + Homoplasmic AF + +
+
+ 0 +
+
+
+
+ + Heteroplasmic AC + +
+
+ 0 +
+
+
+
+ + Heteroplasmic AF + +
+
+ 0 +
+
+
+
+ + Max Observed Heteroplasmy + +
+
+ 0.1000 +
+
+
+
+ + Excluded Allele Count + +
+
+
+
+
+ + Haplogroup Defining + +
+
+ No +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ Total + + + 0 + + + + 0 + + + 0.000 + + + 0 + + + 0.000 +
+ +
+

+ Haplogroup Frequencies + +

+
+
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ Total + + + 0 + + + + 0 + + + 0.000 + + + 0 + + + 0.000 +
+ +
+
+
+
+
+

+ Heteroplasmy Distribution +

+
+
+
+ + + + + + + Heteroplasmy level + + + + + + + + + + + 0 + + + + + + + + + + 10 + + + + + + + + + + 20 + + + + + + + + + + 30 + + + + + + + + + + 40 + + + + + + + + + + 50 + + + + + + + + + + 60 + + + + + + + + + + 70 + + + + + + + + + + 80 + + + + + + + + + + 90 + + + + + + + + + + 100 + + + + + + + + + Individuals + + + + + + + + + + + + + + +
+
+
+
+

+ Age Distribution + +

+
+
+
    +
  • + + + + + Variant carriers + +
  • +
  • + + + + + + + + + + + + + + All individuals + +
  • +
+
+
+ + + + + + + + < 30 + + + + + + + + + + 30-35 + + + + + + + + + + 35-40 + + + + + + + + + + 40-45 + + + + + + + + + + 45-50 + + + + + + + + + + 50-55 + + + + + + + + + + 55-60 + + + + + + + + + + 60-65 + + + + + + + + + + 65-70 + + + + + + + + + + 70-75 + + + + + + + + + + 75-80 + + + + + + + + + + > 80 + + + + + + + + + Age + + + + + + + + + + + 0 + + + + + + + + + + 20 + + + + + + + + + + 40 + + + + + + + + + + 60 + + + + + + + + + + 80 + + + + + + + + + + 100 + + + + + + + + + + 120 + + + + + + + + + + 140 + + + + + + + + + + 160 + + + + + + + + + + 180 + + + + + + + + + + 200 + + + + + + + + + Variant carriers + + + + + + + + + + + 0 + + + + + + + + + + 500 + + + + + + + + + + 1.00K + + + + + + + + + + 1.50K + + + + + + + + + + 2.00K + + + + + + + + + + 2.50K + + + + + + + + + + 3.00K + + + + + + + + + + 3.50K + + + + + + + + + All individuals + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + +
+
+
+
+
+
+
+
+

+ Annotations +

+
    +
+
+
+
+

+ Genotype Quality Metrics +

+
+
+
    +
  • + +
  • +
  • + +
  • +
+
+
+
+
+
    +
  • + + + + + Variant carriers + +
  • +
  • + + + + + + + + + + + + + + All individuals + +
  • +
+
+
+ + + + + + + + > 0.5 + + + + + + + + + Depth + + + + + + + + + + + 0 + + + + + + + + + + 10 + + + + + + + + + + 20 + + + + + + + + + + 30 + + + + + + + + + + 40 + + + + + + + + + + 50 + + + + + + + + + + 60 + + + + + + + + + + 70 + + + + + + + + + + 80 + + + + + + + + + + 90 + + + + + + + + + + 100 + + + + + + + + + Variant carriers + + + + + + + + + + + 0 + + + + + + + + + + 10 + + + + + + + + + + 20 + + + + + + + + + + 30 + + + + + + + + + + 40 + + + + + + + + + + 50 + + + + + + + + + + 60 + + + + + + + + + + 70 + + + + + + + + + + 80 + + + + + + + + + + 90 + + + + + + + + + + 100 + + + + + + + + + All individuals + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+
+ + + + + + + Heteroplasmy level + + + + + + + + + + + 0 + + + + + + + + + + 10 + + + + + + + + + + 20 + + + + + + + + + + 30 + + + + + + + + + + 40 + + + + + + + + + + 50 + + + + + + + + + + 60 + + + + + + + + + + 70 + + + + + + + + + + 80 + + + + + + + + + + 90 + + + + + + + + + + 100 + + + + + + + + + Individuals failing filter + + + + + + + + + + + + + + +
+
+ +
+

+ Note: This plot may include low-quality genotypes that were excluded from allele counts in the tables above. + + + More information. + +

+
+
+
+
+
+
+

+ Site Quality Metrics +

+
+
+
    +
  • + +
  • +
  • + +
  • +
+
+
+
+
+
+
+ + + + + + + + + 0 + + + + + + + + + + 200 + + + + + + + + + + 400 + + + + + + + + + + 600 + + + + + + + + + + 800 + + + + + + + + + + 1000 + + + + + + + + + + 1200 + + + + + + + + + + 1400 + + + + + + + + + + 1600 + + + + + + + + + + 1800 + + + + + + + + + + 2000 + + + + + + + + + + 2200 + + + + + + + + + + 2400 + + + + + + + + + + 2600 + + + + + + + + + + 2800 + + + + + + + + + + 3000 + + + + + + + + + + 3200 + + + + + + + + + + 3400 + + + + + + + + + + 3600 + + + + + + + + + + 3800 + + + + + + + + + + 4000 + + + + + + + + + Mean Depth + + + + + + + + + + + 0 + + + + + + + + + + 500 + + + + + + + + + + 1.00K + + + + + + + + + + 1.50K + + + + + + + + + + 2.00K + + + + + + + + + + 2.50K + + + + + + + + + + 3.00K + + + + + + + + + + 3.50K + + + + + + + + + + 4.00K + + + + + + + + + + 4.50K + + + + + + + + + + 5.00K + + + + + + + + + Variants + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+ + + + + + + + + + + + + +
+ Metric + + Value +
+ Mean Depth + + 0 +
+
+
+
+
+
+
+

+ Read Data +

+

+ Read data is not yet available for mitochondrial variants. +

+
+ +`; diff --git a/browser/src/ReadData/__snapshots__/ReadData.spec.tsx.snap b/browser/src/ReadData/__snapshots__/ReadData.spec.tsx.snap index 962688178..bac4dce27 100644 --- a/browser/src/ReadData/__snapshots__/ReadData.spec.tsx.snap +++ b/browser/src/ReadData/__snapshots__/ReadData.spec.tsx.snap @@ -3502,3 +3502,208 @@ exports[`ReadData with "gnomad_sv_r2_1_non_neuro" dataset selected queries again } " `; + +exports[`ReadData with "gnomad_sv_r3" dataset selected has no unexpected changes with exome and genome data both missing 1`] = ` +
+

+ No read data available for this variant. +

+
+`; + +exports[`ReadData with "gnomad_sv_r3" dataset selected has no unexpected changes with exome data present 1`] = ` +.c2 { + box-sizing: border-box; + height: calc(2em + 2px); + padding: 0.375em 0.75em; + border-color: #6c757d; + border-style: solid; + border-width: 1px; + border-radius: 0.5em; + background-color: #f8f9fa; + cursor: pointer; + font-size: 1em; + line-height: 1.25; + outline: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.c2:active, +.c2:hover { + background-color: #cbd3da; +} + +.c2:disabled { + background-color: rgba(248,249,250,0.5); + cursor: not-allowed; +} + +.c2:focus { + box-shadow: 0 0 0 0.2em rgba(108,117,125,0.5); +} + +.c2 svg { + position: relative; + top: 0.11em; + width: 0.9em; + height: 0.9em; +} + +.c0 { + color: #1173bb; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c0:visited, +.c0:active { + color: #1173bb; +} + +.c0:focus, +.c0:hover { + -webkit-text-decoration: underline; + text-decoration: underline; +} + +.c1 { + padding-right: 80px; + margin-top: 1em; + text-align: center; +} + +.c1 strong { + display: inline-block; + width: 80px; + text-align: right; +} + +.c1 button { + margin-left: 2em; +} + +@media (max-width:500px) { + .c1 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + padding-right: 0; + } + + .c1 strong { + width: auto; + margin-bottom: 0.5em; + } + + .c1 button { + margin-left: 0 !important; + } + + .c1 button:last-child { + margin-top: 1em; + } +} + +
+

+ This interactive + + + IGV.js + + visualization shows reads that went into calling this variant. Reads may not be available for every sample carrying this variant. +

+

+ These are reassembled reads produced by + + + GATK HaplotypeCaller --bamOutput + + , so they accurately represent what HaplotypeCaller was seeing when it called this variant. +

+
+ + Exomes: + + + +
+
+ +
+
+`; + +exports[`ReadData with "gnomad_sv_r3" dataset selected queries against the correct dataset 1`] = ` +" + query ReadData { + variant_0: variantReads(dataset: gnomad_sv_r3, variantId: "123-45-A-G") { + exome { + bamPath + category + indexPath + readGroup + } + genome { + bamPath + category + indexPath + readGroup + } + } + } + " +`; diff --git a/browser/src/RegionPage/__snapshots__/MitochondrialRegionCoverageTrack.spec.tsx.snap b/browser/src/RegionPage/__snapshots__/MitochondrialRegionCoverageTrack.spec.tsx.snap index acdd35e7c..7e8d564cd 100644 --- a/browser/src/RegionPage/__snapshots__/MitochondrialRegionCoverageTrack.spec.tsx.snap +++ b/browser/src/RegionPage/__snapshots__/MitochondrialRegionCoverageTrack.spec.tsx.snap @@ -350,3 +350,36 @@ query MitochondrialCoverageInRegion($start: Int!, $stop: Int!, $datasetId: Datas [Function] `; + +exports[`MitochondrialRegionCoverageTrack with dataset gnomad_sv_r3 queries with appropriate params 1`] = ` + + [Function] + +`; diff --git a/browser/src/RegionPage/__snapshots__/MitochondrialVariantsInRegion.spec.tsx.snap b/browser/src/RegionPage/__snapshots__/MitochondrialVariantsInRegion.spec.tsx.snap index 441a082ca..86c41a56c 100644 --- a/browser/src/RegionPage/__snapshots__/MitochondrialVariantsInRegion.spec.tsx.snap +++ b/browser/src/RegionPage/__snapshots__/MitochondrialVariantsInRegion.spec.tsx.snap @@ -404,3 +404,36 @@ exports[`MitochondrialVariantsInRegion with dataset gnomad_sv_r2_1_non_neuro has , ] `; + +exports[`MitochondrialVariantsInRegion with dataset gnomad_sv_r3 has no unexpected changes 1`] = ` +[ +
+

+ ClinVar variants +

+
, +

+ No ClinVar variants found in this region. +

, +
+

+ gnomAD variants +

+

+ No gnomAD variants found. +

+
, +] +`; diff --git a/browser/src/RegionPage/__snapshots__/RegionPage.spec.tsx.snap b/browser/src/RegionPage/__snapshots__/RegionPage.spec.tsx.snap index a58eced40..416eff2bd 100644 --- a/browser/src/RegionPage/__snapshots__/RegionPage.spec.tsx.snap +++ b/browser/src/RegionPage/__snapshots__/RegionPage.spec.tsx.snap @@ -4208,3 +4208,302 @@ exports[`RegionPage with "gnomad_sv_r2_1_non_neuro" dataset has no unexpected ch `; + +exports[`RegionPage with "gnomad_sv_r3" dataset has no unexpected changes for a mitochondrial region 1`] = ` + + + + + } + selectedDataset="gnomad_sv_r3" + > + M-345-456 + + +
+ +
+ + + +
+
+ + + + + + + + +
+`; + +exports[`RegionPage with "gnomad_sv_r3" dataset has no unexpected changes for a non-mitochondrial region 1`] = ` + + + + + } + selectedDataset="gnomad_sv_r3" + > + 12-345-456 + + +
+ +
+ + + +
+
+ + + + + + + + +
+`; diff --git a/browser/src/RegionPage/__snapshots__/RegionPageContainer.spec.tsx.snap b/browser/src/RegionPage/__snapshots__/RegionPageContainer.spec.tsx.snap index bbf6aeb32..c7a88d256 100644 --- a/browser/src/RegionPage/__snapshots__/RegionPageContainer.spec.tsx.snap +++ b/browser/src/RegionPage/__snapshots__/RegionPageContainer.spec.tsx.snap @@ -839,3 +839,59 @@ exports[`RegionPageContainer with dataset gnomad_sv_r2_1_non_neuro queries API w [Function] `; + +exports[`RegionPageContainer with dataset gnomad_sv_r3 queries API with correct parameters 1`] = ` + + [Function] + +`; diff --git a/browser/src/TranscriptPage/__snapshots__/MitochondrialTranscriptCoverageTrack.spec.tsx.snap b/browser/src/TranscriptPage/__snapshots__/MitochondrialTranscriptCoverageTrack.spec.tsx.snap index 54f391676..d2b7aceec 100644 --- a/browser/src/TranscriptPage/__snapshots__/MitochondrialTranscriptCoverageTrack.spec.tsx.snap +++ b/browser/src/TranscriptPage/__snapshots__/MitochondrialTranscriptCoverageTrack.spec.tsx.snap @@ -341,3 +341,35 @@ query MitochondrialCoverageInTranscript($transcriptId: String!, $datasetId: Data [Function] `; + +exports[`MitochondrialTranscriptCoverageTrack with dataset gnomad_sv_r3 queries with proper parameters 1`] = ` + + [Function] + +`; diff --git a/browser/src/TranscriptPage/__snapshots__/MitochondrialVariantsInTranscript.spec.tsx.snap b/browser/src/TranscriptPage/__snapshots__/MitochondrialVariantsInTranscript.spec.tsx.snap index 3b60cc077..a785a2aa1 100644 --- a/browser/src/TranscriptPage/__snapshots__/MitochondrialVariantsInTranscript.spec.tsx.snap +++ b/browser/src/TranscriptPage/__snapshots__/MitochondrialVariantsInTranscript.spec.tsx.snap @@ -404,3 +404,36 @@ exports[`MitochondrialVariantsInTranscript with dataset gnomad_sv_r2_1_non_neuro , ] `; + +exports[`MitochondrialVariantsInTranscript with dataset gnomad_sv_r3 has no unexpected changes 1`] = ` +[ +
+

+ ClinVar variants +

+
, +

+ No ClinVar variants found in this transcript. +

, +
+

+ gnomAD variants +

+

+ No gnomAD variants found. +

+
, +] +`; diff --git a/browser/src/TranscriptPage/__snapshots__/TranscriptPage.spec.tsx.snap b/browser/src/TranscriptPage/__snapshots__/TranscriptPage.spec.tsx.snap index baf59ee5f..bf71b3280 100644 --- a/browser/src/TranscriptPage/__snapshots__/TranscriptPage.spec.tsx.snap +++ b/browser/src/TranscriptPage/__snapshots__/TranscriptPage.spec.tsx.snap @@ -9713,3 +9713,650 @@ exports[`TranscriptPage with dataset "gnomad_sv_r2_1_non_neuro" has no unexpecte `; + +exports[`TranscriptPage with dataset "gnomad_sv_r3" has no unexpected changes 1`] = ` +
+
+
+
+

+ Transcript: + dummy_transcript + . + 12.34.5 +

+
+ +
+
+
+
+
+
+ Genome build +
+
+ GRCh37 + / + hg19 +
+
+
+
+ Ensembl ID +
+
+ dummy_transcript + . + 12.34.5 +
+
+ +
+
+ Region +
+
+ + 13 + : + 123 + - + 321 + +
+
+
+
+ External resources +
+
+ + Ensembl + + , + + + UCSC Browser + +
+
+
+
+
+

+ Constraint + +

+

+ Constraint not yet available for gnomAD v3. +

+
+
+
+ Viewing full + transcript + . + + +
+
+
+
+ Include: +
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+
+
+
+
+
+ +
+
+
+ + + +
+
+
+
+
+
+
+
+`; diff --git a/browser/src/TranscriptPage/__snapshots__/TranscriptPageContainer.spec.tsx.snap b/browser/src/TranscriptPage/__snapshots__/TranscriptPageContainer.spec.tsx.snap index 5d7494573..44b3199de 100644 --- a/browser/src/TranscriptPage/__snapshots__/TranscriptPageContainer.spec.tsx.snap +++ b/browser/src/TranscriptPage/__snapshots__/TranscriptPageContainer.spec.tsx.snap @@ -14963,3 +14963,5 @@ exports[`TranscriptPageContainer with dataset gnomad_sv_r2_1 has no unexpected c exports[`TranscriptPageContainer with dataset gnomad_sv_r2_1_controls has no unexpected changes 1`] = `null`; exports[`TranscriptPageContainer with dataset gnomad_sv_r2_1_non_neuro has no unexpected changes 1`] = `null`; + +exports[`TranscriptPageContainer with dataset gnomad_sv_r3 has no unexpected changes 1`] = `null`; diff --git a/browser/src/__snapshots__/DatasetSelector.spec.tsx.snap b/browser/src/__snapshots__/DatasetSelector.spec.tsx.snap index 015a90ec3..c2f899b2f 100644 --- a/browser/src/__snapshots__/DatasetSelector.spec.tsx.snap +++ b/browser/src/__snapshots__/DatasetSelector.spec.tsx.snap @@ -8009,3 +8009,537 @@ exports[`DataSelector with "gnomad_sv_r2_1_non_neuro" dataset selected has no un `; + +exports[`DataSelector with "gnomad_sv_r3" dataset selected has no unexpected changes 1`] = ` +.c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding: 0; + border: 1px solid #6c757d; + border-radius: 0.5em; + margin: 0; + list-style-type: none; +} + +.c3 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + box-sizing: border-box; + height: 100%; + padding: 0.375em 0.25em; + color: #000; + outline: none; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c3:visited { + color: #000; +} + +.c3:focus { + box-shadow: 0 0 0 0.2em rgba(66,139,202,0.5); +} + +.c9 { + position: relative; + display: inline-block; +} + +.c9 .c2 { + background: #cbd3da; +} + +.c9:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c9:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c1 { + position: relative; + display: inline-block; +} + +.c1 .c2 { + background: none; +} + +.c1:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c1:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c4 img { + position: relative; + top: 0.11em; + width: 0.9em; + height: 0.9em; +} + +.c5 { + position: absolute; + z-index: 1; + right: 0; + display: none; + width: 220px; + padding: 0.5em 0; + border: 1px solid #6c757d; + margin: 0; + background: #f8f9fa; + list-style-type: none; +} + +.c7 { + display: inline-block; + box-sizing: border-box; + width: 100%; + padding: 0.25em 0.5em; + color: #000; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c7:visited { + color: #000; +} + +.c7:active, +.c7:focus, +.c7:hover { + background: rgba(66,139,202,0.25); +} + +.c7:focus { + outline: 2px solid #428bca; +} + +.c8 { + margin-top: 0.125em; + margin-left: 5px; + font-size: 0.8em; + opacity: 0.6; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + margin-left: 2px; + font-weight: bold; +} + +@media (max-width:1200px) { + .c5 { + right: auto; + left: -100px; + } +} + +@media (max-width:900px) { + .c5 { + left: -150px; + } +} + + +`; diff --git a/browser/src/variantFeedback.spec.ts b/browser/src/variantFeedback.spec.ts index 272327410..d3ed799a5 100644 --- a/browser/src/variantFeedback.spec.ts +++ b/browser/src/variantFeedback.spec.ts @@ -33,6 +33,8 @@ const expectedResults: Record = { 'http://example.com/variant_report_form?dataset_id_parameter=gnomAD%20v2&variant_id_param=1-234-A-C', gnomad_sv_r2_1_non_neuro: 'http://example.com/variant_report_form?dataset_id_parameter=gnomAD%20v2&variant_id_param=1-234-A-C', + gnomad_sv_r3: + 'http://example.com/variant_report_form?dataset_id_parameter=gnomAD%20v3&variant_id_param=1-234-A-C', } const originalEnv = process.env diff --git a/dataset-metadata/metadata.spec.ts b/dataset-metadata/metadata.spec.ts index 3ee1269cd..015130969 100644 --- a/dataset-metadata/metadata.spec.ts +++ b/dataset-metadata/metadata.spec.ts @@ -203,6 +203,7 @@ const expectedCoverageDatasetIds: Record = { gnomad_sv_r2_1: 'gnomad_r2_1', gnomad_sv_r2_1_controls: 'gnomad_r2_1', gnomad_sv_r2_1_non_neuro: 'gnomad_r2_1', + gnomad_sv_r3: 'gnomad_r3', } describe.each(allDatasetIds)('coverageDataset for dataset %s', (datasetId: DatasetId) => { diff --git a/dataset-metadata/metadata.ts b/dataset-metadata/metadata.ts index e7420e201..f51460fda 100644 --- a/dataset-metadata/metadata.ts +++ b/dataset-metadata/metadata.ts @@ -16,6 +16,7 @@ export const datasetLabels = { gnomad_sv_r2_1: 'gnomAD SVs v2.1', gnomad_sv_r2_1_controls: 'gnomAD SVs v2.1 (controls)', gnomad_sv_r2_1_non_neuro: 'gnomAD SVs v2.1 (non-neuro)', + gnomad_sv_r3: 'gnomAD SVs v3', } as const export type DatasetId = keyof typeof datasetLabels @@ -50,16 +51,21 @@ const extractCoverageDatasetId = (datasetId: DatasetId): DatasetId => { return 'gnomad_r2_1' } - // SVs should show gnomAD 2.1 coverage - if (datasetId.startsWith('gnomad_sv')) { + // v2 SVs should show gnomAD 2.1 coverage + if (datasetId.startsWith('gnomad_sv_r2')) { return 'gnomad_r2_1' } + // v3 SVs should show gnomAD 3.1.2 coverage + if (datasetId.startsWith('gnomad_sv_r3')) { + return 'gnomad_r3' + } + return datasetId } const extractVariantFeedbackDescription = (datasetId: DatasetId): string | null => { - if (datasetId.startsWith('gnomad_r3')) { + if (datasetId.startsWith('gnomad_r3') || datasetId.startsWith('gnomad_sv_r3')) { return 'gnomAD v3' } if (datasetId.startsWith('gnomad_r2') || datasetId.startsWith('gnomad_sv_r2')) { @@ -118,20 +124,21 @@ const metadataForDataset = (datasetId: DatasetId): DatasetMetadata => ({ isV3Subset: !fullDatasetIds.includes(datasetId) && datasetId.startsWith('gnomad_r3'), hasShortVariants: !structuralVariantDatasetIds.includes(datasetId), hasStructuralVariants: structuralVariantDatasetIds.includes(datasetId), - hasConstraints: !datasetId.startsWith('gnomad_r3'), hasVariantCoocurrence: datasetId.startsWith('gnomad') && datasetId.includes('r2'), - hasNonCodingConstraints: datasetId.startsWith('gnomad_r3'), - referenceGenome: datasetId.startsWith('gnomad_r3') ? 'GRCh38' : 'GRCh37', - hasExome: !datasetId.startsWith('gnomad_r3'), - genesHaveExomeCoverage: !datasetId.startsWith('gnomad_r3'), - transcriptsHaveExomeCoverage: !datasetId.startsWith('gnomad_r3'), + hasConstraints: !datasetId.startsWith('gnomad_r3') && datasetId !== 'gnomad_sv_r3', + hasNonCodingConstraints: datasetId.startsWith('gnomad_r3') || datasetId === 'gnomad_sv_r3', + referenceGenome: + datasetId.startsWith('gnomad_r3') || datasetId === 'gnomad_sv_r3' ? 'GRCh38' : 'GRCh37', + hasExome: !datasetId.startsWith('gnomad_r3') && datasetId !== 'gnomad_sv_r3', + genesHaveExomeCoverage: !datasetId.startsWith('gnomad_r3') && datasetId !== 'gnomad_sv_r3', + transcriptsHaveExomeCoverage: !datasetId.startsWith('gnomad_r3') && datasetId !== 'gnomad_sv_r3', regionsHaveExomeCoverage: !datasetId.startsWith('gnomad_sv') && !datasetId.startsWith('gnomad_r3'), - hasLocalAncestryPopulations: datasetId.startsWith('gnomad_r3'), + hasLocalAncestryPopulations: datasetId.startsWith('gnomad_r3') || datasetId === 'gnomad_sv_r3', isLiftoverSource: datasetId.startsWith('gnomad_r2_1'), isLiftoverTarget: datasetId.startsWith('gnomad_r3'), - usesGrch37: !datasetId.startsWith('gnomad_r3'), - usesGrch38: datasetId.startsWith('gnomad_r3'), + usesGrch37: !datasetId.startsWith('gnomad_r3') && datasetId !== 'gnomad_sv_r3', + usesGrch38: datasetId.startsWith('gnomad_r3') || datasetId === 'gnomad_sv_r3', isV2: datasetId.startsWith('gnomad_r2'), isV3: datasetId.startsWith('gnomad_r3'), isSVs: datasetId.startsWith('gnomad_sv'), @@ -144,7 +151,7 @@ const metadataForDataset = (datasetId: DatasetId): DatasetMetadata => ({ hasRelatedVariants: datasetId !== 'gnomad_r2_1', showAllIndividualsInAgeDistributionByDefault: datasetId !== 'exac', hasExons: !datasetId.startsWith('gnomad_sv'), - hasShortTandemRepeats: datasetId.startsWith('gnomad_r3'), + hasShortTandemRepeats: datasetId.startsWith('gnomad_r3') || datasetId === 'gnomad_sv_r3', hasMitochondrialGenomeCoverage: !(datasetId === 'exac' || datasetId.startsWith('gnomad_r2')), hasMitochondrialVariants: !(datasetId === 'exac' || datasetId.startsWith('gnomad_r2')), hasNonCodingReadData: !(datasetId === 'exac' || datasetId.startsWith('gnomad_r2')), From b98979b9c97e7a3104e5c7eecf1960b14c762f5f Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Fri, 16 Jun 2023 16:44:28 -0400 Subject: [PATCH 07/24] Add v3 SVs option to main Searchbox --- browser/src/Searchbox.spec.tsx | 54 + browser/src/Searchbox.tsx | 4 + .../src/__snapshots__/HomePage.spec.tsx.snap | 5 + .../src/__snapshots__/NavBar.spec.tsx.snap | 5 + .../src/__snapshots__/Searchbox.spec.tsx.snap | 1327 +++++++++++++++++ 5 files changed, 1395 insertions(+) create mode 100644 browser/src/Searchbox.spec.tsx create mode 100644 browser/src/__snapshots__/Searchbox.spec.tsx.snap diff --git a/browser/src/Searchbox.spec.tsx b/browser/src/Searchbox.spec.tsx new file mode 100644 index 000000000..6df5ea760 --- /dev/null +++ b/browser/src/Searchbox.spec.tsx @@ -0,0 +1,54 @@ +import React from 'react' +import { describe, test, expect } from '@jest/globals' +import { forAllDatasets } from '../../tests/__helpers__/datasets' +import { withDummyRouter } from '../../tests/__helpers__/router' +import renderer from 'react-test-renderer' +import { createBrowserHistory } from 'history' + +import Searchbox from './Searchbox' +import { DatasetId } from '@gnomad/dataset-metadata/metadata' + +describe('Searchbox', () => { + test('has no unexpected changes when no dataset specified', () => { + const tree = renderer.create(withDummyRouter()) + expect(tree).toMatchSnapshot() + }) + + forAllDatasets('with selected dataset %s', (datasetId) => { + test('has no unexpected changes', () => { + const history = createBrowserHistory() + history.push(`/?dataset=${datasetId}`) + const tree = renderer.create(withDummyRouter()) + expect(tree).toMatchSnapshot() + }) + + const expectedDefaultDatasets: Record = { + exac: 'exac', + gnomad_r2_1: 'gnomad_r2_1', + gnomad_r2_1_controls: 'gnomad_r2_1', + gnomad_r2_1_non_cancer: 'gnomad_r2_1', + gnomad_r2_1_non_neuro: 'gnomad_r2_1', + gnomad_r2_1_non_topmed: 'gnomad_r2_1', + gnomad_r3: 'gnomad_r3', + gnomad_r3_controls_and_biobanks: 'gnomad_r3', + gnomad_r3_non_cancer: 'gnomad_r3', + gnomad_r3_non_neuro: 'gnomad_r3', + gnomad_r3_non_topmed: 'gnomad_r3', + gnomad_r3_non_v2: 'gnomad_r3', + gnomad_sv_r2_1: 'gnomad_sv_r2_1', + gnomad_sv_r2_1_controls: 'gnomad_sv_r2_1', + gnomad_sv_r2_1_non_neuro: 'gnomad_sv_r2_1', + gnomad_sv_r3: 'gnomad_sv_r3', + } + + test('has correct default dataset', () => { + const expectedDefaultDataset = expectedDefaultDatasets[datasetId] + const history = createBrowserHistory() + history.push(`/?dataset=${datasetId}`) + const tree = renderer.create(withDummyRouter()) + const datasetSelect = tree.root.findByType('select') + const defaultDataset = datasetSelect.props['value'] + expect(defaultDataset).toEqual(expectedDefaultDataset) + }) + }) +}) diff --git a/browser/src/Searchbox.tsx b/browser/src/Searchbox.tsx index 2d5580ca9..06e27dbf5 100644 --- a/browser/src/Searchbox.tsx +++ b/browser/src/Searchbox.tsx @@ -38,6 +38,9 @@ const getDefaultSearchDataset = (selectedDataset: any) => { if (selectedDataset === 'exac') { return 'exac' } + if (selectedDataset === 'gnomad_sv_r3') { + return 'gnomad_sv_r3' + } } return 'gnomad_r2_1' } @@ -82,6 +85,7 @@ export default withRouter((props: any) => { > + diff --git a/browser/src/__snapshots__/HomePage.spec.tsx.snap b/browser/src/__snapshots__/HomePage.spec.tsx.snap index 3eb355a72..0495ad2fd 100644 --- a/browser/src/__snapshots__/HomePage.spec.tsx.snap +++ b/browser/src/__snapshots__/HomePage.spec.tsx.snap @@ -205,6 +205,11 @@ exports[`Home Page has no unexpected changes 1`] = ` > gnomAD v3.1.2 + gnomAD v3.1.2 + + + +
+ +
+
+
+`; + +exports[`Searchbox with selected dataset exac has no unexpected changes 1`] = ` +
+ + +
+ +
+
+
+`; + +exports[`Searchbox with selected dataset gnomad_r2_1 has no unexpected changes 1`] = ` +
+ + +
+ +
+
+
+`; + +exports[`Searchbox with selected dataset gnomad_r2_1_controls has no unexpected changes 1`] = ` +
+ + +
+ +
+
+
+`; + +exports[`Searchbox with selected dataset gnomad_r2_1_non_cancer has no unexpected changes 1`] = ` +
+ + +
+ +
+
+
+`; + +exports[`Searchbox with selected dataset gnomad_r2_1_non_neuro has no unexpected changes 1`] = ` +
+ + +
+ +
+
+
+`; + +exports[`Searchbox with selected dataset gnomad_r2_1_non_topmed has no unexpected changes 1`] = ` +
+ + +
+ +
+
+
+`; + +exports[`Searchbox with selected dataset gnomad_r3 has no unexpected changes 1`] = ` +
+ + +
+ +
+
+
+`; + +exports[`Searchbox with selected dataset gnomad_r3_controls_and_biobanks has no unexpected changes 1`] = ` +
+ + +
+ +
+
+
+`; + +exports[`Searchbox with selected dataset gnomad_r3_non_cancer has no unexpected changes 1`] = ` +
+ + +
+ +
+
+
+`; + +exports[`Searchbox with selected dataset gnomad_r3_non_neuro has no unexpected changes 1`] = ` +
+ + +
+ +
+
+
+`; + +exports[`Searchbox with selected dataset gnomad_r3_non_topmed has no unexpected changes 1`] = ` +
+ + +
+ +
+
+
+`; + +exports[`Searchbox with selected dataset gnomad_r3_non_v2 has no unexpected changes 1`] = ` +
+ + +
+ +
+
+
+`; + +exports[`Searchbox with selected dataset gnomad_sv_r2_1 has no unexpected changes 1`] = ` +
+ + +
+ +
+
+
+`; + +exports[`Searchbox with selected dataset gnomad_sv_r2_1_controls has no unexpected changes 1`] = ` +
+ + +
+ +
+
+
+`; + +exports[`Searchbox with selected dataset gnomad_sv_r2_1_non_neuro has no unexpected changes 1`] = ` +
+ + +
+ +
+
+
+`; + +exports[`Searchbox with selected dataset gnomad_sv_r3 has no unexpected changes 1`] = ` +
+ + +
+ +
+
+
+`; From 08903e8f7ed7f20412b8f2bbf5f449a46bf948dd Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Tue, 20 Jun 2023 14:06:49 -0400 Subject: [PATCH 08/24] Eliminate PropTypes from StructuralVariantPage --- .../MultiallelicCopyNumberVariantPlot.tsx | 19 ++-- .../StructuralVariantPage/SVReferenceList.tsx | 6 +- .../StructuralVariantAgeDistribution.tsx | 4 +- .../StructuralVariantAttributeList.tsx | 4 +- .../StructuralVariantConsequenceList.tsx | 4 +- .../StructuralVariantDetailPropType.ts | 101 ------------------ ...tructuralVariantGenotypeQualityMetrics.tsx | 4 +- .../StructuralVariantPage.tsx | 43 +++++++- .../StructuralVariantPopulationsTable.tsx | 4 +- 9 files changed, 62 insertions(+), 127 deletions(-) delete mode 100644 browser/src/StructuralVariantPage/StructuralVariantDetailPropType.ts diff --git a/browser/src/StructuralVariantPage/MultiallelicCopyNumberVariantPlot.tsx b/browser/src/StructuralVariantPage/MultiallelicCopyNumberVariantPlot.tsx index 7b1eb86a3..b6b0857c5 100644 --- a/browser/src/StructuralVariantPage/MultiallelicCopyNumberVariantPlot.tsx +++ b/browser/src/StructuralVariantPage/MultiallelicCopyNumberVariantPlot.tsx @@ -7,7 +7,7 @@ import { AxisBottom, AxisLeft } from '@vx/axis' import { TooltipAnchor } from '@gnomad/ui' -import StructuralVariantDetailPropType from './StructuralVariantDetailPropType' +import { StructuralVariant } from './StructuralVariantPage' // The 100% width/height container is necessary the component // to size to fit its container vs staying at its initial size. @@ -51,8 +51,12 @@ const labelProps = { textAnchor: 'middle', } -// @ts-expect-error TS(2339) FIXME: Property 'variant' does not exist on type '{}'. -const MultiallelicCopyNumberVariantPlot = withSize()(({ variant, size: { width } }) => { +type Props = { + variant: StructuralVariant + size: { width: number } +} + +const MultiallelicCopyNumberVariantPlot = withSize()(({ variant, size: { width } }: Props) => { const height = 250 const xScale = scaleBand() @@ -65,7 +69,7 @@ const MultiallelicCopyNumberVariantPlot = withSize()(({ variant, size: { width } .domain([0, max(variant.copy_numbers, (d: any) => d.ac) || 1]) .range([height - (margin.top + margin.bottom), margin.top]) - const labelInterval = Math.max(Math.round(variant.copy_numbers.length / 100) * 10, 1) + const labelInterval = Math.max(Math.round((variant.copy_numbers || []).length / 100) * 10, 1) return ( @@ -93,7 +97,7 @@ const MultiallelicCopyNumberVariantPlot = withSize()(({ variant, size: { width } top={margin.top} /> - {variant.copy_numbers.map(({ copy_number: copyNumber, ac }: any) => ( + {(variant.copy_numbers || []).map(({ copy_number: copyNumber, ac }: any) => ( `https://genome.ucsc.edu/cgi-bin/hgTracks?db=hg19&position=chr${chrom}%3A${pos}-${end}` type SVUCSCLinksProps = { - variant: StructuralVariantDetailPropType + variant: StructuralVariant } const SVUCSCLinks = ({ variant }: SVUCSCLinksProps) => { @@ -49,7 +49,7 @@ const SVUCSCLinks = ({ variant }: SVUCSCLinksProps) => { } type SVReferenceListProps = { - variant: StructuralVariantDetailPropType + variant: StructuralVariant } const SVReferenceList = ({ variant }: SVReferenceListProps) => ( diff --git a/browser/src/StructuralVariantPage/StructuralVariantAgeDistribution.tsx b/browser/src/StructuralVariantPage/StructuralVariantAgeDistribution.tsx index 761714979..cdebaca37 100644 --- a/browser/src/StructuralVariantPage/StructuralVariantAgeDistribution.tsx +++ b/browser/src/StructuralVariantPage/StructuralVariantAgeDistribution.tsx @@ -9,7 +9,7 @@ import overallAgeDistribution from '@gnomad/dataset-metadata/datasets/gnomad-sv- import Legend, { StripedSwatch } from '../Legend' import StackedHistogram from '../StackedHistogram' import ControlSection from '../VariantPage/ControlSection' -import StructuralVariantDetailPropType from './StructuralVariantDetailPropType' +import { StructuralVariant } from './StructuralVariantPage' const LegendWrapper = styled.div` display: flex; @@ -25,7 +25,7 @@ const CheckboxWrapper = styled.div` ` type Props = { - variant: StructuralVariantDetailPropType + variant: StructuralVariant } const StructuralVariantAgeDistribution = ({ variant }: Props) => { diff --git a/browser/src/StructuralVariantPage/StructuralVariantAttributeList.tsx b/browser/src/StructuralVariantPage/StructuralVariantAttributeList.tsx index 5a97634ea..bc3a6e4ad 100644 --- a/browser/src/StructuralVariantPage/StructuralVariantAttributeList.tsx +++ b/browser/src/StructuralVariantPage/StructuralVariantAttributeList.tsx @@ -6,7 +6,7 @@ import AttributeList from '../AttributeList' import InfoButton from '../help/InfoButton' import Link from '../Link' import { svTypeLabels } from '../StructuralVariantList/structuralVariantTypes' -import StructuralVariantDetailPropType from './StructuralVariantDetailPropType' +import { StructuralVariant } from './StructuralVariantPage' const FILTER_LABELS = { LOW_CALL_RATE: 'Low Call Rate', @@ -120,7 +120,7 @@ ComplexTypeHelpButton.defaultProps = { } type StructuralVariantAttributeListProps = { - variant: StructuralVariantDetailPropType + variant: StructuralVariant } const StructuralVariantAttributeList = ({ variant }: StructuralVariantAttributeListProps) => ( diff --git a/browser/src/StructuralVariantPage/StructuralVariantConsequenceList.tsx b/browser/src/StructuralVariantPage/StructuralVariantConsequenceList.tsx index ff9f8a9fa..13a98572a 100644 --- a/browser/src/StructuralVariantPage/StructuralVariantConsequenceList.tsx +++ b/browser/src/StructuralVariantPage/StructuralVariantConsequenceList.tsx @@ -9,7 +9,7 @@ import { svConsequenceCategories, svConsequenceLabels, } from '../StructuralVariantList/structuralVariantConsequences' -import StructuralVariantDetailPropType from './StructuralVariantDetailPropType' +import { StructuralVariant } from './StructuralVariantPage' const Wrapper = styled.ol` display: flex; @@ -29,7 +29,7 @@ const ConsequenceListItem = styled.li` ` type Props = { - variant: StructuralVariantDetailPropType + variant: StructuralVariant } type State = any diff --git a/browser/src/StructuralVariantPage/StructuralVariantDetailPropType.ts b/browser/src/StructuralVariantPage/StructuralVariantDetailPropType.ts deleted file mode 100644 index 8f52297d5..000000000 --- a/browser/src/StructuralVariantPage/StructuralVariantDetailPropType.ts +++ /dev/null @@ -1,101 +0,0 @@ -import PropTypes from 'prop-types' - -type HistogramPropType = { - bin_edges: number[] - bin_freq: number[] - n_smaller: number - n_larger: number -} - -// @ts-expect-error TS(2322) FIXME: Type 'Requireable = PropTypes.shape({ - bin_edges: PropTypes.arrayOf(PropTypes.number).isRequired, - bin_freq: PropTypes.arrayOf(PropTypes.number).isRequired, - n_smaller: PropTypes.number.isRequired, - n_larger: PropTypes.number.isRequired, -}) - -type StructuralVariantDetailPropType = { - age_distribution?: { - het: HistogramPropType - hom: HistogramPropType - } - algorithms?: string[] - alts?: string[] - ac: number - an: number - chrom: string - chrom2?: string - consequences: { - consequence: string - genes: string[] - }[] - copy_numbers?: { - copy_number: number - ac: number - }[] - cpx_intervals?: string[] - cpx_type?: string - end: number - end2?: number - evidence: string[] - filters?: string[] - genes: string[] - genotype_quality?: { - all: HistogramPropType - alt: HistogramPropType - } - length: number - pos: number - pos2?: number - qual: number - type: string - variant_id: string -} - -// @ts-expect-error TS(2322) FIXME: Type 'Requireable = PropTypes.shape( - { - age_distribution: PropTypes.shape({ - het: HistogramPropType.isRequired, - hom: HistogramPropType.isRequired, - }), - algorithms: PropTypes.arrayOf(PropTypes.string.isRequired), - alts: PropTypes.arrayOf(PropTypes.string.isRequired), - ac: PropTypes.number.isRequired, - an: PropTypes.number.isRequired, - chrom: PropTypes.string.isRequired, - chrom2: PropTypes.string, - consequences: PropTypes.arrayOf( - PropTypes.shape({ - consequence: PropTypes.string.isRequired, - genes: PropTypes.arrayOf(PropTypes.string).isRequired, - }) - ).isRequired, - copy_numbers: PropTypes.arrayOf( - PropTypes.shape({ - copy_number: PropTypes.number.isRequired, - ac: PropTypes.number.isRequired, - }) - ), - cpx_intervals: PropTypes.arrayOf(PropTypes.string), - cpx_type: PropTypes.string, - end: PropTypes.number.isRequired, - end2: PropTypes.number, - evidence: PropTypes.arrayOf(PropTypes.string).isRequired, - filters: PropTypes.arrayOf(PropTypes.string.isRequired), - genes: PropTypes.arrayOf(PropTypes.string).isRequired, - genotype_quality: PropTypes.shape({ - all: HistogramPropType.isRequired, - alt: HistogramPropType.isRequired, - }), - length: PropTypes.number.isRequired, - pos: PropTypes.number.isRequired, - pos2: PropTypes.number, - qual: PropTypes.number.isRequired, - type: PropTypes.string.isRequired, - variant_id: PropTypes.string.isRequired, - } -) - -export default StructuralVariantDetailPropType diff --git a/browser/src/StructuralVariantPage/StructuralVariantGenotypeQualityMetrics.tsx b/browser/src/StructuralVariantPage/StructuralVariantGenotypeQualityMetrics.tsx index feb8a917d..52c89d1fd 100644 --- a/browser/src/StructuralVariantPage/StructuralVariantGenotypeQualityMetrics.tsx +++ b/browser/src/StructuralVariantPage/StructuralVariantGenotypeQualityMetrics.tsx @@ -6,7 +6,7 @@ import { Checkbox } from '@gnomad/ui' import Legend, { StripedSwatch } from '../Legend' import StackedHistogram from '../StackedHistogram' -import StructuralVariantDetailPropType from './StructuralVariantDetailPropType' +import { StructuralVariant } from './StructuralVariantPage' const LegendWrapper = styled.div` display: flex; @@ -15,7 +15,7 @@ const LegendWrapper = styled.div` ` type Props = { - variant: StructuralVariantDetailPropType + variant: StructuralVariant } const StructuralVariantGenotypeQualityMetrics = ({ variant }: Props) => { diff --git a/browser/src/StructuralVariantPage/StructuralVariantPage.tsx b/browser/src/StructuralVariantPage/StructuralVariantPage.tsx index 4db2a7baa..94b5fcc60 100644 --- a/browser/src/StructuralVariantPage/StructuralVariantPage.tsx +++ b/browser/src/StructuralVariantPage/StructuralVariantPage.tsx @@ -6,6 +6,7 @@ import { ExternalLink, Page } from '@gnomad/ui' import { DatasetId, labelForDataset } from '@gnomad/dataset-metadata/metadata' import DocumentTitle from '../DocumentTitle' import GnomadPageHeading from '../GnomadPageHeading' +import { Histogram } from '../VariantPage/VariantPage' import InfoButton from '../help/InfoButton' import Query from '../Query' import { variantFeedbackUrl } from '../variantFeedback' @@ -13,7 +14,6 @@ import MultiallelicCopyNumberVariantPlot from './MultiallelicCopyNumberVariantPl import StructuralVariantAgeDistribution from './StructuralVariantAgeDistribution' import StructuralVariantAttributeList from './StructuralVariantAttributeList' import StructuralVariantConsequenceList from './StructuralVariantConsequenceList' -import StructuralVariantDetailPropType from './StructuralVariantDetailPropType' import StructuralVariantGenotypeQualityMetrics from './StructuralVariantGenotypeQualityMetrics' import StructuralVariantPopulationsTable from './StructuralVariantPopulationsTable' import SVReferenceList from './SVReferenceList' @@ -32,9 +32,47 @@ const ResponsiveSection = styled.section` } ` +export type StructuralVariant = { + age_distribution?: { + het: Histogram + hom: Histogram + } + algorithms?: string[] + alts?: string[] + ac: number + an: number + chrom: string + chrom2?: string + consequences: { + consequence: string + genes: string[] + }[] + copy_numbers?: { + copy_number: number + ac: number + }[] + cpx_intervals?: string[] + cpx_type?: string + end: number + end2?: number + evidence: string[] + filters?: string[] + genes: string[] + genotype_quality?: { + all: Histogram + alt: Histogram + } + length: number + pos: number + pos2?: number + qual: number + type: string + variant_id: string +} + type StructuralVariantPageProps = { datasetId: DatasetId - variant: StructuralVariantDetailPropType + variant: StructuralVariant } const StructuralVariantPage = ({ datasetId, variant }: StructuralVariantPageProps) => ( @@ -68,7 +106,6 @@ const StructuralVariantPage = ({ datasetId, variant }: StructuralVariantPageProp

Copy Number Distribution

- {/* @ts-expect-error TS(2322) FIXME: Type '{ variant: StructuralVariantDetailPropType; ... Remove this comment to see the full error message */}
diff --git a/browser/src/StructuralVariantPage/StructuralVariantPopulationsTable.tsx b/browser/src/StructuralVariantPage/StructuralVariantPopulationsTable.tsx index f87340ec8..4547c03ea 100644 --- a/browser/src/StructuralVariantPage/StructuralVariantPopulationsTable.tsx +++ b/browser/src/StructuralVariantPage/StructuralVariantPopulationsTable.tsx @@ -1,7 +1,7 @@ import React from 'react' import { PopulationsTable } from '../VariantPage/PopulationsTable' -import StructuralVariantDetailPropType from './StructuralVariantDetailPropType' +import { StructuralVariant } from './StructuralVariantPage' const populationNames = { afr: 'African/African American', @@ -65,7 +65,7 @@ const addPopulationNames = (populations: any) => { } type StructuralVariantPopulationsTableProps = { - variant: StructuralVariantDetailPropType + variant: StructuralVariant } const StructuralVariantPopulationsTable = ({ variant }: StructuralVariantPopulationsTableProps) => { From fe97f258f5390a90b93cebc14fa43675523579e0 Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Wed, 21 Jun 2023 11:46:32 -0400 Subject: [PATCH 09/24] Characterize StructuralVariantPage --- .../MultiallelicCopyNumberVariantPlot.tsx | 1 - .../StructuralVariantAttributeList.tsx | 3 - .../StructuralVariantPage.spec.tsx | 87 + .../StructuralVariantPage.tsx | 33 +- .../StructuralVariantPage.spec.tsx.snap | 14953 ++++++++++++++++ .../src/__factories__/StructuralVariant.ts | 64 + 6 files changed, 15124 insertions(+), 17 deletions(-) create mode 100644 browser/src/StructuralVariantPage/StructuralVariantPage.spec.tsx create mode 100644 browser/src/StructuralVariantPage/__snapshots__/StructuralVariantPage.spec.tsx.snap create mode 100644 browser/src/__factories__/StructuralVariant.ts diff --git a/browser/src/StructuralVariantPage/MultiallelicCopyNumberVariantPlot.tsx b/browser/src/StructuralVariantPage/MultiallelicCopyNumberVariantPlot.tsx index b6b0857c5..2c8cfd5ca 100644 --- a/browser/src/StructuralVariantPage/MultiallelicCopyNumberVariantPlot.tsx +++ b/browser/src/StructuralVariantPage/MultiallelicCopyNumberVariantPlot.tsx @@ -65,7 +65,6 @@ const MultiallelicCopyNumberVariantPlot = withSize()(({ variant, size: { width } .range([0, width - (margin.left + margin.right)]) const yScale = scaleLinear() - // @ts-expect-error TS(2345) FIXME: Argument of type '(string | number)[]' is not assi... Remove this comment to see the full error message .domain([0, max(variant.copy_numbers, (d: any) => d.ac) || 1]) .range([height - (margin.top + margin.bottom), margin.top]) diff --git a/browser/src/StructuralVariantPage/StructuralVariantAttributeList.tsx b/browser/src/StructuralVariantPage/StructuralVariantAttributeList.tsx index bc3a6e4ad..e33316cb4 100644 --- a/browser/src/StructuralVariantPage/StructuralVariantAttributeList.tsx +++ b/browser/src/StructuralVariantPage/StructuralVariantAttributeList.tsx @@ -127,9 +127,7 @@ const StructuralVariantAttributeList = ({ variant }: StructuralVariantAttributeL {/* @ts-expect-error TS(2604) FIXME: JSX element type 'AttributeList.Item' does not hav... Remove this comment to see the full error message */} - {/* @ts-expect-error TS(2532) FIXME: Object is possibly 'undefined'. */} {variant.filters.length > 0 ? ( - // @ts-expect-error TS(2532) FIXME: Object is possibly 'undefined'. variant.filters.map((filter) => ( // @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message @@ -200,7 +198,6 @@ const StructuralVariantAttributeList = ({ variant }: StructuralVariantAttributeL {/* @ts-expect-error TS(2604) FIXME: JSX element type 'AttributeList.Item' does not hav... Remove this comment to see the full error message */} - {/* @ts-expect-error TS(2532) FIXME: Object is possibly 'undefined'. */} {variant.cpx_intervals.join(', ')}
diff --git a/browser/src/StructuralVariantPage/StructuralVariantPage.spec.tsx b/browser/src/StructuralVariantPage/StructuralVariantPage.spec.tsx new file mode 100644 index 000000000..31c0f0a2f --- /dev/null +++ b/browser/src/StructuralVariantPage/StructuralVariantPage.spec.tsx @@ -0,0 +1,87 @@ +import React from 'react' +import renderer from 'react-test-renderer' +import { jest, expect, test, describe } from '@jest/globals' +import { mockQueries } from '../../../tests/__helpers__/queries' +import Query, { BaseQuery } from '../Query' +import { forDatasetsMatching } from '../../../tests/__helpers__/datasets' +import StructuralVariantPage from './StructuralVariantPage' +import svFactory from '../__factories__/StructuralVariant' +import { withDummyRouter } from '../../../tests/__helpers__/router' + +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() +}) + +forDatasetsMatching(/gnomad_sv_r2/, 'StructuralVariantPage with dataset %s', (datasetId) => { + describe.each(['DEL', 'DUP', 'MCNV', 'INS', 'INV', 'CPX'])( + 'with non-interchromosomal variant of type %s', + (variantType: string) => { + test('has no unexpected changes', () => { + const variant = svFactory.build({ type: variantType }) + setMockApiResponses({ + StructuralVariant: () => ({ + structural_variant: variant, + }), + }) + const tree = renderer.create( + withDummyRouter( + + ) + ) + expect(tree).toMatchSnapshot() + }) + } + ) + + describe.each(['BND', 'CTX'])( + 'with interchromosomal variant of type %s', + (variantType: string) => { + test('has no unexpected changes', () => { + const variant = svFactory.build({ + type: variantType, + chrom2: '22', + pos2: 876, + }) + setMockApiResponses({ + StructuralVariant: () => ({ + structural_variant: variant, + }), + }) + const tree = renderer.create( + withDummyRouter( + + ) + ) + expect(tree).toMatchSnapshot() + }) + } + ) +}) diff --git a/browser/src/StructuralVariantPage/StructuralVariantPage.tsx b/browser/src/StructuralVariantPage/StructuralVariantPage.tsx index 94b5fcc60..0edeebebb 100644 --- a/browser/src/StructuralVariantPage/StructuralVariantPage.tsx +++ b/browser/src/StructuralVariantPage/StructuralVariantPage.tsx @@ -33,38 +33,45 @@ const ResponsiveSection = styled.section` ` export type StructuralVariant = { - age_distribution?: { + age_distribution: { het: Histogram hom: Histogram - } - algorithms?: string[] - alts?: string[] + } | null + algorithms: string[] + alts: string[] | null ac: number an: number chrom: string - chrom2?: string + chrom2: string | null consequences: { consequence: string genes: string[] }[] - copy_numbers?: { + copy_numbers: { copy_number: number ac: number }[] - cpx_intervals?: string[] - cpx_type?: string + cpx_intervals: string[] + cpx_type: string | null end: number - end2?: number + end2: number | null evidence: string[] - filters?: string[] + filters: string[] genes: string[] - genotype_quality?: { + genotype_quality: { all: Histogram alt: Histogram - } + } | null length: number + populations: { + id: string + ac: number + an: number + ac_hemi: number + ac_hom: number + }[] pos: number - pos2?: number + pos2: number | null qual: number type: string variant_id: string diff --git a/browser/src/StructuralVariantPage/__snapshots__/StructuralVariantPage.spec.tsx.snap b/browser/src/StructuralVariantPage/__snapshots__/StructuralVariantPage.spec.tsx.snap new file mode 100644 index 000000000..f6f907d91 --- /dev/null +++ b/browser/src/StructuralVariantPage/__snapshots__/StructuralVariantPage.spec.tsx.snap @@ -0,0 +1,14953 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1 with interchromosomal variant of type BND has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + BND_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Allele Count +
+
+ 123 +
+
+
+
+ Allele Number +
+
+ 345 +
+
+
+
+ Allele Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + +
+
+
+
+ Second Position +
+
+ + 22 + : + 876 + +
+
+
+
+ Class +
+
+ breakend + + +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ Total + + 0 + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1 with interchromosomal variant of type CTX has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + CTX_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Allele Count +
+
+ 123 +
+
+
+
+ Allele Number +
+
+ 345 +
+
+
+
+ Allele Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + +
+
+
+
+ Second Position +
+
+ + 22 + : + 876 + +
+
+
+
+ Class +
+
+ translocation + + +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ Total + + 0 + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1 with non-interchromosomal variant of type CPX has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + CPX_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Allele Count +
+
+ 123 +
+
+
+
+ Allele Number +
+
+ 345 +
+
+
+
+ Allele Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + - + 456 + +
+
+
+
+ Size +
+
+ 333 bp +
+
+
+
+ Class +
+
+ complex + + +
+
+
+
+ Complex SV Class +
+
+ ( + ) + +
+
+
+
+ Rearranged Segments +
+
+ +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ Total + + 0 + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1 with non-interchromosomal variant of type DEL has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + DEL_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Allele Count +
+
+ 123 +
+
+
+
+ Allele Number +
+
+ 345 +
+
+
+
+ Allele Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + - + 456 + +
+
+
+
+ Size +
+
+ 333 bp +
+
+
+
+ Class +
+
+ deletion + + +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ Total + + 0 + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1 with non-interchromosomal variant of type DUP has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + DUP_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Allele Count +
+
+ 123 +
+
+
+
+ Allele Number +
+
+ 345 +
+
+
+
+ Allele Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + - + 456 + +
+
+
+
+ Size +
+
+ 333 bp +
+
+
+
+ Class +
+
+ duplication + + +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ Total + + 0 + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1 with non-interchromosomal variant of type INS has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + INS_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Allele Count +
+
+ 123 +
+
+
+
+ Allele Number +
+
+ 345 +
+
+
+
+ Allele Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + +
+
+
+
+ Size +
+
+ 333 bp +
+
+
+
+ Class +
+
+ insertion + + +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ Total + + 0 + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1 with non-interchromosomal variant of type INV has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + INV_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Allele Count +
+
+ 123 +
+
+
+
+ Allele Number +
+
+ 345 +
+
+
+
+ Allele Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + - + 456 + +
+
+
+
+ Size +
+
+ 333 bp +
+
+
+
+ Class +
+
+ inversion + + +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ Total + + 0 + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1 with non-interchromosomal variant of type MCNV has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + MCNV_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Non-Diploid Samples +
+
+ 123 +
+
+
+
+ Total Samples +
+
+ 345 +
+
+
+
+ Non-diploid CN Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + - + 456 + +
+
+
+
+ Size +
+
+ 333 bp +
+
+
+
+ Class +
+
+ multi CNV + + +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + +
+ + + + + + + +
+ Total + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Copy Number Distribution +

+
+ + + + + + + Copy Number + + + + + + + + + + + 0 + + + + + + + + + + 0.1 + + + + + + + + + + 0.2 + + + + + + + + + + 0.3 + + + + + + + + + + 0.4 + + + + + + + + + + 0.5 + + + + + + + + + + 0.6 + + + + + + + + + + 0.7 + + + + + + + + + + 0.8 + + + + + + + + + + 0.9 + + + + + + + + + + 1 + + + + + + + + + Samples + + + + + + +
+
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_controls with interchromosomal variant of type BND has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + BND_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Allele Count +
+
+ 123 +
+
+
+
+ Allele Number +
+
+ 345 +
+
+
+
+ Allele Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + +
+
+
+
+ Second Position +
+
+ + 22 + : + 876 + +
+
+
+
+ Class +
+
+ breakend + + +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ Total + + 0 + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_controls with interchromosomal variant of type CTX has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + CTX_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Allele Count +
+
+ 123 +
+
+
+
+ Allele Number +
+
+ 345 +
+
+
+
+ Allele Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + +
+
+
+
+ Second Position +
+
+ + 22 + : + 876 + +
+
+
+
+ Class +
+
+ translocation + + +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ Total + + 0 + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_controls with non-interchromosomal variant of type CPX has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + CPX_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Allele Count +
+
+ 123 +
+
+
+
+ Allele Number +
+
+ 345 +
+
+
+
+ Allele Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + - + 456 + +
+
+
+
+ Size +
+
+ 333 bp +
+
+
+
+ Class +
+
+ complex + + +
+
+
+
+ Complex SV Class +
+
+ ( + ) + +
+
+
+
+ Rearranged Segments +
+
+ +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ Total + + 0 + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_controls with non-interchromosomal variant of type DEL has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + DEL_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Allele Count +
+
+ 123 +
+
+
+
+ Allele Number +
+
+ 345 +
+
+
+
+ Allele Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + - + 456 + +
+
+
+
+ Size +
+
+ 333 bp +
+
+
+
+ Class +
+
+ deletion + + +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ Total + + 0 + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_controls with non-interchromosomal variant of type DUP has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + DUP_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Allele Count +
+
+ 123 +
+
+
+
+ Allele Number +
+
+ 345 +
+
+
+
+ Allele Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + - + 456 + +
+
+
+
+ Size +
+
+ 333 bp +
+
+
+
+ Class +
+
+ duplication + + +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ Total + + 0 + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_controls with non-interchromosomal variant of type INS has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + INS_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Allele Count +
+
+ 123 +
+
+
+
+ Allele Number +
+
+ 345 +
+
+
+
+ Allele Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + +
+
+
+
+ Size +
+
+ 333 bp +
+
+
+
+ Class +
+
+ insertion + + +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ Total + + 0 + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_controls with non-interchromosomal variant of type INV has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + INV_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Allele Count +
+
+ 123 +
+
+
+
+ Allele Number +
+
+ 345 +
+
+
+
+ Allele Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + - + 456 + +
+
+
+
+ Size +
+
+ 333 bp +
+
+
+
+ Class +
+
+ inversion + + +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ Total + + 0 + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_controls with non-interchromosomal variant of type MCNV has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + MCNV_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Non-Diploid Samples +
+
+ 123 +
+
+
+
+ Total Samples +
+
+ 345 +
+
+
+
+ Non-diploid CN Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + - + 456 + +
+
+
+
+ Size +
+
+ 333 bp +
+
+
+
+ Class +
+
+ multi CNV + + +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + +
+ + + + + + + +
+ Total + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Copy Number Distribution +

+
+ + + + + + + Copy Number + + + + + + + + + + + 0 + + + + + + + + + + 0.1 + + + + + + + + + + 0.2 + + + + + + + + + + 0.3 + + + + + + + + + + 0.4 + + + + + + + + + + 0.5 + + + + + + + + + + 0.6 + + + + + + + + + + 0.7 + + + + + + + + + + 0.8 + + + + + + + + + + 0.9 + + + + + + + + + + 1 + + + + + + + + + Samples + + + + + + +
+
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_non_neuro with interchromosomal variant of type BND has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + BND_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Allele Count +
+
+ 123 +
+
+
+
+ Allele Number +
+
+ 345 +
+
+
+
+ Allele Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + +
+
+
+
+ Second Position +
+
+ + 22 + : + 876 + +
+
+
+
+ Class +
+
+ breakend + + +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ Total + + 0 + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_non_neuro with interchromosomal variant of type CTX has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + CTX_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Allele Count +
+
+ 123 +
+
+
+
+ Allele Number +
+
+ 345 +
+
+
+
+ Allele Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + +
+
+
+
+ Second Position +
+
+ + 22 + : + 876 + +
+
+
+
+ Class +
+
+ translocation + + +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ Total + + 0 + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_non_neuro with non-interchromosomal variant of type CPX has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + CPX_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Allele Count +
+
+ 123 +
+
+
+
+ Allele Number +
+
+ 345 +
+
+
+
+ Allele Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + - + 456 + +
+
+
+
+ Size +
+
+ 333 bp +
+
+
+
+ Class +
+
+ complex + + +
+
+
+
+ Complex SV Class +
+
+ ( + ) + +
+
+
+
+ Rearranged Segments +
+
+ +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ Total + + 0 + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_non_neuro with non-interchromosomal variant of type DEL has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + DEL_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Allele Count +
+
+ 123 +
+
+
+
+ Allele Number +
+
+ 345 +
+
+
+
+ Allele Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + - + 456 + +
+
+
+
+ Size +
+
+ 333 bp +
+
+
+
+ Class +
+
+ deletion + + +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ Total + + 0 + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_non_neuro with non-interchromosomal variant of type DUP has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + DUP_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Allele Count +
+
+ 123 +
+
+
+
+ Allele Number +
+
+ 345 +
+
+
+
+ Allele Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + - + 456 + +
+
+
+
+ Size +
+
+ 333 bp +
+
+
+
+ Class +
+
+ duplication + + +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ Total + + 0 + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_non_neuro with non-interchromosomal variant of type INS has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + INS_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Allele Count +
+
+ 123 +
+
+
+
+ Allele Number +
+
+ 345 +
+
+
+
+ Allele Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + +
+
+
+
+ Size +
+
+ 333 bp +
+
+
+
+ Class +
+
+ insertion + + +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ Total + + 0 + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_non_neuro with non-interchromosomal variant of type INV has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + INV_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Allele Count +
+
+ 123 +
+
+
+
+ Allele Number +
+
+ 345 +
+
+
+
+ Allele Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + - + 456 + +
+
+
+
+ Size +
+
+ 333 bp +
+
+
+
+ Class +
+
+ inversion + + +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ Total + + 0 + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; + +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_non_neuro with non-interchromosomal variant of type MCNV has no unexpected changes 1`] = ` +
+
+
+

+ Structural variant: + MCNV_21_999 +

+
+ +
+
+
+
+
+
+ Filter +
+
+ + Pass + +
+
+
+
+ Non-Diploid Samples +
+
+ 123 +
+
+
+
+ Total Samples +
+
+ 345 +
+
+
+
+ Non-diploid CN Frequency +
+
+ 0.3565 +
+
+
+
+ Quality score +
+
+ 99 +
+
+
+
+ Position +
+
+ + 21 + : + 123 + - + 456 + +
+
+
+
+ Size +
+
+ 333 bp +
+
+
+
+ Class +
+
+ multi CNV + + +
+
+
+
+ Evidence +
+
+ +
+
+
+
+ Algorithms +
+
+ +
+
+
+
+
+

+ External Resources +

+ +

+ Feedback +

+ + Report an issue with this variant + +
+
+
+

+ Population Frequencies +

+ + + + + + + + + + + + + + + + + +
+ + + + + + + +
+ Total + + 0 + + 0 + + 0.000 +
+
+
+
+

+ Copy Number Distribution +

+
+ + + + + + + Copy Number + + + + + + + + + + + 0 + + + + + + + + + + 0.1 + + + + + + + + + + 0.2 + + + + + + + + + + 0.3 + + + + + + + + + + 0.4 + + + + + + + + + + 0.5 + + + + + + + + + + 0.6 + + + + + + + + + + 0.7 + + + + + + + + + + 0.8 + + + + + + + + + + 0.9 + + + + + + + + + + 1 + + + + + + + + + Samples + + + + + + +
+
+
+
+
+

+ Consequences +

+

+ This variant has consequences in + 0 + gene + s + . +

+
    +
+
+
+
+

+ Genotype Quality +

+

+ Genotype quality is available for this variant. +

+
+
+

+ Age Distribution + +

+

+ Age data is not available for this variant. +

+
+
+
+`; diff --git a/browser/src/__factories__/StructuralVariant.ts b/browser/src/__factories__/StructuralVariant.ts new file mode 100644 index 000000000..a0cfdbe8b --- /dev/null +++ b/browser/src/__factories__/StructuralVariant.ts @@ -0,0 +1,64 @@ +import { Factory } from 'fishery' +import { StructuralVariant } from '../StructuralVariantPage/StructuralVariantPage' + +const structuralVariantFactory = Factory.define( + ({ params, associations, transientParams }) => { + const { + algorithms = [], + alts = null, + ac = 123, + an = 345, + chrom = '21', + chrom2 = null, + copy_numbers = [], + cpx_intervals = [], + cpx_type = null, + end = 456, + end2 = null, + evidence = [], + filters = [], + genes = [], + length = 333, + populations = [], + pos = 123, + pos2 = null, + qual = 99, + type = 'DUP', + } = params + + const { age_distribution = null, consequences = [], genotype_quality = null } = associations + + const { serialNumber = 999 } = transientParams + + const variant_id = `${type}_${chrom}_${serialNumber}` + + return { + age_distribution, + algorithms, + alts, + ac, + an, + chrom, + chrom2, + consequences, + copy_numbers, + cpx_intervals, + cpx_type, + end, + end2, + evidence, + filters, + genes, + genotype_quality, + length, + populations, + pos, + pos2, + qual, + type, + variant_id, + } + } +) + +export default structuralVariantFactory From da82e58907a03397e3db108c9540fe729a318872 Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Wed, 21 Jun 2023 15:52:27 -0400 Subject: [PATCH 10/24] Characterize isStructuralVariantId --- browser/src/identifiers.spec.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 browser/src/identifiers.spec.ts diff --git a/browser/src/identifiers.spec.ts b/browser/src/identifiers.spec.ts new file mode 100644 index 000000000..fffc8e55a --- /dev/null +++ b/browser/src/identifiers.spec.ts @@ -0,0 +1,19 @@ +import { describe, test, expect } from '@jest/globals' +import { isStructuralVariantId } from './identifiers' + +describe('isStructuralVariantId', () => { + const v2VariantTypes = ['BND', 'CPX', 'CTX', 'DEL', 'DUP', 'INS', 'INV', 'MCNV', 'OTH'] + const chromosomes = ['1', '12', 'X', 'Y'] + const positions = ['3', '63', '963'] + + v2VariantTypes.forEach((v2VariantType) => { + chromosomes.forEach((chromosome) => { + positions.forEach((position) => { + const variantId = [v2VariantType, chromosome, position].join('_') + test(`recognizes ${variantId} as a v2 variant ID`, () => { + expect(isStructuralVariantId(variantId)).toEqual(true) + }) + }) + }) + }) +}) From c9fdd4590bd3a07ef78a29dd163461e4535b7fcd Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Wed, 21 Jun 2023 16:18:40 -0400 Subject: [PATCH 11/24] Search recognizes V3 SV ID format --- browser/src/identifiers.spec.ts | 36 +++++++++++++++++++++++++-------- browser/src/identifiers.ts | 24 ++++++++++++++++------ browser/src/search.ts | 30 +++++++++++++-------------- dataset-metadata/metadata.ts | 4 ++++ 4 files changed, 65 insertions(+), 29 deletions(-) diff --git a/browser/src/identifiers.spec.ts b/browser/src/identifiers.spec.ts index fffc8e55a..02274b006 100644 --- a/browser/src/identifiers.spec.ts +++ b/browser/src/identifiers.spec.ts @@ -1,17 +1,37 @@ import { describe, test, expect } from '@jest/globals' import { isStructuralVariantId } from './identifiers' +import { forDatasetsMatching } from '../../tests/__helpers__/datasets' describe('isStructuralVariantId', () => { - const v2VariantTypes = ['BND', 'CPX', 'CTX', 'DEL', 'DUP', 'INS', 'INV', 'MCNV', 'OTH'] const chromosomes = ['1', '12', 'X', 'Y'] - const positions = ['3', '63', '963'] - v2VariantTypes.forEach((v2VariantType) => { - chromosomes.forEach((chromosome) => { - positions.forEach((position) => { - const variantId = [v2VariantType, chromosome, position].join('_') - test(`recognizes ${variantId} as a v2 variant ID`, () => { - expect(isStructuralVariantId(variantId)).toEqual(true) + forDatasetsMatching(/gnomad_sv_r2/, 'with dataset %s', (datasetId) => { + const variantTypes = ['BND', 'CPX', 'CTX', 'DEL', 'DUP', 'INS', 'INV', 'MCNV', 'OTH'] + const positions = ['3', '63', '963'] + + variantTypes.forEach((variantType) => { + chromosomes.forEach((chromosome) => { + positions.forEach((position) => { + const variantId = [variantType, chromosome, position].join('_') + test(`recognizes ${variantId} as a v2 variant ID`, () => { + expect(isStructuralVariantId(variantId, datasetId)).toEqual(true) + }) + }) + }) + }) + }) + + forDatasetsMatching(/gnomad_sv_r3/, 'with dataset %s', (datasetId) => { + const variantTypes = ['BND', 'CPX', 'CTX', 'DEL', 'DUP', 'INS', 'INV', 'CNV'] + const suffixes = ['0F1E2D3C', 'DEADBEEF', '12345678'] + + variantTypes.forEach((variantType) => { + chromosomes.forEach((chromosome) => { + suffixes.forEach((suffix) => { + const variantId = [variantType, `CHR${chromosome}`, suffix].join('_') + test(`recognizes ${variantId} as a v3 variant ID`, () => { + expect(isStructuralVariantId(variantId, datasetId)).toEqual(true) + }) }) }) }) diff --git a/browser/src/identifiers.ts b/browser/src/identifiers.ts index f3297051b..b245ed158 100644 --- a/browser/src/identifiers.ts +++ b/browser/src/identifiers.ts @@ -1,7 +1,17 @@ -const STRUCTURAL_VARIANT_ID_REGEX = /^(BND|CPX|CTX|DEL|DUP|INS|INV|MCNV|OTH)_(\d+|X|Y)_([1-9][0-9]*)$/i +import { DatasetId, isV3SVs } from '@gnomad/dataset-metadata/metadata' -export const isStructuralVariantId = (str: any) => { - const match = STRUCTURAL_VARIANT_ID_REGEX.exec(str) +const V2_STRUCTURAL_VARIANT_ID_REGEX = + /^(BND|CPX|CTX|DEL|DUP|INS|INV|MCNV|OTH)_(\d+|X|Y)_([1-9][0-9]*)$/i + +const V3_STRUCTURAL_VARIANT_ID_REGEX = + /^(BND|CPX|CTX|DEL|DUP|INS|INV|CNV)_CHR(\d+|X|Y)_([0-9a-f]*)$/i + +export const isStructuralVariantId = (str: string, datasetId: DatasetId) => { + const svRegex = isV3SVs(datasetId) + ? V3_STRUCTURAL_VARIANT_ID_REGEX + : V2_STRUCTURAL_VARIANT_ID_REGEX + + const match = svRegex.exec(str) if (!match) { return false } @@ -12,9 +22,11 @@ export const isStructuralVariantId = (str: any) => { return false } - const id = Number(match[3]) - if (id > 1e9) { - return false + if (!isV3SVs(datasetId)) { + const id = Number(match[3]) + if (id > 1e9) { + return false + } } return true diff --git a/browser/src/search.ts b/browser/src/search.ts index a7bc4eb16..e9e082d16 100644 --- a/browser/src/search.ts +++ b/browser/src/search.ts @@ -9,18 +9,18 @@ import { import { DatasetId, referenceGenome } from '@gnomad/dataset-metadata/metadata' import { isStructuralVariantId } from './identifiers' -export const fetchSearchResults = (dataset: DatasetId, query: string) => { - if (dataset.startsWith('gnomad_sv')) { +export const fetchSearchResults = (datasetId: DatasetId, query: string) => { + if (datasetId.startsWith('gnomad_sv')) { // ============================================================================================== // Structural Variants // ============================================================================================== - if (isStructuralVariantId(query)) { + if (isStructuralVariantId(query, datasetId)) { const structuralVariantId = query.toUpperCase() return Promise.resolve([ { label: structuralVariantId, - value: `/variant/${structuralVariantId}?dataset=${dataset}`, + value: `/variant/${structuralVariantId}?dataset=${datasetId}`, }, ]) } @@ -34,7 +34,7 @@ export const fetchSearchResults = (dataset: DatasetId, query: string) => { return Promise.resolve([ { label: variantId, - value: `/variant/${variantId}?dataset=${dataset}`, + value: `/variant/${variantId}?dataset=${datasetId}`, }, ]) } @@ -44,7 +44,7 @@ export const fetchSearchResults = (dataset: DatasetId, query: string) => { return Promise.resolve([ { label: rsId, - value: `/variant/${rsId}?dataset=${dataset}`, + value: `/variant/${rsId}?dataset=${datasetId}`, }, ]) } @@ -54,7 +54,7 @@ export const fetchSearchResults = (dataset: DatasetId, query: string) => { return Promise.resolve([ { label: caid, - value: `/variant/${caid}?dataset=${dataset}`, + value: `/variant/${caid}?dataset=${datasetId}`, }, ]) } @@ -64,7 +64,7 @@ export const fetchSearchResults = (dataset: DatasetId, query: string) => { return Promise.resolve([ { label: clinvarVariationId, - value: `/variant/${clinvarVariationId}?dataset=${dataset}`, + value: `/variant/${clinvarVariationId}?dataset=${datasetId}`, }, ]) } @@ -80,7 +80,7 @@ export const fetchSearchResults = (dataset: DatasetId, query: string) => { const results = [ { label: regionId, - value: `/region/${regionId}?dataset=${dataset}`, + value: `/region/${regionId}?dataset=${datasetId}`, }, ] @@ -90,7 +90,7 @@ export const fetchSearchResults = (dataset: DatasetId, query: string) => { const windowRegionId = `${chrom}-${Math.max(1, start - 20)}-${stop + 20}` results.unshift({ label: windowRegionId, - value: `/region/${windowRegionId}?dataset=${dataset}`, + value: `/region/${windowRegionId}?dataset=${datasetId}`, }) } @@ -108,7 +108,7 @@ export const fetchSearchResults = (dataset: DatasetId, query: string) => { return Promise.resolve([ { label: geneId, - value: `/gene/${geneId}?dataset=${dataset}`, + value: `/gene/${geneId}?dataset=${datasetId}`, }, ]) } @@ -122,7 +122,7 @@ export const fetchSearchResults = (dataset: DatasetId, query: string) => { return Promise.resolve([ { label: transcriptId, - value: `/transcript/${transcriptId}?dataset=${dataset}`, + value: `/transcript/${transcriptId}?dataset=${datasetId}`, }, ]) } @@ -142,7 +142,7 @@ export const fetchSearchResults = (dataset: DatasetId, query: string) => { } } `, - variables: { query, referenceGenome: referenceGenome(dataset) }, + variables: { query, referenceGenome: referenceGenome(datasetId) }, }), method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -184,7 +184,7 @@ export const fetchSearchResults = (dataset: DatasetId, query: string) => { ? `${gene.symbol} (${gene.ensembl_id})` : gene.symbol, - value: `/gene/${gene.ensembl_id}?dataset=${dataset}`, + value: `/gene/${gene.ensembl_id}?dataset=${datasetId}`, })) }) } @@ -200,7 +200,7 @@ export const fetchSearchResults = (dataset: DatasetId, query: string) => { return Promise.resolve([ { label: `${variantOneId} and ${variantTwoId} co-occurrence`, - value: `/variant-cooccurrence?dataset=${dataset}&variant=${variantOneId}&variant=${variantTwoId}`, + value: `/variant-cooccurrence?dataset=${datasetId}&variant=${variantOneId}&variant=${variantTwoId}`, }, ]) } diff --git a/dataset-metadata/metadata.ts b/dataset-metadata/metadata.ts index f51460fda..757511c1a 100644 --- a/dataset-metadata/metadata.ts +++ b/dataset-metadata/metadata.ts @@ -97,6 +97,7 @@ type DatasetMetadata = { isV3: boolean isExac: boolean isSVs: boolean + isV3SVs: boolean hasV2Genome: boolean metricsIncludeLowQualityGenotypes: boolean has1000GenomesPopulationFrequencies: boolean @@ -122,6 +123,7 @@ const metadataForDataset = (datasetId: DatasetId): DatasetMetadata => ({ label: datasetLabels[datasetId], isSubset: !fullDatasetIds.includes(datasetId), isV3Subset: !fullDatasetIds.includes(datasetId) && datasetId.startsWith('gnomad_r3'), + isV3SVs: datasetId === 'gnomad_sv_r3', hasShortVariants: !structuralVariantDatasetIds.includes(datasetId), hasStructuralVariants: structuralVariantDatasetIds.includes(datasetId), hasVariantCoocurrence: datasetId.startsWith('gnomad') && datasetId.includes('r2'), @@ -265,3 +267,5 @@ export const coverageDatasetId = (datasetId: DatasetId) => export const variantFeedbackDescription = (datasetId: DatasetId) => getMetadata(datasetId, 'variantFeedbackDescription') + +export const isV3SVs = (datasetId: DatasetId) => getMetadata(datasetId, 'isV3SVs') From 65f25c02e376e0594a9483fb22526aa9b468edab Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Thu, 22 Jun 2023 13:46:28 -0400 Subject: [PATCH 12/24] Add new consequences for v3 SVs --- .../structuralVariantConsequences.ts | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/browser/src/StructuralVariantList/structuralVariantConsequences.ts b/browser/src/StructuralVariantList/structuralVariantConsequences.ts index 405eb2bc1..0228c4195 100644 --- a/browser/src/StructuralVariantList/structuralVariantConsequences.ts +++ b/browser/src/StructuralVariantList/structuralVariantConsequences.ts @@ -9,21 +9,47 @@ const rankedConsequences = [ label: 'int. exon duplication', category: 'dup_lof', }, + { + term: 'intragenic_exon_dup', + label: 'int. exon duplication', + category: 'dup_lof', + }, + { + term: 'partial_exon_dup', + label: 'partial exon duplication', + category: 'dup_lof', + }, + { term: 'copy_gain', label: 'copy gain', category: 'copy_gain', }, + { + term: 'tss_dup', + label: 'TSS duplication', + category: 'other', + }, { term: 'dup_partial', label: 'partial duplication', category: 'other', }, + { + term: 'breakend_exonic', + label: 'exonic breakend', + category: 'other', + }, { term: 'msv_exon_ovr', label: 'MCNV overlap', category: 'other', }, + { + term: 'msv_exon_overlap', + label: 'MCNV overlap', + category: 'other', + }, { term: 'intronic', label: 'intronic', From c46a5b3af3167d0f2ca797e11fd7b8598c06513c Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Thu, 22 Jun 2023 13:58:57 -0400 Subject: [PATCH 13/24] Display SV IDs in all upper case The hexidecimal suffixes for the new v3 IDs was in lowercase, which looked sloppy. --- browser/src/GenePage/StructuralVariantsInGene.tsx | 14 ++++++++++---- .../src/RegionPage/StructuralVariantsInRegion.tsx | 13 +++++++++---- .../StructuralVariantPage.tsx | 6 +++++- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/browser/src/GenePage/StructuralVariantsInGene.tsx b/browser/src/GenePage/StructuralVariantsInGene.tsx index 7fe2bb094..be1e99a5c 100644 --- a/browser/src/GenePage/StructuralVariantsInGene.tsx +++ b/browser/src/GenePage/StructuralVariantsInGene.tsx @@ -4,6 +4,7 @@ import { referenceGenome } from '@gnomad/dataset-metadata/metadata' import Query from '../Query' import { filterStructuralVariantsInZoomRegion } from '../RegionViewer/filterVariantsInZoomRegion' import StructuralVariants from '../StructuralVariantList/StructuralVariants' +import { StructuralVariant } from '../StructuralVariantPage/StructuralVariantPage' type OwnProps = { datasetId: string @@ -61,15 +62,20 @@ const StructuralVariantsInGene = ({ datasetId, gene, zoomRegion, ...rest }: Prop success={(data: any) => data.gene && data.gene.structural_variants} > {({ data }: any) => { + const structural_variants = filterStructuralVariantsInZoomRegion( + data.gene.structural_variants, + zoomRegion + ).map((variant: StructuralVariant) => ({ + ...variant, + variant_id: variant.variant_id.toUpperCase(), + })) + return ( ) }} diff --git a/browser/src/RegionPage/StructuralVariantsInRegion.tsx b/browser/src/RegionPage/StructuralVariantsInRegion.tsx index a6918db19..36b49e573 100644 --- a/browser/src/RegionPage/StructuralVariantsInRegion.tsx +++ b/browser/src/RegionPage/StructuralVariantsInRegion.tsx @@ -4,6 +4,7 @@ import { referenceGenome } from '@gnomad/dataset-metadata/metadata' import Query from '../Query' import { filterStructuralVariantsInZoomRegion } from '../RegionViewer/filterVariantsInZoomRegion' import StructuralVariants from '../StructuralVariantList/StructuralVariants' +import { StructuralVariant } from '../StructuralVariantPage/StructuralVariantPage' type OwnProps = { datasetId: string @@ -65,16 +66,20 @@ const StructuralVariantsInRegion = ({ datasetId, region, zoomRegion, ...rest }: > {({ data }: any) => { const regionId = `${region.chrom}-${region.start}-${region.stop}` + const variants = filterStructuralVariantsInZoomRegion( + data.region.structural_variants, + zoomRegion + ).map((variant: StructuralVariant) => ({ + ...variant, + variant_id: variant.variant_id.toUpperCase(), + })) return ( ) }} diff --git a/browser/src/StructuralVariantPage/StructuralVariantPage.tsx b/browser/src/StructuralVariantPage/StructuralVariantPage.tsx index 0edeebebb..c380642b2 100644 --- a/browser/src/StructuralVariantPage/StructuralVariantPage.tsx +++ b/browser/src/StructuralVariantPage/StructuralVariantPage.tsx @@ -247,7 +247,11 @@ const ConnectedStructuralVariantPage = ({ success={(data: any) => data.structural_variant} > {({ data }: any) => { - return + const variant = { + ...data.structural_variant, + variant_id: data.structural_variant.variant_id.toUpperCase(), + } + return }} ) From 116a6ef97ee3397b3b5488f364dea9979fe9d80c Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Thu, 6 Jul 2023 14:21:31 -0400 Subject: [PATCH 14/24] Add helpers for missing copy --- .../StructuralVariantAttributeList.tsx | 27 +- .../StructuralVariantPage.spec.tsx | 22 +- .../StructuralVariantPage.spec.tsx.snap | 360 +++++++++--------- browser/src/missingContent.spec.ts | 19 + browser/src/missingContent.ts | 5 + 5 files changed, 246 insertions(+), 187 deletions(-) create mode 100644 browser/src/missingContent.spec.ts create mode 100644 browser/src/missingContent.ts diff --git a/browser/src/StructuralVariantPage/StructuralVariantAttributeList.tsx b/browser/src/StructuralVariantPage/StructuralVariantAttributeList.tsx index e33316cb4..6d5eb499b 100644 --- a/browser/src/StructuralVariantPage/StructuralVariantAttributeList.tsx +++ b/browser/src/StructuralVariantPage/StructuralVariantAttributeList.tsx @@ -7,6 +7,7 @@ import InfoButton from '../help/InfoButton' import Link from '../Link' import { svTypeLabels } from '../StructuralVariantList/structuralVariantTypes' import { StructuralVariant } from './StructuralVariantPage' +import { textOrMissingTextWarning } from '../missingContent' const FILTER_LABELS = { LOW_CALL_RATE: 'Low Call Rate', @@ -56,6 +57,18 @@ const COMPLEX_TYPE_LABELS = { piDUP_RF: 'Palindromic inverted duplication', } +const algorithmLabel = (algorithm: string) => + textOrMissingTextWarning('algorithm label', ALGORITHM_LABELS, algorithm) + +const complexTypeLabel = (complexType: string) => + textOrMissingTextWarning('complex type label', COMPLEX_TYPE_LABELS, complexType) + +const filterLabel = (filter: string) => + textOrMissingTextWarning('filter label', FILTER_LABELS, filter) + +const filterDescription = (filter: string) => + textOrMissingTextWarning('filter description', FILTER_DESCRIPTIONS, filter) + type OwnPointLinkProps = { chrom: string pos: number @@ -129,10 +142,8 @@ const StructuralVariantAttributeList = ({ variant }: StructuralVariantAttributeL {variant.filters.length > 0 ? ( variant.filters.map((filter) => ( - // @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message - - {/* @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message */} - {FILTER_LABELS[filter] || filter} + + {filterLabel(filter)} )) ) : ( @@ -188,12 +199,11 @@ const StructuralVariantAttributeList = ({ variant }: StructuralVariantAttributeL .join(', ')})`} - {variant.type === 'CPX' && ( + {variant.type === 'CPX' && variant.cpx_type && ( {/* @ts-expect-error TS(2604) FIXME: JSX element type 'AttributeList.Item' does not hav... Remove this comment to see the full error message */} - {/* @ts-expect-error TS(2538) FIXME: Type 'undefined' cannot be used as an index type. */} - {variant.cpx_type} ({COMPLEX_TYPE_LABELS[variant.cpx_type]}){' '} + {variant.cpx_type} ({complexTypeLabel(variant.cpx_type)}){' '} {/* @ts-expect-error TS(2604) FIXME: JSX element type 'AttributeList.Item' does not hav... Remove this comment to see the full error message */} @@ -209,8 +219,7 @@ const StructuralVariantAttributeList = ({ variant }: StructuralVariantAttributeL {/* @ts-expect-error TS(2604) FIXME: JSX element type 'AttributeList.Item' does not hav... Remove this comment to see the full error message */} - {/* @ts-expect-error TS(2532) FIXME: Object is possibly 'undefined'. */} - {variant.algorithms.map((a) => ALGORITHM_LABELS[a]).join(', ')} + {variant.algorithms.map((a) => algorithmLabel(a)).join(', ')} ) diff --git a/browser/src/StructuralVariantPage/StructuralVariantPage.spec.tsx b/browser/src/StructuralVariantPage/StructuralVariantPage.spec.tsx index 31c0f0a2f..810c831a2 100644 --- a/browser/src/StructuralVariantPage/StructuralVariantPage.spec.tsx +++ b/browser/src/StructuralVariantPage/StructuralVariantPage.spec.tsx @@ -41,7 +41,7 @@ afterEach(() => { }) forDatasetsMatching(/gnomad_sv_r2/, 'StructuralVariantPage with dataset %s', (datasetId) => { - describe.each(['DEL', 'DUP', 'MCNV', 'INS', 'INV', 'CPX'])( + describe.each(['DEL', 'DUP', 'MCNV', 'INS', 'INV'])( 'with non-interchromosomal variant of type %s', (variantType: string) => { test('has no unexpected changes', () => { @@ -84,4 +84,24 @@ forDatasetsMatching(/gnomad_sv_r2/, 'StructuralVariantPage with dataset %s', (da }) } ) + + describe('with a complex variant', () => { + test('has no unexpected changes', () => { + const variant = svFactory.build({ + type: 'CPX', + cpx_type: 'CCR', + }) + setMockApiResponses({ + StructuralVariant: () => ({ + structural_variant: variant, + }), + }) + const tree = renderer.create( + withDummyRouter( + + ) + ) + expect(tree).toMatchSnapshot() + }) + }) }) diff --git a/browser/src/StructuralVariantPage/__snapshots__/StructuralVariantPage.spec.tsx.snap b/browser/src/StructuralVariantPage/__snapshots__/StructuralVariantPage.spec.tsx.snap index f6f907d91..ce4e28ede 100644 --- a/browser/src/StructuralVariantPage/__snapshots__/StructuralVariantPage.spec.tsx.snap +++ b/browser/src/StructuralVariantPage/__snapshots__/StructuralVariantPage.spec.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`StructuralVariantPage with dataset gnomad_sv_r2_1 with interchromosomal variant of type BND has no unexpected changes 1`] = ` +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1 with a complex variant has no unexpected changes 1`] = `
@@ -14,7 +14,7 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1 with interchromosomal className="GnomadPageHeading__PageHeadingText-sc-sgz3rr-3 edXBqX" > Structural variant: - BND_21_999 + CPX_21_999
- Second Position + Size
- - 22 - : - 876 - + 333 bp
@@ -258,7 +252,7 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1 with interchromosomal Class
- breakend + complex
+
+
+ Complex SV Class +
+
+ CCR + ( + Complex chromosomal rearrangement + ) + +
+
+
+
+ Rearranged Segments +
+
+ +
+
Evidence @@ -320,25 +334,13 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1 with interchromosomal
  • - UCSC - - position - - , - - - second position + UCSC
  • @@ -568,7 +570,7 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1 with interchromosomal
    `; -exports[`StructuralVariantPage with dataset gnomad_sv_r2_1 with interchromosomal variant of type CTX has no unexpected changes 1`] = ` +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1 with interchromosomal variant of type BND has no unexpected changes 1`] = `
    @@ -582,7 +584,7 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1 with interchromosomal className="GnomadPageHeading__PageHeadingText-sc-sgz3rr-3 edXBqX" > Structural variant: - CTX_21_999 + BND_21_999
    - translocation + breakend
    - Size + Second Position
    - 333 bp + + 22 + : + 876 +
    @@ -1388,7 +1396,7 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1 with non-interchromos Class
    - complex + translocation
    -
    -
    - Complex SV Class -
    -
    - ( - ) - -
    -
    -
    -
    - Rearranged Segments -
    -
    - -
    -
    Evidence @@ -1468,13 +1458,25 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1 with non-interchromos
  • + UCSC + - UCSC + position + + , + + + second position
  • @@ -4984,7 +4986,7 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1 with non-interchromos
    `; -exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_controls with interchromosomal variant of type BND has no unexpected changes 1`] = ` +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_controls with a complex variant has no unexpected changes 1`] = `
    @@ -4998,7 +5000,7 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_controls with interch className="GnomadPageHeading__PageHeadingText-sc-sgz3rr-3 edXBqX" > Structural variant: - BND_21_999 + CPX_21_999
    - Second Position + Size
    - - 22 - : - 876 - + 333 bp
    @@ -5242,7 +5238,7 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_controls with interch Class
    - breakend + complex
    +
    +
    + Complex SV Class +
    +
    + CCR + ( + Complex chromosomal rearrangement + ) + +
    +
    +
    +
    + Rearranged Segments +
    +
    + +
    +
    Evidence @@ -5304,25 +5320,13 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_controls with interch
  • - UCSC - - position - - , - - - second position + UCSC
  • @@ -5552,7 +5556,7 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_controls with interch
    `; -exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_controls with interchromosomal variant of type CTX has no unexpected changes 1`] = ` +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_controls with interchromosomal variant of type BND has no unexpected changes 1`] = `
    @@ -5566,7 +5570,7 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_controls with interch className="GnomadPageHeading__PageHeadingText-sc-sgz3rr-3 edXBqX" > Structural variant: - CTX_21_999 + BND_21_999
    - translocation + breakend
    - Size + Second Position
    - 333 bp + + 22 + : + 876 +
    @@ -6372,7 +6382,7 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_controls with non-int Class
    - complex + translocation
    -
    -
    - Complex SV Class -
    -
    - ( - ) - -
    -
    -
    -
    - Rearranged Segments -
    -
    - -
    -
    Evidence @@ -6452,13 +6444,25 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_controls with non-int
  • + UCSC + - UCSC + position + + , + + + second position
  • @@ -9968,7 +9972,7 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_controls with non-int
    `; -exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_non_neuro with interchromosomal variant of type BND has no unexpected changes 1`] = ` +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_non_neuro with a complex variant has no unexpected changes 1`] = `
    @@ -9982,7 +9986,7 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_non_neuro with interc className="GnomadPageHeading__PageHeadingText-sc-sgz3rr-3 edXBqX" > Structural variant: - BND_21_999 + CPX_21_999
    - Second Position + Size
    - - 22 - : - 876 - + 333 bp
    @@ -10226,7 +10224,7 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_non_neuro with interc Class
    - breakend + complex
    +
    +
    + Complex SV Class +
    +
    + CCR + ( + Complex chromosomal rearrangement + ) + +
    +
    +
    +
    + Rearranged Segments +
    +
    + +
    +
    Evidence @@ -10288,25 +10306,13 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_non_neuro with interc
  • - UCSC - - - position - - , - - second position + UCSC
  • @@ -10536,7 +10542,7 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_non_neuro with interc
    `; -exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_non_neuro with interchromosomal variant of type CTX has no unexpected changes 1`] = ` +exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_non_neuro with interchromosomal variant of type BND has no unexpected changes 1`] = `
    @@ -10550,7 +10556,7 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_non_neuro with interc className="GnomadPageHeading__PageHeadingText-sc-sgz3rr-3 edXBqX" > Structural variant: - CTX_21_999 + BND_21_999
    - translocation + breakend
    - Size + Second Position
    - 333 bp + + 22 + : + 876 +
    @@ -11356,7 +11368,7 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_non_neuro with non-in Class
    - complex + translocation
    -
    -
    - Complex SV Class -
    -
    - ( - ) - -
    -
    -
    -
    - Rearranged Segments -
    -
    - -
    -
    Evidence @@ -11436,13 +11430,25 @@ exports[`StructuralVariantPage with dataset gnomad_sv_r2_1_non_neuro with non-in
  • + UCSC + - UCSC + position + + , + + + second position
  • diff --git a/browser/src/missingContent.spec.ts b/browser/src/missingContent.spec.ts new file mode 100644 index 000000000..e3e6d65a5 --- /dev/null +++ b/browser/src/missingContent.spec.ts @@ -0,0 +1,19 @@ +import { describe, test, expect } from '@jest/globals' +import { textOrMissingTextWarning } from './missingContent' + +describe('textOrMissingTextWarning', () => { + const labels = { + foo: 'bar', + baz: 'quux', + } + + test('uses label from labels map if present', () => { + expect(textOrMissingTextWarning('item', labels, 'foo')).toEqual('bar') + expect(textOrMissingTextWarning('item', labels, 'baz')).toEqual('quux') + }) + + test('gives warning if requested label is missing', () => { + expect(textOrMissingTextWarning('item', {}, 'foo')).toEqual('TEXT NEEDED FOR ITEM "foo"') + expect(textOrMissingTextWarning('item', {}, 'baz')).toEqual('TEXT NEEDED FOR ITEM "baz"') + }) +}) diff --git a/browser/src/missingContent.ts b/browser/src/missingContent.ts new file mode 100644 index 000000000..ae6a027c5 --- /dev/null +++ b/browser/src/missingContent.ts @@ -0,0 +1,5 @@ +export const textOrMissingTextWarning = ( + entityType: string, + textMapping: Record, + key: string +) => textMapping[key] || `TEXT NEEDED FOR ${entityType.toUpperCase()} "${key}"` From 79775d88ac732017432604033aaefecb92084b87 Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Fri, 23 Jun 2023 12:46:20 -0400 Subject: [PATCH 15/24] Add new pop names to v3 SV table --- .../StructuralVariantPopulationsTable.tsx | 12 ++---------- dataset-metadata/gnomadPopulations.ts | 5 +++++ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/browser/src/StructuralVariantPage/StructuralVariantPopulationsTable.tsx b/browser/src/StructuralVariantPage/StructuralVariantPopulationsTable.tsx index 4547c03ea..552123eaf 100644 --- a/browser/src/StructuralVariantPage/StructuralVariantPopulationsTable.tsx +++ b/browser/src/StructuralVariantPage/StructuralVariantPopulationsTable.tsx @@ -2,14 +2,7 @@ import React from 'react' import { PopulationsTable } from '../VariantPage/PopulationsTable' import { StructuralVariant } from './StructuralVariantPage' - -const populationNames = { - afr: 'African/African American', - amr: 'Latino', - eas: 'East Asian', - eur: 'European', - oth: 'Other', -} +import { populationName } from '@gnomad/dataset-metadata/gnomadPopulations' const nestPopulations = (populations: any) => { const popIndices = [] @@ -57,8 +50,7 @@ const addPopulationNames = (populations: any) => { } else if (pop.id === 'XY' || pop.id.endsWith('_XY')) { name = 'XY' } else { - // @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message - name = populationNames[pop.id] || pop.id + name = populationName(pop.id) } return { ...pop, name } }) diff --git a/dataset-metadata/gnomadPopulations.ts b/dataset-metadata/gnomadPopulations.ts index 35fe85170..a22597e8a 100644 --- a/dataset-metadata/gnomadPopulations.ts +++ b/dataset-metadata/gnomadPopulations.ts @@ -1,3 +1,5 @@ +import { textOrMissingTextWarning } from '../browser/src/missingContent' + export const GNOMAD_POPULATION_NAMES = { afr: 'African/African American', ami: 'Amish', @@ -25,3 +27,6 @@ export const GNOMAD_POPULATION_NAMES = { } as const export type PopulationId = keyof typeof GNOMAD_POPULATION_NAMES + +export const populationName = (populationId: string) => + textOrMissingTextWarning('population name', GNOMAD_POPULATION_NAMES, populationId) From 641892fa2b86636185474f15756fcffdc4a84b1d Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Thu, 12 Oct 2023 13:42:50 -0400 Subject: [PATCH 16/24] Add v3 SVs to dataset selector --- browser/src/DatasetSelector.spec.tsx | 22 +- browser/src/DatasetSelector.tsx | 67 +- .../__snapshots__/GenePage.spec.tsx.snap | 380 +- .../MitochondrialVariantPage.spec.tsx.snap | 12 +- .../StructuralVariantPage.spec.tsx.snap | 528 + .../TranscriptPage.spec.tsx.snap | 4 +- .../DatasetSelector.spec.tsx.snap | 9344 ++++++++++++++++- dataset-metadata/metadata.ts | 34 + dataset-metadata/sampleCounts.ts | 2 + 9 files changed, 10290 insertions(+), 103 deletions(-) diff --git a/browser/src/DatasetSelector.spec.tsx b/browser/src/DatasetSelector.spec.tsx index e8edf7690..2d1d52ce2 100644 --- a/browser/src/DatasetSelector.spec.tsx +++ b/browser/src/DatasetSelector.spec.tsx @@ -5,7 +5,7 @@ import React from 'react' import renderer from 'react-test-renderer' import DatasetSelector from './DatasetSelector' -import { forAllDatasets } from '../../tests/__helpers__/datasets' +import { forAllDatasets, forDatasetsMatching } from '../../tests/__helpers__/datasets' import { withDummyRouter } from '../../tests/__helpers__/router' forAllDatasets('DataSelector with "%s" dataset selected', (datasetId) => { @@ -15,4 +15,24 @@ forAllDatasets('DataSelector with "%s" dataset selected', (datasetId) => { ) expect(tree).toMatchSnapshot() }) + + test('has no unexpected changes when showing all possible datasets', () => { + const tree = renderer.create( + withDummyRouter( + + ) + ) + expect(tree).toMatchSnapshot() + }) }) diff --git a/browser/src/DatasetSelector.tsx b/browser/src/DatasetSelector.tsx index 9c5fe092e..85c4b6e25 100644 --- a/browser/src/DatasetSelector.tsx +++ b/browser/src/DatasetSelector.tsx @@ -14,6 +14,8 @@ import { hasShortVariants, hasStructuralVariants, referenceGenome, + shortVariantDatasetId, + structuralVariantDatasetId, } from '@gnomad/dataset-metadata/metadata' const NavigationMenuWrapper = styled.ul` @@ -124,7 +126,6 @@ const SubNavigationLink = styled.a` } `.withComponent(Link) - const ItemDescription = styled.div` margin-top: 0.125em; margin-left: 5px; @@ -148,13 +149,13 @@ type ChildDataset = { } type Props = { - items: ({ + items: { id: string isActive?: boolean label: string url: string | any children: ChildDataset[] - })[] + }[] } type State = any @@ -394,27 +395,29 @@ class NavigationMenu extends Component { ).map((childReferenceGenome) => (
  • {childReferenceGenome} - {item.children - .filter((childItem) => childItem.childReferenceGenome === childReferenceGenome) - .map((childItem) => ( -
  • - { - this.setState({ expandedItem: null }) - this.focusItem(item.id) - }} - onKeyDown={this.onKeyDownSubMenuItem} - > - {childItem.label} - {childItem.description && ( - {childItem.description} - )} - -
  • - ))} + {item.children + .filter( + (childItem) => childItem.childReferenceGenome === childReferenceGenome + ) + .map((childItem) => ( +
  • + { + this.setState({ expandedItem: null }) + this.focusItem(item.id) + }} + onKeyDown={this.onKeyDownSubMenuItem} + > + {childItem.label} + {childItem.description && ( + {childItem.description} + )} + +
  • + ))} ))} @@ -444,10 +447,8 @@ const DatasetSelector = withRouter(({ datasetOptions, history, selectedDataset } search: queryString.stringify({ dataset: datasetId }), }) - const defaultTopLevelShortVariantDataset = includeGnomad2 ? 'gnomad_r2_1' : 'gnomad_r3' - const topLevelShortVariantDataset = hasShortVariants(selectedDataset) - ? selectedDataset - : defaultTopLevelShortVariantDataset + const topLevelShortVariantDataset = shortVariantDatasetId(selectedDataset) + const topLevelStructuralVariantDataset = structuralVariantDatasetId(selectedDataset) let datasets: any = [] @@ -580,10 +581,6 @@ const DatasetSelector = withRouter(({ datasetOptions, history, selectedDataset } } if (includeStructuralVariants) { - const topLevelStructuralVariantDataset = hasStructuralVariants(selectedDataset) - ? selectedDataset - : 'gnomad_sv_r2_1' - datasets.push( { id: 'current_sv_dataset', @@ -596,6 +593,12 @@ const DatasetSelector = withRouter(({ datasetOptions, history, selectedDataset } isActive: hasStructuralVariants(selectedDataset), label: 'More datasets', children: [ + { + id: 'gnomad_sv_r3', + label: labelForDataset('gnomad_sv_r3'), + url: datasetLink('gnomad_sv_r3'), + description: `${sampleCounts.gnomad_sv_r3.total.toLocaleString()} samples`, + }, { id: 'gnomad_sv_r2_1', label: labelForDataset('gnomad_sv_r2_1'), diff --git a/browser/src/GenePage/__snapshots__/GenePage.spec.tsx.snap b/browser/src/GenePage/__snapshots__/GenePage.spec.tsx.snap index 616a40060..972be77c4 100644 --- a/browser/src/GenePage/__snapshots__/GenePage.spec.tsx.snap +++ b/browser/src/GenePage/__snapshots__/GenePage.spec.tsx.snap @@ -338,6 +338,28 @@ exports[`GenePage with SV dataset "gnomad_sv_r2_1" has no unexpected changes 1`] +`; + +exports[`DataSelector with "gnomad_r3" dataset selected has no unexpected changes 1`] = ` +.c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding: 0; + border: 1px solid #6c757d; + border-radius: 0.5em; + margin: 0; + list-style-type: none; +} + +.c3 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + box-sizing: border-box; + height: 100%; + padding: 0.375em 0.25em; + color: #000; + outline: none; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c3:visited { + color: #000; +} + +.c3:focus { + box-shadow: 0 0 0 0.2em rgba(66,139,202,0.5); +} + +.c1 { + position: relative; + display: inline-block; +} + +.c1 .c2 { + background: #cbd3da; +} + +.c1:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c1:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c9 { + position: relative; + display: inline-block; +} + +.c9 .c2 { + background: none; +} + +.c9:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c9:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c4 img { + position: relative; + top: 0.11em; + width: 0.9em; + height: 0.9em; +} + +.c5 { + position: absolute; + z-index: 1; + right: 0; + display: none; + width: 220px; + padding: 0.5em 0; + border: 1px solid #6c757d; + margin: 0; + background: #f8f9fa; + list-style-type: none; +} + +.c7 { + display: inline-block; + box-sizing: border-box; + width: 100%; + padding: 0.25em 0.5em; + color: #000; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c7:visited { + color: #000; +} + +.c7:active, +.c7:focus, +.c7:hover { + background: rgba(66,139,202,0.25); +} + +.c7:focus { + outline: 2px solid #428bca; +} + +.c8 { + margin-top: 0.125em; + margin-left: 5px; + font-size: 0.8em; + opacity: 0.6; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + margin-left: 2px; + font-weight: bold; +} + +@media (max-width:1200px) { + .c5 { + right: auto; + left: -100px; + } +} + +@media (max-width:900px) { + .c5 { + left: -150px; + } +} + + +`; + +exports[`DataSelector with "gnomad_r3" dataset selected has no unexpected changes when showing all possible datasets 1`] = ` +.c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding: 0; + border: 1px solid #6c757d; + border-radius: 0.5em; + margin: 0; + list-style-type: none; +} + +.c3 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + box-sizing: border-box; + height: 100%; + padding: 0.375em 0.25em; + color: #000; + outline: none; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c3:visited { + color: #000; +} + +.c3:focus { + box-shadow: 0 0 0 0.2em rgba(66,139,202,0.5); +} + +.c1 { + position: relative; + display: inline-block; +} + +.c1 .c2 { + background: #cbd3da; +} + +.c1:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c1:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c9 { + position: relative; + display: inline-block; +} + +.c9 .c2 { + background: none; +} + +.c9:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c9:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c4 img { + position: relative; + top: 0.11em; + width: 0.9em; + height: 0.9em; +} + +.c5 { + position: absolute; + z-index: 1; + right: 0; + display: none; + width: 220px; + padding: 0.5em 0; + border: 1px solid #6c757d; + margin: 0; + background: #f8f9fa; + list-style-type: none; +} + +.c7 { + display: inline-block; + box-sizing: border-box; + width: 100%; + padding: 0.25em 0.5em; + color: #000; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c7:visited { + color: #000; +} + +.c7:active, +.c7:focus, +.c7:hover { + background: rgba(66,139,202,0.25); +} + +.c7:focus { + outline: 2px solid #428bca; +} + +.c8 { + margin-top: 0.125em; + margin-left: 5px; + font-size: 0.8em; + opacity: 0.6; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + margin-left: 2px; + font-weight: bold; +} + +@media (max-width:1200px) { + .c5 { + right: auto; + left: -100px; + } +} + +@media (max-width:900px) { + .c5 { + left: -150px; + } +} + + +`; + +exports[`DataSelector with "gnomad_r3_controls_and_biobanks" dataset selected has no unexpected changes 1`] = ` +.c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding: 0; + border: 1px solid #6c757d; + border-radius: 0.5em; + margin: 0; + list-style-type: none; +} + +.c3 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + box-sizing: border-box; + height: 100%; + padding: 0.375em 0.25em; + color: #000; + outline: none; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c3:visited { + color: #000; +} + +.c3:focus { + box-shadow: 0 0 0 0.2em rgba(66,139,202,0.5); +} + +.c1 { + position: relative; + display: inline-block; +} + +.c1 .c2 { + background: #cbd3da; +} + +.c1:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c1:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c9 { + position: relative; + display: inline-block; +} + +.c9 .c2 { + background: none; +} + +.c9:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c9:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c4 img { + position: relative; + top: 0.11em; + width: 0.9em; + height: 0.9em; +} + +.c5 { + position: absolute; + z-index: 1; + right: 0; + display: none; + width: 220px; + padding: 0.5em 0; + border: 1px solid #6c757d; + margin: 0; + background: #f8f9fa; + list-style-type: none; +} + +.c7 { + display: inline-block; + box-sizing: border-box; + width: 100%; + padding: 0.25em 0.5em; + color: #000; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c7:visited { + color: #000; +} + +.c7:active, +.c7:focus, +.c7:hover { + background: rgba(66,139,202,0.25); +} + +.c7:focus { + outline: 2px solid #428bca; +} + +.c8 { + margin-top: 0.125em; + margin-left: 5px; + font-size: 0.8em; + opacity: 0.6; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + margin-left: 2px; + font-weight: bold; +} + +@media (max-width:1200px) { + .c5 { + right: auto; + left: -100px; + } +} + +@media (max-width:900px) { + .c5 { + left: -150px; + } +} + + +`; + +exports[`DataSelector with "gnomad_r3_controls_and_biobanks" dataset selected has no unexpected changes when showing all possible datasets 1`] = ` +.c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding: 0; + border: 1px solid #6c757d; + border-radius: 0.5em; + margin: 0; + list-style-type: none; +} + +.c3 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + box-sizing: border-box; + height: 100%; + padding: 0.375em 0.25em; + color: #000; + outline: none; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c3:visited { + color: #000; +} + +.c3:focus { + box-shadow: 0 0 0 0.2em rgba(66,139,202,0.5); +} + +.c1 { + position: relative; + display: inline-block; +} + +.c1 .c2 { + background: #cbd3da; +} + +.c1:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c1:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c9 { + position: relative; + display: inline-block; +} + +.c9 .c2 { + background: none; +} + +.c9:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c9:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c4 img { + position: relative; + top: 0.11em; + width: 0.9em; + height: 0.9em; +} + +.c5 { + position: absolute; + z-index: 1; + right: 0; + display: none; + width: 220px; + padding: 0.5em 0; + border: 1px solid #6c757d; + margin: 0; + background: #f8f9fa; + list-style-type: none; +} + +.c7 { + display: inline-block; + box-sizing: border-box; + width: 100%; + padding: 0.25em 0.5em; + color: #000; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c7:visited { + color: #000; +} + +.c7:active, +.c7:focus, +.c7:hover { + background: rgba(66,139,202,0.25); +} + +.c7:focus { + outline: 2px solid #428bca; +} + +.c8 { + margin-top: 0.125em; + margin-left: 5px; + font-size: 0.8em; + opacity: 0.6; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + margin-left: 2px; + font-weight: bold; +} + +@media (max-width:1200px) { + .c5 { + right: auto; + left: -100px; + } +} + +@media (max-width:900px) { + .c5 { + left: -150px; + } +} + + +`; + +exports[`DataSelector with "gnomad_r3_non_cancer" dataset selected has no unexpected changes 1`] = ` +.c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding: 0; + border: 1px solid #6c757d; + border-radius: 0.5em; + margin: 0; + list-style-type: none; +} + +.c3 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + box-sizing: border-box; + height: 100%; + padding: 0.375em 0.25em; + color: #000; + outline: none; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c3:visited { + color: #000; +} + +.c3:focus { + box-shadow: 0 0 0 0.2em rgba(66,139,202,0.5); +} + +.c1 { + position: relative; + display: inline-block; +} + +.c1 .c2 { + background: #cbd3da; +} + +.c1:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c1:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c9 { + position: relative; + display: inline-block; +} + +.c9 .c2 { + background: none; +} + +.c9:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c9:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c4 img { + position: relative; + top: 0.11em; + width: 0.9em; + height: 0.9em; +} + +.c5 { + position: absolute; + z-index: 1; + right: 0; + display: none; + width: 220px; + padding: 0.5em 0; + border: 1px solid #6c757d; + margin: 0; + background: #f8f9fa; + list-style-type: none; +} + +.c7 { + display: inline-block; + box-sizing: border-box; + width: 100%; + padding: 0.25em 0.5em; + color: #000; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c7:visited { + color: #000; +} + +.c7:active, +.c7:focus, +.c7:hover { + background: rgba(66,139,202,0.25); +} + +.c7:focus { + outline: 2px solid #428bca; +} + +.c8 { + margin-top: 0.125em; + margin-left: 5px; + font-size: 0.8em; + opacity: 0.6; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + margin-left: 2px; + font-weight: bold; +} + +@media (max-width:1200px) { + .c5 { + right: auto; + left: -100px; + } +} + +@media (max-width:900px) { + .c5 { + left: -150px; + } +} + + +`; + +exports[`DataSelector with "gnomad_r3_non_cancer" dataset selected has no unexpected changes when showing all possible datasets 1`] = ` +.c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding: 0; + border: 1px solid #6c757d; + border-radius: 0.5em; + margin: 0; + list-style-type: none; +} + +.c3 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + box-sizing: border-box; + height: 100%; + padding: 0.375em 0.25em; + color: #000; + outline: none; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c3:visited { + color: #000; +} + +.c3:focus { + box-shadow: 0 0 0 0.2em rgba(66,139,202,0.5); +} + +.c1 { + position: relative; + display: inline-block; +} + +.c1 .c2 { + background: #cbd3da; +} + +.c1:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c1:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c9 { + position: relative; + display: inline-block; +} + +.c9 .c2 { + background: none; +} + +.c9:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c9:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c4 img { + position: relative; + top: 0.11em; + width: 0.9em; + height: 0.9em; +} + +.c5 { + position: absolute; + z-index: 1; + right: 0; + display: none; + width: 220px; + padding: 0.5em 0; + border: 1px solid #6c757d; + margin: 0; + background: #f8f9fa; + list-style-type: none; +} + +.c7 { + display: inline-block; + box-sizing: border-box; + width: 100%; + padding: 0.25em 0.5em; + color: #000; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c7:visited { + color: #000; +} + +.c7:active, +.c7:focus, +.c7:hover { + background: rgba(66,139,202,0.25); +} + +.c7:focus { + outline: 2px solid #428bca; +} + +.c8 { + margin-top: 0.125em; + margin-left: 5px; + font-size: 0.8em; + opacity: 0.6; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + margin-left: 2px; + font-weight: bold; +} + +@media (max-width:1200px) { + .c5 { + right: auto; + left: -100px; + } +} + +@media (max-width:900px) { + .c5 { + left: -150px; + } +} + + +`; + +exports[`DataSelector with "gnomad_r3_non_neuro" dataset selected has no unexpected changes 1`] = ` +.c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding: 0; + border: 1px solid #6c757d; + border-radius: 0.5em; + margin: 0; + list-style-type: none; +} + +.c3 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + box-sizing: border-box; + height: 100%; + padding: 0.375em 0.25em; + color: #000; + outline: none; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c3:visited { + color: #000; +} + +.c3:focus { + box-shadow: 0 0 0 0.2em rgba(66,139,202,0.5); +} + +.c1 { + position: relative; + display: inline-block; +} + +.c1 .c2 { + background: #cbd3da; +} + +.c1:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c1:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c9 { + position: relative; + display: inline-block; +} + +.c9 .c2 { + background: none; +} + +.c9:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c9:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c4 img { + position: relative; + top: 0.11em; + width: 0.9em; + height: 0.9em; +} + +.c5 { + position: absolute; + z-index: 1; + right: 0; + display: none; + width: 220px; + padding: 0.5em 0; + border: 1px solid #6c757d; + margin: 0; + background: #f8f9fa; + list-style-type: none; +} + +.c7 { + display: inline-block; + box-sizing: border-box; + width: 100%; + padding: 0.25em 0.5em; + color: #000; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c7:visited { + color: #000; +} + +.c7:active, +.c7:focus, +.c7:hover { + background: rgba(66,139,202,0.25); +} + +.c7:focus { + outline: 2px solid #428bca; +} + +.c8 { + margin-top: 0.125em; + margin-left: 5px; + font-size: 0.8em; + opacity: 0.6; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + margin-left: 2px; + font-weight: bold; +} + +@media (max-width:1200px) { + .c5 { + right: auto; + left: -100px; + } +} + +@media (max-width:900px) { + .c5 { + left: -150px; + } +} + + +`; + +exports[`DataSelector with "gnomad_r3_non_neuro" dataset selected has no unexpected changes when showing all possible datasets 1`] = ` +.c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding: 0; + border: 1px solid #6c757d; + border-radius: 0.5em; + margin: 0; + list-style-type: none; +} + +.c3 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + box-sizing: border-box; + height: 100%; + padding: 0.375em 0.25em; + color: #000; + outline: none; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c3:visited { + color: #000; +} + +.c3:focus { + box-shadow: 0 0 0 0.2em rgba(66,139,202,0.5); +} + +.c1 { + position: relative; + display: inline-block; +} + +.c1 .c2 { + background: #cbd3da; +} + +.c1:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c1:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c9 { + position: relative; + display: inline-block; +} + +.c9 .c2 { + background: none; +} + +.c9:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c9:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c4 img { + position: relative; + top: 0.11em; + width: 0.9em; + height: 0.9em; +} + +.c5 { + position: absolute; + z-index: 1; + right: 0; + display: none; + width: 220px; + padding: 0.5em 0; + border: 1px solid #6c757d; + margin: 0; + background: #f8f9fa; + list-style-type: none; +} + +.c7 { + display: inline-block; + box-sizing: border-box; + width: 100%; + padding: 0.25em 0.5em; + color: #000; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c7:visited { + color: #000; +} + +.c7:active, +.c7:focus, +.c7:hover { + background: rgba(66,139,202,0.25); +} + +.c7:focus { + outline: 2px solid #428bca; +} + +.c8 { + margin-top: 0.125em; + margin-left: 5px; + font-size: 0.8em; + opacity: 0.6; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + margin-left: 2px; + font-weight: bold; +} + +@media (max-width:1200px) { + .c5 { + right: auto; + left: -100px; + } +} + +@media (max-width:900px) { + .c5 { + left: -150px; + } +} + + +`; + +exports[`DataSelector with "gnomad_r3_non_topmed" dataset selected has no unexpected changes 1`] = ` +.c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding: 0; + border: 1px solid #6c757d; + border-radius: 0.5em; + margin: 0; + list-style-type: none; +} + +.c3 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + box-sizing: border-box; + height: 100%; + padding: 0.375em 0.25em; + color: #000; + outline: none; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c3:visited { + color: #000; +} + +.c3:focus { + box-shadow: 0 0 0 0.2em rgba(66,139,202,0.5); +} + +.c1 { + position: relative; + display: inline-block; +} + +.c1 .c2 { + background: #cbd3da; +} + +.c1:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c1:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c9 { + position: relative; + display: inline-block; +} + +.c9 .c2 { + background: none; +} + +.c9:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c9:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c4 img { + position: relative; + top: 0.11em; + width: 0.9em; + height: 0.9em; +} + +.c5 { + position: absolute; + z-index: 1; + right: 0; + display: none; + width: 220px; + padding: 0.5em 0; + border: 1px solid #6c757d; + margin: 0; + background: #f8f9fa; + list-style-type: none; +} + +.c7 { + display: inline-block; + box-sizing: border-box; + width: 100%; + padding: 0.25em 0.5em; + color: #000; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c7:visited { + color: #000; +} + +.c7:active, +.c7:focus, +.c7:hover { + background: rgba(66,139,202,0.25); +} + +.c7:focus { + outline: 2px solid #428bca; +} + +.c8 { + margin-top: 0.125em; + margin-left: 5px; + font-size: 0.8em; + opacity: 0.6; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + margin-left: 2px; + font-weight: bold; +} + +@media (max-width:1200px) { + .c5 { + right: auto; + left: -100px; + } +} + +@media (max-width:900px) { + .c5 { + left: -150px; + } +} + + +`; + +exports[`DataSelector with "gnomad_r3_non_topmed" dataset selected has no unexpected changes when showing all possible datasets 1`] = ` +.c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding: 0; + border: 1px solid #6c757d; + border-radius: 0.5em; + margin: 0; + list-style-type: none; +} + +.c3 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + box-sizing: border-box; + height: 100%; + padding: 0.375em 0.25em; + color: #000; + outline: none; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c3:visited { + color: #000; +} + +.c3:focus { + box-shadow: 0 0 0 0.2em rgba(66,139,202,0.5); +} + +.c1 { + position: relative; + display: inline-block; +} + +.c1 .c2 { + background: #cbd3da; +} + +.c1:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c1:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c9 { + position: relative; + display: inline-block; +} + +.c9 .c2 { + background: none; +} + +.c9:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c9:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c4 img { + position: relative; + top: 0.11em; + width: 0.9em; + height: 0.9em; +} + +.c5 { + position: absolute; + z-index: 1; + right: 0; + display: none; + width: 220px; + padding: 0.5em 0; + border: 1px solid #6c757d; + margin: 0; + background: #f8f9fa; + list-style-type: none; +} + +.c7 { + display: inline-block; + box-sizing: border-box; + width: 100%; + padding: 0.25em 0.5em; + color: #000; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c7:visited { + color: #000; +} + +.c7:active, +.c7:focus, +.c7:hover { + background: rgba(66,139,202,0.25); +} + +.c7:focus { + outline: 2px solid #428bca; +} + +.c8 { + margin-top: 0.125em; + margin-left: 5px; + font-size: 0.8em; + opacity: 0.6; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + margin-left: 2px; + font-weight: bold; +} + +@media (max-width:1200px) { + .c5 { + right: auto; + left: -100px; + } +} + +@media (max-width:900px) { + .c5 { + left: -150px; + } +} + + +`; + +exports[`DataSelector with "gnomad_r3_non_v2" dataset selected has no unexpected changes 1`] = ` +.c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding: 0; + border: 1px solid #6c757d; + border-radius: 0.5em; + margin: 0; + list-style-type: none; +} + +.c3 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + box-sizing: border-box; + height: 100%; + padding: 0.375em 0.25em; + color: #000; + outline: none; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c3:visited { + color: #000; +} + +.c3:focus { + box-shadow: 0 0 0 0.2em rgba(66,139,202,0.5); +} + +.c1 { + position: relative; + display: inline-block; +} + +.c1 .c2 { + background: #cbd3da; +} + +.c1:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c1:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c9 { + position: relative; + display: inline-block; +} + +.c9 .c2 { + background: none; +} + +.c9:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c9:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c4 img { + position: relative; + top: 0.11em; + width: 0.9em; + height: 0.9em; +} + +.c5 { + position: absolute; + z-index: 1; + right: 0; + display: none; + width: 220px; + padding: 0.5em 0; + border: 1px solid #6c757d; + margin: 0; + background: #f8f9fa; + list-style-type: none; +} + +.c7 { + display: inline-block; + box-sizing: border-box; + width: 100%; + padding: 0.25em 0.5em; + color: #000; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c7:visited { + color: #000; +} + +.c7:active, +.c7:focus, +.c7:hover { + background: rgba(66,139,202,0.25); +} + +.c7:focus { + outline: 2px solid #428bca; +} + +.c8 { + margin-top: 0.125em; + margin-left: 5px; + font-size: 0.8em; + opacity: 0.6; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + margin-left: 2px; + font-weight: bold; +} + +@media (max-width:1200px) { + .c5 { + right: auto; + left: -100px; + } +} + +@media (max-width:900px) { + .c5 { + left: -150px; + } +} + + +`; + +exports[`DataSelector with "gnomad_r3_non_v2" dataset selected has no unexpected changes when showing all possible datasets 1`] = ` +.c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding: 0; + border: 1px solid #6c757d; + border-radius: 0.5em; + margin: 0; + list-style-type: none; +} + +.c3 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + box-sizing: border-box; + height: 100%; + padding: 0.375em 0.25em; + color: #000; + outline: none; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c3:visited { + color: #000; +} + +.c3:focus { + box-shadow: 0 0 0 0.2em rgba(66,139,202,0.5); +} + +.c1 { + position: relative; + display: inline-block; +} + +.c1 .c2 { + background: #cbd3da; +} + +.c1:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c1:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c9 { + position: relative; + display: inline-block; +} + +.c9 .c2 { + background: none; +} + +.c9:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c9:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c4 img { + position: relative; + top: 0.11em; + width: 0.9em; + height: 0.9em; +} + +.c5 { + position: absolute; + z-index: 1; + right: 0; + display: none; + width: 220px; + padding: 0.5em 0; + border: 1px solid #6c757d; + margin: 0; + background: #f8f9fa; + list-style-type: none; +} + +.c7 { + display: inline-block; + box-sizing: border-box; + width: 100%; + padding: 0.25em 0.5em; + color: #000; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c7:visited { + color: #000; +} + +.c7:active, +.c7:focus, +.c7:hover { + background: rgba(66,139,202,0.25); +} + +.c7:focus { + outline: 2px solid #428bca; +} + +.c8 { + margin-top: 0.125em; + margin-left: 5px; + font-size: 0.8em; + opacity: 0.6; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + margin-left: 2px; + font-weight: bold; +} + +@media (max-width:1200px) { + .c5 { + right: auto; + left: -100px; + } +} + +@media (max-width:900px) { + .c5 { + left: -150px; + } +} + + +`; + +exports[`DataSelector with "gnomad_sv_r2_1" dataset selected has no unexpected changes 1`] = ` +.c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding: 0; + border: 1px solid #6c757d; + border-radius: 0.5em; + margin: 0; + list-style-type: none; +} + +.c3 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + box-sizing: border-box; + height: 100%; + padding: 0.375em 0.25em; + color: #000; + outline: none; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c3:visited { + color: #000; +} + +.c3:focus { + box-shadow: 0 0 0 0.2em rgba(66,139,202,0.5); +} + +.c9 { + position: relative; + display: inline-block; +} + +.c9 .c2 { + background: #cbd3da; +} + +.c9:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c9:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c1 { + position: relative; + display: inline-block; +} + +.c1 .c2 { + background: none; +} + +.c1:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c1:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c4 img { + position: relative; + top: 0.11em; + width: 0.9em; + height: 0.9em; +} + +.c5 { + position: absolute; + z-index: 1; + right: 0; + display: none; + width: 220px; + padding: 0.5em 0; + border: 1px solid #6c757d; + margin: 0; + background: #f8f9fa; + list-style-type: none; +} + +.c7 { + display: inline-block; + box-sizing: border-box; + width: 100%; + padding: 0.25em 0.5em; + color: #000; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c7:visited { + color: #000; +} + +.c7:active, +.c7:focus, +.c7:hover { + background: rgba(66,139,202,0.25); +} + +.c7:focus { + outline: 2px solid #428bca; +} + +.c8 { + margin-top: 0.125em; + margin-left: 5px; + font-size: 0.8em; + opacity: 0.6; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + margin-left: 2px; + font-weight: bold; +} + +@media (max-width:1200px) { + .c5 { + right: auto; + left: -100px; + } +} + +@media (max-width:900px) { + .c5 { + left: -150px; + } +} + + +`; + +exports[`DataSelector with "gnomad_sv_r2_1" dataset selected has no unexpected changes when showing all possible datasets 1`] = ` +.c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding: 0; + border: 1px solid #6c757d; + border-radius: 0.5em; + margin: 0; + list-style-type: none; +} + +.c3 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + box-sizing: border-box; + height: 100%; + padding: 0.375em 0.25em; + color: #000; + outline: none; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c3:visited { + color: #000; +} + +.c3:focus { + box-shadow: 0 0 0 0.2em rgba(66,139,202,0.5); +} + +.c9 { + position: relative; + display: inline-block; +} + +.c9 .c2 { + background: #cbd3da; +} + +.c9:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c9:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c1 { + position: relative; + display: inline-block; +} + +.c1 .c2 { + background: none; +} + +.c1:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c1:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c4 img { + position: relative; + top: 0.11em; + width: 0.9em; + height: 0.9em; +} + +.c5 { + position: absolute; + z-index: 1; + right: 0; + display: none; + width: 220px; + padding: 0.5em 0; + border: 1px solid #6c757d; + margin: 0; + background: #f8f9fa; + list-style-type: none; +} + +.c7 { + display: inline-block; + box-sizing: border-box; + width: 100%; + padding: 0.25em 0.5em; + color: #000; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c7:visited { + color: #000; +} + +.c7:active, +.c7:focus, +.c7:hover { + background: rgba(66,139,202,0.25); +} + +.c7:focus { + outline: 2px solid #428bca; +} + +.c8 { + margin-top: 0.125em; + margin-left: 5px; + font-size: 0.8em; + opacity: 0.6; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + margin-left: 2px; + font-weight: bold; +} + +@media (max-width:1200px) { + .c5 { + right: auto; + left: -100px; + } +} + +@media (max-width:900px) { + .c5 { + left: -150px; + } +} + + +`; + +exports[`DataSelector with "gnomad_sv_r2_1_controls" dataset selected has no unexpected changes 1`] = ` +.c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding: 0; + border: 1px solid #6c757d; + border-radius: 0.5em; + margin: 0; + list-style-type: none; +} + +.c3 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + box-sizing: border-box; + height: 100%; + padding: 0.375em 0.25em; + color: #000; + outline: none; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c3:visited { + color: #000; +} + +.c3:focus { + box-shadow: 0 0 0 0.2em rgba(66,139,202,0.5); +} + +.c9 { + position: relative; + display: inline-block; +} + +.c9 .c2 { + background: #cbd3da; +} + +.c9:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c9:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c1 { + position: relative; + display: inline-block; +} + +.c1 .c2 { + background: none; +} + +.c1:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c1:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c4 img { + position: relative; + top: 0.11em; + width: 0.9em; + height: 0.9em; +} + +.c5 { + position: absolute; + z-index: 1; + right: 0; + display: none; + width: 220px; + padding: 0.5em 0; + border: 1px solid #6c757d; + margin: 0; + background: #f8f9fa; + list-style-type: none; +} + +.c7 { + display: inline-block; + box-sizing: border-box; + width: 100%; + padding: 0.25em 0.5em; + color: #000; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c7:visited { + color: #000; +} + +.c7:active, +.c7:focus, +.c7:hover { + background: rgba(66,139,202,0.25); +} + +.c7:focus { + outline: 2px solid #428bca; +} + +.c8 { + margin-top: 0.125em; + margin-left: 5px; + font-size: 0.8em; + opacity: 0.6; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + margin-left: 2px; + font-weight: bold; +} + +@media (max-width:1200px) { + .c5 { + right: auto; + left: -100px; + } +} + +@media (max-width:900px) { + .c5 { + left: -150px; + } +} + + +`; + +exports[`DataSelector with "gnomad_sv_r2_1_controls" dataset selected has no unexpected changes when showing all possible datasets 1`] = ` +.c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding: 0; + border: 1px solid #6c757d; + border-radius: 0.5em; + margin: 0; + list-style-type: none; +} + +.c3 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + box-sizing: border-box; + height: 100%; + padding: 0.375em 0.25em; + color: #000; + outline: none; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c3:visited { + color: #000; +} + +.c3:focus { + box-shadow: 0 0 0 0.2em rgba(66,139,202,0.5); +} + +.c9 { + position: relative; + display: inline-block; +} + +.c9 .c2 { + background: #cbd3da; +} + +.c9:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c9:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c1 { + position: relative; + display: inline-block; +} + +.c1 .c2 { + background: none; +} + +.c1:first-child .c2 { + padding-left: 0.75em; + border-top-left-radius: 0.5em; + border-bottom-left-radius: 0.5em; +} + +.c1:last-child .c2 { + padding-right: 0.75em; + border-top-right-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +.c4 img { + position: relative; + top: 0.11em; + width: 0.9em; + height: 0.9em; +} + +.c5 { + position: absolute; + z-index: 1; + right: 0; + display: none; + width: 220px; + padding: 0.5em 0; + border: 1px solid #6c757d; + margin: 0; + background: #f8f9fa; + list-style-type: none; +} + +.c7 { + display: inline-block; + box-sizing: border-box; + width: 100%; + padding: 0.25em 0.5em; + color: #000; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c7:visited { + color: #000; +} + +.c7:active, +.c7:focus, +.c7:hover { + background: rgba(66,139,202,0.25); +} + +.c7:focus { + outline: 2px solid #428bca; +} + +.c8 { + margin-top: 0.125em; + margin-left: 5px; + font-size: 0.8em; + opacity: 0.6; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + margin-left: 2px; + font-weight: bold; +} + +@media (max-width:1200px) { + .c5 { + right: auto; + left: -100px; + } +} + +@media (max-width:900px) { + .c5 { + left: -150px; + } +} + + `; -exports[`DataSelector with "gnomad_sv_r3" dataset selected has no unexpected changes 1`] = ` +exports[`DataSelector with "gnomad_sv_r4" dataset selected has no unexpected changes 1`] = ` .c0 { display: -webkit-box; display: -webkit-flex; @@ -17175,12 +17175,12 @@ exports[`DataSelector with "gnomad_sv_r3" dataset selected has no unexpected cha - gnomAD SVs v3 + gnomAD SVs v4
  • - gnomAD SVs v3 + gnomAD SVs v4
  • - gnomAD SVs v3 + gnomAD SVs v4
    diff --git a/browser/src/__snapshots__/HomePage.spec.tsx.snap b/browser/src/__snapshots__/HomePage.spec.tsx.snap index 0495ad2fd..9fb17ac45 100644 --- a/browser/src/__snapshots__/HomePage.spec.tsx.snap +++ b/browser/src/__snapshots__/HomePage.spec.tsx.snap @@ -206,9 +206,9 @@ exports[`Home Page has no unexpected changes 1`] = ` gnomAD v3.1.2 `; -exports[`Searchbox with selected dataset gnomad_sv_r3 has no unexpected changes 1`] = ` +exports[`Searchbox with selected dataset gnomad_sv_r4 has no unexpected changes 1`] = `