Skip to contents

Overview

colocPipeline() runs pairwise QTL ↔︎ GWAS colocalization using coloc::coloc.bf_bf on the SuSiE log Bayes-factor (LBF) matrices carried by each fine-mapping entry. For multi-trait colocalization across many QTL outcomes in one model, use colocboostPipeline instead.

Inputs:

  • QTL input — a QtlFineMappingResult produced by fineMappingPipeline.
  • GWAS input — either a GwasSumStats (fine-mapping run internally) or a GwasFineMappingResult (used directly).

The output is a ColocResult: one element per tested (QTL credible set, GWAS credible set, block) pair, holding that pair’s aligned variants. Pair-level posteriors (PP.H0.abfPP.H4.abf) and the per-variant SNP.PP.H4 are both kept, and four accessors project the object to whichever granularity an analysis needs — see Reading the result.

Bundled inputs

data(qtlDatasetExample, gwasSumStatsS4Example)

# Build a QtlFineMappingResult from the bundled QtlDataset.
qtlFmr <- fineMappingPipeline(
    qtlDatasetExample,
    methods = "susie",
    cisWindow = 1e6
)

QTL FMR + GWAS sumstats (inline GWAS fine-mapping)

The recommend approach is to provide colocPipeline() a QtlFineMappingResult and a GwasSumStats. The pipeline runs fineMappingPipeline() internally on the GWAS sumstats (with finemappingMethods) over the exact window used in the QtlFineMappingResult, then runs coloc.bf_bf per (QTL, GWAS) pair.

res <- colocPipeline(
    qtlFineMappingResult = qtlFmr,
    gwasInput = gwasSumStatsS4Example,
    finemappingMethods = "susie"
)
res
## ColocResult with 10 colocalized pair(s)
##   QTL studies : study1 
##   GWAS studies: trait1 
##   variants    : 1980 across all pairs
##   max PP.H4   : 0.9166

Use returnGwasFineMapping = TRUE to get the inline GWAS FMR back as an attribute on the result:

res2 <- colocPipeline(
    qtlFineMappingResult = qtlFmr,
    gwasInput = gwasSumStatsS4Example,
    returnGwasFineMapping = TRUE
)
attr(res2, "gwasFineMapping")

If the QTL FineMappingResult has an LD sketch because it was run on summary statistics it must match the LD sketch for the GWASSumStats.

QTL FMR + pre-computed GWAS FMR

If you already have a GwasFineMappingResult (typically computed over LD blocks), you can use that fine-mapping result directly:

gwasFmr <- fineMappingPipeline(gwasSumStatsS4Example, methods = "susie")
colocPipeline(qtlFineMappingResult = qtlFmr, gwasInput = gwasFmr)

The disadvantage of this approach is that LD blocks will not align with cis-QTL windows. Ultimately this means that the variable selection in the QTL and GWAS fine-mapping will have been done over different variant sets, which may reduce the sensitivity for colocalizations, particuarly in areas with complex LD.

Filtering effects fed into coloc

coloc::coloc.bf_bf accepts one LBF matrix for the QTL and one for hte GWAS. By default, every effect with non-trivial prior variance (V > priorTol) gets included. Two opt-in filters can adjust this:

Filter Description Default
filterLbfCs TRUE keeps only effects that produced a credible set (trimmedFit$sets$cs_index). FALSE
filterLbfCsSecondary Numeric coverage in (0,1). Runs a CS-concentration filter at that coverage. NULL
filterLbfCsConcentration Numeric in (0,1). Concentration factor: a CS at coverage X is kept only if it spans fewer than nVariants * X * concentration variants. 0.5
priorTol Drop effects whose estimated prior variance is at or below this threshold. 1e-9
colocPipeline(
    qtlFineMappingResult = qtlFmr,
    gwasInput = gwasSumStatsS4Example,
    filterLbfCsSecondary = 0.5, # 50% CS concentration filter
    filterLbfCsConcentration = 0.5
) # span < 25% of locus variants

Enrichment-aware coloc (enloc mode)

