This article will show you how to create and customise ordination plots, like PCA and RDA, with microViz.
For an even quicker start with ordinating your phyloseq data, check
out the ord_explore
Shiny
app, which allows you to create ordination plots with a point and
click interface, and generates ord_plot
code for you to
copy. Return to this article to understand more about creating and
customising your ordination plotting script.
library(phyloseq)
library(ggplot2)
library(microViz)
#> microViz version 0.12.5 - Copyright (C) 2021-2024 David Barnett
#> ! Website: https://david-barnett.github.io/microViz
#> ✔ Useful? For citation details, run: `citation("microViz")`
#> ✖ Silence? `suppressPackageStartupMessages(library(microViz))`
knitr::opts_chunk$set(fig.width = 7, fig.height = 6)
We will use example data from stool samples from an inflammatory
bowel disease (IBD) study, borrowed from the great corncob
package. See the article about working
with phyloseq objects if you want to get started with your own data,
or just to learn more about manipulating phyloseq objects with
microViz.
ibd <- microViz::ibd
ibd
#> phyloseq-class experiment-level object
#> otu_table() OTU Table: [ 36349 taxa and 91 samples ]
#> sample_data() Sample Data: [ 91 samples by 15 sample variables ]
#> tax_table() Taxonomy Table: [ 36349 taxa by 7 taxonomic ranks ]
First we fix any uninformative tax_table entries and check the phyloseq object (see the article on fixing your tax_table for more info).
ibd <- tax_fix(ibd) # try tax_fix_interactive if you have problems with your own data
ibd <- phyloseq_validate(ibd, remove_undetected = TRUE)
Ordination plots are a great way to see any clustering or other
patterns of microbiota (dis)similarity in (many) samples. Ordinations
like PCA or PCoA show the largest patterns of variation in your data,
and constrained ordination techniques like RDA or CCA can show you
microbial variation that could be explained by other variables in your
sample_data (but interpret constrained ordinations with care, and
ideally test for the statistical significance of any hypothesised
associations using a method like PERMANOVA, see
dist_permanova()
).
Check out the GUide to STatistical Analysis in Microbial Ecology (GUSTA ME)website for a gentle theoretical introduction to PCA, PCoA, RDA, CCA and more.
Ordination plots can also be paired with barplots for greater insight
into microbial compositions, e.g. see ord_plot_iris()
and
the ord_explore()
interactive Shiny
app.
When creating an ordination plot, you first need to prepare the microbiota variables.
Decide at which taxonomic rank to aggregate your data, e.g. “Genus”
Consider transforming the microbial counts, e.g. using the “clr” (centred log ratio) transformation, which is often recommended for compositional data (like sequencing data)
ibd %>%
tax_transform(trans = "clr", rank = "Genus")
#> psExtra object - a phyloseq object with extra slots:
#>
#> phyloseq-class experiment-level object
#> otu_table() OTU Table: [ 178 taxa and 91 samples ]
#> sample_data() Sample Data: [ 91 samples by 15 sample variables ]
#> tax_table() Taxonomy Table: [ 178 taxa by 6 taxonomic ranks ]
#>
#> otu_get(counts = TRUE) [ 178 taxa and 91 samples ]
#>
#> psExtra info:
#> tax_agg = "Genus" tax_trans = "clr"
dist_calc()
. Normally you should NOT transform your data
when using a distance-based method, but it is useful to record an
“identity” transformation anyway, to make it clear you have not
transformed your data.
ibd %>%
tax_transform(trans = "identity", rank = "Genus") %>%
dist_calc("bray") # bray curtis distance
#> psExtra object - a phyloseq object with extra slots:
#>
#> phyloseq-class experiment-level object
#> otu_table() OTU Table: [ 178 taxa and 91 samples ]
#> sample_data() Sample Data: [ 91 samples by 15 sample variables ]
#> tax_table() Taxonomy Table: [ 178 taxa by 6 taxonomic ranks ]
#>
#> psExtra info:
#> tax_agg = "Genus" tax_trans = "identity"
#>
#> bray distance matrix of size 91
#> 0.8294664 0.7156324 0.5111652 0.5492537 0.8991251 ...
tax_filter()
before using
dist_calc(ps, dist = "unifrac")
. Distances that are
(implicitly) abundance weighted, including Generalised UniFrac,
Bray-Curtis and Aitchison distance, should be less sensitive to rare
taxa / filtering threshold choices.Notice that the objects created above are of class “psExtra”. This is
an S4 class object that holds your phyloseq object with additional slots
for stuff created from this phyloseq object, such as a distance matrix,
as well as info on any transformation and aggregation applied to your
taxa. microViz uses this to automatically create plot captions, to help
you and your collaborators remember how you made each plot! You can
access the phyloseq object, distance matrix and other parts of a psExtra
object with ps_get()
, dist_get()
, and
friends.
Principal Components Analysis is an
unconstrained method that does not use a distance matrix. PCA directly
uses the (transformed) microbial variables, so you do not need
dist_calc()
. ord_calc
performs the ordination
(adding it to the psExtra object) and ord_plot()
creates
the ggplot2 scatterplot (which you can customise like other ggplot
objects).
Each point is a sample, and samples that appear closer together are typically more similar to each other than samples which are further apart. So by colouring the points by IBD status you can see that the microbiota from people with IBD is often, but not always, highly distinct from people without IBD.
ibd %>%
tax_transform("clr", rank = "Genus") %>%
# when no distance matrix or constraints are supplied, PCA is the default/auto ordination method
ord_calc() %>%
ord_plot(color = "ibd", shape = "DiseaseState", size = 2) +
scale_colour_brewer(palette = "Dark2")
One benefit of not using a distance matrix, is that you can plot taxa “loadings” onto your PCA axes, using the plot_taxa argument. microViz plots all of the taxa loading vectors in light grey, and you choose how many of the vectors to label, starting with the longest arrows (alternatively you can name particular taxa to label).
The relative length of each loading vector indicates its contribution to each PCA axis shown, and allows you to roughly estimate which samples will contain more of that taxon e.g. samples on the left of the plot below, will typically contain more Escherichia/Shigella than samples on the right, and this taxon contributes heavily to the PC1 axis.
ibd %>%
tax_transform("clr", rank = "Genus") %>%
# when no distance matrix or constraints are supplied, PCA is the default/auto ordination method
ord_calc(method = "PCA") %>%
ord_plot(color = "ibd", shape = "DiseaseState", plot_taxa = 1:5, size = 2) +
scale_colour_brewer(palette = "Dark2")
microViz also allows you directly visualize the sample compositions on a circular barplot or “iris plot” (named because it looks kinda like an eyeball) alongside the PCA plot. The samples on the iris plot are automatically arranged by their rotational position around the center/origin of the PCA plot.
ibd %>%
tax_transform("clr", rank = "Genus") %>%
# when no distance matrix or constraints are supplied, PCA is the default/auto ordination method
ord_calc() %>%
ord_plot_iris(tax_level = "Genus", ord_plot = "above", anno_colour = "ibd")
Here we created the ordination plot as a quick accompaniment to the
circular barchart, but it is more flexible to create and customise the
ordination plot and iris plot separately, and then pair them afterwards
with patchwork. See the ord_plot_iris
docs
for examples.
Principal Co-ordinates Analysis is also an unconstrained method, but it does require a distance matrix. In an ecological context, a distance (or more generally a “dissimilarity”) measure indicates how different a pair of (microbial) ecosystems are. This can be calculated in many ways.
The Euclidean distance is similar to the distance we humans are familiar with in the physical world. The results of a PCA is practically equivalent to a PCoA with Euclidean distances. The Aitchison distance is a dissimilarity measure calculated as the Euclidean distance between observations (samples) after performing a centered log ratio (“clr”) transformation. That is why the Aitchison distance PCoA, below, looks the same as the PCA we made earlier. However, we cannot use plot_taxa, as the taxa loadings are only available for PCA (and related methods like RDA).
ibd %>%
tax_transform("identity", rank = "Genus") %>% # don't transform!
dist_calc("aitchison") %>%
ord_calc("PCoA") %>%
ord_plot(color = "ibd", shape = "DiseaseState", size = 2) +
scale_colour_brewer(palette = "Dark2")
Note that PCoA is also known as MDS, for (metric) Multi-Dimensional Scaling, hence the axes names.
Over the years, ecologists have invented numerous ways of quantifying dissimilarity between pairs of ecosystems. One ubiquitous example is the Bray-Curtis dissimilarity measure, shown below.
ibd %>%
tax_transform("identity", rank = "Genus") %>% # don't transform!
dist_calc("bray") %>%
ord_calc("PCoA") %>%
ord_plot(color = "ibd", shape = "DiseaseState", size = 2) +
scale_colour_brewer(palette = "Dark2")
Beyond Bray-Curtis, microViz dist_calc()
can also help
you calculate all the other ecological distances listed in
phyloseq::distanceMethodList
such the Jensen-Shannon
Divergence, "jsd"
, or Jaccard dissimilarity
"jaccard"
. Beware that if you want a binary dissimilarity
measure from vegan::vegdist()
(i.e. only using
presence/absence info, and noting all the caveats about sensitivity to
low abundance taxa) you will need to pass binary = TRUE
, as
below.
ibd %>%
tax_transform("identity", rank = "Genus") %>%
dist_calc(dist = "jaccard", binary = TRUE) %>%
ord_calc("PCoA") %>%
ord_plot(color = "ibd", shape = "DiseaseState", size = 2) +
scale_colour_brewer(palette = "Dark2")
If you have a phylogenetic tree available, and attached
to your phyloseq object. You can calculate dissimilarities from the
UniFrac family of
methods, which take into account the phylogenetic relatedness of the
taxa / sequences in your samples when calculating dissimilarity.
Un-weighted UniFrac, dist_calc(dist = "unifrac")
, does not
consider the relative abundance of taxa, only their presence (detection)
or absence, which can make it (overly) sensitive to rare taxa,
sequencing artefacts, and abundance filtering choices. Conversely,
weighted UniFrac, "wunifrac"
, does put (perhaps too much)
more importance on highly abundant taxa, when determining
dissimilarities. The Generalised UniFrac, "gunifrac"
, finds
a balance between these two extremes, and by adjusting the
gunifrac_alpha
argument of dist_calc()
, you
can tune this balance to your liking (although the 0.5 default should be
fine!).
Below is a Generalised UniFrac example using a different, and tiny, example dataset from the phyloseq package that has a phylogenetic tree.
You should not aggregate taxa before using a phylogenetic distance measure, but you can and probably should register the choice not to transform or aggregate, as below.
data("esophagus", package = "phyloseq")
esophagus %>%
phyloseq_validate(verbose = FALSE) %>%
tax_transform("identity", rank = "unique") %>%
dist_calc("gunifrac", gunifrac_alpha = 0.5)
#> Registered S3 method overwritten by 'rmutil':
#> method from
#> print.response httr
#> psExtra object - a phyloseq object with extra slots:
#>
#> phyloseq-class experiment-level object
#> otu_table() OTU Table: [ 58 taxa and 3 samples ]
#> sample_data() Sample Data: [ 3 samples by 1 sample variables ]
#> tax_table() Taxonomy Table: [ 58 taxa by 1 taxonomic ranks ]
#> phy_tree() Phylogenetic Tree: [ 58 tips and 57 internal nodes ]
#>
#> psExtra info:
#> tax_agg = "unique" tax_trans = "identity"
#>
#> gunifrac_0.5 distance matrix of size 3
#> 0.4404284 0.4332325 0.4969773 ...
You can show other dimensions / axes of an ordination than just the first two, by setting the axes argument. You can judge from the variation explained by each successive axis (on a scree plot) whether this is worthwhile information to show, e.g. in the example below, it could be interesting to also show the 3rd axis, but not any others.
ibd %>%
tax_transform("identity", rank = "Genus") %>% # don't transform!
dist_calc("bray") %>%
ord_calc("PCoA") %>%
ord_get() %>%
phyloseq::plot_scree() + theme(axis.text.x = element_text(size = 6))
Let us view the 1st and 3rd axes.
ibd %>%
tax_transform("identity", rank = "Genus") %>% # don't transform!
dist_calc("bray") %>%
ord_calc("PCoA") %>%
ord_plot(axes = c(1, 3), color = "ibd", shape = "DiseaseState", size = 2) +
scale_colour_brewer(palette = "Dark2")
As the ordination figures are (pretty much) just standard ggplot
objects, integration with other ggplot extensions like
ggside
is typically possible. Below are a couple of
examples using the ggside
package to add univariable
distribution plots for each PC, split by the same groups as in the main
plot.
ibd %>%
tax_transform("identity", rank = "Genus") %>%
dist_calc(dist = "aitchison") %>%
ord_calc("PCoA") %>%
ord_plot(color = "ibd", shape = "DiseaseState", size = 2) +
scale_colour_brewer(palette = "Dark2", aesthetics = c("fill", "colour")) +
theme_bw() +
ggside::geom_xsideboxplot(aes(fill = ibd, y = ibd), orientation = "y") +
ggside::geom_ysideboxplot(aes(fill = ibd, x = ibd), orientation = "x") +
ggside::scale_xsidey_discrete(labels = NULL) +
ggside::scale_ysidex_discrete(labels = NULL) +
ggside::theme_ggside_void()
#> Registered S3 method overwritten by 'ggside':
#> method from
#> +.gg ggplot2
ibd %>%
tax_transform("identity", rank = "Genus") %>%
dist_calc(dist = "aitchison") %>%
ord_calc("PCoA") %>%
ord_plot(color = "ibd", shape = "DiseaseState", size = 2) +
scale_colour_brewer(palette = "Dark2", aesthetics = c("fill", "colour"), name = "IBD") +
theme_bw() +
ggside::geom_xsidedensity(aes(fill = ibd), alpha = 0.5, show.legend = FALSE) +
ggside::geom_ysidedensity(aes(fill = ibd), alpha = 0.5, show.legend = FALSE) +
ggside::theme_ggside_void()
Redundancy analysis is a constrained ordination method. It displays the microbial variation that can also be explained by selected constraint variables.
Behind the scenes, a linear regression model is created for each microbial abundance variable (using the constraints as the explanatory variables) and a PCA is performed using the fitted values of the microbial abundances.
Starting from the same phyloseq object ibd
the code
below first creates a couple of binary (0/1) numeric variables to use a
constraint variables. This is easy enough with ps_mutate.
Then we aggregate and transform our taxa, and like PCA we skip the dist_calc step.
ibd %>%
ps_mutate(
IBD = as.numeric(ibd == "ibd"),
Female = as.numeric(gender == "female"),
Abx. = as.numeric(abx == "abx")
) %>%
tax_transform("clr", rank = "Genus") %>%
ord_calc(
constraints = c("IBD", "Female", "Abx."),
# method = "RDA", # Note: you can specify RDA explicitly, and it is good practice to do so, but microViz can guess automatically that you want an RDA here (helpful if you don't remember the name?)
scale_cc = FALSE # doesn't make a difference
) %>%
ord_plot(
colour = "DiseaseState", size = 2, alpha = 0.5, shape = "active",
plot_taxa = 1:8
)
The plot above looks okay by default, but it is fairly easy to tweak ord_plot further to get the style just how you want it. The code below has comments to explain which part makes which changes to the plot.
# first we make a function that replaces any unwanted "_" in our taxa labels with spaces
library(stringr)
renamer <- function(x) str_replace(x, pattern = "_", replacement = " ")
ibd %>%
ps_mutate(
IBD = as.numeric(ibd == "ibd"),
Female = as.numeric(gender == "female"),
Abx. = as.numeric(abx == "abx")
) %>%
tax_transform("clr", rank = "Genus") %>%
ord_calc(
constraints = c("IBD", "Female", "Abx."),
method = "RDA",
scale_cc = FALSE # doesn't make a difference
) %>%
ord_plot(
colour = "DiseaseState", size = 2, alpha = 0.5, shape = "active",
auto_caption = NA, # remove the helpful automatic caption
plot_taxa = 1:8, taxon_renamer = renamer, # renamer is the function we made earlier
tax_vec_length = 5, # this value is a scalar multiplier for the biplot score vectors
tax_lab_length = 6, # this multiplier moves the labels, independently of the arrowheads
tax_lab_style = tax_lab_style(size = 1.8, alpha = 0.5), # create a list of options to tweak the taxa labels' default style
constraint_vec_length = 3, # this adjusts the length of the constraint arrows, and the labels track these lengths by default
constraint_vec_style = vec_constraint(1.5, alpha = 0.5), # this styles the constraint arrows
constraint_lab_style = constraint_lab_style(size = 3) # this styles the constraint labels
) +
# the functions below are from ggplot2:
# You can pick a different colour scale, such as a color_brewer palette
scale_colour_brewer(palette = "Set1") +
# You can set any scale's values manually, such as the shapes used
scale_shape_manual(values = c(
active = "circle", mild = "circle cross",
inactive = "circle open", control = "square open"
)) +
# this is how you add a title and subtitle
ggtitle(
label = "[Insert your exciting interpretations here?]",
subtitle = "RDA with clr-transformed genera: constraints in red, taxa in black"
) +
# and this is how you make your own caption
labs(caption = "91 samples, 178 genera. Type 2 scaling.") +
# this is one way to set the aspect ratio of the plot
coord_fixed(ratio = 1, clip = "off")
tax_lab_style()
is a helper function that gives you some
options for customising the look of the taxa loading labels, including,
in this example, using rotated, bold and italic text for the taxa
names.
constraint_lab_style()
is a similar helper function for
customising the constraint labels. When rotating labels (not text) the
ggtext package must be installed.
ibd %>%
ps_mutate(
IBD = as.numeric(ibd == "ibd"),
Female = as.numeric(gender == "female"),
Abx. = as.numeric(abx == "abx")
) %>%
tax_transform("clr", rank = "Genus") %>%
ord_calc(
constraints = c("IBD", "Female", "Abx."),
method = "RDA",
scale_cc = FALSE # doesn't make a difference
) %>%
ord_plot(
colour = "DiseaseState", size = 2, alpha = 0.5, shape = "active",
auto_caption = NA,
plot_taxa = 1:8, taxon_renamer = renamer,
# with rotated labels, it is nicer to keep lab_length closer to vec_length
tax_vec_length = 4.5, tax_lab_length = 4.6,
tax_lab_style = tax_lab_style(
type = "text", max_angle = 90, fontface = "bold.italic"
),
constraint_vec_style = vec_constraint(1.5, alpha = 0.5),
constraint_vec_length = 3, constraint_lab_length = 3.3,
constraint_lab_style = constraint_lab_style(
alpha = 0.8, size = 3, max_angle = 90, perpendicular = TRUE
)
) +
# SETTING A FIXED RATIO IDENTICAL TO THE aspect_ratio ARGUMENT IN
# tax_lab_style() IS NECESSARY FOR THE ANGLES OF TEXT TO ALIGN WITH ARROWS!
coord_fixed(ratio = 1, clip = "off", xlim = c(-6, 6)) +
# The scales below are set the same as in the previous customisation:
scale_colour_brewer(palette = "Set1") +
scale_shape_manual(values = c(
active = "circle", mild = "circle cross",
inactive = "circle open", control = "square open"
))
Tutorial coming soon, for now see ord_plot()
for
examples.
devtools::session_info()
#> ─ Session info ───────────────────────────────────────────────────────────────
#> setting value
#> version R version 4.4.2 (2024-10-31)
#> os Ubuntu 22.04.5 LTS
#> system x86_64, linux-gnu
#> ui X11
#> language en
#> collate C.UTF-8
#> ctype C.UTF-8
#> tz UTC
#> date 2024-11-18
#> pandoc 3.1.11 @ /opt/hostedtoolcache/pandoc/3.1.11/x64/ (via rmarkdown)
#>
#> ─ Packages ───────────────────────────────────────────────────────────────────
#> package * version date (UTC) lib source
#> ade4 1.7-22 2023-02-06 [1] RSPM
#> ape 5.8 2024-04-11 [1] RSPM
#> Biobase 2.66.0 2024-10-29 [1] Bioconduc~
#> BiocGenerics 0.52.0 2024-10-29 [1] Bioconduc~
#> biomformat 1.34.0 2024-10-29 [1] Bioconduc~
#> Biostrings 2.74.0 2024-10-29 [1] Bioconduc~
#> bslib 0.8.0 2024-07-29 [1] RSPM
#> cachem 1.1.0 2024-05-16 [1] RSPM
#> cli 3.6.3 2024-06-21 [1] RSPM
#> clue 0.3-66 2024-11-13 [1] RSPM
#> cluster 2.1.6 2023-12-01 [3] CRAN (R 4.4.2)
#> codetools 0.2-20 2024-03-31 [3] CRAN (R 4.4.2)
#> colorspace 2.1-1 2024-07-26 [1] RSPM
#> commonmark 1.9.2 2024-10-04 [1] RSPM
#> crayon 1.5.3 2024-06-20 [1] RSPM
#> data.table 1.16.2 2024-10-10 [1] RSPM
#> desc 1.4.3 2023-12-10 [1] RSPM
#> devtools 2.4.5 2022-10-11 [1] RSPM
#> digest 0.6.37 2024-08-19 [1] RSPM
#> dplyr 1.1.4 2023-11-17 [1] RSPM
#> ellipsis 0.3.2 2021-04-29 [1] RSPM
#> evaluate 1.0.1 2024-10-10 [1] RSPM
#> fansi 1.0.6 2023-12-08 [1] RSPM
#> farver 2.1.2 2024-05-13 [1] RSPM
#> fastmap 1.2.0 2024-05-15 [1] RSPM
#> fBasics 4041.97 2024-08-19 [1] RSPM
#> foreach 1.5.2 2022-02-02 [1] RSPM
#> fs 1.6.5 2024-10-30 [1] RSPM
#> generics 0.1.3 2022-07-05 [1] RSPM
#> GenomeInfoDb 1.42.0 2024-10-29 [1] Bioconduc~
#> GenomeInfoDbData 1.2.13 2024-11-01 [1] Bioconductor
#> ggplot2 * 3.5.1 2024-04-23 [1] RSPM
#> ggrepel 0.9.6 2024-09-07 [1] RSPM
#> ggside 0.3.1 2024-03-01 [1] RSPM
#> ggtext 0.1.2 2022-09-16 [1] RSPM
#> glue 1.8.0 2024-09-30 [1] RSPM
#> gridtext 0.1.5 2022-09-16 [1] RSPM
#> gtable 0.3.6 2024-10-25 [1] RSPM
#> GUniFrac 1.8 2023-09-14 [1] RSPM
#> htmltools 0.5.8.1 2024-04-04 [1] RSPM
#> htmlwidgets 1.6.4 2023-12-06 [1] RSPM
#> httpuv 1.6.15 2024-03-26 [1] RSPM
#> httr 1.4.7 2023-08-15 [1] RSPM
#> igraph 2.1.1 2024-10-19 [1] RSPM
#> inline 0.3.20 2024-11-10 [1] RSPM
#> IRanges 2.40.0 2024-10-29 [1] Bioconduc~
#> iterators 1.0.14 2022-02-05 [1] RSPM
#> jquerylib 0.1.4 2021-04-26 [1] RSPM
#> jsonlite 1.8.9 2024-09-20 [1] RSPM
#> knitr 1.49 2024-11-08 [1] RSPM
#> labeling 0.4.3 2023-08-29 [1] RSPM
#> later 1.3.2 2023-12-06 [1] RSPM
#> lattice 0.22-6 2024-03-20 [3] CRAN (R 4.4.2)
#> lifecycle 1.0.4 2023-11-07 [1] RSPM
#> magrittr 2.0.3 2022-03-30 [1] RSPM
#> markdown 1.13 2024-06-04 [1] RSPM
#> MASS 7.3-61 2024-06-13 [3] CRAN (R 4.4.2)
#> Matrix 1.7-1 2024-10-18 [3] CRAN (R 4.4.2)
#> matrixStats 1.4.1 2024-09-08 [1] RSPM
#> memoise 2.0.1 2021-11-26 [1] RSPM
#> mgcv 1.9-1 2023-12-21 [3] CRAN (R 4.4.2)
#> microbiome 1.28.0 2024-10-29 [1] Bioconduc~
#> microViz * 0.12.5 2024-11-18 [1] local
#> mime 0.12 2021-09-28 [1] RSPM
#> miniUI 0.1.1.1 2018-05-18 [1] RSPM
#> modeest 2.4.0 2019-11-18 [1] RSPM
#> multtest 2.62.0 2024-10-29 [1] Bioconduc~
#> munsell 0.5.1 2024-04-01 [1] RSPM
#> nlme 3.1-166 2024-08-14 [3] CRAN (R 4.4.2)
#> patchwork 1.3.0 2024-09-16 [1] RSPM
#> permute 0.9-7 2022-01-27 [1] RSPM
#> phyloseq * 1.50.0 2024-10-29 [1] Bioconduc~
#> pillar 1.9.0 2023-03-22 [1] RSPM
#> pkgbuild 1.4.5 2024-10-28 [1] RSPM
#> pkgconfig 2.0.3 2019-09-22 [1] RSPM
#> pkgdown 2.1.1 2024-09-17 [1] RSPM
#> pkgload 1.4.0 2024-06-28 [1] RSPM
#> plyr 1.8.9 2023-10-02 [1] RSPM
#> profvis 0.4.0 2024-09-20 [1] RSPM
#> promises 1.3.0 2024-04-05 [1] RSPM
#> purrr 1.0.2 2023-08-10 [1] RSPM
#> R6 2.5.1 2021-08-19 [1] RSPM
#> ragg 1.3.3 2024-09-11 [1] RSPM
#> RColorBrewer 1.1-3 2022-04-03 [1] RSPM
#> Rcpp 1.0.13-1 2024-11-02 [1] RSPM
#> remotes 2.5.0 2024-03-17 [1] RSPM
#> reshape2 1.4.4 2020-04-09 [1] RSPM
#> rhdf5 2.50.0 2024-10-29 [1] Bioconduc~
#> rhdf5filters 1.18.0 2024-10-29 [1] Bioconduc~
#> Rhdf5lib 1.28.0 2024-10-29 [1] Bioconduc~
#> rlang 1.1.4 2024-06-04 [1] RSPM
#> rmarkdown 2.29 2024-11-04 [1] RSPM
#> rmutil 1.1.10 2022-10-27 [1] RSPM
#> rpart 4.1.23 2023-12-05 [3] CRAN (R 4.4.2)
#> Rtsne 0.17 2023-12-07 [1] RSPM
#> S4Vectors 0.44.0 2024-10-29 [1] Bioconduc~
#> sass 0.4.9 2024-03-15 [1] RSPM
#> scales 1.3.0 2023-11-28 [1] RSPM
#> sessioninfo 1.2.2 2021-12-06 [1] RSPM
#> shiny 1.9.1 2024-08-01 [1] RSPM
#> spatial 7.3-17 2023-07-20 [3] CRAN (R 4.4.2)
#> stable 1.1.6 2022-03-02 [1] RSPM
#> stabledist 0.7-2 2024-08-17 [1] RSPM
#> statip 0.2.3 2019-11-17 [1] RSPM
#> statmod 1.5.0 2023-01-06 [1] RSPM
#> stringi 1.8.4 2024-05-06 [1] RSPM
#> stringr * 1.5.1 2023-11-14 [1] RSPM
#> survival 3.7-0 2024-06-05 [3] CRAN (R 4.4.2)
#> systemfonts 1.1.0 2024-05-15 [1] RSPM
#> textshaping 0.4.0 2024-05-24 [1] RSPM
#> tibble 3.2.1 2023-03-20 [1] RSPM
#> tidyr 1.3.1 2024-01-24 [1] RSPM
#> tidyselect 1.2.1 2024-03-11 [1] RSPM
#> timeDate 4041.110 2024-09-22 [1] RSPM
#> timeSeries 4041.111 2024-09-22 [1] RSPM
#> UCSC.utils 1.2.0 2024-10-29 [1] Bioconduc~
#> urlchecker 1.0.1 2021-11-30 [1] RSPM
#> usethis 3.0.0 2024-07-29 [1] RSPM
#> utf8 1.2.4 2023-10-22 [1] RSPM
#> vctrs 0.6.5 2023-12-01 [1] RSPM
#> vegan 2.6-8 2024-08-28 [1] RSPM
#> withr 3.0.2 2024-10-28 [1] RSPM
#> xfun 0.49 2024-10-31 [1] RSPM
#> xml2 1.3.6 2023-12-04 [1] RSPM
#> xtable 1.8-4 2019-04-21 [1] RSPM
#> XVector 0.46.0 2024-10-29 [1] Bioconduc~
#> yaml 2.3.10 2024-07-26 [1] RSPM
#> zlibbioc 1.52.0 2024-10-29 [1] Bioconduc~
#>
#> [1] /home/runner/work/_temp/Library
#> [2] /opt/R/4.4.2/lib/R/site-library
#> [3] /opt/R/4.4.2/lib/R/library
#>
#> ──────────────────────────────────────────────────────────────────────────────