Skip to contents

Overview

causalInferencePipeline() pairs QTL fine-mapping and/or regularized regression weights one or more GWAS studies to produce, per (qtlStudy, context, trait, method, gwasStudy) tuple:

  • a TWAS Z-score (and p-value), and
  • when fineMappingResult is supplied, a Mendelian Randomization Wald-ratio estimate over the QTL credible sets.

Three valid input combinations:

What you supply TWAS-Z source MR?
twasWeights only per-tuple weights from TwasWeights no
fineMappingResult only SuSiE coefficients from topLoci() yes
both weights from TwasWeights yes (MR uses the FMR)

Bundled inputs

data(qtlDatasetExample, gwasSumStatsS4Example)

# Pre-compute the QTL-side products from the bundled QtlDataset.
# crossValidation carries the per-fold susie fits to the weights pipeline,
# which never fine-maps for itself.
fmr <- fineMappingPipeline(
    qtlDatasetExample,
    methods = "susie",
    cisWindow = 1e6,
    crossValidationParam = CrossValidationParam(folds = 3)
)
tw <- twasWeightsPipeline(
    qtlDatasetExample,
    methods = "susie",
    cisWindow = 1e6,
    fineMappingResult = fmr
)

TWAS Z only (weights alone)

res <- causalInferencePipeline(
    gwasSumStats = gwasSumStatsS4Example,
    twasWeights = tw
)
head(S4Vectors::mcols(res))
## DataFrame with 1 row and 14 columns
##      qtlStudy     context        trait      method   gwasStudy     twasZ
##   <character> <character>  <character> <character> <character> <numeric>
## 1      study1       brain ENSG_example       susie      trait1   13.8179
##      twasPval waldRatio waldRatioSe    mrPval       nIV         Q        I2
##     <numeric> <numeric>   <numeric> <numeric> <integer> <numeric> <numeric>
## 1 1.98845e-43        NA          NA        NA        NA        NA        NA
##         nCs
##   <integer>
## 1        NA

The result is a GRanges object positioned at the variant span of each QTL weight set, with identity columns (qtlStudy, context, trait, method, gwasStudy) and the TWAS columns (twasZ, twasPval). MR columns are NA in this mode.

TWAS Z + MR (weights + fine-mapping)

When you also pass fineMappingResult, the pipeline adds Wald-ratio MR on top of the TWAS computation. The MR uses each fine-mapping entry’s topLoci rows as candidate instrumental variables.

res2 <- causalInferencePipeline(
    gwasSumStats = gwasSumStatsS4Example,
    twasWeights = tw,
    fineMappingResult = fmr,
    mrParam = MrParam(method = "ivwPerVariant", pipCutoff = 0.5)
)
S4Vectors::mcols(res2)[, c(
    "twasZ",
    "twasPval",
    "waldRatio",
    "waldRatioSe",
    "mrPval",
    "nIV"
)]
## DataFrame with 1 row and 6 columns
##       twasZ    twasPval waldRatio waldRatioSe    mrPval       nIV
##   <numeric>   <numeric> <numeric>   <numeric> <numeric> <integer>
## 1   13.8179 1.98845e-43        NA          NA        NA         0

MR variants: per-variant vs CS-aware IVW

MrParam(method=) What it does Extra filters
"ivwPerVariant" (default) Treats every topLoci variant with pip > pipCutoff as an IV; pools their Wald ratios via inverse-variance weighting. pipCutoff
"csAware" Groups variants by credible set (column cs in topLoci), forms a PIP-weighted composite Wald ratio per CS (subject to per-CS cumulative-PIP cutoff cpipCutoff), then IVW-pools across CSs. Reports Cochran’s Q and I-squared. cpipCutoff
causalInferencePipeline(
    gwasSumStats = gwasSumStatsS4Example,
    twasWeights = tw,
    fineMappingResult = fmr,
    mrParam = MrParam(method = "csAware", cpipCutoff = 0.5)
)

Cross-method p-value combination

When a (qtlStudy, context, trait, gwasStudy) group has TWAS results from multiple weight methods, combineMethods runs combinePValues() to produce a single combined p-value per group.

# Multi-method weights so combination is meaningful
tw_multi <- twasWeightsPipeline(
    qtlDatasetExample,
    methods = c("susie", "lasso")
)
causalInferencePipeline(
    gwasSumStats = gwasSumStatsS4Example,
    twasWeights = tw_multi,
    combineMethods = c("acat", "hmp")
)

Accepted values for combineMethods: acat, hmp, bonferroni, fisher, stouffer, invchisq, gbj, bj, hc, ghc, minp, gbj_omni, aspu, gates (see ?combinePValues).

The per-tuple p-value itself comes from waldTestPval(), which is exported so the same test can be applied to any effect estimate and standard error:

waldTestPval(beta = 2.5, se = 0.8, n = 10000)
## [1] 0.00178314

n sets the degrees of freedom, so a small study gives a more conservative p-value than the normal approximation would.

LD reference consistency

Both twasWeights and fineMappingResult record an LD reference per row. Where a row has one, it must be the same LD reference as the gwasSumStats rows it overlaps carry. The pipeline errors on mismatch.

A QTL row with no LD reference (e.g. weights learned from individual-level data without any RSS step) skips the panel check — useful for analyses that mix individual-level QTL fits with sumstats GWAS.

Common parameters

causalInferencePipeline(
    gwasSumStats = gwasSumStatsS4Example,
    twasWeights = tw,
    fineMappingResult = fmr,
    mrParam = MrParam(
        method = "ivwPerVariant",
        pipCutoff = 0.5 # cpipCutoff instead, for method = "csAware"
    ),
    combineMethods = NULL
) # e.g. c("acat", "hmp")

