Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Genotype PLINK File Quality Control

Runs kinship estimation, variant- and sample-level filtering, and LD pruning over a merged PLINK genotype set, producing the QC-ed genotypes and the pruned variant list used for PCA.

Overview

This module is the standard quality-control pass over a merged PLINK genotype set. It estimates kinship to identify related individuals, filters variants and samples on allele frequency, missingness and Hardy-Weinberg equilibrium, and LD-prunes what survives into the variant set used for PCA. Input may be PLINK1 (bed/bim/fam) or PLINK2 (pgen/pvar/psam); VCF has to be converted first by genotype_formatting.

Four workflows are available, and how they are combined depends on whether the cohort contains relatives.

  • king estimates kinship with KING, flags pairs above --kinship, and splits the cohort into an *.unrelated and a *.related PLINK set. When no pair passes the threshold it writes an empty related-ID list and stops without splitting.

  • qc applies the variant- and sample-level filters and then LD-prunes, writing both the filtered set and the .prune.in variant list.

  • qc_no_prune is that same filtering step without the pruning stage, which is what to run when the pruned variant list already exists and only has to be extracted.

  • genotype_phenotype_sample_overlap intersects the genotype sample list with the samples in a molecular phenotype file. A two-column --sample-participant-lookup (genotype_id, sample_id) translates between naming schemes; without one, the names are assumed to match already.

The usual sequence is qc_no_prune for basic filtering, genotype_phenotype_sample_overlap to restrict to samples that have phenotype data, king to detect relatives, and finally qc on the unrelated set to produce the pruned variants for PCA. If KING finds no relatives there is nothing to split, and qc runs on the full filtered set with --keep-samples instead.

The defaults follow Table 1 of this GWAS quality-control tutorial and are deliberately permissive, because the appropriate thresholds depend on the analysis that follows:

  • kinship coefficient 0.0625, which is third-degree relatives and closer

  • MAF and MAC both 0, so common and rare variants are kept

  • variant-level and sample-level missingness both 0.1

  • HWE 1e-15, which is very lenient

  • LD pruning over a 50-variant window, shifting 10 variants at a time, at r2 0.1

For PCA a MAF cutoff of 0.01 is the usual choice, since common variants are the appropriate basis; for single-variant association a MAC floor of 5 is typical.

One constraint is structural: because both sample- and variant-level QC are applied together, all samples and chromosomes have to be merged into a single file first. That has been run at the scale of 200K exomes and 15 million variants on one merged PLINK set.

When to run it. After genotype_formatting has merged the per-chromosome genotypes, and before PCA and any association scan. The sample-overlap workflow additionally needs the molecular phenotype file to exist.

Input

  • --genoFile -- the merged genotype set, PLINK1 bed/bim/fam or PLINK2 pgen/pvar/psam, e.g. output/genotype_formatting/plink/protocol_example.genotype.merged.bed. king takes the QC-ed .bed, while genotype_phenotype_sample_overlap takes the .fam instead. Samples are identified by the FID and IID columns:

    0	SAMPLE_001	0	0	0	-9
    0	SAMPLE_002	0	0	0	-9
    0	SAMPLE_003	0	0	0	-9
  • --phenoFile -- the molecular phenotype whose samples are matched against the genotype, bed.gz or tsv, e.g. tests/fixtures/gene_annotation/protocol_example.rnaseq.bed.gz. Sample IDs are the column names after the four positional columns:

    #chr	start	end	ID	SAMPLE_001	SAMPLE_002	SAMPLE_003	SAMPLE_004	SAMPLE_005	SAMPLE_006	SAMP
  • --name -- string identifying the run; it is inserted into every output file name.

  • --cwd -- output directory, default output.

Restricting samples and variants:

  • --keep-samples / --remove-samples -- FID/IID lists limiting or excluding samples; --keep-samples is how the QC step is confined to, say, one ancestry group, or to the samples that have phenotype data.

  • --keep-variants / --exclude-variants -- variant ID lists. Supplying --keep-variants also inserts .extracted into the output file name.

  • --sample-participant-lookup -- two-column table (genotype_id, sample_id) used when genotype and phenotype name their samples differently.

Filter thresholds:

  • --kinship -- kinship coefficient above which a pair counts as related, default 0.0625.

  • --kin-maf -- MAF floor applied before the KING estimate, default 0.01.

  • --maf-filter / --maf-max-filter and --mac-filter / --mac-max-filter -- allele frequency and count bounds; 0 disables a bound.

  • --geno-filter -- maximum missingness per variant, default 0.1.

  • --mind-filter -- maximum missingness per sample, default 0.1.

  • --hwe-filter -- Hardy-Weinberg p-value cutoff, default 1e-15.

  • --rm-dups -- drop duplicate variants.

  • --treat-dosage-missing -- handle dosage data.

  • --meta-only -- write only the SNP and sample lists rather than a PLINK binary set.

  • --other-args -- extra PLINK arguments passed through, such as snps_only or write-samples.

