TSSr Vignette

Zhaolian Lu, Keenan Berry, Zhenbin Hu, Yu Zhan, Tae-Hyuk Ahn, Zhenguo Lin

2026-09-21

Introduction

TSSr is a comprehensive R/Bioconductor package for analyzing transcription start site (TSS) sequencing data. It supports multiple input formats including BAM, BED, BigWig, and TSS tables, and provides a complete workflow from TSS identification through downstream analyses such as core promoter shape analysis, gene annotation, differential expression, and promoter shifting.

Installation

Install TSSr through Bioconductor with BiocManager:

if (!requireNamespace("BiocManager", quietly = TRUE))
    install.packages("BiocManager")

BiocManager::install("TSSr")

And load TSSr:

library(TSSr)

Citation

If you use TSSr, please cite the following article:

citation("TSSr")
#> To cite package 'TSSr' in publications use:
#> 
#>   Lu Z, Berry K, Hu Z, Zhan Y, Ahn T, Lin Z (2021). "TSSr: an R package
#>   for comprehensive analyses of TSS sequencing data." _NAR Genomics and
#>   Bioinformatics_, *3*(4), lqab108. doi:10.1093/nargab/lqab108
#>   <https://doi.org/10.1093/nargab/lqab108>.
#> 
#> A BibTeX entry for LaTeX users is
#> 
#>   @Article{,
#>     title = {TSSr: an R package for comprehensive analyses of TSS sequencing data},
#>     author = {Zhaolian Lu and Keenan Berry and Zhenbin Hu and Yu Zhan and Tae-Hyuk Ahn and Zhenguo Lin},
#>     journal = {NAR Genomics and Bioinformatics},
#>     year = {2021},
#>     volume = {3},
#>     number = {4},
#>     pages = {lqab108},
#>     doi = {10.1093/nargab/lqab108},
#>   }

Getting help

For general questions about the usage of TSSr, use the official Bioconductor support forum and tag your question “TSSr”. We strive to answer questions as quickly as possible.

For technical questions, bug reports and suggestions for new features, we refer to the TSSr github page.

Quick start

This vignette runs an analysis from input files rather than beginning with a precomputed TSSr object. The same object, named myTSSr, is returned and reassigned at every stage of the workflow.

Bundled input files

The example TSS table contains four samples. The accompanying GFF file provides gene coordinates for annotation. system.file() locates these files inside the installed package, and mustWork = TRUE ensures that a missing file is reported immediately.

exampleInput <- system.file(
    "extdata",
    "example-tss-table.tsv",
    package = "TSSr",
    mustWork = TRUE
)
exampleAnnotation <- system.file(
    "extdata",
    "example-annotation.gff3",
    package = "TSSr",
    mustWork = TRUE
)

We create one TSSr object named myTSSr and retain this name throughout the vignette. The four input samples are assigned to two merged groups: SL01 and SL02 form the control group, while SL03 and SL04 form the treat group.

myTSSr <- TSSr(
    genomeName = "BSgenome.Scerevisiae.UCSC.sacCer3",
    inputFiles = exampleInput,
    inputFilesType = "TSStable",
    sampleLabels = c("SL01", "SL02", "SL03", "SL04"),
    sampleLabelsMerged = c("control", "treat"),
    mergeIndex = c(1, 1, 2, 2),
    refSource = exampleAnnotation
)

myTSSr
#> TSSr object
#>   Genome: BSgenome.Scerevisiae.UCSC.sacCer3
#>   Samples: 4 (SL01, SL02, SL03, SL04)
#>   Merged samples: 2 (control, treat)
#>   TSSs: raw 0; processed 0
#>   Analyses:
#>     Tag clusters: <not run>
#>     Consensus clusters: <not run>
#>     Cluster shapes: <not run>
#>     Assigned clusters: <not run>
#>     Unassigned clusters: <not run>
#>     Filtered clusters: <not run>
#>     Enhancers: <not run>
#>     DE comparisons: <not run>
#>     TAG tables: <not run>
#>     Promoter shifts: <not run>

