Author: Felix G.M. Ernst and Denis L.J. Lafontaine
Date: 2026-04-28

# RNAmodR: RiboMethSeq

Felix G.M. Ernst and Denis L.J. Lafontaine

#### 2026-04-28

#### Abstract

Detection of 2’-O methylations by RiboMethSeq

# 1 Introduction

Among the various post-transcriptional RNA modifications, 2’-O methylations are commonly found in rRNA and tRNA. They promote the endo conformation of the ribose and confere resistance to alkaline degradation by preventing a nucleophilic attack on the 3’-phosphate especially in flexible RNA, which is fascilitated by high pH conditions. This property can be queried using a method called RiboMethSeq (Birkedal et al. 2015) for which RNA is treated in alkaline conditions and RNA fragments are used to prepare a sequencing library (Marchand et al. 2017).

At position containing a 2’-O methylations, read ends are less frequent, which is used to detect and score the 2’-O methylations.

The `ModRiboMethSeq` class uses the the `ProtectedEndSequenceData` class to store and aggregate data along the transcripts. The calculated scores follow the nomenclature of (Birkedal et al. 2015; Galvanin et al. 2019) with the names `scoreRMS` (default), `scoreA`, `scoreB` and `scoreMean`.

    ## No methods found in package 'rtracklayer' for request: 'trackName<-' when loading 'AnnotationHubData'

    ## Warning: replacing previous import 'utils::findMatches' by
    ## 'S4Vectors::findMatches' when loading 'ExperimentHubData'

    library(rtracklayer)
    library(GenomicRanges)
    library(RNAmodR.RiboMethSeq)
    library(RNAmodR.Data)

# 2 Example workflow

The example workflow is limited to two 2’-O methylated position on 5.8S rRNA, since the size of the raw data is limited. For annotation data either a gff file or a `TxDb` object and for sequence data a fasta file or a `BSgenome` object can be used. The data is provided as bam files.

    annotation <- GFF3File(RNAmodR.Data.example.RMS.gff3())
    sequences <- RNAmodR.Data.example.RMS.fasta()
    files <- list("Sample1" = c(treated = RNAmodR.Data.example.RMS.1()),
                  "Sample2" = c(treated = RNAmodR.Data.example.RMS.2()))

# 3 Analysis of data

The analysis is triggered by the construction of a `ModSetRiboMethSeq` object. Internally parallelization is used via the `BiocParallel` package, which would allow optimization depending on number/size of input files (number of samples, number of replicates, number of transcripts, etc).

    msrms <- ModSetRiboMethSeq(files, annotation = annotation, sequences = sequences)

    ## Import genomic features from the file as a GRanges object ... OK
    ## Prepare the 'metadata' data frame ... OK
    ## Make the TxDb object ...

    ## Warning in .makeTxDb_normarg_chrominfo(chrominfo): genome version information
    ## is not available for this TxDb object

    ## OK

    msrms

    ## ModSetRiboMethSeq of length 2
    ## names(2): Sample1 Sample2
    ## | Modification type(s):  Am / Cm / Gm / Um
    ##                        Sample1 Sample2
    ## | Modifications found:      no yes (1)
    ## | Settings:
    ##         minCoverage minReplicate  find.mod maxLength minSignal flankingRegion
    ##           <integer>    <integer> <logical> <integer> <integer>      <integer>
    ## Sample1          10            1      TRUE        50        10              6
    ## Sample2          10            1      TRUE        50        10              6
    ##         minScoreA minScoreB minScoreRMS minScoreMean flankingRegionMean
    ##         <numeric> <numeric>   <numeric>    <numeric>          <integer>
    ## Sample1       0.6       3.6        0.75         0.75                  2
    ## Sample2       0.6       3.6        0.75         0.75                  2
    ##                 weights
    ##           <NumericList>
    ## Sample1 0.9,1.0,0.0,...
    ## Sample2 0.9,1.0,0.0,...
    ##         scoreOperator
    ##           <character>
    ## Sample1             &
    ## Sample2             &

# 4 Visualizing the results

