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.

TWAS, cTWAS and MR

Runs transcriptome-wide association analysis, quantile TWAS, and cTWAS fine-mapping to identify which gene and SNP signals are likely to be causal.

Overview

A TWAS scan tests each gene’s genetically predicted expression against a trait, but a significant gene is not necessarily a causal one: nearby variants with direct effects on the trait, and the predicted expression of neighbouring genes, are correlated with the gene’s own eQTLs and act as confounders. cTWAS addresses this by fine-mapping genes and variants jointly within a region, so a gene is credited only for signal that its expression explains beyond the surrounding variants and genes, and reports a posterior inclusion probability rather than a p-value (Zhao et al., 2024). finemapCtwasRegions) and offers four workflows:

This module provides software implementations for transcriptome-wide association analysis (TWAS), Quantile TWAS, and variant selection that yields sparse signals for cTWAS (causal TWAS) analysis following the multi-group cTWAS method of Qian et al. (2024+). It additionally performs Mendelian Randomization using fine-mapping instrumental variables (IV) as described in Zhang et al. (2020) for “causal” effect estimation and model validation. The unit of analysis is a single gene-trait pair.

This notebook runs TWAS followed by cTWAS fine-mapping on a toy chr22 dataset: starting from pre-computed SuSiE-TWAS prediction weights for one gene, it tests each molecular context for association with a GWAS trait, keeps the imputable models selected by cross-validation, and then jointly fine-maps genes and SNPs within an LD block to identify which signals are likely to be directly causal rather than driven by correlation. Quantile TWAS extends traditional TWAS by testing genetic effects at different quantiles of the trait distribution.

This procedure is a continuation of the SuSiE-TWAS workflow: it assumes that xQTL fine-mapping has been performed and molecular-trait prediction weights pre-computed (to be used for TWAS). Cross-validation of TWAS weights is optional but highly recommended.

Prerequisites: TWAS weights (protocol_example.twas_weights.rds) from mnm_regression, plus GWAS summary statistics and an LD matrix for the region of interest.

Timing (toy chr22 dataset): twas ~50 sec; ctwas ~42 sec.

MR can be run for candidate genes afterwards, limited to genes with cTWAS significance and a strong instrumental variable, using fine-mapped xQTL with GWAS data; multiple IVs aggregate by fixed-effect meta-analysis, and results with severe exclusion-restriction violations are excluded.

When to run it. After you have TWAS weights (from mnm_regression) and GWAS summary statistics. cTWAS consumes weights, it does not produce them.

Input

  • --gwas_meta_data tests/fixtures/twas/protocol_example.twas.gwas_meta.tsv (one row per GWAS study. Columns study_id, chrom, file_path, sample_size; file_path points at the summary statistics for that chromosome.)