Using your own data

To analyse your own data, replace the values in the TSSr() call above while keeping the object name myTSSr. The supplied values must satisfy the requirements below.

Constructor arguments

Argument Required Accepted values and restrictions
genomeName Yes A single character string naming an installed BSgenome package that matches the genome assembly used to generate the input files, for example "BSgenome.Scerevisiae.UCSC.sacCer3".
inputFiles Yes A character vector containing paths to existing regular files. For "bam", "bamPairedEnd", "bed", "tss", and "BigWig", supply one file per original sample. For "TSStable", supply exactly one table containing all samples.
inputFilesType Yes One case-sensitive value chosen from "bam", "bamPairedEnd", "bed", "tss", "BigWig", or "TSStable". See the table below.
sampleLabels Yes A non-empty character vector naming the original samples. Except for "TSStable", its length must equal length(inputFiles). For "TSStable", the labels identify sample columns in the single input table.
sampleLabelsMerged No A character vector naming the groups produced by replicate merging, in the order indicated by mergeIndex. It must be supplied together with mergeIndex. If both arguments are omitted, each sample is treated as a separate group.
mergeIndex No A numeric vector assigning every original sample to a merged group. Its length must equal length(sampleLabels). Use consecutive positive integers beginning with 1, such as c(1, 1, 2, 2). The number of unique indices must equal length(sampleLabelsMerged).
refSource No Zero or one path to an existing genome-annotation file used by annotateCluster(). Supply it when cluster annotation will be performed and no annotation table has otherwise been added to the object.
organismName No Zero or one character string describing the organism. This optional metadata is not required for TSS clustering.

Accepted input types

The value of inputFilesType is case-sensitive and must be one of the following:

inputFilesType Input represented Required file arrangement
"bam" Single-end BAM alignments One BAM file per sample
"bamPairedEnd" Paired-end BAM alignments One BAM file per sample
"bed" BED-formatted TSS data One BED file per sample
"tss" CTSS/TSS position-and-signal data One file per sample
"BigWig" BigWig signal data One BigWig file per sample
"TSStable" A tabular TSS matrix containing multiple samples Exactly one table containing all sample columns

For example, four original samples can be merged into two experimental groups using sampleLabelsMerged = c("control", "treat") and mergeIndex = c(1, 1, 2, 2). Index 1 corresponds to "control", and index 2 corresponds to "treat"; the ordering of sampleLabelsMerged must therefore match the numeric group indices.

If replicate merging is not required, omit both sampleLabelsMerged and mergeIndex. TSSr() will automatically retain each original sample as a separate group. Do not supply only one of these two arguments.

Importing TSS data

getTSS() reads the input file and stores the imported signal in the raw TSS matrix. Displaying its dimensions provides a quick confirmation that the data were imported before later analysis steps are run.

myTSSr <- getTSS(myTSSr)
dim(TSSmatrix(myTSSr, data = "raw"))
#> [1] 482   7

For formats other than "TSStable", the import step may require additional format-specific settings. See ?getTSS before adapting the example to BAM or other position-based files.

TSS data processing

The myTSSr object now contains the chromosome I signals imported above. The next chunk merges the original samples into their experimental groups, normalizes the merged signals, and applies the TPM filter in sequence.

# Merge replicates
myTSSr <- mergeSamples(myTSSr)
# Normalization
myTSSr <- normalizeTSS(myTSSr)
#> 
#> Normalizing TSS matrix...
# TSS filtering
rowsBeforeFiltering <- nrow(TSSmatrix(myTSSr, data = "processed"))
myTSSr <- filterTSS(myTSSr, method = "TPM", tpmLow = 2)
#> 
#> Filtering data with TPM method...
c(
    before = rowsBeforeFiltering,
    after = nrow(TSSmatrix(myTSSr, data = "processed"))
)
#> before  after 
#>    482    482