Pass a per-(gwasStudy, qtlContext) enrichment table (the output of qtlEnrichmentPipeline()) to scale the shared-signal prior:

p_{12}^{\text{used}} = \min\bigl(p_{12}\,(1 + \text{enrichment}),\, p_{12,\max}\bigr)

Pairs without a matching enrichment row fall back to the baseline p12 with a warning. Two extra columns are added to the output: enrichment (the lookup) and p12Used (what was actually passed to coloc.bf_bf).

enrichmentTable <- data.frame(
    gwasStudy = "trait1",
    qtlContext = "brain",
    enrichment = 2.5,
    stringsAsFactors = FALSE
)
colocPipeline(
    qtlFineMappingResult = qtlFmr,
    gwasInput = gwasSumStatsS4Example,
    enrichment = enrichmentTable,
    p12Max = 1e-3
)

PIP renormalization on variant intersection

When the QTL and GWAS fine-mapping results were fit on different variant sets (common when the user declines RAISS imputation, or when the GWAS FMR carries variants the QTL FMR doesn’t), adjustPips = TRUE (default) renormalizes the PIPs for each objectl to the cross-FMR variant intersection before any per-pair inference. Pass FALSE to use the FMRs as supplied.

colocPipeline(
    qtlFineMappingResult = qtlFmr,
    gwasInput = gwasSumStatsS4Example,
    adjustPips = TRUE
) # default

Common parameters

colocPipeline(
    qtlFineMappingResult = qtlFmr,
    gwasInput = gwasSumStatsS4Example,
    filterLbfCs = FALSE,
    filterLbfCsSecondary = NULL, # e.g. 0.5
    filterLbfCsConcentration = 0.5,
    priorTol = 1e-9,
    p1 = 1e-4,
    p2 = 1e-4,
    p12 = 5e-6,
    finemappingMethods = "susie", # inline GWAS FM when needed
    returnGwasFineMapping = FALSE,
    enrichment = NULL, # data.frame for enloc mode
    p12Max = 1e-3,
    adjustPips = TRUE
)

Reading the result

Nothing is filtered when the result is written, so every narrowing below is a view decision the caller makes — and can revisit — rather than something baked in at run time.

Pairs

The native coloc.bf_bf granularity: one row per tested pair. Every testable pair is reported verbatim, including both halves of a credible set that straddles a block boundary.

pairs <- getColocPairs(res)
head(pairs[order(pairs$PP.H4.abf, decreasing = TRUE), ])
## # A tibble: 6 × 21
##   study  context trait    method gwasStudy gwasMethod blockId qtlCs gwasCs nSnps
##   <chr>  <chr>   <chr>    <chr>  <chr>     <chr>      <chr>   <int>  <int> <int>
## 1 study1 brain   ENSG_ex… susie  trait1    susie      chr22_…     1      2   198
## 2 study1 brain   ENSG_ex… susie  trait1    susie      chr22_…     1      4   198
## 3 study1 brain   ENSG_ex… susie  trait1    susie      chr22_…     1      6   198
## 4 study1 brain   ENSG_ex… susie  trait1    susie      chr22_…     1      8   198
## 5 study1 brain   ENSG_ex… susie  trait1    susie      chr22_…     1     10   198
## 6 study1 brain   ENSG_ex… susie  trait1    susie      chr22_…     1      1   198
## # ℹ 11 more variables: hit1 <chr>, hit2 <chr>, PP.H0.abf <dbl>,
## #   PP.H1.abf <dbl>, PP.H2.abf <dbl>, PP.H3.abf <dbl>, PP.H4.abf <dbl>,
## #   idx1 <int>, idx2 <int>, qtlRetainedMass <dbl>, gwasRetainedMass <dbl>

qtlCs / gwasCs are the fine-mapping effect indices, which are stable across blocks; coloc’s own idx1 / idx2 number the rows of a single call and are not comparable between them. qtlRetainedMass / gwasRetainedMass report how much of each effect’s posterior survived reconciliation to the shared variant set — a low value means the effect rested largely on variants the other side does not carry.