study_id	chrom	file_path	sample_size
protocol_example_twas_chr22	22	protocol_example.twas.gwas_sumstats.chr22.tsv.gz	200000
  • --xqtl_meta_data tests/fixtures/twas/protocol_example.twas.xqtl_meta.tsv (one row per gene or region with its weight file. Columns #chr, start, end, region_id, TSS, original_data, contexts.)

#chr	start	end	region_id	TSS	original_data	contexts
chr22	10000000	19000000	ENSG00000130538	15528191	tests/fixtures/twas/protocol_example.twas.reshaped_toy.chr22_ENSG00000130538.univariate_twas_weights.rds	bulk_rnaseq
  • --ld_meta_data tests/fixtures/ld_reference/ld_meta_file.tsv (LD blocks and where the matrices live. Columns #chr, start, end, path. Produced by ld_reference_generation.)

#chr	start	end	path
chr1	16103	2888443	chr1/protocol_example.LD.chr1
chr1	2888443	4320284	chr1/protocol_example.LD.chr1
  • --regions tests/fixtures/twas/protocol_example.twas.LD_blocks.chr22.bed (the LD blocks to analyze. Columns chr, start, stop.)

chr	start	stop
chr22	10000000	19000000
  • --xqtl_type_table tests/fixtures/twas/protocol_example.twas.data_type_table.txt (maps each xQTL context to its modality, used when grouping contexts for cTWAS)

context	type
bulk_rnaseq	eQTL
  • --cwd output/twas (working directory all outputs are written under)

  • --name protocol_example (tag used in every output filename)

  • --region-name chr22_10000000_19000000 (optional; restrict to named regions)

Model and filtering options:

  • --ld_reference_sample_size (sample size of the LD reference panel, used to scale the LD matrices)

  • --prior_var_structure (how the cTWAS prior variance is shared across groups)

  • --rsq_cutoff (minimum cross-validation r-squared for a weight model to be used)

  • --rsq_pval_cutoff (maximum cross-validation p-value for a weight model to be used)

  • --twas_weight_cutoff (drop weights below this magnitude before assembling cTWAS inputs)

  • --thin (fraction of SNPs retained when thinning for parameter estimation)

  • --run_param_est (estimate cTWAS group priors)

  • --run_finemapping (run cTWAS fine-mapping after the priors are estimated)

  • --skip_assembly (reuse an existing ctwas_inputs.rds instead of rebuilding it)

File formats:

  • GWAS summary statistics are tab-delimited and tabix-indexed by chrom/pos; the first four columns are chrom, pos, A1, A2. For MR, effect_allele_frequency and a sample-size column are also required.

  • The GWAS meta-file may carry an optional column_mapping_file column pointing at a YAML that renames columns: required chrom, pos, A1, A2, z (or betahat/sebetahat); optional n, var_y. chrom 0 means genome-wide.

  • The LD reference meta-file gives the LD-matrix path as a comma-separated matrix,bim pair, plus the genome build. See ld_reference_generation.

  • xQTL weights are an RDS database keyed region to context to weight matrix. Weights from LASSO, Elastic Net and mr.ash are taken as-is for QTL variants overlapping GWAS variants; SuSiE weights are adjusted to match GWAS variants exactly.

  • Use --comment_string "#" if the summary statistics carry comment lines; no comment character is assumed by default.

  • --cs_min_cor (minimum correlation for a cTWAS credible set; default 0)

  • --min_pip_cutoff (minimum PIP for a variant to be reported; default 0)

  • --max_num_variants (cap on variants considered per region; default unlimited)

  • --multi_group (use the multi-group cTWAS model instead of a single shared prior)

Output

  • output/twas/twas/<name>.<region_id>.<gene>.twas.rds (twas) (per-gene TWAS result, one file per gene in the region)

  • output/twas/twas/<name>.<region_id>.twas.tsv.gz (twas, side file) (the TWAS table for the whole region. Columns gwas_study, chrom, start, end, block, gene, TSS, context, is_imputable, method, is_selected_method, rsq_adj_cv, pval_cv, twas_z, twas_pval. is_selected_method marks the best-performing model per gene-context pair -- the one with the highest cross-validation r-square.)

chr	molecular_id	TSS	start	end	context	gwas_study	method	is_imputable
22	ENSG00000130538	15528191	10000000	19000000	bulk_rnaseq	protocol_example_twas_chr22	bayes_c	TRUE
22	ENSG00000130538	15528191	10000000	19000000	bulk_rnaseq	protocol_example_twas_chr22	bayes_r	TRUE
  • output/twas/twas/<name>.<region_id>.mr_result.tsv.gz (twas, side file) (Mendelian Randomization results for the same region)

gene_name	num_CS	num_IV	cpip	meta_eff	se_meta_eff	meta_pval	Q
ENSG00000130538							
  • <cwd>/ctwas/<name>.ctwas_inputs.rds (ctwas_1) (assembled cTWAS inputs: weights, LD and GWAS z-scores for the regions to be fine-mapped)

  • <cwd>/ctwas/<name>.ctwas_est.rds (ctwas_2) (estimated cTWAS group prior parameters)

  • <cwd>/ctwas/<name>.ctwas_finemap.rds (ctwas_3) (cTWAS fine-mapping result: posterior inclusion probabilities for genes and SNPs in each LD block)

Only the .twas.rds files are declared in the twas step output: statement. The .twas.tsv.gz, .mr_result.tsv.gz, .twas_data.rds, .gwas_sumstats.rds and .twas_weights.rds files, and the cor_cache/ directory, are written alongside but not tracked by SoS.

Minimal Working Example

The three methods below are independent: run whichever you need. All use the chr22 example data in this repository.

Standard TWAS scan

twas extracts the GWAS z-scores and LD matrix for each region, processes the SuSiE-TWAS weights, and runs the association test for each molecular context, keeping the best cross-validated model per gene. Genes that clear neither --rsq_cutoff nor --rsq_pval_cutoff in any method are dropped as non-imputable.

Timing: TBD (on toy dataset)

cTWAS fine-mapping

ctwas combines the selected TWAS models, gene and SNP z-scores and the LD reference into a per-region input, estimates the global group prior across regions, then fine-maps each region for posterior inclusion probabilities over genes and SNPs. It is one workflow run three times, switched by --run_param_est and --run_finemapping; --skip_assembly reuses the assembled inputs rather than rebuilding them.

Requires the cTWAS R package: remotes::install_github("xinhe-lab/ctwas", ref = "multigroup").

-n cannot preview this chain: ctwas_1 reads a manifest that get_analysis_regions only writes at run time, so a dry run stops at the first step.

Step 1.: Assemble region data

Timing: TBD (on toy dataset)

Step 2.: Estimate global parameters

Timing: TBD (on toy dataset)

Step 3.: Fine-map causal genes and SNPs

Timing: TBD (on toy dataset)

Quantile TWAS

Use pre-computed TWAS weights for quantile-specific testing: for each quantile level, cluster and integrate by fixed and dynamic region groups, extract the relevant GWAS z-scores and LD matrix for the region, and perform quantile region-specific association tests, identifying variants whose effects vary across different quantile regions of the phenotype distribution. Use --region-name (formatted as chr_start_stop) to focus on specific blocks, or --region to analyze a selected list of regions.

Timing: TBD (on toy dataset)

Command Interface

usage: sos run pipeline/twas_ctwas.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:
  get_analysis_regions
  twas
  ctwas
  quantile_twas

Global Workflow Options:
  --cwd output (as path)
  --modular-script-dir code/script (as path)
  --gwas-meta-data . (as path)
  --xqtl-meta-data . (as path)
  --ld-meta-data . (as path)
  --ld-reference-sample-size 17000 (as int)
  --xqtl-type-table ''
  --gwas-name  (as list)
  --gwas-data  (as list)
  --column-mapping  (as list)
  --regions . (as path)
  --region-name  (as list)
                        Optional: if a region name is provided the analysis
                        would be focused on the union of provides region list
                        and region names
  --name  f"{xqtl_meta_data:bn}.{gwas_meta_data:bn}"

  --container ''
  --job-size 100 (as int)
  --walltime 5m
  --mem 8G
  --numThreads 1 (as int)
  --name-suffix ''
                        name suffix add to end of the name variable for the
                        output files
  --gwas-study  (as list)
                        optional parameter in ctwas to only perform gwas
                        specific analysis

Sections
  get_analysis_regions:
  twas:
    Workflow Options:
      --coverage 'cs_coverage_0.95'
                        Legacy CLI retained. Wired to the pecotmr selection
                        knobs: rsq_cutoff, rsq_pval_cutoff, rsq_option,
                        rsq_pval_option (CV weight selection). MR is deferred,
                        so mr_pval_cutoff and the remaining legacy params are
                        kept declared for CLI stability but are not consumed by
                        the S4 path.
      --rsq-cutoff 0.01 (as float)
                        Thresholds for rsq and CV p-value for imputability/best-
                        model selection
      --rsq-pval-cutoff 0.05 (as float)
      --mr-pval-cutoff 0.05 (as float)
      --[no-]save-ctwas-data (default to True)
      --[no-]save-mr-result (default to True)
      --rsq-option rsq
      --rsq-pval-option adj_rsq_pval pval (as list)
      --batch-load-memory 500 (as int)
                        load by batches if memory resource is limited, default
                        to load all at once
      --event-filter-rules . (as path)
      --comment-string NULL
      --[no-]rename-column (default to False)
  ctwas_1:
    Workflow Options:
      --chrom ''
                        chromosome to assemble (integer or 'chrN'); default: the
                        lone gene-bearing chrom
      --twas-weight-cutoff 0.0 (as float)
                        weight pre-filters passed to assembleCtwasInputs
      --max-num-variants Inf
      --cs-min-cor 0.0 (as float)
      --min-pip-cutoff 0.0 (as float)
      --thin 1.0 (as float)
                        declared for CLI stability; consumed downstream / not by
                        assembleCtwasInputs
      --maxSNP 20000 (as int)
      --[no-]multi-group (default to True)
      --[no-]skip-assembly (default to False)
      --twas-weights  (as list)
                        TwasWeights source (option c): empty -> the upstream
                        twas step's per-gene weights
                        ({cwd}/twas/{name}.{region}.{gene}.twas_weights.rds);
                        override with a list of prebuilt TwasWeights RDS (e.g.
                        the blessed ctwas weights extracted by the blessed S4
                        ctwas weights) when the toy twas weights carry no
                        signal.
  ctwas_2:
    Workflow Options:
      --[no-]run-param-est (default to False)
                        cTWAS step 2 (estimate priors): estCtwasParam via
                        ctwas_est.R. Reads the assembled inputs from [ctwas_1]
                        on disk so it can be run independently. --fallback-to-
                        prefit recovers the prefit estimate when the accurate EM
                        cannot be estimated (e.g. the single-gene MWE),
                        mirroring the legacy ctwas_2 workaround.
      --[no-]skip-assembly (default to False)
      --thin 1.0 (as float)
      --prior-var-structure 'shared_all'
      --niter 50 (as int)
      --[no-]multi-group (default to True)
                        declared for CLI stability; not consumed by the S4 path
  ctwas_3:
    Workflow Options:
      --[no-]run-finemapping (default to False)
                        cTWAS step 3 (screen + finemap): screenCtwasRegions +
                        finemapCtwasRegions via ctwas_finemap.R. Reads the
                        estimated params from [ctwas_2] on disk so it can be run
                        independently. Emits the per-gene cTWAS fine-mapping
                        result.
      --L 5 (as int)
      --min-nonSNP-PIP 0.5 (as float)
      --[no-]merge-regions (default to False)
                        Boundary-gene region merging (legacy ctwas_3
                        merge_regions, default-off): when True, after fine-
                        mapping, each high-PIP boundary gene's adjacent LD
                        blocks are merged and re-fine-mapped via
                        mergeCtwasBoundaryRegions (require-in-CS, like the
                        legacy susie_pip>0.5 & !is.na(cs) selection); maxSNP
                        caps SNPs per merged region.
      --maxSNP 20000 (as int)
      --[no-]keep-snps (default to True)
                        retain the SNP background as a dedicated
                        study=context="SNP" CtwasResult row; default True
                        matches the legacy pipeline, which kept SNP rows in the
                        finemap output
      --thin 1.0 (as float)
                        declared for CLI stability; not consumed by the S4 path
      --max-iter 0 (as int)
      --prior-var-structure 'shared_all'
      --subset-context  (as list)
      --[no-]multi-group (default to True)
      --p-diff-thresh 5e-08 (as float)
      --alias NULL
  quantile_twas:
    Workflow Options:
      --[no-]save-ctwas-data (default to True)
      --[no-]save-mr-result (default to False)

Workflow implementation

The following cells define the SoS workflow steps ([global], [get_analysis_regions], [twas], [ctwas_1], [ctwas_2], [ctwas_3], [quantile_twas]) invoked by the commands in the steps above.

References
  1. Zhao, S., Crouse, W., Qian, S., Luo, K., Stephens, M., & He, X. (2024). Adjusting for genetic confounders in transcriptome-wide association studies improves discovery of risk genes of complex traits. Nature Genetics, 56(2), 336–347. 10.1038/s41588-023-01648-9