These functions populate the processed TSS matrix in the returned object. The reported row counts show how many genomic TSS positions remain after the TPM filter. Both values are 482 for the bundled fixture because no positions are removed at the selected threshold; user datasets may show a decrease at this step. Use TSSmatrix() to inspect this matrix through the public accessor:

# Access the processed TSS matrix without exposing internal storage
head(TSSmatrix(myTSSr, data = "processed"))
#>    chr  pos strand   control     treat
#> 1 chrI 6530      + 144.16146  29.87661
#> 2 chrI 9277      +   0.00000  59.75322
#> 3 chrI 9325      +  48.05382   0.00000
#> 4 chrI 9327      + 192.21528 239.01288
#> 5 chrI 9338      +  96.10764 149.38305
#> 6 chrI 9340      +  48.05382  29.87661

The first three columns identify the chromosome, genomic position, and strand; the remaining columns contain processed signals for the merged sample groups. This matrix is the input for TSS clustering.

TSS clustering

Nearby TSSs can represent transcription initiation from the same core promoter. clusterTSS() groups these positions into sample-specific tag clusters using the peak-based peakclu method. Here, candidate peaks must be at least 100 bp apart, a cluster can extend across gaps of at most 30 bp, TSSs below 2% of the local peak are removed, and clusters with signal below 1 TPM are discarded. consensusCluster() then relates tag clusters across sample groups whose dominant TSSs are within 50 bp, providing common regions for comparative analyses.

# TSS clustering
myTSSr <- clusterTSS(myTSSr,
    method = "peakclu", peakDistance = 100, extensionDistance = 30,
    localThreshold = 0.02, clusterThreshold = 1,
    useMultiCore = FALSE, numCores = NULL
)
#> 
#> Clustering TSS data with peakclu method...

# Aggregating consensus clusters
myTSSr <- consensusCluster(myTSSr, dis = 50, useMultiCore = FALSE)
#> 
#> Creating consensus clusters...

The returned object now contains both tagClusters and consensusClusters. Their accessors expose the sample-specific calls and the cross-sample regions, respectively:

# Tag clusters per sample
head(tagClusters(myTSSr, sample = "control"))
#>   cluster  chr start   end strand dominant_tss       tags tags.dominant_tss
#> 1       1 chrI  6530  6530      +         6530  144.16146         144.16146
#> 2       2 chrI  9325  9411      +         9327  768.86112         192.21528
#> 3       3 chrI  9442  9479      +         9442  528.59202         288.32292
#> 4       4 chrI  9860  9860      +         9860   48.05382          48.05382
#> 5       5 chrI 11061 11061      +        11061   48.05382          48.05382
#> 6       6 chrI 11253 11343      +        11329 6295.05046        2739.06776
#>   q_0.1 q_0.9 interquantile_width
#> 1  6530  6530                   1
#> 2  9327  9391                  65
#> 3  9442  9468                  27
#> 4  9860  9860                   1
#> 5 11061 11061                   1
#> 6 11275 11329                  55

# Consensus clusters across samples
head(consensusClusters(myTSSr, sample = "control"))
#>   cluster  chr start   end strand dominant_tss       tags tags.dominant_tss
#> 1       1 chrI  6530  6530      +         6530  144.16146         144.16146
#> 2       2 chrI  9325  9411      +         9327  768.86112         192.21528
#> 3       3 chrI  9442  9479      +         9442  528.59202         288.32292
#> 4       4 chrI  9860  9860      +         9860   48.05382          48.05382
#> 5       5 chrI 11061 11061      +        11061   48.05382          48.05382
#> 6       6 chrI 11253 11343      +        11329 6295.05046        2739.06776
#>   q_0.1 q_0.9 interquantile_width
#> 1  6530  6530                   1
#> 2  9327  9391                  65
#> 3  9442  9468                  27
#> 4  9860  9860                   1
#> 5 11061 11061                   1
#> 6 11275 11329                  55