Variants

The per-variant layer: colocPp is PP.H4.abf * SNP.PP.H4, the posterior that this particular variant is the shared causal one.

variants <- getColocVariants(res)
head(variants[order(variants$colocPp, decreasing = TRUE), ])
## # A tibble: 6 × 24
##   study  context trait    method gwasStudy gwasMethod blockId qtlCs gwasCs nSnps
##   <chr>  <chr>   <chr>    <chr>  <chr>     <chr>      <chr>   <int>  <int> <int>
## 1 study1 brain   ENSG_ex… susie  trait1    susie      chr22_…     1      2   198
## 2 study1 brain   ENSG_ex… susie  trait1    susie      chr22_…     1      4   198
## 3 study1 brain   ENSG_ex… susie  trait1    susie      chr22_…     1      6   198
## 4 study1 brain   ENSG_ex… susie  trait1    susie      chr22_…     1      8   198
## 5 study1 brain   ENSG_ex… susie  trait1    susie      chr22_…     1     10   198
## 6 study1 brain   ENSG_ex… susie  trait1    susie      chr22_…     1      1   198
## # ℹ 14 more variables: hit1 <chr>, hit2 <chr>, PP.H0.abf <dbl>,
## #   PP.H1.abf <dbl>, PP.H2.abf <dbl>, PP.H3.abf <dbl>, PP.H4.abf <dbl>,
## #   idx1 <int>, idx2 <int>, qtlRetainedMass <dbl>, gwasRetainedMass <dbl>,
## #   variant_id <chr>, SNP.PP.H4 <dbl>, colocPp <dbl>

Credible sets

The coloc credible set is the smallest set of variants whose cumulative SNP.PP.H4 reaches coverage. It is a third variant set — not guaranteed to be a subset of either input credible set — so its purity is recomputed from LD rather than inherited. Filtering happens before any LD extraction, so a stricter threshold costs strictly less.

head(getColocCredibleSets(res, coverage = 0.95, minPp4 = 0.1))
## # A tibble: 6 × 27
##   study  context trait    method gwasStudy gwasMethod blockId qtlCs gwasCs nSnps
##   <chr>  <chr>   <chr>    <chr>  <chr>     <chr>      <chr>   <int>  <int> <int>
## 1 study1 brain   ENSG_ex… susie  trait1    susie      chr22_…     1      1   198
## 2 study1 brain   ENSG_ex… susie  trait1    susie      chr22_…     1      2   198
## 3 study1 brain   ENSG_ex… susie  trait1    susie      chr22_…     1      3   198
## 4 study1 brain   ENSG_ex… susie  trait1    susie      chr22_…     1      4   198
## 5 study1 brain   ENSG_ex… susie  trait1    susie      chr22_…     1      5   198
## 6 study1 brain   ENSG_ex… susie  trait1    susie      chr22_…     1      6   198
## # ℹ 17 more variables: hit1 <chr>, hit2 <chr>, PP.H0.abf <dbl>,
## #   PP.H1.abf <dbl>, PP.H2.abf <dbl>, PP.H3.abf <dbl>, PP.H4.abf <dbl>,
## #   idx1 <int>, idx2 <int>, qtlRetainedMass <dbl>, gwasRetainedMass <dbl>,
## #   csSize <int>, csCoverage <dbl>, leadVariant <chr>, leadPp <dbl>,
## #   csVariants <list>, purity <dbl>

Genes

Pooled to one row per gene. Within a QTL credible set the per-block and per-GWAS-credible-set results are mutually exclusive — the shared causal variant is in one block or the other — so they are summed; distinct QTL credible sets are independent signals and combine as 1 - prod(1 - p).

## # A tibble: 1 × 9
##   study  context trait        method gwasStudy gwasMethod PP.H4 nQtlCs nPairs
##   <chr>  <chr>   <chr>        <chr>  <chr>     <chr>      <dbl>  <int>  <int>
## 1 study1 brain   ENSG_example susie  trait1    susie          1      1     10