LD pruning:

  • --window, --shift, --r2 -- pruning window in variants (default 50), how far it moves each time (10), and the r2 ceiling (0.1). Setting --r2 0 skips pruning altogether.

  • --bad-ld -- pass PLINK --bad-ld, which suppresses the pruning diagnostics that otherwise abort on regions of extreme LD.

Runtime:

  • --numThreads, --job-size, --walltime, --mem -- threads (default 20) and cluster resources.

  • --modular-script-dir -- location of the shell and R drivers, default code/script.

Output

  • <genotype>.<name>.plink_qc.{bed,bim,fam} -- the filtered genotype set, written by qc_no_prune and by the filtering step of qc. .extracted is inserted when --keep-variants was supplied, and --meta-only produces a .snplist instead of a binary set.

  • <genotype>.<name>.plink_qc.prune.{bed,bim,fam} and <genotype>.<name>.plink_qc.prune.in -- the LD-pruned genotype set and the variant list that defines it. The .prune.in list is what PCA consumes:

    chr1:820919_CACTACCTGCTTGTCCAGCAGGTCCACCCTGTCTACACTACCTGCCTGCAAAGCAGATCCACCCTGTCTACACTACCTGGCTGG
    chr1:820929_TTGTCCAGCAGGTCCACCCTGTCTACACTACCTGCCTGCAAAGCAGATCCACCCTGTCTACACTACCTGGCTGGCCAGTAGATC
    chr1:820929_TTGTCCAGCAGGTCCACCCTGTCTACACTACCTGCCTGCAAAGCAGATCCACCCTGTCTACACTACCTGGCTGGCCAGTAGATC
  • <genotype>.<name>.kin0 -- the KING kinship table, one row per pair above the threshold, with the kinship coefficient in the last column:

    #FID1	IID1	FID2	IID2	NSNP	HETHET	IBS0	KINSHIP
    0	SAMPLE_060	0	SAMPLE_059	59818	0.108178	0	0.248649
  • <genotype>.<name>.related_id -- the individuals dropped to leave a maximal unrelated set; the file is created empty when no pair passes --kinship:

    0 SAMPLE_060
  • <genotype>.<name>.unrelated.{bed,bim,fam} and <genotype>.<name>.related.{bed,bim,fam} -- the split cohort, written only when relatives were found.

  • <phenotype>.sample_genotypes.txt -- FID/IID of the samples present in both genotype and phenotype, in the form PLINK --keep expects:

    0	SAMPLE_001
    0	SAMPLE_002
    0	SAMPLE_003
  • <phenotype>.sample_overlap.txt -- the same overlap as a genotype_id / sample_id table:

    genotype_id	sample_id
    SAMPLE_001	SAMPLE_001
    SAMPLE_002	SAMPLE_002

Each step also writes PLINK .log files and .stdout / .stderr beside its output. Example results for the toy data are under output/gwas_qc/.

Minimal Working Example

Genotype QC of the protocol example data

The chr1_chr6 set was merged from the chr1 and chr6 data with the merge_plink command in genotype formatting. The steps below run in order, each consuming what the earlier ones produced.

Step 1. Basic QC (rare and common variants)

Apply the variant- and sample-level filters: missingness, HWE and MAC.

Timing: <1 min (on toy dataset)

Step 2. Sample match with phenotype

Find the samples shared between genotype and phenotype and write the overlapping sample lists.

Timing: <1 min (on toy dataset)

Step 3. Kinship QC

Estimate kinship with KING and split the samples into related and unrelated sets. In the toy data SAMPLE_059 and SAMPLE_060 are a parent-offspring pair, so KING does find relatives and writes both *.related.bed and *.unrelated.bed.

Timing: <2 min (on toy dataset)

Step 4. Prepare unrelated individuals for PCA

Because Step 3 found related individuals, run qc on the KING *.unrelated.bed to produce the LD-pruned, unrelated genotype set used downstream for PCA.

Timing: <1 min (on toy dataset)

If KING reports no related individuals and writes no *.unrelated.bed, run qc on the QC-ed genotype with --keep-samples instead. Relatives are present in this toy data, so Step 4 is the path that applies here and the command below is shown only for reference.

Timing: <1 min (on toy dataset)

Step 5. Extract pruned variants for PCA

Extract the LD-pruned variants from Step 4 out of the full genotype set, applying only sample-level missingness, in preparation for PCA.

Timing: TBD (on toy dataset)

Command Interface

usage: sos run pipeline/GWAS_QC.ipynb
               [workflow_name | -t targets] [options] [workflow_options]
  workflow_name:        Single or combined workflows defined in this script
  targets:              One or more targets to generate
  options:              Single-hyphen sos parameters (see "sos run -h" for details)
  workflow_options:     Double-hyphen workflow-specific parameters