Each table reports cluster coordinates, the dominant TSS, TSS signal, and inter-quantile boundaries. Consensus clusters are used below so that promoter shape, annotation, and between-group comparisons refer to the same genomic regions. See ?clusterTSS and ?consensusCluster for parameter details.

Core promoter shape

Core promoter shape describes how initiation signals are distributed within a cluster. shapeCluster() can calculate either the Shape Index (SI) or Promoter Shape Score (PSS); this example calculates PSS for the consensus clusters. PSS combines the inter-quantile width with the distribution of TSS signals. Smaller PSS values indicate sharper promoters, and a singleton has a score of zero.

# Calculating core promoter shape score
myTSSr <- shapeCluster(myTSSr,
    clusters = "consensusClusters", method = "PSS",
    useMultiCore = FALSE, numCores = NULL
)
#> 
#> Calculating consensusClusters shape with PSS method...

The scores are stored in clusterShape for each merged sample group and can be retrieved without accessing the object’s internal slots:

# Shape scores per cluster
head(clusterShape(myTSSr, sample = "control"))
#>   cluster  chr start   end strand dominant_tss       tags tags.dominant_tss
#> 1       1 chrI  6530  6530      +         6530  144.16146         144.16146
#> 2       2 chrI  9325  9411      +         9327  768.86112         192.21528
#> 3       3 chrI  9442  9479      +         9442  528.59202         288.32292
#> 4       4 chrI  9860  9860      +         9860   48.05382          48.05382
#> 5       5 chrI 11061 11061      +        11061   48.05382          48.05382
#> 6       6 chrI 11253 11343      +        11329 6295.05046        2739.06776
#>   q_0.1 q_0.9 interquantile_width shape.score
#> 1  6530  6530                   1    0.000000
#> 2  9327  9391                  65   17.767262
#> 3  9442  9468                  27    7.469693
#> 4  9860  9860                   1    0.000000
#> 5 11061 11061                   1    0.000000
#> 6 11275 11329                  55   15.740261

These values can be used to compare promoter architectures across samples or exported with exportShapeTable(). Only the most recently calculated shape method is retained; see ?shapeCluster for the SI alternative.

Annotation of core promoters

Annotation connects consensus clusters to downstream genes so that subsequent analyses can operate at gene level. The refSource supplied when myTSSr was constructed points to the bundled GFF annotation. With the settings below, a cluster is considered up to 1000 bp upstream of a gene start; overlapping upstream features use the more restrictive 500-bp rule. Weak downstream clusters below 2% of the strongest cluster in the promoter region are filtered to reduce recapping and other low-signal events.

# Assign clusters to the annotated features
myTSSr <- annotateCluster(myTSSr, clusters = "consensusClusters",
    filterCluster = TRUE, filterClusterThreshold = 0.02,
    annotationType = "genes", upstream = 1000,
    upstreamOverlap = 500, downstream = 0)
#> 
#> Annotating...
#> Import genomic features from the file as a GRanges object ... OK
#> Prepare the 'metadata' data frame ... OK
#> Make the TxDb object ... OK

The returned object separates clusters into assigned, unassigned, and, when filtering is enabled, filtered tables. The following accessor displays clusters that were assigned to genes in the control group:

# Clusters assigned to genes
head(assignedClusters(myTSSr, sample = "control"))
#>   cluster  chr start   end strand dominant_tss       tags tags.dominant_tss
#> 1       2 chrI  9325  9411      +         9327  768.86112         192.21528
#> 2       3 chrI  9442  9479      +         9442  528.59202         288.32292
#> 3       4 chrI  9860  9860      +         9860   48.05382          48.05382
#> 4       5 chrI 11061 11061      +        11061   48.05382          48.05382
#> 5       6 chrI 11253 11343      +        11329 6295.05046        2739.06776
#> 6       7 chrI 11652 11652      +        11652   48.05382          48.05382
#>   q_0.1 q_0.9 interquantile_width      gene inCoding
#> 1  9327  9391                  65   YAL066W     <NA>
#> 2  9442  9468                  27   YAL066W     <NA>
#> 3  9860  9860                   1   YAL066W     <NA>
#> 4 11061 11061                   1 YAL064W-B     <NA>
#> 5 11275 11329                  55 YAL064W-B     <NA>
#> 6 11652 11652                   1 YAL064W-B     <NA>

