RBPSpecificity provides tools to analyze RNA-Binding Protein (RBP) binding specificities from high-throughput sequencing data. This package provides tools for:
The package implements two key metrics for characterizing RBP binding behavior:
These metrics enable quantitative comparison of RBP binding properties across different experimental conditions or between different RBPs.
For a detailed description of these metrics and their biological applications, please refer to:
Yi S, Singh SS, Ye X, Krishna R, Kothwela V, Jankowsky E, Luna JM. (2025). Inherent Specificity and Mutational Sensitivity as Quantitative Metrics for RBP Binding. bioRxiv. https://www.biorxiv.org/content/10.1101/2025.03.28.646018v4
RBPSpecificity is designed to seamlessly integrate into standard Bioconductor sequence and genomic analysis workflows:
GRanges objects using rtracklayer::import() and standard annotation
packages (e.g. GenomicFeatures).motifEnrichment() function interfaces directly with
BSgenome genome packages (e.g., BSgenome.Hsapiens.UCSC.hg38) to extract genomic
sequences for enrichment calculations.DiffBind, DESeq2), regulatory network modeling, or motif
annotation pipelines.The sample data included in this package were obtained from the ENCODE portal.
RNA Bind-n-Seq (RBNS) datasets provide in vitro RNA-RBP affinity measurements. For each K-mer enrichment dataset, the RBP concentration generating the highest R-value was selected as the representative sample. The collected RBNS R scores were feature-scaled to [1, e] followed by natural log transformation to normalize to a 0-to-1 scale.
eCLIP datasets provide in vivo RBP binding site information. Peak coordinates were extended 25 nucleotides upstream from the 5’-end. Motif enrichment was calculated by counting K-mer appearances across extended peaks and subtracting background counts from randomly shifted genomic regions (up to 500 nt away). Background generation was repeated 100 times for robust averaging.
if (!requireNamespace("BiocManager", quietly = TRUE)) {
install.packages("BiocManager")
}
BiocManager::install("RBPSpecificity")
library(RBPSpecificity)
library(ggplot2)
This workflow demonstrates how to calculate specificity and sensitivity from pre-computed enrichment scores, such as those from RBNS (RNA Bind-n-Seq) experiments.
The sample data contains normalized 5-mer enrichment scores for four RBPs: HNRNPC, PCBP2 (structural context independent), RBFOX2, and EIF4G2 (structural context dependent).
# Load sample RBNS data from package
rbns_file <- system.file("extdata", "RBNS_normalized_5mer.csv",
package = "RBPSpecificity"
)
rbns_data <- read.csv(rbns_file, stringsAsFactors = FALSE)
# Preview the data
head(rbns_data)
#> Motif EIF4G2 HNRNPC RBFOX2 PCBP2
#> 1 AAAAA 0.4667673 0.02115767 0.05019945 0.02791232
#> 2 AAAAC 0.3879612 0.02118148 0.02586520 0.05477091
#> 3 AAAAG 0.4692119 0.01456301 0.05103704 0.01947033
#> 4 AAAAU 0.4591129 0.02351263 0.04702782 0.02892464
#> 5 AAACA 0.3666514 0.02098727 0.02119075 0.02849734
#> 6 AAACC 0.3428551 0.03361433 0.01435467 0.18305568
The package expects a data.frame with MOTIF and Score columns:
rbps <- c("HNRNPC", "PCBP2", "RBFOX2", "EIF4G2")
rbns_metrics <- lapply(rbps, function(rbp) {
rbns_enrichment <- data.frame(
MOTIF = rbns_data$Motif,
Score = rbns_data[[rbp]]
)
is_val <- returnSpecificity(rbns_enrichment)
vs_val <- returnSensitivity(rbns_enrichment, output_type = "number")
list(
enrichment = rbns_enrichment,
Specificity = is_val,
Sensitivity = vs_val
)
})
names(rbns_metrics) <- rbps
# Display in vitro metrics
invitro_summary <- data.frame(
RBP = rbps,
Specificity = sapply(rbns_metrics, function(x) round(x$Specificity, 2)),
Sensitivity = sapply(rbns_metrics, function(x) round(x$Sensitivity, 4))
)
print(invitro_summary)
#> RBP Specificity Sensitivity
#> HNRNPC HNRNPC 50.84 0.8580
#> PCBP2 PCBP2 21.57 0.4932
#> RBFOX2 RBFOX2 31.51 0.9027
#> EIF4G2 EIF4G2 2.04 0.4359
The plotSpecificity() function displays the distribution of k-mer scores, highlighting
the top motif and its specificity value:
plotSpecificity(rbns_metrics[["HNRNPC"]]$enrichment)
Figure 1: Distribution of k-mer scores from RBNS data for four RBPs
plotSpecificity(rbns_metrics[["PCBP2"]]$enrichment)
Figure 2: Distribution of k-mer scores from RBNS data for four RBPs
plotSpecificity(rbns_metrics[["RBFOX2"]]$enrichment)
Figure 3: Distribution of k-mer scores from RBNS data for four RBPs
plotSpecificity(rbns_metrics[["EIF4G2"]]$enrichment)
Figure 4: Distribution of k-mer scores from RBNS data for four RBPs
The plotSensitivity() function visualizes how sensitive binding is to mutations at each
position:
plotSensitivity(rbns_metrics[["HNRNPC"]]$enrichment)
Figure 5: Sensitivity profiles from RBNS data for four RBPs
plotSensitivity(rbns_metrics[["PCBP2"]]$enrichment)
Figure 6: Sensitivity profiles from RBNS data for four RBPs
plotSensitivity(rbns_metrics[["RBFOX2"]]$enrichment)
Figure 7: Sensitivity profiles from RBNS data for four RBPs
plotSensitivity(rbns_metrics[["EIF4G2"]]$enrichment)
Figure 8: Sensitivity profiles from RBNS data for four RBPs
This workflow demonstrates how to calculate enrichment scores directly from
peak data using the motifEnrichment() function.
Note: While this example uses eCLIP-derived peaks,
motifEnrichment()works with any peak data in BED format (e.g., iCLIP, PAR-CLIP, or other ChIP-seq derived peaks).
Requirement: This workflow requires
BSgenome.Hsapiens.UCSC.hg38to be installed.
When calculating enrichment from cellular peak data, the resulting metrics are referred to as Cellular Specificity and Cellular Sensitivity, as they reflect in vivo binding behavior rather than intrinsic biochemical affinity.
# Load eCLIP peaks (10-column narrowPeak format) from package
bed_cols <- c(
"chr", "start", "end", "name", "score", "strand",
"signalValue", "pValue", "qValue", "peak"
)
rbp_names <- c("HNRNPC", "PCBP2", "RBFOX2", "EIF4G2")
cell_lines <- c("K562", "HepG2", "K562", "K562")
peak_data <- lapply(seq_along(rbp_names), function(i) {
bed_file <- system.file("extdata",
sprintf("ENCODE_eCLIP_%s_%s_narrowPeak.bed", rbp_names[i], cell_lines[i]),
package = "RBPSpecificity"
)
peaks <- read.table(bed_file, header = FALSE, sep = "\t")
colnames(peaks) <- bed_cols
message("Loaded ", nrow(peaks), " ", rbp_names[i], " peaks.")
peaks
})
names(peak_data) <- rbp_names
In addition to standard input variables, motifEnrichment() provides several
parameters for customization:
| Parameter | Description |
|---|---|
extension |
Numeric vector of length 2: c(five_prime, three_prime) indicating shifting of 5’ and 3’ ends. Positive extends, negative trims. |
method |
Enrichment model: "anr" (default, any number of repetitions, conditional Binomial test) or "zoops" (zero-or-one occurrence per sequence, Hypergeometric test) |
bkg_iter |
Number of background iterations for averaging (higher = more robust) |
bkg_min_dist |
Minimum distance (bp) to shift peaks when generating background regions |
bkg_max_dist |
Maximum distance (bp) for shifting peaks in background generation |
scramble_bkg |
Logical, scramble background sequences to control for nucleotide composition (default: FALSE) |
nucleic_acid_type |
Character string, "DNA" or "RNA" (default: "DNA") |
ZOOPS method can also be used instead. Note that ANR and ZOOPS calculation can
result in different motif enrichment values and thus different specificity and
sensitivity calculations. For more information on ANR vs. ZOOPS, please check
the GitHub README and Further Reading section. In addition, the scramble
background option can be turned on (scramble_bkg = TRUE) to control for
nucleotide composition.
# NOTE: This requires BSgenome.Hsapiens.UCSC.hg38
cellular_results <- lapply(rbp_names, function(rbp) {
message("Running motifEnrichment for ", rbp, "...")
enrichment <- motifEnrichment(
coordinates = peak_data[[rbp]],
species_or_build = "hg38",
K = 5,
extension = c(25, 0),
method = "anr",
bkg_iter = 100,
scramble_bkg = FALSE
)
cs_val <- returnSpecificity(enrichment)
cvs_val <- returnSensitivity(enrichment, output_type = "number")
list(
enrichment = enrichment,
Specificity = cs_val,
Sensitivity = cvs_val
)
})
#>
|
| | 0%
|
|======================================================================| 100%
#>
|
| | 0%
|
|==================== | 28%
|
|======================================= | 56%
|
|=========================================================== | 84%
|
|======================================================================| 100%
#>
|
| | 0%
|
|================================================ | 69%
|
|======================================================================| 100%
#>
|
| | 0%
|
|==================================== | 52%
|
|======================================================================| 100%
names(cellular_results) <- rbp_names
# Display cellular metrics
cellular_summary <- data.frame(
RBP = rbp_names,
Specificity = sapply(cellular_results, function(x) round(x$Specificity, 2)),
Sensitivity = sapply(cellular_results, function(x) round(x$Sensitivity, 4))
)
print(cellular_summary)
#> RBP Specificity Sensitivity
#> HNRNPC HNRNPC 36.10 0.9423
#> PCBP2 PCBP2 6.93 0.6575
#> RBFOX2 RBFOX2 2.99 0.4807
#> EIF4G2 EIF4G2 16.43 0.8935
The same plotSpecificity() and plotSensitivity() functions used for RBNS data can be applied
to visualize cellular specificity and cellular sensitivity from eCLIP enrichment results:
# Specificity Distribution plots
plotSpecificity(cellular_results[["HNRNPC"]]$enrichment)
plotSpecificity(cellular_results[["PCBP2"]]$enrichment)
plotSpecificity(cellular_results[["RBFOX2"]]$enrichment)
plotSpecificity(cellular_results[["EIF4G2"]]$enrichment)
# Sensitivity Profile plots
plotSensitivity(cellular_results[["HNRNPC"]]$enrichment)
plotSensitivity(cellular_results[["PCBP2"]]$enrichment)
plotSensitivity(cellular_results[["RBFOX2"]]$enrichment)
plotSensitivity(cellular_results[["EIF4G2"]]$enrichment)
A key application is comparing specificity and sensitivity across in vitro and cellular contexts. RBPs that bind directly to single-stranded sequence motifs (e.g., HNRNPC, PCBP2) are expected to show correlated specificity and sensitivity values. RBPs whose binding depends on structural context (e.g., RBFOX2, EIF4G2) may show divergence between in vitro and cellular metrics.
comparison <- data.frame(
RBP = rbp_names,
Structural_Context = c("Independent", "Independent", "Dependent", "Dependent"),
In_Vitro_Specificity = sapply(rbns_metrics[rbp_names], function(x) round(x$Specificity, 2)),
Cellular_Specificity = sapply(cellular_results, function(x) round(x$Specificity, 2)),
In_Vitro_Sensitivity = sapply(rbns_metrics[rbp_names], function(x) round(x$Sensitivity, 4)),
Cellular_Sensitivity = sapply(cellular_results, function(x) round(x$Sensitivity, 4))
)
print(comparison)
#> RBP Structural_Context In_Vitro_Specificity Cellular_Specificity
#> HNRNPC HNRNPC Independent 50.84 36.10
#> PCBP2 PCBP2 Independent 21.57 6.93
#> RBFOX2 RBFOX2 Dependent 31.51 2.99
#> EIF4G2 EIF4G2 Dependent 2.04 16.43
#> In_Vitro_Sensitivity Cellular_Sensitivity
#> HNRNPC 0.8580 0.9423
#> PCBP2 0.4932 0.6575
#> RBFOX2 0.9027 0.4807
#> EIF4G2 0.4359 0.8935
sessionInfo()
#> R version 4.6.1 (2026-06-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 24.04.4 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] stats4 stats graphics grDevices utils datasets methods
#> [8] base
#>
#> other attached packages:
#> [1] BSgenome.Hsapiens.UCSC.hg38_1.4.5 BSgenome_1.81.0
#> [3] rtracklayer_1.73.0 BiocIO_1.23.3
#> [5] Biostrings_2.81.5 XVector_0.53.0
#> [7] GenomicRanges_1.65.1 GenomeInfoDb_1.49.1
#> [9] Seqinfo_1.3.0 IRanges_2.47.2
#> [11] S4Vectors_0.51.5 BiocGenerics_0.59.10
#> [13] generics_0.1.4 ggplot2_4.0.3
#> [15] RBPSpecificity_0.99.6 BiocStyle_2.41.0
#>
#> loaded via a namespace (and not attached):
#> [1] SummarizedExperiment_1.43.0 gtable_0.3.6
#> [3] rjson_0.2.23 xfun_0.60
#> [5] bslib_0.11.0 Biobase_2.73.1
#> [7] lattice_0.22-9 vctrs_0.7.3
#> [9] tools_4.6.1 bitops_1.0-9
#> [11] curl_7.1.0 parallel_4.6.1
#> [13] tibble_3.3.1 pkgconfig_2.0.3
#> [15] BiocBaseUtils_1.15.1 Matrix_1.7-5
#> [17] RColorBrewer_1.1-3 S7_0.2.2
#> [19] cigarillo_1.3.1 lifecycle_1.0.5
#> [21] stringr_1.6.0 compiler_4.6.1
#> [23] farver_2.1.2 Rsamtools_2.29.0
#> [25] tinytex_0.60 codetools_0.2-20
#> [27] htmltools_0.5.9 sass_0.4.10
#> [29] RCurl_1.98-1.19 yaml_2.3.12
#> [31] pillar_1.11.1 crayon_1.5.3
#> [33] jquerylib_0.1.4 BiocParallel_1.47.0
#> [35] cachem_1.1.0 DelayedArray_0.39.3
#> [37] magick_2.9.1 abind_1.4-8
#> [39] tidyselect_1.2.1 digest_0.6.39
#> [41] stringi_1.8.7 reshape2_1.4.5
#> [43] dplyr_1.2.1 restfulr_0.0.17
#> [45] bookdown_0.47 labeling_0.4.3
#> [47] fastmap_1.2.0 grid_4.6.1
#> [49] cli_3.6.6 SparseArray_1.13.2
#> [51] magrittr_2.0.5 S4Arrays_1.13.0
#> [53] dichromat_2.0-0.1 XML_3.99-0.23
#> [55] withr_3.0.3 UCSC.utils_1.9.0
#> [57] scales_1.4.0 rmarkdown_2.31
#> [59] httr_1.4.8 matrixStats_1.5.0
#> [61] otel_0.2.0 evaluate_1.0.5
#> [63] knitr_1.51 rlang_1.3.0
#> [65] Rcpp_1.1.2 glue_1.8.1
#> [67] BiocManager_1.30.27 jsonlite_2.0.0
#> [69] plyr_1.8.9 R6_2.6.1
#> [71] MatrixGenerics_1.25.0 GenomicAlignments_1.49.1