Maintainer: Jianhai Zhang
The spatialHeatmap package offers a generic and flexible environment for visualizing spatial bulk and single-cell assays in anatomical images. It colors spatial features (e.g. tissues) annotated in the images according to the quantitative abundance levels of measured biomolecules (e.g. mRNAs) using a color key. This core functionality of the package is called a spatial heatmap (SHM) plot. Single-cell data can be co-visualized in composite plots that combine SHMs with embedding plots of high-dimensional data. Additional important functionalities include the automated identification of biomolecules with spatially selective abundance patterns and clusters of biomolecules sharing similar abundance profiles.
To plot SHMs, a pair of assay data and anatomical image is required. The format of the latter should be annotated Scalable Vector Graphics (aSVG), where spatial features such as cells, tissues, and organs are annotated with unique identifiers. In addition to the public SVG repository EBI anatomogram, spatialHeatmap also supports custom aSVGs, which is one of the most important features. This tutorial explains how to create custom aSVGs for plotting SHMs. spatialHeatmap offers its own SVG repository (SHM SVG repo) for depositing aSVGs created using this tutorial (SHM SVGs). Furthermore, the Supplement provides information on converting SHM SVG format to EBI SVG format.
First, install the spatialHeatmap
package from Bioconductor.
if (!requireNamespace("BiocManager", quietly = TRUE))
install.packages("BiocManager")
BiocManager::install("spatialHeatmap")
Next, the packages required for running the sample code in this tutorial need to be loaded.
library(spatialHeatmap); library(SummarizedExperiment); library(GEOquery)
The following lists the vignette(s) of spatialHeatmap in an HTML browser. Clicking the corresponding name will open this vignette.
browseVignettes('spatialHeatmap')
This tutorial showcases the creation of custom aSVGs using the SVG editor Inkscape. Within Inkscape, there are three methods for generating spatial features: drawing with templates, employing geometric shapes, and utilizing GIMP.
A template is a raster image that contains spatial features. An example template of Arabidopsis thaliana (Arabidopsis) root is provided here (Mustroph et al. 2009). Download this template and open it in Inkscape (Figure 1A). Select “Draw Bezier curves and straight lines (shift+F6)” on the left tool bar (Figure 1B).
Select “Fill and Stroke…” under the “Object” tab on the top (Figure 2A). On the right panel “Fill and Stroke (Shift+Ctrl+F)”, set “Stroke style” 3.000 px (Figure 2B) and press “Enter” key.
Press the “+” key to zoom in and select a template shape to start. Draw an outline for each shape by clicking at differencet corners of the shape (Figure 3A-B). At last, click at the start point to seal the outline (Figure 3C), then a spatial feature is created.
If the created spatial feature is filled with a color, click “No paint” under the “Fill” tab on the panel “Fill and Stroke (Shift+Ctrl+F)” (Figure 4A). Then it will become transparent (Figure 4B).
Select “Edit paths by nodes (F2)” on the left tool bar (Figure 5A), and draw a rectangle over the created spatial feature (Figure 5B). Select “Make selected nodes corner” (Figure 5C) on the top.
Drag nodes and edges to well align the spatial feature with the template shape (Figure 6A). On the fill and stroke panel, under the “Fill” tab select “Flat color” and optionally adjust the color scales to label the spatial feature (Figure 6B). Then the first spatial feature is done (Figure 6C).
This section showcases transforming basic geometric shapes (e.g. rectangles and circles) into spatial features, serving as a method to create the second spatial feature.
Select “Create rectangles and squares (F4)” on the left (Figure 7A), and draw a rectangle object (Figure 7B). Convert this object to paths by selecting “Object to Path” under the “Path” tab on the top (Figure 6C).
Click “No paint” under the “Fill” tab on the fill and stroke panel to make the rectangle transparent (Figure 8A). Rotate the rectangle if needed (Figure 8B). Select “Edit paths by nodes (F2)” on the left tool bar. If necessary, add a node by double-clicking on an edge (Figure 8C). Drag nodes and edges to align the rectangle with the underlying shape template (Figure 8C).
Select “Edit paths by nodes (F2)” on the left tool bar (Figure 9A), and draw a rectangle over the spatial feature (Figure 9B). Select “Make selected nodes corner” on the top (Figure 9C).
Drag the handles at the nodes of the spatial feature to fine adjust the edges for alignment with the template shape (Figure 10A). On the fill and stroke panel select “Flat color” under the “Fill” tab to optionally color this spatial feature (Figure 10B). Then the second spatial feature is done.
If shapes in the template image have clear outlines, the SVG image can be automatically extracted with GIMP. Note, unclear outlines would lead to extraction of messy spatial feature.
Open the template image in GIMP (Figure 11A), then open the “Paths” panel (Figure 11B-C). Right click and select “By Color” (Figure 11D).
Now the shapes can be selected by colors. For exmaple, first click on a whilte shape to select all shapes in white, then right click and select “To Path” (Figure 12A). After that, all the white shapes are extracted to the “Paths” panel (Figure 12B). Similarly, extract shapes of other colors.
Click in front of each extracted shape to show the “eye” icon (Figure 13A). Mouse over the extracted shapes, right click, select “Merge Visible Paths” (Figure 13B). After merged, export the paths as an SVG image (here root_gimp.svg) (Figure 13C). Next, proceed to edit the exported SVG image in Inkscape.
Open the exported SVG image (root_gimp.svg) in Inkscape (Figure 14A). Under ‘Object’ tab at the top, select “Fill and Stroke…” (Figure 2A). To make all shapes visible, click the image, select “Flat color” the under “Fill” tab, then adjust color scales (Figure 14B-C).
By default, all shapes (paths) in the SVG image extracted by GIMP are combined as a whole. To separate them, first click the image then click “Break Apart” under the top “Path” tab (Figure 15A). After separated, the shape outlines are not stroked by default. To stroke the outlines, first use “Ctrl+A” to select all shapes, on the fill and stroke panel select “Flat color” under the “Stroke paint” tab (Figure 15B), then set a number under the “Stroke style” tab (e.g. 1.333 px) (Figure 15C).
Click anywhere in the white area to unselect the whole image. Press “+” key to zoom in, then move certain shapes to expected locations if needed. To delete byproduct shapes, first select them then press the “Delete” key (Figure 16A-C).
Use “Ctrl+A” to select all shapes. Click “No paint” under the “Fill” tab on the fill and stroke panel (Figure 17A). Click anywhere in the white area to unselect the whole image. Then the editing of the extracted SVG by GIMP is done. The edited SVG file (Figure 17B) is downloadable here.
If the SVG image includes numerous spatial features (Figure 18A), the speed of creating SHMs in spatialHeatmap could be compromised. In such cases, a workaround is to overlay elongated and thin shapes existing in two layers to visually represent smaller shapes (Figure 18B). This strategy allows shared borders between spatial features and thus improves the runtime when spatialHeatmap extracting coordinates of the spatial features.
For plotting SHMs with spatialHeatmap, the spatial features in the SVGs should be formatted according to some conventions. This section focuses on the details of formatting SVGs. In addition, SVGs from EBI Anatomogram are also supported in spatialHeatmap.
If a complex spatial feature consists of multile sub-features, these sub-features should be grouped rather than combined (Ctrl+K). Take the root atrichoblast epidermis feature as example. First, select the sub-features of this tissue by clicking their edges while holding down the “Shift” key (Figure 19A). Next, mouse over any edge of the selected sub-features, then right-click and choose “Group” (Figure 19B). Note, if the spatial features are not expected to be colored in SHMs, it is not necessary to group them.
In order to make the grouped spatial features visually different from other features, the group can be colored. Sepecifically, click “Flat color” under the “Fill” tab on the fill and stroke panel (Figure 20A), then fill the group with a preferred color (Figure 20B).
A group (e.g. root_pSCR/root endodermis in Figure 21B) could be resized by simply dragging the black arrows on the edge or changing the width (H), height (H) values on the top toolbar. In either case, in the “XML Editor” panel the resized group would have an attribute of transform
with a value of matrix
(Figure 21B), indicating the coordinates of this group are transformed because of resizing. spatialHeatmap does not accept this “tranform-matrix” pair in groups. To remove this attribute, simply ungroup (Ctrl+Shift+G) and regroup (Ctrl+G) the relevant spatial features.
To enable coloring based on numeric values in the assay data, it’s necessary for spatial features to be annotated with unique identifiers that correspond to their counterparts in the data. The annotated SVGs are referred to as aSVGs. For grouped features, the group rather individual features needs to be annotated. Figure 22 is the annotating of the “root_pGL2” (root atrichoblast epidermis) group. Specifically, under the “Edit” tab on the top (Figure 22A), select “XML Editor…” (Figure 22B). Click the “root_pGL2” feature to select it. On the “XML Editor (Shift+Ctrl+X)” panel, first click “id”, then type in “root_pGL2” and click “Set” at the bottom. Note, if the spatial features are not expected to be colored in SHMs, it is not necessary to annotate them.
In addition, it is optional to add an “ontology” attribute for spatial features. Take the spatial feature “root_pGL2” (root atrichoblast epidermis) as an example. First, retrieve the ontology id for this feature at Ontology Lookup Service. Click the feature in the XML Editor, at the bottom type “ontology” and the retreived id in front of and below “Set” respectively, then click “Set” (Figure 23).
Similarly, group and annotate other spatial features as required. When grouping the small vasculature features in the center, a shortcut is to draw a rectangle over them to select multiple features, instead of clicking on each one individually. Figure 24 is the final aSVG of Arabidopsis root, colors representing different spatial features.
It is optional to include text in the aSVG. First click “Create and edit text objects (F8)” on the left tool bar (Figure 25A), then click on the target position and type text, here “root_pGL2” (Figure 25B).
On top tool bar, click on “View and select font family, font size, and other text properties (Shift+Ctrl+T)” (Figure 26A), then on the text panel, change text styles such as font size (Figure 26B).
Select the text object and convert it to path (Figure 27), then the text becomes a group (indicated by “svg:g” in Figure 27B).
The id of a text group must have specific prefixes and suffixes to achieve the desired appearance in SHMs. Specifically, the prefix should be “text”; otherwise, the text letters in SHMs might become distorted. The suffix should be either “_localLGD” or “_globalLGD”; otherwise, the text color (black) might be missing and the text could appear transparent. If “_localLGD” is used, the text will only be present in the legend plot (Figure 33 right), while if “_globalLGD” is used, the text will be present in both the SHM (Figure 33 middle) and the legend plots. An example of a valid text group id is “text927_globalLGD”.
If non-text shapes are included as legends, their ids only need to have the suffix “_localLGD” or “_globalLGD” such as “rect161_globalLGD”. Without these suffixes, the legend may appear transparent in SHMs.
All shapes, including text, need to be grouped as a whole. The id of this overall group can be random. To achieve this, select all the shapes using “Ctrl+A,” mouse over the selection, right-click, and then click “Group” (Figure 30A). It’s important to note that this overall group must be the last element in the ‘XML Editor’ (Figure 30B).
All the shapes need to have absolute positions. To achieve so, click “Preferences…” under the “Edit” tab (Figure 31A). Next, go to “Input/Output” → “SVG Output” → “Path data” → “Path string format”, then select “Absolute” (Figure 31B). To trigger the effcts on all shapes, click “Select All in All Layers” under the “Edit” tab (Figure 31C), and use the arrow key to nudge the selection, e.g. one step forward and one step backward. Then all the shapes are rewritten and absolutely positioned. The absolut position is indicated by the capital letters (M, C, etc.) in the “d” attribute of a shape (Figure 31D).
To ensure the best overall height and width of the aSVG, go to “Document Properties…” under the “File” tab and select “Custom size” under the “Page” tab, then set “Units” to “px” and click on “Resize page to drawing or selection” (Figure 32). The fully formatted Arabidopsis root aSVG file is downloadable here.
In spatialHeatmap, the naming convention for the aSVG file follows the pattern “<species>_[view]_shm.svg,” for example, “arabidopsis.thaliana_root.cross_shm.svg.” It’s important to note that the aSVG file name must end with “.svg,” and the beginning of the file name should only include letters, digits, dots, or underscores. Parentheses should be avoided. For instance, a name like “arabidopsis.thaliana_root.cross_shm(1).svg” is not supported.
When plotting SHMs, only spatial features that have common identifiers between the aSVG and assay data are colored. As a result, it’s crucial to format the assay data. The supported data containers include vector
, data frame
, and SummarizedExperiment
(SE) (Morgan et al. 2018). This section focuses on SE
. Details of the other two data containers are provided in the spatialHeatmap vignette.
For plotting SHMs, the two most important slots in SE
are assay
and colData
. The assay
slot stores the numeric data matrix, where rows and columns are biomolecules (e.g. genes) and samples respectively, while the colData
slot stores experimental design information such as replicates and treatments. Formatting SE
objects is essentially editing information in the colData
slot.
The experimental design information can be imported to the colData
slot from a tabular targets file. The target file should meet the following requirements:
It contains at least two columns. One column represents spatial features (spFeature
) and the other one experimental variables (variable
) such as treatments. The rows in the target file correspond to the columns of the numeric data stored in the assay
slot.
To be colored in SHMs, the spatial features must have common identifiers between the assay data and aSVG. Note, the double underscore is a special string reserved for specific purposes in spatialHeatmap, and thus should be avoided for naming spatial features and variables.
The following example illustrates the design of a valid SummarizedExperiment
object for generating SHMs. In this example, “root_pGL2” (root atrichoblast epidermis) has 2 experiment variables (“control” and “hypoxia”) and each has 2 replicates. Thus, there are 4 assays for “root_pGL2”. The same design applies to root_pCO2
(root cortex). These information is stored in a targets file target.test
.
spft <- c(rep('root_pGL2', 4), rep('root_pCO2', 4))
vars <- rep(c('control', 'control', 'hypoxia', 'hypoxia'), 2)
target.test <- data.frame(spFeature=spft, variable=vars, row.names=paste0('assay', 1:8))
target.test
## spFeature variable
## assay1 root_pGL2 control
## assay2 root_pGL2 control
## assay3 root_pGL2 hypoxia
## assay4 root_pGL2 hypoxia
## assay5 root_pCO2 control
## assay6 root_pCO2 control
## assay7 root_pCO2 hypoxia
## assay8 root_pCO2 hypoxia
The assay
slot is populated with a data.frame
containing random
numbers. Each column corresponds to an assay in the target file, while each row corresponds to a gene.
set.seed(10)
df.se <- data.frame(matrix(sample(x=1:1000, size=160), nrow=20))
rownames(df.se) <- paste0('gene', 1:20)
colnames(df.se) <- row.names(target.test)
df.se[1:3, ]
## assay1 assay2 assay3 assay4 assay5 assay6 assay7 assay8
## gene1 491 351 946 361 74 192 176 384
## gene2 649 392 670 729 570 761 94 612
## gene3 330 622 324 712 679 847 660 571
Next, a SummarizedExperiment
object is constructed by providing the
numeric and target data under the assays
and colData
arguments,
respectively.
se <- SummarizedExperiment(assays=df.se, colData=target.test)
se
## class: SummarizedExperiment
## dim: 20 8
## metadata(0):
## assays(1): ''
## rownames(20): gene1 gene2 ... gene19 gene20
## rowData names(0):
## colnames(8): assay1 assay2 ... assay7 assay8
## colData names(2): spFeature variable
The replicates are aggregated by means.
se.aggr <- aggr_rep(data=se, sam.factor='spFeature', con.factor='variable', aggr='mean')
assay(se.aggr)[1:2, ]
## root_pGL2__control root_pGL2__hypoxia root_pCO2__control root_pCO2__hypoxia
## gene1 421.0 653.5 133.0 280
## gene2 520.5 699.5 665.5 353
The aSVG file “arabidopsis.thaliana_root.cross_shm.svg” created in this tutorial are imported to an SVG
object (see details here). The annotated spatial features are stored in the “feature” column.
svg.root <- read_svg('data/arabidopsis.thaliana_root.cross_shm.svg')
## Parsing: arabidopsis.thaliana_root.cross_shm.svg ...
## CPU cores: 1
##
## Potential error detected in these elements: 'root_pWOL;root_pWOL'! If they are groups, please remove the 'transform' attribute with a 'matrix' value by ungrouping and regrouping the respective groups in Inkscape. If individual paths, consider deleting them in Inkscape. Otherwise, colors in spatial heatmap might be shifted!
svg.root[, 2][[1]][1:3, 1]
## # A tibble: 3 × 1
## feature
## <chr>
## 1 root_pSCR
## 2 root_pSCR
## 3 root_pSCR
Spatial features between the assay data and aSVG have common identifiers.
se.aggr$spFeature %in% svg.root[, 2][[1]]$feature
## [1] TRUE TRUE TRUE TRUE
With the fully formatted assay data and aSVG, SHMs are plotted for gene1.
dat <- SPHM(svg=svg.root, bulk=se.aggr)
shm(data=dat, sam.factor='spFeature', con.factor='variable', ID=c("gene1"), legend.nrow=4, bar.width=0.1, legend.r=1, h=0.7)
If errors occur when plotting SHMs, the following suggestions may be helpful:
Make sure that spatial feature groups do not contain nested groups.
SVGs are XML-like files (as shown in Figure 30B). Ensure that the SVG elements used are limited to “g,” “path,” “rect,” “ellipse,” “use,” and “title.” Using other elements could result in errors or warnings when utilizing spatialHeatmap. Note that “use” elements are not permitted within “g” elements.
Carefully review the formatting conventions for both SVGs and assay data to ensure compliance.
spatialHeatmap also works with EBI SVGs that are used in Expression Atlas Anatomogram. This section illustrates the conversion of SHM SVGs to EBI SVGs.
Download the EBI SVG template EBI_template.svg (Figure 34A) and open it in Inkscape (Figure 34B). The template contains 2 layers “LAYER_OUTLINE” and “LAYER_EFO” (Figure 34C). The former is expected to store outline shapes that encircle all spatial feature shapes while the latter to store shapes of individual spatial features. As a template, both layers are empty (Figure 34B) except that “LAYER_OUTLINE” contains a green icon that links to Expression Atlas Licence.
Note, in the EBI format, the “LAYER_OUTLINE” and “LAYER_EFO” elements start with “svg:g”, but they are actually layers, which is indicated by the “groupmode” attribute with the “layer” value (Figure 34D).
Copy “height”, “width”, “viewBox” values in the top “<svg …>” element from arabidopsis.thaliana_root.cross_shm.svg (Figure 35A) to “EBI_template.svg” (Figure 35B).
If the green icon is shrunk, it can be resized. First, select it (Figure 36A), then click the lock on the top toolbar (Figure 36B), which maintains the aspect ratio. Next, increase the height (H) or width (W). Move the icon to the bottom left corner.
Open arabidopsis.thaliana_root.cross_shm.svg in Inkscape, ungroup (Ctrl+Shift+G) the overall group (Figure 37), then select and copy all shapes.
In “EBI_template.svg”, open layer panel (Ctrl+Shift+L) and make sure the “unlock” icon is present in front of “EFO” and “Outline” (Figure 38A). Click the “EFO” layer and paste all shapes into the “EFO” layer (Figure 38A-C).
In EBI SVGs, spatial features are annotated with unique identifiers and optional ontology ids. Take the “root_pSCR” (root endodermis) feature for example. Click the shape in “XML Editor” (Figure 39A), then click “New element node” on the top (Figure 39B). Type in “svg:title” and click “Create” (Figure 39C). Then a “title” node is created at the bottom of “root_pSCR”.
Click the “title” node and click “New text node” at the top (Figure 40A). Then an empty text node is created inside the “title” node (Figure 40B). Click the text node and type in “root_pSCR” on the right (Figure 40C).
Set title id as “root_pSCR” (Figure 41), then the title is done.
Look up for “root endodermis” (root_pSCR) in Ontology Lookup Service (Figure 42A), and set the “root_pSCR” group id as the retrieved ontolody id “PO:0005059” (Figure 42B). Then the annotation of “root_pSCR” is done. Annotate other tissues in the same way.
The “LAYER_OUTLINE” layer is used to store the optional outline shapes. For illustration purpose, a root outline is created.
Click “Outline in the layer panel (Figure 43A), and draw an outline as explained above (Figure 43B-C).
Make sure all paths have absolute coordinates as shown in Section Absolute Path Position.
Next, resize the canvas as shown in the Section Resizing Canvas.
According to the EBI requirements, all shapes (“EFO” layer) need to be transparent by setting style="fill:none; stroke:none"
. To do so, click on “EFO” in the layer panel (Figure 44A), select all shapes (Ctrl+A), then click “No paint” under both “Fill” and “Stroke paint” in the “XML Editor” panel (Figure 44B-C). After that, only the outline shape is visible (Figure 44D).
According to the naming scheme of EBI SVGs, the aSVG is named arabidopsis_thaliana.root_cross.svg, which is ready to use for plotting SHMs.
sessionInfo()
## R version 4.3.0 (2023-04-21)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 20.04.3 LTS
##
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
## LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8 LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 LC_PAPER=en_US.UTF-8 LC_NAME=C
## [9] LC_ADDRESS=C LC_TELEPHONE=C LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
##
## time zone: America/Los_Angeles
## tzcode source: system (glibc)
##
## attached base packages:
## [1] stats4 stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] GEOquery_2.70.0 SummarizedExperiment_1.32.0 Biobase_2.62.0 GenomicRanges_1.54.1 GenomeInfoDb_1.38.1 IRanges_2.36.0 S4Vectors_0.40.2
## [8] BiocGenerics_0.48.1 MatrixGenerics_1.14.0 matrixStats_1.1.0 spatialHeatmap_2.9.1 knitr_1.45 BiocStyle_2.30.0 nvimcom_0.9-128
## [15] colorout_1.2-2
##
## loaded via a namespace (and not attached):
## [1] jsonlite_1.8.8 magrittr_2.0.3 magick_2.8.1 ggbeeswarm_0.7.2 farver_2.1.1 rmarkdown_2.25 fs_1.6.3
## [8] zlibbioc_1.48.0 vctrs_0.6.5 memoise_2.0.1 DelayedMatrixStats_1.24.0 RCurl_1.98-1.13 htmltools_0.5.7 S4Arrays_1.2.0
## [15] BiocNeighbors_1.20.0 SparseArray_1.2.2 gridGraphics_0.5-1 sass_0.4.8 KernSmooth_2.23-22 bslib_0.6.1 plyr_1.8.9
## [22] cachem_1.0.8 igraph_1.5.1 mime_0.12 lifecycle_1.0.4 pkgconfig_2.0.3 rsvd_1.0.5 Matrix_1.6-4
## [29] R6_2.5.1 fastmap_1.1.1 GenomeInfoDbData_1.2.11 shiny_1.8.0 digest_0.6.33 rsvg_2.6.0 colorspace_2.1-0
## [36] AnnotationDbi_1.64.1 scater_1.30.1 dqrng_0.3.2 irlba_2.3.5.1 shinytoastr_2.2.0 RSQLite_2.3.3 beachmat_2.18.0
## [43] labeling_0.4.3 fansi_1.0.5 httr_1.4.7 abind_1.4-5 compiler_4.3.0 withr_2.5.2 bit64_4.0.5
## [50] BiocParallel_1.36.0 viridis_0.6.4 DBI_1.1.3 shinyAce_0.4.2 highr_0.10 gplots_3.1.3 DelayedArray_0.28.0
## [57] bluster_1.12.0 gtools_3.9.5 caTools_1.18.2 tools_4.3.0 vipor_0.4.5 beeswarm_0.4.0 httpuv_1.6.12
## [64] glue_1.6.2 promises_1.2.1 grid_4.3.0 cluster_2.1.6 reshape2_1.4.4 generics_0.1.3 gtable_0.3.4
## [71] tzdb_0.4.0 spsComps_0.3.3.0 tidyr_1.3.0 hms_1.1.3 data.table_1.14.8 xml2_1.3.6 BiocSingular_1.18.0
## [78] ScaledMatrix_1.10.0 metapod_1.10.0 utf8_1.2.4 XVector_0.42.0 ggrepel_0.9.4 pillar_1.9.0 stringr_1.5.1
## [85] yulab.utils_0.1.0 limma_3.58.1 later_1.3.1 genefilter_1.84.0 splines_4.3.0 dplyr_1.1.4 lattice_0.22-5
## [92] survival_3.5-5 bit_4.0.5 annotate_1.80.0 tidyselect_1.2.0 SingleCellExperiment_1.24.0 locfit_1.5-9.8 Biostrings_2.70.1
## [99] scuttle_1.12.0 gridExtra_2.3 bookdown_0.37 edgeR_4.0.2 shinydashboard_0.7.2 xfun_0.41 statmod_1.5.0
## [106] stringi_1.8.2 yaml_2.3.7 evaluate_0.23 codetools_0.2-19 tibble_3.2.1 BiocManager_1.30.22 ggplotify_0.1.2
## [113] cli_3.6.1 xtable_1.8-4 munsell_0.5.0 jquerylib_0.1.4 Rcpp_1.0.11 grImport_0.9-7 png_0.1-8
## [120] XML_3.99-0.16 parallel_4.3.0 ellipsis_0.3.2 readr_2.1.4 assertthat_0.2.1 ggplot2_3.4.4 blob_1.2.4
## [127] scran_1.30.0 sparseMatrixStats_1.14.0 bitops_1.0-7 viridisLite_0.4.2 scales_1.3.0 purrr_1.0.2 crayon_1.5.2
## [134] rlang_1.1.2 KEGGREST_1.42.0