The gene column records the assigned feature, while the cluster columns retain the genomic position and signal information. Assigned clusters support the gene-level differential expression and promoter-shift analyses below; unassigned clusters are considered during enhancer identification. See ?annotateCluster when adapting promoter windows to another organism.

Enhancer identification

Active enhancers can produce nearby, divergent transcription signals. callEnhancer() searches the unassigned clusters for opposite-strand pairs no more than 400 bp apart, applies a directionality filter, and excludes candidates within 2000 bp of a gene’s main annotated promoter. The result should therefore be interpreted as a set of putative enhancers rather than independently validated regulatory elements.

myTSSr <- callEnhancer(myTSSr, flanking = 400, dis2gene = 2000)
#> 
#> Calculating enhancers...

Candidate pairs and their strand-specific signals are stored in the enhancers slot. Use the public accessor to inspect one sample group:

# Putative enhancers per sample
head(enhancers(myTSSr, sample = "control"))
#>   enhancer cluster.m cluster.p  chr dominant_tss.m dominant_tss.p     tags.m
#> 1        2       137        16 chrI          31502          31891 1537.72225
#> 2        3       140        20 chrI          34336          34583   48.05382
#> 3        4       141        21 chrI          34784          35147  144.16146
#> 4        5       145        30 chrI          43402          43754  144.16146
#> 5        7       152        38 chrI          57399          57515  192.21528
#> 6        8       156        43 chrI          62512          62842   96.10764
#>      tags.p          D
#> 1 288.32292 -0.6842105
#> 2 240.26910  0.6666667
#> 3 144.16146  0.0000000
#> 4  48.05382 -0.5000000
#> 5 432.48438  0.3846154
#> 6 432.48438  0.6363636

The output identifies the paired clusters, their dominant TSS positions and signals, and the directionality score D. See ?callEnhancer for the candidate selection parameters and exportEnhancerTable() for saving the complete table.

Differential expression analysis

After annotation, TSSr can aggregate raw TSS counts from assigned clusters by gene and use DESeq2 to compare sample groups. comparePairs sets the order of the comparison, here control versus treat, and pval = 0.01 retains genes with an adjusted p value below 0.01 in the significant-results table. DESeq2 is a suggested dependency and must be installed to run this step. The bundled example contains only a few annotated genes, so it uses fitType = "mean" to avoid an unstable local dispersion-trend fit. The default remains fitType = "parametric" for ordinary analyses.

# Gene-level differential expression using DESeq2
myTSSr <- deGene(myTSSr, comparePairs = list(c("control", "treat")),
    pval = 0.01, useMultiCore = FALSE, numCores = NULL,
    fitType = "mean")
#> 
#> Calculating gene differential expression...
#> estimating size factors
#> estimating dispersions
#> gene-wise dispersion estimates
#> mean-dispersion relationship
#> final dispersion estimates
#> fitting model and testing

The returned object stores the gene-level count tables and both complete and significant DESeq2 results. DEtables() selects a comparison and result set:

# All differential expression results
head(DEtables(
    myTSSr,
    comparison = "control_VS_treat",
    result = "all"
))
#>        gene  baseMean log2FoldChange     lfcSE       stat      pvalue
#> 1   YAL063C 15.558156    -1.77844558 0.5935313 -2.9963805 0.002732053
#> 2 YAL063C-A 29.676573     0.21760642 0.5292249  0.4111795 0.680940941
#> 3   YAL064W  3.673666     0.27184892 0.8805771  0.3087168 0.757536972
#> 4 YAL064W-B 97.503791     0.14320588 0.4293669  0.3335280 0.738735777
#> 5   YAL066W 18.941666    -0.06771274 0.5347945 -0.1266145 0.899245503
#> 6   YAL067C 25.055727    -0.02456972 0.5054333 -0.0486112 0.961229146
#>         padj
#> 1 0.01639232
#> 2 0.96122915
#> 3 0.96122915
#> 4 0.96122915
#> 5 0.96122915
#> 6 0.96122915

