references/citation.bib
@ARTICLE{Karczewski2020,
ABSTRACT = {Genetic variants that inactivate protein-coding genes are a powerful source of information about the phenotypic consequences of gene disruption: genes that are crucial for the function of an organism will be depleted of such variants in natural populations, whereas non-essential genes will tolerate their accumulation. However, predicted loss-of-function variants are enriched for annotation errors, and tend to be found at extremely low frequencies, so their analysis requires careful variant annotation and very large sample sizes1. Here we describe the aggregation of 125,748 exomes and 15,708 genomes from human sequencing studies into the Genome Aggregation Database (gnomAD). We identify 443,769 high-confidence predicted loss-of-function variants in this cohort after filtering for artefacts caused by sequencing and annotation errors. Using an improved model of human mutation rates, we classify human protein-coding genes along a spectrum that represents tolerance to inactivation, validate this classification using data from model organisms and engineered human cells, and show that it can be used to improve the power of gene discovery for both common and rare diseases.},
AUTHOR = {Karczewski, Konrad J. and Francioli, Laurent C. and Tiao, Grace and Cummings, Beryl B. and Alföldi, Jessica and Wang, Qingbo and Collins, Ryan L. and Laricchia, Kristen M. and Ganna, Andrea and Birnbaum, Daniel P. and Gauthier, Laura D. and Brand, Harrison and Solomonson, Matthew and Watts, Nicholas A. and Rhodes, Daniel and Singer-Berk, Moriel and England, Eleina M. and Seaby, Eleanor G. and Kosmicki, Jack A. and Walters, Raymond K. and Tashman, Katherine and Farjoun, Yossi and Banks, Eric and Poterba, Timothy and Wang, Arcturus and Seed, Cotton and Whiffin, Nicola and Chong, Jessica X. and Samocha, Kaitlin E. and Pierce-Hoffman, Emma and Zappala, Zachary and O'Donnell-Luria, Anne H. and Minikel, Eric Vallabh and Weisburd, Ben and Lek, Monkol and Ware, James S. and Vittal, Christopher and Armean, Irina M. and Bergelson, Louis and Cibulskis, Kristian and Connolly, Kristen M. and Covarrubias, Miguel and Donnelly, Stacey and Ferriera, Steven and Gabriel, Stacey and Gentry, Jeff and Gupta, Namrata and Jeandet, Thibault and Kaplan, Diane and Llanwarne, Christopher and Munshi, Ruchi and Novod, Sam and Petrillo, Nikelle and Roazen, David and Ruano-Rubio, Valentin and Saltzman, Andrea and Schleicher, Molly and Soto, Jose and Tibbetts, Kathleen and Tolonen, Charlotte and Wade, Gordon and Talkowski, Michael E. and Aguilar Salinas, Carlos A. and Ahmad, Tariq and Albert, Christine M. and Ardissino, Diego and Atzmon, Gil and Barnard, John and Beaugerie, Laurent and Benjamin, Emelia J. and Boehnke, Michael and Bonnycastle, Lori L. and Bottinger, Erwin P. and Bowden, Donald W. and Bown, Matthew J. and Chambers, John C. and Chan, Juliana C. and Chasman, Daniel and Cho, Judy and Chung, Mina K. and Cohen, Bruce and Correa, Adolfo and Dabelea, Dana and Daly, Mark J. and Darbar, Dawood and Duggirala, Ravindranath and Dupuis, Josée and Ellinor, Patrick T. and Elosua, Roberto and Erdmann, Jeanette and Esko, Tõnu and Färkkilä, Martti and Florez, Jose and Franke, Andre and Getz, Gad and Glaser, Benjamin and Glatt, Stephen J. and Goldstein, David and Gonzalez, Clicerio and Groop, Leif and Haiman, Christopher and Hanis, Craig and Harms, Matthew and Hiltunen, Mikko and Holi, Matti M. and Hultman, Christina M. and Kallela, Mikko and Kaprio, Jaakko and Kathiresan, Sekar and Kim, Bong-Jo and Kim, Young Jin and Kirov, George and Kooner, Jaspal and Koskinen, Seppo and Krumholz, Harlan M. and Kugathasan, Subra and Kwak, Soo Heon and Laakso, Markku and Lehtimäki, Terho and Loos, Ruth J. F. and Lubitz, Steven A. and Ma, Ronald C. W. and MacArthur, Daniel G. and Marrugat, Jaume and Mattila, Kari M. and McCarroll, Steven and McCarthy, Mark I. and McGovern, Dermot and McPherson, Ruth and Meigs, James B. and Melander, Olle and Metspalu, Andres and Neale, Benjamin M. and Nilsson, Peter M. and O'Donovan, Michael C. and Ongur, Dost and Orozco, Lorena and Owen, Michael J. and Palmer, Colin N. A. and Palotie, Aarno and Park, Kyong Soo and Pato, Carlos and Pulver, Ann E. and Rahman, Nazneen and Remes, Anne M. and Rioux, John D. and Ripatti, Samuli and Roden, Dan M. and Saleheen, Danish and Salomaa, Veikko and Samani, Nilesh J. and Scharf, Jeremiah and Schunkert, Heribert and Shoemaker, Moore B. and Sklar, Pamela and Soininen, Hilkka and Sokol, Harry and Spector, Tim and Sullivan, Patrick F. and Suvisaari, Jaana and Tai, E. Shyong and Teo, Yik Ying and Tiinamaija, Tuomi and Tsuang, Ming and Turner, Dan and Tusie-Luna, Teresa and Vartiainen, Erkki and Vawter, Marquis P. and Watkins, Hugh and Weersma, Rinse K. and Wessman, Maija and Wilson, James G. and Xavier, Ramnik J. and {Genome Aggregation Database Consortium}},
URL = {https://doi.org/10.1038/s41586-020-2308-7},
DATE = {2020-05-01},
DOI = {10.1038/s41586-020-2308-7},
ISSN = {1476-4687},
JOURNALTITLE = {Nature},
NUMBER = {7809},
PAGES = {434--443},
TITLE = {The mutational constraint spectrum quantified from variation in 141,456 humans},
VOLUME = {581},
}
scripts/get_variant_frequency.py
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Fetches variant frequency from gnomAD."""
# /// script
# requires-python = ">=3.10"
# dependencies = [
# "polite-http",
# ]
# ///
import argparse
import json
import os
import sys
from polite_http import http_client
# Respect 10 queries per minute requirement.
CLIENT = http_client.HttpClient("https://gnomad.broadinstitute.org", qps=0.1666)
def resolve_rsid(rsid: str, dataset: str) -> str:
"""Resolves an rsID to a variant ID."""
url = "https://gnomad.broadinstitute.org/api"
query = """
query($query: String!, $dataset: DatasetId!) {
variant_search(query: $query, dataset: $dataset) {
variant_id
}
}
"""
variables = {"query": rsid, "dataset": dataset}
response_data = CLIENT.fetch_json(
url, method="POST", json_body={"query": query, "variables": variables}
)
variants = response_data.get("data", {}).get("variant_search", [])
if not variants:
print(
json.dumps({"error": f"Could not resolve rsID {rsid}"}), file=sys.stderr
)
sys.exit(1)
# For simplicity, return the first match if multiple
return variants[0]["variant_id"]
def get_variant_frequency(
variant_id: str,
rsid: str,
dataset: str,
output_path: str,
):
"""Fetches variant frequency from gnomAD."""
if rsid and not variant_id:
variant_id = resolve_rsid(rsid, dataset)
elif not variant_id:
print(
json.dumps({"error": "Must provide either variant_id or rsid"}),
file=sys.stderr,
)
sys.exit(1)
url = "https://gnomad.broadinstitute.org/api"
# GraphQL query for variant frequency and filtering allele frequency
query = """
query($variantId: String!, $dataset: DatasetId!) {
variant(variantId: $variantId, dataset: $dataset) {
variant_id
rsids
exome {
ac
an
af
homozygote_count
hemizygote_count
faf95 {
popmax
popmax_population
}
faf99 {
popmax
popmax_population
}
populations {
id
ac
an
homozygote_count
hemizygote_count
}
}
genome {
ac
an
af
homozygote_count
hemizygote_count
faf95 {
popmax
popmax_population
}
faf99 {
popmax
popmax_population
}
populations {
id
ac
an
homozygote_count
hemizygote_count
}
}
joint {
ac
an
homozygote_count
hemizygote_count
faf95 {
popmax
popmax_population
}
faf99 {
popmax
popmax_population
}
}
}
}
"""
variables = {"variantId": variant_id, "dataset": dataset}
response_data = CLIENT.fetch_json(
url, method="POST", json_body={"query": query, "variables": variables}
)
result = json.dumps(response_data, indent=2)
os.makedirs(os.path.dirname(output_path), exist_ok=True)
with open(output_path, "w") as f:
f.write(result)
f.write("\n")
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Fetch variant frequency from gnomAD"
)
parser.add_argument(
"--variant_id",
help="Variant ID in chrom-pos-ref-alt format",
)
parser.add_argument(
"--rsid",
help="Variant rsID (e.g. rs121918506)",
)
parser.add_argument(
"--dataset", default="gnomad_r4", help="gnomAD dataset to query"
)
parser.add_argument(
"--output",
"-o",
required=True,
help="Output file path.",
)
args = parser.parse_args()
get_variant_frequency(args.variant_id, args.rsid, args.dataset, args.output)
scripts/search_variants.py
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Searches for variants in a gene or region from gnomAD."""
# /// script
# requires-python = ">=3.10"
# dependencies = [
# "polite-http",
# ]
# ///
import argparse
import json
import os
import sys
from polite_http import http_client
# Respect 10 queries per minute requirement.
CLIENT = http_client.HttpClient("https://gnomad.broadinstitute.org", qps=0.1666)
def search_variants_gene(
gene_symbol: str,
consequence: str,
dataset: str,
output_path: str,
):
"""Searches for variants in a gene from gnomAD."""
url = "https://gnomad.broadinstitute.org/api"
query = """
query($geneSymbol: String!, $dataset: DatasetId!, $referenceGenome: ReferenceGenomeId!) {
gene(gene_symbol: $geneSymbol, reference_genome: $referenceGenome) {
variants(dataset: $dataset) {
variant_id
rsids
consequence
exome {
ac
an
af
homozygote_count
hemizygote_count
populations {
id
ac
an
homozygote_count
hemizygote_count
}
}
genome {
ac
an
af
homozygote_count
hemizygote_count
populations {
id
ac
an
homozygote_count
hemizygote_count
}
}
}
}
}
"""
variables = {
"geneSymbol": gene_symbol,
"dataset": dataset,
"referenceGenome": "GRCh38",
}
response_data = CLIENT.fetch_json(
url, method="POST", json_body={"query": query, "variables": variables}
)
data = response_data
if "data" in data and data["data"].get("gene"):
variants = data["data"]["gene"].get("variants", [])
if consequence:
variants = [
v
for v in variants
if consequence.lower() in (v.get("consequence") or "").lower()
]
data["data"]["gene"]["variants"] = variants
result = json.dumps(data, indent=2)
os.makedirs(os.path.dirname(output_path), exist_ok=True)
with open(output_path, "w") as f:
f.write(result)
f.write("\n")
def search_variants_region(
chrom: str,
start: int,
stop: int,
dataset: str,
output_path: str,
):
"""Searches for variants in a region from gnomAD."""
url = "https://gnomad.broadinstitute.org/api"
query = """
query($chrom: String!, $start: Int!, $stop: Int!, $dataset: DatasetId!, $referenceGenome: ReferenceGenomeId!) {
region(chrom: $chrom, start: $start, stop: $stop, reference_genome: $referenceGenome) {
variants(dataset: $dataset) {
variant_id
rsids
consequence
exome {
ac
an
af
homozygote_count
hemizygote_count
populations {
id
ac
an
homozygote_count
hemizygote_count
}
}
genome {
ac
an
af
homozygote_count
hemizygote_count
populations {
id
ac
an
homozygote_count
hemizygote_count
}
}
}
}
}
"""
variables = {
"chrom": str(chrom),
"start": int(start),
"stop": int(stop),
"dataset": dataset,
"referenceGenome": "GRCh38",
}
response_data = CLIENT.fetch_json(
url, method="POST", json_body={"query": query, "variables": variables}
)
result = json.dumps(response_data, indent=2)
os.makedirs(os.path.dirname(output_path), exist_ok=True)
with open(output_path, "w") as f:
f.write(result)
f.write("\n")
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Search variants in a gene or region from gnomAD"
)
parser.add_argument("--gene", help="Gene symbol (e.g. PCSK9)")
parser.add_argument("--chrom", help="Chromosome")
parser.add_argument("--start", type=int, help="Start position")
parser.add_argument("--end", type=int, help="End position")
parser.add_argument(
"--consequence", help="Filter by consequence (e.g. pLoF, missense)"
)
parser.add_argument(
"--dataset", default="gnomad_r4", help="gnomAD dataset to query"
)
parser.add_argument("--output", "-o", required=True, help="Output file path.")
args = parser.parse_args()
if args.gene:
search_variants_gene(args.gene, args.consequence, args.dataset, args.output)
elif args.chrom and args.start and args.end:
search_variants_region(
args.chrom, args.start, args.end, args.dataset, args.output
)
else:
print(
json.dumps({
"error": "Must provide either --gene OR --chrom, --start, and --end"
}),
file=sys.stderr,
)
sys.exit(1)