Workflows:
  king
  qc_no_prune
  qc
  genotype_phenotype_sample_overlap

Global Workflow Options:
  --modular-script-dir code/script (as path)
  --cwd output (as path)
                        the output directory for generated files
  --name VAL (as str, required)
                        A string to identify your analysis run
  --genoFile  paths

                        PLINK binary files (either BED/BIM/FAM or PGEN/PVAR/PSAM
                        format)
  --remove-samples . (as path)
                        The path to the file that contains the list of samples
                        to remove (format FID, IID)
  --keep-samples . (as path)
                        The path to the file that contains the list of samples
                        to keep (format FID, IID)
  --keep-variants . (as path)
                        The path to the file that contains the list of variants
                        to keep
  --exclude-variants . (as path)
                        The path to the file that contains the list of variants
                        to exclude
  --kinship 0.0625 (as float)
                        Kinship coefficient threshold for related individuals
                        (e.g first degree above 0.25, second degree above 0.125,
                        third degree above 0.0625)
  --job-size 1 (as int)
                        For cluster jobs, number commands to run per job
  --walltime 5h
                        Wall clock time expected
  --mem 16G
                        Memory expected
  --numThreads 20 (as int)
                        Number of threads

Sections
  king_1:               Inference of relationships in the sample to identify
                        closely related individuals
    Workflow Options:
      --kin-maf 0.01 (as float)
                        PLINK binary file
  king_2:               Select a list of unrelated individual with an attempt to
                        maximize the unrelated individuals selected from the
                        data
  king_3:               Split genotype data into related and unrelated samples,
                        if related individuals are detected
  qc_no_prune, qc_1:    Filter SNPs and select individuals
    Workflow Options:
      --maf-filter 0.0 (as float)
                        minimum MAF filter to use. 0 means do not apply this
                        filter.
      --maf-max-filter 0.0 (as float)
                        maximum MAF filter to use. 0 means do not apply this
                        filter.
      --mac-filter 0.0 (as float)
                        minimum MAC filter to use. 0 means do not apply this
                        filter.
      --mac-max-filter 0.0 (as float)
                        maximum MAC filter to use. 0 means do not apply this
                        filter.
      --geno-filter 0.1 (as float)
                        Maximum missingess per-variant
      --mind-filter 0.1 (as float)
                        Maximum missingness per-sample
      --hwe-filter 1e-15 (as float)
                        HWE filter -- a very lenient one
      --other-args  (as list)
                        Other PLINK arguments e.g snps_only, write-samples, etc
      --[no-]meta-only (default to False)
                        Only output SNP and sample list, rather than the PLINK
                        binary format of subset data
      --[no-]rm-dups (default to False)
                        Remove duplicate variants
      --[no-]treat-dosage-missing (default to False)
                        Add option to process dosage
  qc_2:                 LD prunning and remove related individuals (both ind of
                        a pair) Plink2 has multi-threaded calculation for LD
                        prunning
    Workflow Options:
      --window 50 (as int)
                        Window size
      --shift 10 (as int)
                        Shift window every 10 snps
      --r2 0.1 (as float)
      --mac-filter 0.0 (as float)
      --other-args  (as list)
      --[no-]bad-ld (default to False)
                        Use PLINK --bad-ld flag (skip LD pruning diagnostics for
                        regions with extreme LD)
  genotype_phenotype_sample_overlap: This workflow extracts overlapping samples
                        for genotype data with phenotype data, and output the
                        filtered sample genotype list as well as sample
                        phenotype list
    Workflow Options:
      --phenoFile VAL (as path, required)
                        A phenotype file, can be bed.gz or tsv
      --sample-participant-lookup . (as path)
                        If this file is provided, a genotype/phenotype sample
                        name match will be performed It must contain two column
                        names: genotype_id, sample_id

Workflow implementation

The SoS workflow definitions below are unchanged from the original protocol.

Kinship estimation and cohort split

king_1 runs KING to produce the kinship table, king_2 chooses which individuals to drop, and king_3 writes the related and unrelated PLINK sets.

Variant and sample filtering

qc_no_prune, which doubles as the first step of qc, applies the frequency, missingness and HWE filters; qc_2 performs the LD pruning.

Genotype-phenotype sample matching

An auxiliary step matching genotype to phenotype samples through the optional look-up table; if no table is given, or the file is not found, the names are assumed to match already.

References
  1. Marees, A. T., de Kluiver, H., Stringer, S., Vorspan, F., Curis, E., Marie‐Claire, C., & Derks, E. M. (2018). A tutorial on conducting genome‐wide association studies: Quality control and statistical analysis. International Journal of Methods in Psychiatric Research, 27(2). 10.1002/mpr.1608