Each row in the displayed table corresponds to one annotated gene and includes the DESeq2 effect-size and significance statistics. result = "significant" returns the subset with an adjusted p value below the pval threshold. At pval = 0.01, none of the six genes in this small bundled dataset meet that criterion, so its significant-results table is empty. Use plotDE() to visualize the results or exportDETable() to save them.

Core promoter shifts

Genes with multiple core promoters may use them at different proportions between conditions. shiftPromoter() tests the annotated promoter profiles for the requested control-versus-treat comparison. Sparse gene-level 2-by-2 tables can have small expected counts; in that case, the function emits one summary warning for all affected tests and their approximate p values may be unreliable. See ?shiftPromoter for details.

# Calculate core promoter shifts
myTSSr <- shiftPromoter(myTSSr, comparePairs = list(c("control", "treat")),
    pval = 0.01)
#> 
#> Calculating core promoter shifts...
#> Warning: Chi-squared approximation may be incorrect for 4 gene-level test(s)
#> with small expected counts; the affected p-values may be unreliable.

The test results are stored by comparison in the PromoterShift slot. The accessor below retrieves the table for this pair:

# Promoter shift results
head(PromoterShift(myTSSr, comparison = "control_VS_treat"))
#>      gene         Ds         pval         padj
#> 1 YAL066W -13.565114 9.479127e-07 5.687476e-06
#> 2 YAL067C   2.864633 1.809581e-04 5.428742e-04

The table reports gene-level promoter-shift statistics and associated p values. Because small expected counts weaken the chi-squared approximation, inspect the underlying promoter signals before interpreting affected genes.

Exporting results

TSSr can save processed TSS values and cluster tables for downstream analysis, or write genome-browser tracks for visualization. The functions below write to the current working directory. The vignette temporarily switches to tempdir() so that rendering does not add result files to the package source.

oldwd <- setwd(tempdir())

# Export processed TSS values to ALL.samples.TSS.processed.txt
exportTSStable(myTSSr, data = "processed")
#> Exporting TSS table...

# Export cluster tables
exportClustersTable(myTSSr, data = "assigned")
#> Exporting assignedClusters table...

# Export to BED format for genome browsers
exportClustersToBed(myTSSr, data = "consensusClusters")
#> Exporting clusters to bed...

# Export TSS to bedGraph
exportTSStoBedgraph(myTSSr, data = "processed")
#> Exporting TSS to bedgraph...
#> Exporting TSS to bedgraph...

setwd(oldwd)

This creates a tab-delimited processed TSS table, per-sample assigned-cluster tables, BED files for assigned consensus clusters, and strand-specific bedGraph tracks for the processed TSS signal. BED and bedGraph files can be loaded into genome browsers such as UCSC Genome Browser or IGV. In an interactive analysis, set the working directory to the desired output location before calling these functions; see the individual export help pages for file-naming options.

Precomputed example object

The package also includes exampleTSSr, a precomputed object for users who want to inspect a populated TSSr object without rerunning the workflow. It is not used as the input to the analysis above and does not replace myTSSr.

data("exampleTSSr")
exampleTSSr
#> TSSr object
#>   Genome: BSgenome.Scerevisiae.UCSC.sacCer3
#>   Samples: 4 (SL01, SL02, SL03, SL04)
#>   Merged samples: 2 (control, treat)
#>   TSSs: raw 29,456; processed 14,895
#>   Analyses:
#>     Tag clusters: control 765; treat 843
#>     Consensus clusters: control 765; treat 842
#>     Cluster shapes: control 765; treat 842
#>     Assigned clusters: control 12; treat 13
#>     Unassigned clusters: control 753; treat 829
#>     Filtered clusters: control 765; treat 840
#>     Enhancers: control 74; treat 64
#>     DE comparisons: 1 (control_VS_treat)
#>     TAG tables: control 12; treat 13
#>     Promoter shifts: control_VS_treat 2

