Abstract
Visualize epigeomic data in 2D or 3D plots.
The chromatin interactions is involved in precise quantitative and spatiotemporal control of gene expression. The development of high-throughput experimental techniques, such as HiC-seq, HiCAR-seq, and InTAC-seq, for analyzing both the higher-order structure of chromatin and the interactions between protein and their nearby and remote regulatory elements has been developed to reveal how gene expression is controlled in genome-wide. The geomeTriD package enables users to visualize epigenomic data in both 2D and 3D.
if (!require("BiocManager", quietly = TRUE)) {
install.packages("BiocManager")
}
BiocManager::install("geomeTriD")
There are three major steps to view the epigenomic data by geomeTriD in 3D.
Load data in the GRanges
object with metadata of positions.
Parse the data into a list of threeJsGeometry
objects.
View the data by threeJsViewer
function by threeJs
. .
library(geomeTriD)
## load data
obj <- readRDS(system.file("extdata", "4DNFI1UEG1HD.chr21.FLAMINGO.res.rds",
package = "geomeTriD"
))
head(obj, n = 2)
## GRanges object with 2 ranges and 3 metadata columns:
## seqnames ranges strand | x y z
## <Rle> <IRanges> <Rle> | <numeric> <numeric> <numeric>
## [1] chr21 31370001-31375000 * | 6.33426e-06 -8.63705e-06 3.89647e-06
## [2] chr21 31375001-31380000 * | 2.82577e-06 -4.26812e-06 1.95232e-06
## -------
## seqinfo: 1 sequence from an unspecified genome; no seqlengths
feature.gr <- readRDS(system.file("extdata", "4DNFI1UEG1HD.feature.gr.rds",
package = "geomeTriD"
))
head(feature.gr, n = 2)
## GRanges object with 2 ranges and 4 metadata columns:
## seqnames ranges strand | gene_id label
## <Rle> <IRanges> <Rle> | <character> <character>
## 100506215 chr21 32728097-32746781 + | 100506215 PAXBP1-AS1
## 100551499 chr21 32080316-32197813 - | 100551499 LINC00159
## col type
## <integer> <character>
## 100506215 3 gene
## 100551499 5 gene
## -------
## seqinfo: 711 sequences (1 circular) from hg38 genome
## create threeJsGeometry objects
list3d <- view3dStructure(obj,
feature.gr = feature.gr,
renderer = "none"
)
## plot the data
threeJsViewer(list3d)
if you have trouble in seeing the results, such as Firefox snap installation issue, please try to save it as a file and open it in an explorer.
widget <- threeJsViewer(list3d)
tmpdir <- 'path/to/a/folder'
dir.create(tmpdir, recursive = TRUE)
tmp <- tempfile(tmpdir = tmpdir, fileext = '.html')
htmlwidgets::saveWidget(widget, file=tmp)
utils::browseURL(tmp)
The genomic contact frequency, eg output from HiC, can be converted into spatial distances and then visualized using optimization-based (such as manifold learning techniques) or probabilistic approaches (such as Markov Chain Monte Carlo). Available tools include, but not limited to, ShRec3D, GEM-FISH, Hierarchical3DGenome, RPR, SuperRec, ShNeigh, PASTIS, and FLAMINGO.
Above example are data generated by FLAMINGOrLite from the chromosome 21 of the HiC contact matrix of human GM12878 cells downloaded from 4DN.
In this package, a simple method to calculate the spatial positions from bin-based contact matrix by multi-dimensional scaling (MDS) algorithm is provided.
The data in .hic
or .cool
can be imported into GInteractions
objects by trackViewer::importGInteractions
function. Here we show how to generate the 3D coordinates using the mdsPlot
function from the bin-based contact matrix by Kruskal’s Non-metric Multidimensional Scaling.
library(trackViewer)
library(InteractionSet)
# load the interaction data.
# to import your own data, please refer trackViewer help documents
gi_nij <- readRDS(system.file("extdata", "nij.chr6.51120000.53200000.gi.rds",
package = "geomeTriD"
))
# the data is a GInteractions object with metadata score
head(gi_nij, n = 2)
## GInteractions object with 2 interactions and 1 metadata column:
## seqnames1 ranges1 seqnames2 ranges2 | score
## <Rle> <IRanges> <Rle> <IRanges> | <numeric>
## [1] chr6 51120000-51160000 --- chr6 51120000-51160000 | 45.1227
## [2] chr6 51120000-51160000 --- chr6 51160000-51200000 | 35.0006
## -------
## regions: 53 ranges and 0 metadata columns
## seqinfo: 1 sequence from an unspecified genome; no seqlengths
# define a range to plot
range_chr6 <- GRanges("chr6", IRanges(51120000, 53200000))
# plot it if interactive
if (interactive()) { ## not run to reduce the package size.
mdsPlot(gi_nij, range = range_chr6, k = 3, render = "threejs")
}
Here we show how to add gene information along the strand.
# create gene annotations
library(TxDb.Hsapiens.UCSC.hg19.knownGene)
library(org.Hs.eg.db)
## get all genes
feature.gr <- genes(TxDb.Hsapiens.UCSC.hg19.knownGene)
## subset the data by target viewer region
feature.gr <- subsetByOverlaps(feature.gr, range(regions(gi_nij)))
## assign symbols for each gene
symbols <- mget(feature.gr$gene_id, org.Hs.egSYMBOL, ifnotfound = NA)
feature.gr$label[lengths(symbols) == 1] <-
unlist(symbols[lengths(symbols) == 1])
## assign colors for each gene
feature.gr$col <- sample(1:7, length(feature.gr), replace = TRUE)
## Here we replaced the some gene feature as cis-regulatory elements
## to validate how it will be treated by the plot
feature.gr$type <- sample(c("cRE", "gene"),
length(feature.gr),
replace = TRUE,
prob = c(0.1, 0.9)
)
## set the size the cRE in the plot
feature.gr$pch <- rep(NA, length(feature.gr))
feature.gr$pch[feature.gr$type == "cRE"] <- 0.5
## features header
head(feature.gr, n = 2)
## GRanges object with 2 ranges and 5 metadata columns:
## seqnames ranges strand | gene_id label
## <Rle> <IRanges> <Rle> | <character> <character>
## 100847075 chr6 53141791-53141869 + | 100847075 MIR5685
## 112744 chr6 52101484-52109298 - | 112744 IL17F
## col type pch
## <integer> <character> <numeric>
## 100847075 2 gene NA
## 112744 5 gene NA
## -------
## seqinfo: 93 sequences (1 circular) from hg19 genome
# plot it if interactive
if (interactive()) { ## not run to reduce the package size.
mdsPlot(gi_nij,
range = range_chr6, feature.gr = feature.gr,
k = 3, render = "threejs"
)
}
Here we show how to add CTCF ATAC-seq signals along the strand.
# one layer of signals. It is a `track` object
ctcf <- readRDS(system.file("extdata", "ctcf.sample.rds",
package = "trackViewer"
))
# plot it if interactive
if (interactive()) { ## not run to reduce the package size.
mdsPlot(gi_nij,
range = range_chr6, feature.gr = feature.gr,
genomicSigs = ctcf,
## we reverse the ATAC-seq signale to show where is open
reverseGenomicSigs = TRUE,
k = 3, render = "threejs"
)
}
Add more signals such as ChIP-seq.
# create a random signal for demonstration
set.seed(1)
randomSig <- ctcf$dat
randomSig <- randomSig[sort(sample(seq_along(randomSig), 50))]
randomSig$score <- randomSig$score * 2 * runif(50)
head(randomSig, n = 2)
## GRanges object with 2 ranges and 1 metadata column:
## seqnames ranges strand | score
## <Rle> <IRanges> <Rle> | <numeric>
## [1] chr6 51188134-51188334 * | 0.779979
## [2] chr6 51267112-51270512 * | 1.554641
## -------
## seqinfo: 22 sequences from an unspecified genome
objs <- mdsPlot(gi_nij,
range = range_chr6, feature.gr = feature.gr,
genomicSigs = list(ctcf = ctcf, test = randomSig),
reverseGenomicSigs = c(TRUE, FALSE),
k = 3, render = "none"
)
## initial value 46.625959
## iter 5 value 18.494050
## iter 10 value 14.996469
## iter 15 value 11.509102
## iter 20 value 9.159639
## iter 25 value 8.392723
## iter 30 value 8.060898
## iter 35 value 7.956958
## final value 7.939262
## converged
threeJsViewer(objs)
rgl
## not run to reduce the package size.
library(rgl)
library(manipulateWidget)
rgl::clear3d() # Remove the earlier display
rglViewer(objs, background = "white")
rgl::rglwidget() %>%
rgl::toggleWidget(tags = "tick_minor") %>%
toggleWidget(tags = "tick_major") %>%
toggleWidget(tags = "tick_labels") %>%
toggleWidget(tags = "ctcf") %>%
toggleWidget(tags = "test") %>%
toggleWidget(tags = "backbone") %>%
toggleWidget(tags = "gene_body") %>%
toggleWidget(tags = "tss_labels") %>%
toggleWidget(tags = "gene_labels") %>%
toggleWidget(tags = "cRE") %>%
rgl::asRow(last = 10)
Here we will show how to add the interaction pairs into the 3d plot.
## get the backbone 3d positions,
## it will be used as a position reference for the interaction data.
xyz <- extractBackbonePositions(objs)
# make the example easy to see
gi.subset <- gi_nij[distance(first(gi_nij), second(gi_nij))>50000]
hic <- create3dGenomicSignals(
gi.subset,
xyz,
name='segment', # name prefix for the geometry
tag='hic', # name for the layer in the scene
color = c('green', 'darkred'),
topN=3, # only plot the top 3 events ordered by the scores.
lwd.maxGenomicSigs = 3,
alpha=0.5
)
hic2 <- create3dGenomicSignals(
gi.subset,
xyz,
name='polygon', # name prefix for the geometry
tag='hic', # name for the layer in the scene
color = c('blue', 'darkred'),
topN=seq(4, 10), # only plot the top 4-10 events ordered by the scores.
type = 'polygon'
)
width(regions(gi.subset)) <- 101#for high resolution input (such as reads pairs)
hic3 <- create3dGenomicSignals(
gi.subset,
xyz,
name='segment', # name prefix for the geometry
tag='hic', # name for the layer in the scene
color = rainbow(40),
topN=length(gi.subset),
lwd.maxGenomicSigs = 5,
alpha = 0.1
)
# plot it if interactive
if (interactive()) { ## not run to reduce the package size.
threeJsViewer(c(objs, hic, hic2, hic3))
}
loopBouquet
or MDS
plotPlot the data in 3D using the mdsPlot
function to generate the 3D coordinates. Alternatively, users can plot it in 2d. Please note that current 2d plot can only handle one genomic signals.
## not run to reduce the package size.
geomeTriD::mdsPlot(gi_nij, range = range_chr6, feature.gr = feature.gr, genomicSigs = ctcf)
Different from most of the available tools, loopBouquetPlot
try to plot the loops with the 2D structure. The nodes indicate the region with interactions and the edges indicates the interactions. The size of the nodes are relative to the width of the region. The features could be the cRE or gene. The cRE are shown as points with symbol 11.
gi_chr2 <- readRDS(system.file("extdata", "gi.rds", package = "trackViewer"))
range_chr2 <- GRanges("chr2", IRanges(234300000, 235000000))
gene_hg19 <- suppressMessages(genes(TxDb.Hsapiens.UCSC.hg19.knownGene))
feature.gr_chr2 <- subsetByOverlaps(gene_hg19, range(regions(gi_chr2)))
feature.gr_chr2$col <- sample(2:7, length(feature.gr_chr2), replace = TRUE)
feature.gr_chr2$type <- sample(c("cRE", "gene"),
length(feature.gr_chr2),
replace = TRUE,
prob = c(0.1, 0.9)
)
feature.gr_chr2$pch <- rep(NA, length(feature.gr_chr2))
feature.gr_chr2$pch[feature.gr_chr2$type == "cRE"] <- 11
symbol <- mget(feature.gr_chr2$gene_id, org.Hs.egSYMBOL, ifnotfound = NA)
symbol <- unlist(lapply(symbol, function(.ele) .ele[1]))
feature.gr_chr2$label <- symbol
geomeTriD::loopBouquetPlot(gi_chr2, range_chr2, feature.gr_chr2)
## filter the links to simulate the data with less interactions
keep <- distance(first(gi_nij), second(gi_nij)) > 5e5 & gi_nij$score > 35
gi_nij <- gi_nij[keep]
# narrow the width of anchors to enhance the plots
reg <- regions(gi_nij)
wr <- floor(width(reg) / 4)
start(reg) <- start(reg) + wr
end(reg) <- end(reg) - wr
regions(gi_nij) <- reg
feature.gr <- subsetByOverlaps(gene_hg19, range(regions(gi_nij)))
feature.gr$col <- sample(2:7, length(feature.gr), replace = TRUE)
feature.gr$type <- sample(c("cRE", "gene"),
length(feature.gr),
replace = TRUE,
prob = c(0.1, 0.9)
)
symbol <- mget(feature.gr$gene_id, org.Hs.egSYMBOL, ifnotfound = NA)
symbol <- unlist(lapply(symbol, function(.ele) .ele[1]))
feature.gr$label <- symbol
feature.gr <- c(
feature.gr[sample(seq_along(feature.gr), 5)],
feature.gr[feature.gr$type == "cRE"][1]
)
feature.gr <- unique(sort(feature.gr))
geomeTriD::loopBouquetPlot(gi_nij, range_chr6, feature.gr,
coor_tick_unit = 5e4,
coor_mark_interval = 5e5,
genomicSigs = ctcf
)
geomeTriD
can be used to view data in 3D. Here we will show how to use it to plot the single cell data in 3D. The input data should be a data.frame with x,y,z coordinates.
library(geomeTriD)
cells <- readRDS(system.file("extdata", "pbmc_small.3d.rds",
package = "geomeTriD"
))
head(cells)
## umap_1 umap_2 umap_3 nCount_RNA nFeature_RNA
## ATGCCAGAACGACT -2.195171 0.6205683 1.1399260 70 47
## CATGGCCTGTGCAT -2.425737 0.3946877 1.5394660 85 52
## GAACCTGATGAACC -1.300247 -2.0641031 0.2079445 87 50
## TGACTGGATTCTCA -1.280686 2.2639842 1.0135704 127 56
## AGTCAGACTGCACA -2.077747 0.1443148 1.2094155 173 53
## TCTGATACACGTGT -1.896454 0.3670673 0.7782331 70 48
## RNA_snn_res.0.8 letter.idents groups RNA_snn_res.1 CD7
## ATGCCAGAACGACT 0 A g2 0 5.658486
## CATGGCCTGTGCAT 0 A g1 0 5.465077
## GAACCTGATGAACC 1 B g2 0 5.441920
## TGACTGGATTCTCA 0 A g2 0 5.468990
## AGTCAGACTGCACA 0 A g2 0 4.758809
## TCTGATACACGTGT 0 A g1 0 4.968821
## CCL5 LCK S100A8 TYMP S100A9 HLA-DPB1 MS4A1
## ATGCCAGAACGACT 0.00000 0.000000 0 0.000000 0.000000 0 0
## CATGGCCTGTGCAT 0.00000 5.869131 0 0.000000 4.776153 0 0
## GAACCTGATGAACC 0.00000 5.441920 0 0.000000 4.753095 0 0
## TGACTGGATTCTCA 5.06563 0.000000 0 0.000000 0.000000 0 0
## AGTCAGACTGCACA 0.00000 4.074201 0 4.074201 0.000000 0 0
## TCTGATACACGTGT 0.00000 4.968821 0 0.000000 0.000000 0 0
## HLA-DQB1
## ATGCCAGAACGACT 4.968821
## CATGGCCTGTGCAT 0.000000
## GAACCTGATGAACC 0.000000
## TGACTGGATTCTCA 0.000000
## AGTCAGACTGCACA 0.000000
## TCTGATACACGTGT 0.000000
## color the cells by 'groups' info
cellobjs <- view3dCells(cells,
x = "umap_1", y = "umap_2", z = "umap_3",
color = "groups",
colorFun = function(x) {
ifelse(x == "g1", "red", "blue")
},
renderer = "none"
)
Plot the cells by rgl
.
## not run to reduce the package size.
library(manipulateWidget)
clear3d() # Remove the earlier display
rglViewer(cellobjs, background = "white")
rglwidget()
Plot it by threeJs
.
threeJsViewer(cellobjs)
We can also try to color the cells by a numeric column.
# plot it if interactive
if (interactive()) {
view3dCells(cells,
x = "umap_1", y = "umap_2", z = "umap_3",
color = "nCount_RNA",
colorFun = function(x, pal = colorRampPalette(c("black", "red"))(5)) {
limits <- range(x)
pal[findInterval(x, seq(limits[1], limits[2],
length.out = length(pal) + 1
),
all.inside = TRUE
)]
},
renderer = "threejs"
)
}
threeJsViewer
By default, the viewer built on three.js allows objects in a scene to be separated into layers based on tags. Users can easily toggle the visibility of these layers using the ‘toggle’ button in the controller. Additionally, layers can be grouped into two main categories (top and bottom), enabling the option to hide internal or auxiliary objects as needed.
In this example, we will move all the ticks and tss markers into bottom group. Please note that labels will not be affected by this methods.
for(i in seq_along(objs)){
if(grepl('tick|arrow|cRE|tss', names(objs)[i])){
objs[[i]]$layer <- 'bottom'
}
}
if(interactive()){
threeJsViewer(objs)
}
The threeJsViewer
allows users to view two 3D structures side by side. It is recommended to align the 3D coordinates by alignCoor
function before generating the threeJsGeometry
objects for optimal comparison.
objs2 <- lapply(objs, function(.ele){
.ele$side <- 'right'
.ele
})
if(interactive()){
threeJsViewer(objs, objs2)
}
Starting from the raw data, you will be prompted to provide the backbone to which materials will be attached. The backbone is a GRanges
object containing the x, y, and z coordinates. Since the current resolution of Hi-C data is relatively low, we will first smooth the coordinates. The materials, also input as a GRanges
object, will have their 3D positions derived from the backbone.
## simulate a backbone
library(GenomicRanges)
library(geomeTriD)
backbone <- GRanges(1, IRanges(seq(1, 10000, by=1000), width = 1000))
## set x, y, z position, we will use the torus knots equation
t <- seq(0, 2*pi, length.out=length(backbone))
p <- 3
q <- 2
r <- cos(p*t) + 2
backbone$x <- 2*r*cos(q*t)
backbone$y <- 2*r*sin(q*t)
backbone$z <- -2*sin(p*t)
## simulate the signals to be add
N1 <- 30
sig1 <- GRanges(1, IRanges(sample(seq.int(10000), N1), width = 10),
score=runif(N1, min=1, max=10))
N2 <- 8
sig2 <- GRanges(1, IRanges(sample(seq.int(10000), N2), width = 1),
score=runif(N2, min=0.05, max=1),
shape=sample(c('dodecahedron', 'icosahedron',
'octahedron', 'tetrahedron'),
N2, replace = TRUE),
color=sample(seq.int(7)[-1], N2, replace = TRUE))
## do smooth for the coordinates
backbone <- smooth3dPoints(backbone, resolution=10)
## create the line geometry
geo_backbone <- threeJsGeometry(
x=c(backbone$x0, backbone$x1[length(backbone)]),
y=c(backbone$y0, backbone$y1[length(backbone)]),
z=c(backbone$z0, backbone$y1[length(backbone)]),
colors = "black",
type = "line",
tag = "tagNameHere",
properties= list(size = 2)
)
## create the sphere geometry for sig1
geo_sig1_sphere <- create3dGenomicSignals(
GenoSig = sig1,
targetObj = backbone,
positionTransformFun = function(x) {
x$y0 <- x$y0 + 0.5 # offset from y
x$y1 <- x$y1 + 0.5
x
}, reverseGenomicSigs = FALSE,
type = 'sphere',
tag = 'head', name = 'head',
color = c('blue', 'red'),
radius = .25)
## create the cylinder geometry for sig1
geo_sig1_body <- create3dGenomicSignals(
GenoSig = sig1,
targetObj = backbone,
positionTransformFun = function(x) {
x$y0 <- x$y0 + 0.25 # offset from y
x$y1 <- x$y1 + 0.25
x
}, reverseGenomicSigs = FALSE,
type = 'cylinder',
tag = 'body', name = 'body',
height = .5, radiusTop = .05, radiusBottom = .15)
## create two small spheres
geo_sig1_ear1 <- create3dGenomicSignals(
GenoSig = sig1,
targetObj = backbone,
positionTransformFun = function(x) {
x$x0 <- x$x0 - 0.25 # offset from x
x$x1 <- x$x1 - 0.25
x$y0 <- x$y0 + 0.75 # offset from y
x$y1 <- x$y1 + 0.75
x
}, reverseGenomicSigs = FALSE,
type = 'sphere',
tag = 'ear', name = 'ear1',
color = c('blue', 'red'),
radius = .1)
geo_sig1_ear2 <- create3dGenomicSignals(
GenoSig = sig1,
targetObj = backbone,
positionTransformFun = function(x) {
x$x0 <- x$x0 + 0.25 # offset from x
x$x1 <- x$x1 + 0.25
x$y0 <- x$y0 + 0.75 # offset from y
x$y1 <- x$y1 + 0.75
x
}, reverseGenomicSigs = FALSE,
type = 'sphere',
tag = 'ear', name = 'ear2',
color = c('blue', 'red'),
radius = .1)
geo_sig1_nose <- create3dGenomicSignals(
GenoSig = sig1,
targetObj = backbone,
positionTransformFun = function(x) {
x$y0 <- x$y0 + 0.5 # offset from y
x$y1 <- x$y1 + 0.5
x$z0 <- x$z0 - 0.25 # offset from z
x$z1 <- x$z1 - 0.25
x
}, reverseGenomicSigs = FALSE,
type = 'capsule',
tag = 'nose', name = 'nose',
color = c('red', 'blue'),
radius = .05, height=.05)
## create the icosahedron geometry for sig2
geo_sig2 <- lapply(seq_along(sig2), function(id){
create3dGenomicSignals(
GenoSig = sig2[id],
targetObj = backbone,
reverseGenomicSigs = FALSE,
type=sig2[id]$shape,
tag = 'sig2', name = as.character(id),
color = sig2[id]$color,
radius = sig2[id]$score
)})
## create the a customized geometry by a json file
geo_json <- create3dGenomicSignals(
GenoSig = GRanges(1, IRanges(5000, width=1), score=1),
targetObj = backbone,
type = 'json',
tag = 'json', name='monkey',
color = 'green',
rotation = c(pi, 0, pi), ## we need to rotate the model to change the facing side
path = system.file('extdata', 'suzanne_buffergeometry.json',
package = 'geomeTriD')
)
threeJsViewer(c(backbone=geo_backbone,
geo_sig1_sphere, geo_sig1_body,
geo_sig1_ear1, geo_sig1_ear2, geo_sig1_nose,
geo_sig2, geo_json))
sessionInfo()
R version 4.4.1 (2024-06-14) Platform: x86_64-pc-linux-gnu Running under: Ubuntu 24.04.1 LTS
Matrix products: default BLAS: /home/biocbuild/bbs-3.20-bioc/R/lib/libRblas.so LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.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] grid stats4 stats graphics grDevices utils datasets [8] methods base
other attached packages: [1] trackViewer_1.42.0
[2] rgl_1.3.12
[3] InteractionSet_1.34.0
[4] SummarizedExperiment_1.36.0
[5] MatrixGenerics_1.18.0
[6] matrixStats_1.4.1
[7] org.Hs.eg.db_3.20.0
[8] TxDb.Hsapiens.UCSC.hg19.knownGene_3.2.2 [9] GenomicFeatures_1.58.0
[10] AnnotationDbi_1.68.0
[11] Biobase_2.66.0
[12] GenomicRanges_1.58.0
[13] GenomeInfoDb_1.42.0
[14] IRanges_2.40.0
[15] S4Vectors_0.44.0
[16] BiocGenerics_0.52.0
[17] geomeTriD_1.0.0
loaded via a namespace (and not attached): [1] strawr_0.0.92 RColorBrewer_1.1-3 rstudioapi_0.17.1
[4] jsonlite_1.8.9 magrittr_2.0.3 rmarkdown_2.28
[7] BiocIO_1.16.0 zlibbioc_1.52.0 vctrs_0.6.5
[10] memoise_2.0.1 Rsamtools_2.22.0 RCurl_1.98-1.16
[13] base64enc_0.1-3 htmltools_0.5.8.1 S4Arrays_1.6.0
[16] progress_1.2.3 plotrix_3.8-4 curl_5.2.3
[19] Rhdf5lib_1.28.0 rhdf5_2.50.0 SparseArray_1.6.0
[22] Formula_1.2-5 sass_0.4.9 bslib_0.8.0
[25] htmlwidgets_1.6.4 Gviz_1.50.0 httr2_1.0.5
[28] cachem_1.1.0 GenomicAlignments_1.42.0 igraph_2.1.1
[31] lifecycle_1.0.4 pkgconfig_2.0.3 Matrix_1.7-1
[34] R6_2.5.1 fastmap_1.2.0 GenomeInfoDbData_1.2.13 [37] digest_0.6.37 colorspace_2.1-1 Hmisc_5.2-0
[40] RSQLite_2.3.7 filelock_1.0.3 fansi_1.0.6
[43] httr_1.4.7 abind_1.4-8 compiler_4.4.1
[46] bit64_4.5.2 htmlTable_2.4.3 backports_1.5.0
[49] BiocParallel_1.40.0 DBI_1.2.3 highr_0.11
[52] biomaRt_2.62.0 MASS_7.3-61 rappdirs_0.3.3
[55] DelayedArray_0.32.0 rjson_0.2.23 tools_4.4.1
[58] foreign_0.8-87 nnet_7.3-19 glue_1.8.0
[61] restfulr_0.0.15 rhdf5filters_1.18.0 checkmate_2.3.2
[64] cluster_2.1.6 generics_0.1.3 gtable_0.3.6
[67] BSgenome_1.74.0 ensembldb_2.30.0 data.table_1.16.2
[70] hms_1.1.3 xml2_1.3.6 utf8_1.2.4
[73] XVector_0.46.0 pillar_1.9.0 stringr_1.5.1
[76] dplyr_1.1.4 BiocFileCache_2.14.0 lattice_0.22-6
[79] deldir_2.0-4 rtracklayer_1.66.0 bit_4.5.0
[82] biovizBase_1.54.0 tidyselect_1.2.1 Biostrings_2.74.0
[85] knitr_1.48 gridExtra_2.3 ProtGenerics_1.38.0
[88] xfun_0.48 stringi_1.8.4 UCSC.utils_1.2.0
[91] lazyeval_0.2.2 yaml_2.3.10 evaluate_1.0.1
[94] codetools_0.2-20 interp_1.1-6 tibble_3.2.1
[97] BiocManager_1.30.25 cli_3.6.3 rpart_4.1.23
[100] munsell_0.5.1 jquerylib_0.1.4 dichromat_2.0-0.1
[103] Rcpp_1.0.13 grImport_0.9-7 dbplyr_2.5.0
[106] png_0.1-8 XML_3.99-0.17 parallel_4.4.1
[109] ggplot2_3.5.1 blob_1.2.4 prettyunits_1.2.0
[112] jpeg_0.1-10 latticeExtra_0.6-30 AnnotationFilter_1.30.0 [115] bitops_1.0-9 txdbmaker_1.2.0 VariantAnnotation_1.52.0 [118] scales_1.3.0 crayon_1.5.3 BiocStyle_2.34.0
[121] rlang_1.1.4 KEGGREST_1.46.0