To compare samples, we need to know, which positions should be part of the comparison. This can either be done by aggregating the detect over all samples and use the union or intersect or by using publish data. We want to assemble a GRanges object from the latter by utilising the infomation from the snoRNAdb (Lestrade and Weber 2006).

In this specific example only information for the 5.8S RNA is used, since the example data would be to big otherwise. The information regarding the parent and seqname must match the information used as the annotation data. Check that it matches the output of `ranges()` on a `SequenceData`, `Modifier` oder `ModifierSet` object.

    table <- read.csv2(RNAmodR.Data.snoRNAdb(), stringsAsFactors = FALSE)

    ## see ?RNAmodR.Data and browseVignettes('RNAmodR.Data') for documentation

    ## loading from cache

    table <- table[table$hgnc_id == "53533",] # Subset to RNA5.8S
    # keep only the current coordinates
    table <- table[,1L:7L]
    snoRNAdb <- GRanges(seqnames = "chr1",
                  ranges = IRanges(start = table$position,
                                   width = 1),
                  strand = "+",
                  type = "RNAMOD",
                  mod = table$modification,
                  Parent = "1", #this is the transcript id
                  Activity = IRanges::CharacterList(strsplit(table$guide,",")))
    coord <- split(snoRNAdb,snoRNAdb$Parent)

In addition to the coordinates of published, we also want to include more meaningful names for the transcripts. For this we provide a `data.frame` with two columns, `tx_id` and `name`. All values in the first column have to match transcript IDs.

    ranges(msrms)

    ## GRangesList object of length 1:
    ## $`1`
    ## GRanges object with 1 range and 3 metadata columns:
    ##       seqnames    ranges strand |   exon_id   exon_name exon_rank
    ##          <Rle> <IRanges>  <Rle> | <integer> <character> <integer>
    ##   [1]     chr1     1-157      + |         1 NR_003285.2         1
    ##   -------
    ##   seqinfo: 1 sequence from an unspecified genome; no seqlengths

    alias <- data.frame(tx_id = "1", name = "5.8S rRNA", stringsAsFactors = FALSE)

    plotCompareByCoord(msrms[c(2L,1L)], coord, alias = alias)

Figure 1: Heatmap showing RiboMethSeq scores for 2’-O methylated positions on the 5.8S rRNA

Results can also be compared on a sequence level, by selecting specific coordinates to compare.

    singleCoord <- coord[[1L]][1L,]
    plotDataByCoord(msrms, singleCoord)

Figure 2: RiboMethSeq scores around Um(14) on 5.8S rRNA

By default only the RiboMethSeq score and the ScoreMean are shown. The raw sequence data can be inspected as well

    singleCoord <- coord[[1L]][1L,]
    plotDataByCoord(msrms, singleCoord, showSequenceData = TRUE)

Figure 3: RiboMethSeq scores around Um(14) on 5.8S rRNA
Sequence data is shown by setting `showSequenceData = TRUE`.

# 5 Performance

To access the performance of the method in combination with samples used, use the `plotROC` function.

    plotROC(msrms,coord)

Figure 4: TPR versus FPR plot

The example given here should be regarded as a proof of concept. Based on the results, minimal scores for calling modified positions can be adjusted to the individual requirements.

    settings(msrms) <- list(minScoreMean = 0.7)
    msrms

    ## ModSetRiboMethSeq of length 2
    ## names(2): Sample1 Sample2
    ## | Modification type(s):  Am / Cm / Gm / Um
    ##                        Sample1 Sample2
    ## | Modifications found:      no yes (1)
    ## | Settings:
    ##         minCoverage minReplicate  find.mod maxLength minSignal flankingRegion
    ##           <integer>    <integer> <logical> <integer> <integer>      <integer>
    ## Sample1          10            1      TRUE        50        10              6
    ## Sample2          10            1      TRUE        50        10              6
    ##         minScoreA minScoreB minScoreRMS minScoreMean flankingRegionMean
    ##         <numeric> <numeric>   <numeric>    <numeric>          <integer>
    ## Sample1       0.6       3.6        0.75          0.7                  2
    ## Sample2       0.6       3.6        0.75          0.7                  2
    ##                 weights
    ##           <NumericList>
    ## Sample1 0.9,1.0,0.0,...
    ## Sample2 0.9,1.0,0.0,...
    ##         scoreOperator
    ##           <character>
    ## Sample1             &
    ## Sample2             &

    ## Warning: Settings were changed after data aggregation or modification search.
    ## Rerun with modify(x,force = TRUE) to update with current settings.