Complete workflow in one pipeline

The step-by-step assignments above make intermediate results easy to inspect. Once the settings have been established, the same analysis can be expressed as one base R pipeline. The object is still named myTSSr; only the style of the assignment changes. Replace the constructor values with the paths, labels, genome, and annotation for your own experiment.

myTSSr <- TSSr(
    genomeName = "BSgenome.Scerevisiae.UCSC.sacCer3",
    inputFiles = exampleInput,
    inputFilesType = "TSStable",
    sampleLabels = c("SL01", "SL02", "SL03", "SL04"),
    sampleLabelsMerged = c("control", "treat"),
    mergeIndex = c(1, 1, 2, 2),
    refSource = exampleAnnotation
) |>
    getTSS() |>
    mergeSamples() |>
    normalizeTSS() |>
    filterTSS(method = "TPM", tpmLow = 2) |>
    clusterTSS(
        method = "peakclu",
        peakDistance = 100,
        extensionDistance = 30,
        localThreshold = 0.02,
        clusterThreshold = 1,
        useMultiCore = FALSE,
        numCores = NULL
    ) |>
    consensusCluster(
        dis = 50,
        useMultiCore = FALSE
    ) |>
    shapeCluster(
        clusters = "consensusClusters",
        method = "PSS",
        useMultiCore = FALSE,
        numCores = NULL
    ) |>
    annotateCluster(
        clusters = "consensusClusters",
        filterCluster = TRUE,
        filterClusterThreshold = 0.02,
        annotationType = "genes",
        upstream = 1000,
        upstreamOverlap = 500,
        downstream = 0
    ) |>
    callEnhancer(
        flanking = 400,
        dis2gene = 2000
    ) |>
    deGene(
        comparePairs = list(c("control", "treat")),
        pval = 0.01,
        useMultiCore = FALSE,
        numCores = NULL,
        fitType = "mean"
    ) |>
    shiftPromoter(
        comparePairs = list(c("control", "treat")),
        pval = 0.01
    )

The export functions are intentionally kept outside this pipeline because they write files rather than add a new analysis stage to the returned object.

Session info

Recording package and R versions makes the rendered analysis easier to reproduce and diagnose:

sessionInfo()
#> R version 4.6.1 (2026-06-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 24.04.5 LTS
#> 
#> Matrix products: default
#> BLAS:   /home/biocbuild/bbs-3.24-bioc/R/lib/libRblas.so 
#> LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.12.0  LAPACK version 3.12.0
#> 
#> locale:
#>  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
#>  [3] LC_TIME=en_GB              LC_COLLATE=C              
#>  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
#>  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
#>  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
#> 
#> time zone: America/New_York
#> tzcode source: system (glibc)
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#> [1] TSSr_0.99.21
#> 
#> loaded via a namespace (and not attached):
#>   [1] tidyselect_1.2.1                       
#>   [2] dplyr_1.2.1                            
#>   [3] farver_2.1.2                           
#>   [4] blob_1.3.0                             
#>   [5] filelock_1.0.3                         
#>   [6] Biostrings_2.81.9                      
#>   [7] S7_0.2.2                               
#>   [8] bitops_1.1-0                           
#>   [9] fastmap_1.2.0                          
#>  [10] RCurl_1.98-1.20                        
#>  [11] BiocFileCache_3.3.0                    
#>  [12] GenomicAlignments_1.49.2               
#>  [13] XML_3.99-0.24                          
#>  [14] digest_0.6.39                          
#>  [15] lifecycle_1.0.5                        
#>  [16] KEGGREST_1.53.6                        
#>  [17] RSQLite_3.53.3                         
#>  [18] magrittr_2.0.5                         
#>  [19] compiler_4.6.1                         
#>  [20] BSgenome.Scerevisiae.UCSC.sacCer3_1.4.0
#>  [21] rlang_1.3.0                            
#>  [22] sass_0.4.10                            
#>  [23] progress_1.2.3                         
#>  [24] tools_4.6.1                            
#>  [25] yaml_2.3.12                            
#>  [26] data.table_1.18.6.1                    
#>  [27] rtracklayer_1.73.0                     
#>  [28] knitr_1.52                             
#>  [29] prettyunits_1.2.0                      
#>  [30] S4Arrays_1.13.0                        
#>  [31] bit_4.6.0                              
#>  [32] curl_8.0.0                             
#>  [33] DelayedArray_0.39.6                    
#>  [34] RColorBrewer_1.1-3                     
#>  [35] abind_1.4-8                            
#>  [36] BiocParallel_1.47.0                    
#>  [37] txdbmaker_1.9.0                        
#>  [38] BiocGenerics_0.59.12                   
#>  [39] grid_4.6.1                             
#>  [40] stats4_4.6.1                           
#>  [41] ggplot2_4.0.3                          
#>  [42] scales_1.4.0                           
#>  [43] dichromat_2.0-1                        
#>  [44] biomaRt_2.69.4                         
#>  [45] SummarizedExperiment_1.43.0            
#>  [46] cli_3.6.6                              
#>  [47] rmarkdown_2.32                         
#>  [48] crayon_1.5.3                           
#>  [49] generics_0.1.4                         
#>  [50] otel_0.2.0                             
#>  [51] httr_1.4.9                             
#>  [52] rjson_0.2.23                           
#>  [53] BiocBaseUtils_1.15.1                   
#>  [54] DBI_1.3.0                              
#>  [55] cachem_1.1.0                           
#>  [56] stringr_1.6.0                          
#>  [57] parallel_4.6.1                         
#>  [58] AnnotationDbi_1.75.2                   
#>  [59] XVector_0.53.0                         
#>  [60] restfulr_0.0.17                        
#>  [61] matrixStats_1.5.0                      
#>  [62] vctrs_0.7.3                            
#>  [63] Matrix_1.7-6                           
#>  [64] jsonlite_2.0.0                         
#>  [65] IRanges_2.47.5                         
#>  [66] hms_1.1.4                              
#>  [67] S4Vectors_0.51.10                      
#>  [68] bit64_4.8.6                            
#>  [69] GenomicFeatures_1.65.0                 
#>  [70] locfit_1.5-9.12                        
#>  [71] jquerylib_0.1.4                        
#>  [72] glue_1.8.1                             
#>  [73] codetools_0.2-20                       
#>  [74] stringi_1.8.9                          
#>  [75] gtable_0.3.6                           
#>  [76] GenomeInfoDb_1.49.1                    
#>  [77] BiocIO_1.23.3                          
#>  [78] GenomicRanges_1.65.4                   
#>  [79] UCSC.utils_1.9.0                       
#>  [80] tibble_3.3.1                           
#>  [81] pillar_1.11.1                          
#>  [82] htmltools_0.5.9                        
#>  [83] Seqinfo_1.3.2                          
#>  [84] BSgenome_1.81.1                        
#>  [85] R6_2.6.1                               
#>  [86] dbplyr_2.6.0                           
#>  [87] httr2_1.3.0                            
#>  [88] lattice_0.23-1                         
#>  [89] evaluate_1.0.5                         
#>  [90] Biobase_2.73.2                         
#>  [91] png_0.1-9                              
#>  [92] Rsamtools_2.29.0                       
#>  [93] cigarillo_1.3.1                        
#>  [94] memoise_2.0.1                          
#>  [95] bslib_0.12.0                           
#>  [96] Rcpp_1.1.2                             
#>  [97] SparseArray_1.13.2                     
#>  [98] DESeq2_1.53.3                          
#>  [99] xfun_0.61                              
#> [100] MatrixGenerics_1.25.0                  
#> [101] pkgconfig_2.0.3