The warning above is the diagnostic that rule produces: a within-credible-set sum above 1 means several GWAS credible sets are competing for one QTL signal. The value is clipped to 1, and the pair view shows which pairs were involved.

If you need the flat table the pipeline used to return, as.data.frame(res) gives the pair view.

Session info

## R version 4.5.3 (2026-03-11)
## Platform: x86_64-conda-linux-gnu
## Running under: Ubuntu 24.04.4 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.7.8
## 
## loaded via a namespace (and not attached):
##   [1] coloc_5.2.3                 bitops_1.0-9               
##   [3] gridExtra_2.3.1             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              systemfonts_1.3.2          
##  [11] vctrs_0.7.3                 quadprog_1.5-8             
##  [13] stringr_1.6.0               pkgconfig_2.0.3            
##  [15] crayon_1.5.3                fastmap_1.2.0              
##  [17] XVector_0.50.0              utf8_1.2.6                 
##  [19] Rsamtools_2.26.0            rmarkdown_2.32             
##  [21] tzdb_0.5.0                  ragg_1.5.2                 
##  [23] purrr_1.2.2                 bit_4.6.0                  
##  [25] xfun_0.60                   Rfast_2.1.5.2              
##  [27] MultiAssayExperiment_1.36.1 cachem_1.1.0               
##  [29] jsonlite_2.0.0              DelayedArray_0.36.0        
##  [31] reshape_0.8.10              tictoc_1.2.1               
##  [33] BiocParallel_1.44.0         irlba_2.3.7                
##  [35] parallel_4.5.3              R6_2.6.1                   
##  [37] bslib_0.12.0                stringi_1.8.9              
##  [39] RColorBrewer_1.1-3          GenomicRanges_1.62.1       
##  [41] jquerylib_0.1.4             numDeriv_2016.8-1.1        
##  [43] Rcpp_1.1.2                  Seqinfo_1.0.0              
##  [45] SummarizedExperiment_1.40.0 knitr_1.51                 
##  [47] readr_2.2.0                 IRanges_2.44.0             
##  [49] BiocBaseUtils_1.12.0        Matrix_1.7-6               
##  [51] splines_4.5.3               tidyselect_1.2.1           
##  [53] abind_1.4-8                 yaml_2.3.12                
##  [55] viridis_0.6.5               codetools_0.2-20           
##  [57] metafor_5.0-1               lattice_0.23-1             
##  [59] tibble_3.3.1                plyr_1.8.9                 
##  [61] Biobase_2.70.0              withr_3.0.3                
##  [63] S7_0.2.2                    evaluate_1.0.5             
##  [65] archive_1.1.13              desc_1.4.3                 
##  [67] survival_3.8-11             RcppParallel_5.1.11-2      
##  [69] snpStats_1.60.0             Biostrings_2.78.0          
##  [71] pillar_1.11.1               MatrixGenerics_1.22.0      
##  [73] metadat_1.6-0               stats4_4.5.3               
##  [75] generics_0.1.4              vroom_1.7.1                
##  [77] mathjaxr_2.0-0              S4Vectors_0.48.0           
##  [79] hms_1.1.4                   ggplot2_4.0.3              
##  [81] scales_1.4.0                glue_1.8.1                 
##  [83] tools_4.5.3                 data.table_1.18.6.1        
##  [85] fs_2.1.0                    grid_4.5.3                 
##  [87] tidyr_1.3.2                 nlme_3.1-170               
##  [89] cli_3.6.6                   zigg_0.0.2                 
##  [91] textshaping_1.0.5           mixsqp_0.3-54              
##  [93] S4Arrays_1.10.1             viridisLite_0.4.3          
##  [95] dplyr_1.2.1                 gtable_0.3.6               
##  [97] sass_0.4.10                 digest_0.6.39              
##  [99] BiocGenerics_0.56.0         SparseArray_1.10.8         
## [101] htmlwidgets_1.6.4           farver_2.1.2               
## [103] htmltools_0.5.9             pkgdown_2.2.1              
## [105] lifecycle_1.0.5             bit64_4.8.6                
## [107] MASS_7.3-66