As the warning suggested, after modifying the settings the results should be updated by running `modify(x,force = TRUE)`.

    msrms2 <- modify(msrms,force = TRUE)

# 6 Session info

    sessionInfo()

    ## R version 4.6.0 RC (2026-04-17 r89917)
    ## 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] Rsamtools_2.29.0           RNAmodR.Data_1.25.0
    ##  [3] ExperimentHubData_1.39.0   AnnotationHubData_1.43.0
    ##  [5] futile.logger_1.4.9        ExperimentHub_3.3.0
    ##  [7] AnnotationHub_4.3.0        BiocFileCache_3.3.0
    ##  [9] dbplyr_2.5.2               RNAmodR.RiboMethSeq_1.27.0
    ## [11] RNAmodR_1.27.0             Modstrings_1.29.0
    ## [13] Biostrings_2.81.0          XVector_0.53.0
    ## [15] rtracklayer_1.73.0         GenomicRanges_1.65.0
    ## [17] Seqinfo_1.3.0              IRanges_2.47.0
    ## [19] S4Vectors_0.51.0           BiocGenerics_0.59.0
    ## [21] generics_0.1.4             BiocStyle_2.41.0
    ##
    ## loaded via a namespace (and not attached):
    ##   [1] BiocIO_1.23.0               bitops_1.0-9
    ##   [3] filelock_1.0.3              tibble_3.3.1
    ##   [5] graph_1.91.0                XML_3.99-0.23
    ##   [7] rpart_4.1.27                lifecycle_1.0.5
    ##   [9] httr2_1.2.2                 lattice_0.22-9
    ##  [11] ensembldb_2.37.0            OrganismDbi_1.55.0
    ##  [13] backports_1.5.1             magrittr_2.0.5
    ##  [15] Hmisc_5.2-5                 sass_0.4.10
    ##  [17] rmarkdown_2.31              jquerylib_0.1.4
    ##  [19] yaml_2.3.12                 otel_0.2.0
    ##  [21] RUnit_0.4.33.1              Gviz_1.57.0
    ##  [23] DBI_1.3.0                   RColorBrewer_1.1-3
    ##  [25] abind_1.4-8                 purrr_1.2.2
    ##  [27] AnnotationFilter_1.37.0     biovizBase_1.61.0
    ##  [29] RCurl_1.98-1.18             nnet_7.3-20
    ##  [31] VariantAnnotation_1.59.0    rappdirs_0.3.4
    ##  [33] AnnotationForge_1.55.0      codetools_0.2-20
    ##  [35] DelayedArray_0.39.0         tidyselect_1.2.1
    ##  [37] UCSC.utils_1.9.0            farver_2.1.2
    ##  [39] matrixStats_1.5.0           base64enc_0.1-6
    ##  [41] GenomicAlignments_1.49.0    jsonlite_2.0.0
    ##  [43] Formula_1.2-5               tools_4.6.0
    ##  [45] progress_1.2.3              stringdist_0.9.17
    ##  [47] Rcpp_1.1.1-1.1              glue_1.8.1
    ##  [49] gridExtra_2.3               SparseArray_1.13.0
    ##  [51] BiocBaseUtils_1.15.0        xfun_0.57
    ##  [53] MatrixGenerics_1.25.0       GenomeInfoDb_1.49.0
    ##  [55] dplyr_1.2.1                 withr_3.0.2
    ##  [57] formatR_1.14                BiocManager_1.30.27
    ##  [59] fastmap_1.2.0               latticeExtra_0.6-31
    ##  [61] digest_0.6.39               R6_2.6.1
    ##  [63] colorspace_2.1-2            jpeg_0.1-11
    ##  [65] dichromat_2.0-0.1           biomaRt_2.69.0
    ##  [67] RSQLite_2.4.6               cigarillo_1.3.0
    ##  [69] data.table_1.18.2.1         prettyunits_1.2.0
    ##  [71] httr_1.4.8                  htmlwidgets_1.6.4
    ##  [73] S4Arrays_1.13.0             pkgconfig_2.0.3
    ##  [75] gtable_0.3.6                blob_1.3.0
    ##  [77] S7_0.2.2                    htmltools_0.5.9
    ##  [79] bookdown_0.46               RBGL_1.89.0
    ##  [81] ProtGenerics_1.45.0         scales_1.4.0
    ##  [83] Biobase_2.73.0              png_0.1-9
    ##  [85] colorRamps_2.3.4            knitr_1.51
    ##  [87] lambda.r_1.2.4              rstudioapi_0.18.0
    ##  [89] reshape2_1.4.5              rjson_0.2.23
    ##  [91] checkmate_2.3.4             curl_7.1.0
    ##  [93] biocViews_1.81.0            cachem_1.1.0
    ##  [95] stringr_1.6.0               BiocVersion_3.24.0
    ##  [97] parallel_4.6.0              foreign_0.8-91
    ##  [99] AnnotationDbi_1.75.0        restfulr_0.0.16
    ## [101] pillar_1.11.1               grid_4.6.0
    ## [103] vctrs_0.7.3                 cluster_2.1.8.2
    ## [105] htmlTable_2.5.0             evaluate_1.0.5
    ## [107] magick_2.9.1                tinytex_0.59
    ## [109] GenomicFeatures_1.65.0      cli_3.6.6
    ## [111] compiler_4.6.0              futile.options_1.0.1
    ## [113] rlang_1.2.0                 crayon_1.5.3
    ## [115] labeling_0.4.3              interp_1.1-6
    ## [117] plyr_1.8.9                  stringi_1.8.7
    ## [119] deldir_2.0-4                BiocParallel_1.47.0
    ## [121] BiocCheck_1.49.0            txdbmaker_1.9.0
    ## [123] lazyeval_0.2.3              Matrix_1.7-5
    ## [125] BSgenome_1.81.0             hms_1.1.4
    ## [127] bit64_4.8.0                 ggplot2_4.0.3
    ## [129] KEGGREST_1.53.0             SummarizedExperiment_1.43.0
    ## [131] ROCR_1.0-12                 memoise_2.0.1
    ## [133] bslib_0.10.0                bit_4.6.0