Reading the result

The GRanges output indexes results by the QTL variant span (the union of variants used in each tuple’s weights). Extract per-tuple values with S4Vectors::mcols():

mc <- as.data.frame(S4Vectors::mcols(res2))
# Significant TWAS hits at Bonferroni alpha = 0.05 across rows
mc[mc$twasPval < 0.05 / nrow(mc), ]

Session info

## R version 4.5.3 (2026-03-11)
## Platform: x86_64-conda-linux-gnu
## Running under: Ubuntu 24.04.5 LTS
## 
## Matrix products: default
## BLAS/LAPACK: /home/runner/work/pecotmr/pecotmr/.pixi/envs/default/lib/libopenblasp-r0.3.34.so;  LAPACK version 3.12.0
## 
## locale:
##  [1] LC_CTYPE=C.UTF-8       LC_NUMERIC=C           LC_TIME=C.UTF-8       
##  [4] LC_COLLATE=C.UTF-8     LC_MONETARY=C.UTF-8    LC_MESSAGES=C.UTF-8   
##  [7] LC_PAPER=C.UTF-8       LC_NAME=C              LC_ADDRESS=C          
## [10] LC_TELEPHONE=C         LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C   
## 
## time zone: Etc/UTC
## tzcode source: system (glibc)
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] pecotmr_0.9.4
## 
## loaded via a namespace (and not attached):
##   [1] DBI_1.3.0                   bitops_1.1-0               
##   [3] httr2_1.3.0                 rlang_1.3.0                
##   [5] magrittr_2.0.5              otel_0.2.0                 
##   [7] matrixStats_1.5.0           susieR_0.16.6              
##   [9] compiler_4.5.3              RSQLite_3.53.3             
##  [11] systemfonts_1.3.2           vctrs_0.7.3                
##  [13] quadprog_1.5-8              stringr_1.6.0              
##  [15] pkgconfig_2.0.3             crayon_1.5.3               
##  [17] fastmap_1.2.0               dbplyr_2.6.0               
##  [19] backports_1.5.1             XVector_0.50.0             
##  [21] Rsamtools_2.26.0            rmarkdown_2.32             
##  [23] tzdb_0.5.0                  UCSC.utils_1.6.1           
##  [25] ragg_1.5.2                  purrr_1.2.2                
##  [27] bit_4.6.0                   xfun_0.61                  
##  [29] Rfast_2.1.5.2               MultiAssayExperiment_1.36.2
##  [31] cachem_1.1.0                GenomeInfoDb_1.46.2        
##  [33] jsonlite_2.0.0              blob_1.3.0                 
##  [35] DelayedArray_0.36.1         reshape_0.8.10             
##  [37] tictoc_1.2.1                BiocParallel_1.44.0        
##  [39] irlba_2.4.1                 parallel_4.5.3             
##  [41] R6_2.6.1                    bslib_0.12.0               
##  [43] stringi_1.8.9               RColorBrewer_1.1-3         
##  [45] GenomicRanges_1.62.1        jquerylib_0.1.4            
##  [47] numDeriv_2016.8-1.1         Rcpp_1.1.2                 
##  [49] Seqinfo_1.0.0               SummarizedExperiment_1.40.0
##  [51] knitr_1.52                  readr_2.2.0                
##  [53] IRanges_2.44.0              BiocBaseUtils_1.12.0       
##  [55] Matrix_1.7-6                tidyselect_1.2.1           
##  [57] abind_1.4-8                 yaml_2.3.12                
##  [59] codetools_0.2-20            curl_8.0.0                 
##  [61] metafor_5.0-1               lattice_0.23-1             
##  [63] tibble_3.3.1                plyr_1.8.9                 
##  [65] withr_3.0.3                 Biobase_2.70.0             
##  [67] S7_0.2.2                    evaluate_1.0.5             
##  [69] archive_1.1.13              desc_1.4.3                 
##  [71] RcppParallel_5.1.11-2       BiocFileCache_3.0.0        
##  [73] Biostrings_2.78.0           filelock_1.0.3             
##  [75] pillar_1.11.1               MatrixGenerics_1.22.0      
##  [77] metadat_1.6-0               checkmate_2.3.3            
##  [79] stats4_4.5.3                generics_0.1.4             
##  [81] vroom_1.7.1                 mathjaxr_2.0-0             
##  [83] S4Vectors_0.48.1            hms_1.1.4                  
##  [85] ggplot2_4.0.3               scales_1.4.0               
##  [87] glue_1.8.1                  tools_4.5.3                
##  [89] robustbase_0.99-7           fs_2.1.0                   
##  [91] grid_4.5.3                  PlinkMatrix_1.0.0          
##  [93] tidyr_1.3.2                 nlme_3.1-170               
##  [95] cli_3.6.6                   zigg_0.0.2                 
##  [97] textshaping_1.0.5           mixsqp_0.3-54              
##  [99] S4Arrays_1.10.1             dplyr_1.2.1                
## [101] gtable_0.3.6                DEoptimR_1.2-1             
## [103] sass_0.4.10                 digest_0.6.39              
## [105] BiocGenerics_0.56.0         SparseArray_1.10.10        
## [107] htmlwidgets_1.6.4           farver_2.1.2               
## [109] memoise_2.0.1               htmltools_0.5.9            
## [111] pkgdown_2.2.1               lifecycle_1.0.5            
## [113] httr_1.4.9                  bit64_4.8.6                
## [115] MASS_7.3-66