# References

Birkedal, Ulf, Mikkel Christensen-Dalsgaard, Nicolai Krogh, Radhakrishnan Sabarinathan, Jan Gorodkin, and Henrik Nielsen. 2015. “Profiling of Ribose Methylations in Rna by High-Throughput Sequencing.” Angewandte Chemie (International Ed. In English) 54 (2): 451–55. https://doi.org/10.1002/anie.201408362.

Galvanin, Adeline, Lilia Ayadi, Mark Helm, Yuri Motorin, and Virginie Marchand. 2019. “Mapping and Quantification of tRNA 2’-O-Methylation by Ribomethseq.” Edited by Narendra Wajapeyee and Romi Gupta, 273–95. https://doi.org/10.1007/978-1-4939-8808-2_21.

Lestrade, Laurent, and Michel J. Weber. 2006. “snoRNA-LBME-db, a comprehensive database of human H/ACA and C/D box snoRNAs.” Nucleic Acids Research 34 (January): D158–D162. https://doi.org/10.1093/nar/gkj002.

Marchand, Virginie, Lilia Ayadi, Aseel El Hajj, Florence Blanloeil-Oillo, Mark Helm, and Yuri Motorin. 2017. “High-Throughput Mapping of 2’-O-Me Residues in Rna Using Next-Generation Sequencing (Illumina Ribomethseq Protocol).” Methods in Molecular Biology (Clifton, N.J.) 1562: 171–87. https://doi.org/10.1007/978-1-4939-6807-7_12.