In order to aid the interpretation of the clustering results that we covered in the previous section, it is helpful to identify genes that contribute to the separation of cells into those clusters.
The main approach to achieve this, is to identify genes that are differently expressed between clusters. These may be, for example, exclusively expressed in a single cluster or perhaps differentiate between a few different clusters. There are different methods to identify expression differences between clusters: using mean expression level, or the ranking of the gene by its expression, or the proportions of cells that express the gene.
Our main objective in this section is to cover some of the methods that can be used to achieve this goal, and obtain a summary table of results. As always, the OSCA chapter on marker detection contains additional detail and advice.
library(scater)
library(scran)
library(pheatmap)
library(tidyverse)
library(patchwork)
We will use the data set generated in the clustering session. This contains 7 samples from the Caron data set. For the purposes of these materials, in the interests of time, each sample has been downsampled to only contain 500 cells.
sce <- readRDS("R_objects/Caron_clustered.500.rds")
Note that we have also replaced the gene names (rownames) of our
objects to use common gene names instead of Ensembl IDs. This was done
using the uniquifyFeatureNames()
function makes this
safely, avoiding duplicate gene names.
rownames(sce)[11:20]
## [1] "ENSG00000230699" "ENSG00000241180" "SAMD11" "NOC2L"
## [5] "KLHL17" "PLEKHN1" "ENSG00000272512" "HES4"
## [9] "ISG15" "ENSG00000224969"
For this demonstration we will investigate the clustering generated
using the Leiden clustering algorithm with k set to 25. The
results of this clustering have been added to a column in the
colData
called “label” using the
colLabels
accessor. The advantage of this is that should we
later decide to use a different clustering, we can simply change the
contents of this column and there would be no need to modify any
subsequent code.
Double check that the “label” column contains the clustering that we are interested in:
all(sce$k.25_cluster.fun.leiden==sce$label)
## [1] TRUE
To remind ourselves, we can visualise the clusters on a UMAP:
plotReducedDim(sce,
dimred = "UMAP_corrected",
colour_by = "label",
text_by = "label")
Our objective is to identify genes that distinguish these clusters from one another - “cluster marker genes”. Intuitively we hope that the clusters relate to specific cell populations, and therefore we are trying to find genes that will allow us to identify the cell types for each cluster.
For example genes such as the “CST3” gene, which is a known monocyte marker:
plotReducedDim(sce,
dimred = "UMAP_corrected",
colour_by = "CST3",
text_by = "label",
by_exprs_values = "reconstructed",
add_legend = FALSE)
Although we have defined our clusters based on the batch-corrected
expression values, these should not be used for for
gene-based analyses like marker gene detection. Instead, we should
use the uncorrected (normalised) expression values for
differential expression between clusters. This is because data
integration algorithms bring cells together based on their overall gene
expression, but for each gene individually the data transformation may
introduce artificial agreement between batches, which is not ideal for
gene-level differential analysis. Furthermore, the severity of these
biases is dependent on the parameters used for data integration (such as
the number of nearest neighbours in the fastMNN()
method).
Valid assays to use in gene based differential analysis tests are the
normalised counts obtained from the deconvolution method (using
scuttle::computePooledFactors()
+
scuttle::logNormCounts()
) or from the variance stabilising
transformation method (using sctransform::vst()
). In our
SCE object, we have the normalised counts in the “logcounts” assay,
which we can access with assay(sce, "logcounts")
(or using
the shortcut logcounts(sce)
).
The basic approach for marker gene identification across clusters is
to perform statistical tests for each gene between every pair of
clusters. The scoreMarkers
function can do this for us,
while accounting for known factors (aka “blocking factors” or “blocks”),
such as sample batch.
The scoreMarkers
function outputs a list of
DataFrames
, one for each cluster compared to all others.
However, note that the blocking assumes that each pair of clusters is
present in at least one of the blocks. If there are two clusters which
are not both present in at least one block (in our cases Samples), then
that pairwise comparison will by necessity be omitted.
By default the scoreMarkers
function will use the log
normalised counts as stored in the “logcounts” assay slot of the single
cell object.
markers <- scoreMarkers(sce,
groups = sce$label,
block = sce$SampleName)
The returned object is a list of the same length as the number of clusters. We can access the results for a particular cluster thus:
c10_markers <- as.data.frame(markers[["10"]])
head(c10_markers)
## self.average other.average self.detected other.detected
## MIR1302-2HG -0.0001085355 0.0005858623 0.000000e+00 3.432104e-04
## ENSG00000238009 -0.0006415454 0.0006144301 7.996515e-04 1.814199e-03
## ENSG00000239945 0.0000000000 0.0000000000 1.561251e-17 7.569702e-18
## ENSG00000241860 0.0146328719 0.0035313453 1.270370e-02 2.165388e-03
## LINC01409 0.0143823227 0.0590411706 8.083049e-03 3.468521e-02
## LINC00115 0.0006428644 0.0042533539 5.312893e-03 5.607109e-03
## mean.logFC.cohen min.logFC.cohen median.logFC.cohen
## MIR1302-2HG -0.006580174 -0.07238191 0.000000000
## ENSG00000238009 -0.017591283 -0.09310718 0.000000000
## ENSG00000239945 0.000000000 0.00000000 0.000000000
## ENSG00000241860 0.141411918 0.06093559 0.149321693
## LINC01409 -0.143168150 -0.42779501 -0.131631772
## LINC00115 0.013097401 -0.12320130 0.009314297
## max.logFC.cohen rank.logFC.cohen mean.AUC min.AUC median.AUC
## MIR1302-2HG 0.0000000 7524 0.4998119 0.4979311 0.5000000
## ENSG00000238009 0.0000000 8439 0.4988630 0.4922411 0.5000000
## ENSG00000239945 0.0000000 7524 0.5000000 0.5000000 0.5000000
## ENSG00000241860 0.1995937 2822 0.5074604 0.5038890 0.5080630
## LINC01409 0.1390217 8790 0.4823370 0.4350181 0.4884527
## LINC00115 0.1888446 8123 0.5007662 0.4904221 0.5016101
## max.AUC rank.AUC mean.logFC.detected min.logFC.detected
## MIR1302-2HG 0.5000000 5268 -3.703415e-02 -4.073757e-01
## ENSG00000238009 0.5000000 7065 -6.317926e-02 -2.793215e-01
## ENSG00000239945 0.5000000 5268 -3.952634e-17 -2.528729e-16
## ENSG00000241860 0.5105900 2431 5.706501e-01 1.368573e-01
## LINC01409 0.5075643 8600 -6.884798e-01 -1.870109e+00
## LINC00115 0.5093492 6870 5.199862e-02 -6.760815e-01
## median.logFC.detected max.logFC.detected rank.logFC.detected
## MIR1302-2HG 0.000000e+00 3.851448e-17 4739
## ENSG00000238009 -3.611062e-17 7.269500e-18 7010
## ENSG00000239945 0.000000e+00 3.851448e-17 4739
## ENSG00000241860 4.818850e-01 1.015435e+00 971
## LINC01409 -6.314390e-01 1.032376e-01 8701
## LINC00115 5.993567e-02 9.536183e-01 6470
This DataFrame contains the results for cluster 8. The first four columns contain summary statistics:
The remaining columns contain summaries of three scores from the pairwise comparisons. The three scores are:
More detail on the differences between these effect size scores can be found in the “Advanced” Marker detection chapter of the OSCA book.
Whilst all the pairwise scores can be retrieved by adding the
argument full.stats=TRUE
to scoreMarkers()
, by
default this function returns 5 summary statistics for each score:
The choice of the summary used for ranking will effect the stringency of the selection. See the the OSCA books “Basic” chapter on Marker gene detection for further discussion of these different summaries. In general the mean and median make reasonable defaults for most applications. In practice, the minimum and maximum are most helpful for diagnosing discrepancies between the mean and median, rather than being used directly for ranking.
Selecting genes based on a given min-rank, say 5, is useful as it will generate a list of genes that is the union of genes with a rank of 5 or less for any pairwise comparison. This will ensure we get at least 5 genes that distinguish the cluster of interest from all other clusters.
For example using the min-rank for Cohen’s d on cluster 10 yields 20 marker genes:
c10_markers %>%
select(contains("cohen")) %>%
filter(rank.logFC.cohen <= 5) %>%
arrange(rank.logFC.cohen)
## mean.logFC.cohen min.logFC.cohen median.logFC.cohen
## S100A6 3.9980968 1.6451192 3.6333222
## MNDA 2.8846906 2.4886487 2.8608354
## FCER1G 3.5312969 0.5090234 3.4586321
## LYZ 4.6547138 2.1232942 4.8565839
## TYROBP 4.2129157 2.3217781 4.5349668
## CST3 3.7611775 1.0118157 4.2018285
## TMSB4X 2.9711679 0.8917935 2.6002233
## S100A4 3.9758078 1.8470682 4.3663636
## LYN 1.6353181 -0.2301748 1.9335304
## SRGN 3.5078590 1.3596723 3.4614617
## COTL1 3.2156435 1.4159094 3.2713360
## FTL 2.7266481 -0.3085039 2.7633264
## TMSB10 2.0387403 0.7580912 1.7825497
## GAPDH 2.2130250 0.4319294 2.1553465
## ENSG00000257764 2.5969689 1.6831756 2.5855829
## LGALS1 3.8793702 1.8834508 4.0252487
## LST1 3.2858400 2.1604681 3.3118139
## AIF1 2.9115158 1.9807963 3.0578504
## RPS3A 0.8666418 -0.8608249 0.1660708
## SNX10 1.8079267 0.3188842 1.4977122
## max.logFC.cohen rank.logFC.cohen
## S100A6 7.930903 1
## MNDA 3.469624 1
## FCER1G 7.030043 1
## LYZ 6.254798 1
## TYROBP 6.053634 1
## CST3 5.005112 1
## TMSB4X 6.659286 1
## S100A4 6.661203 2
## LYN 3.331864 2
## SRGN 5.519514 2
## COTL1 6.408767 2
## FTL 6.913409 2
## TMSB10 4.735887 3
## GAPDH 4.617009 3
## ENSG00000257764 3.497302 3
## LGALS1 4.802365 3
## LST1 4.431111 4
## AIF1 3.569574 4
## RPS3A 6.575678 5
## SNX10 4.861811 5
As we suspected, cluster 10 is likely to contain monocytes, based on the expression of CST3 and TYROBP, for example.
We can visualise the expression of some of the other top-ranked genes:
p1 <- plotReducedDim(sce,
dimred = "UMAP_corrected",
colour_by = "LYZ",
text_by = "label")
p2 <- plotExpression(sce, features = "LYZ", x = "label")
p1 + p2
Based on the expression of CD3D, which is a known marker for T cells, it seems likely that cells in clusters 5 and 6 are T-cells.
plotReducedDim(sce,
dimred = "UMAP_corrected",
colour_by = "CD3D",
text_by = "label")
plotExpression(sce,
features = "CD3D",
x = "label")
We would like to confirm this by identifying other genes that differentiate these two clusters from the rest of the cells.
rank.logFC.detected
or rank.logFC.cohen
or a
combination of both!Fix the code below (where the word “FIXME” appears) to extract the
data frame with metrics for this cluster (from our markers
object), filter it and then plot the expression of a few of the
genes.
# extract results from cluster 4 and convert to data.frame
c5_markers <- FIXME
# filter the data.frame using your choice of ranking statistic
# `rank.logFC.detected` or `rank.logFC.cohen`
# or a combination of both!
c5_markers %>%
filter(FIXME)
# visualise the expression of genes that seem interesting from your filters
plotExpression(sce,
features = FIXME,
x = "label")
Start by extracting the marker results for cluster 5 from our list:
c5_markers <- as.data.frame(markers[["5"]])
In our case, we chose to then filter our table with two criteria to find genes that:
AND
We obtain 6 genes with these criteria:
top_genes <- c5_markers %>%
filter(rank.logFC.detected <= 2 & rank.logFC.cohen <= 10)
top_genes
## self.average other.average self.detected other.detected mean.logFC.cohen
## BACH2 1.057763 0.2957412 0.5855458 0.32817785 0.8641514
## CD3E 1.602520 0.2242160 0.4799064 0.04797738 1.5593600
## CD3D 1.792324 0.1556523 0.4099144 0.03288734 1.9586249
## PRKCH 1.667023 0.3410926 0.7535383 0.23039125 1.4343425
## BCL11B 1.787629 0.1791308 0.9170275 0.17868512 1.9255985
## IL32 1.851906 0.3739783 0.6028484 0.07852677 1.7594579
## min.logFC.cohen median.logFC.cohen max.logFC.cohen rank.logFC.cohen
## BACH2 -2.16459592 1.177666 2.838441 5
## CD3E -0.06064829 1.695426 2.021056 7
## CD3D 0.08663408 2.213165 2.557380 1
## PRKCH -0.35849274 1.725187 2.290630 4
## BCL11B 0.52733516 2.028536 2.642743 2
## IL32 -0.69864630 1.911143 2.824283 6
## mean.AUC min.AUC median.AUC max.AUC rank.AUC mean.logFC.detected
## BACH2 0.6390374 0.06097018 0.7601988 0.9184906 13 1.091456
## CD3E 0.7961033 0.48139833 0.8206927 0.8631532 19 3.149840
## CD3D 0.8334423 0.51754330 0.8657850 0.9018868 6 2.995497
## PRKCH 0.7655168 0.41270045 0.8230271 0.8777358 20 1.995629
## BCL11B 0.8342915 0.64198204 0.8544745 0.9086792 5 3.100349
## IL32 0.7844467 0.29377806 0.8086737 0.9123118 28 2.875264
## min.logFC.detected median.logFC.detected max.logFC.detected
## BACH2 -0.3363883 1.105615 2.382381
## CD3E -0.0112436 3.514154 4.819173
## CD3D 0.1049703 3.152769 4.993183
## PRKCH -0.2409163 2.350629 3.882522
## BCL11B 0.3937579 3.183535 4.647754
## IL32 -0.3780674 2.960978 4.951184
## rank.logFC.detected
## BACH2 1
## CD3E 2
## CD3D 1
## PRKCH 2
## BCL11B 1
## IL32 1
Finally, we visualize the expression of these genes:
plotExpression(sce,
features = rownames(top_genes),
x = "label")
We can see all these genes except BACH2 behave in a similar way to our known marker CD3D, suggesting they are good markers for these cell types. This makes sense as CD3D and CD3E encode T cell surface proteins. IL32 encodes a cytokine, which is often associated with cancer and BCL11B is a transcription factor that has been linked with T-Cell malignancy. This result could open an avenue for further investigation in this study.
We have already seen how we can use the plotExpression()
function to visualise the distribution of expression in our data between
clusters. We have also seen how to use plotReducedDim()
to
visualise a gene’s expression on the projected reduced dimensionality
space.
Another useful type of visualisation is to use heatmaps to show the expression of these genes of interest. We will demonstrate this using the top marker genes for cluster 10.
c10_top_genes <- c10_markers %>%
filter(rank.logFC.cohen <= 5)
We can make generate a heatmap showing the expression in individual
cells using the function plotHeatmap()
. We will arrange the
columns (cells) so that cells from the same cluster and cells from the
same samplegroup are grouped together.
plotHeatmap(sce,
features = rownames(c10_top_genes),
order_columns_by = c("label", "SampleGroup"))
Alternatively, we can summarise the expression across sample goups
and generate a heatmap showing the average expression across cells
within each group using the function plotGroupedHeatmap()
.
We can specify any factors causing batch effects using the
block
arguments and the batch effects will be regressed out
of the averages.
plotGroupedHeatmap(sce,
features = rownames(c10_top_genes),
group = "label",
block = "SampleGroup")
In both cases, the colour scale of expression is showing the logcounts in their original scale. However, for this kind of visualisation, it may sometimes be useful to scale the data (aka Z-score), which brings all the genes to the same relative scale.
plotHeatmap(sce,
features = rownames(c10_top_genes),
order_columns_by = c("label", "SampleGroup"),
scale = TRUE,
center = TRUE,
zlim = c(-3, 3))
plotGroupedHeatmap(sce,
features = rownames(c10_top_genes),
group = "label",
block = "SampleGroup",
scale = TRUE,
center = TRUE,
zlim = c(-3, 3))
In this case, the colour scale can be interpreted as the number of standard deviations above/below the mean of that gene across all cells.
The AUC and Cohen’s d scores incorporate both the gene
expression differences between the clusters and the variance in gene
expression scores within each cluster. If a gene has low variance, it is
possible that it will be ranked highly even if the magnitude of the
difference between the clusters is low. These genes will not necessarily
make good marker genes. It may therefore be desirable to favour the
detection of genes with larger log-fold changes. A log-fold change
threshold can be set using the lfc=
argument in score
markers.
For example, in the results from cluster 12, the gene FLT3 was one of twelve genes with a min-rank for Cohen’s d of <= 2:
c12_top_markers <- markers[["12"]] %>%
as.data.frame() %>%
filter(rank.logFC.cohen <= 2)
c12_top_markers
## self.average other.average self.detected other.detected mean.logFC.cohen
## BCL11A 2.5597632 0.673656529 1.0000000 0.43500060 4.295020
## BARD1 0.2689306 0.160150947 0.4098060 0.16325835 2.072739
## ITM2C 2.3944964 0.261977162 1.0000000 0.21510550 3.970727
## JCHAIN 3.6828986 0.147571599 0.9942291 0.12729264 4.643411
## RUNX2 1.9940529 0.027061353 0.9621311 0.04774555 4.011271
## IRF7 2.2625850 -0.005048526 1.0000000 0.10968092 3.724924
## FLT3 0.7501986 0.389592874 0.8358371 0.19755797 4.383935
## RNASE6 2.0619414 0.101283020 0.9581394 0.04106427 15.755818
## MYL12B 1.7985204 1.051154164 1.0000000 0.65839735 1.583985
## TCF4 3.8230779 1.098850268 1.0000000 0.51814747 5.824225
## APP 3.3179797 0.559174688 1.0000000 0.31835937 6.149314
## CSF2RA 1.0149433 0.067897536 0.7995278 0.04476525 4.403210
## min.logFC.cohen median.logFC.cohen max.logFC.cohen rank.logFC.cohen
## BCL11A 1.1065147 3.1470728 9.465890 2
## BARD1 -0.9333552 0.6497261 13.830714 2
## ITM2C 2.1315731 3.5748377 6.236486 1
## JCHAIN 2.5834601 4.9212007 7.133094 2
## RUNX2 1.9091452 3.2871376 6.552932 1
## IRF7 2.5483824 3.7248230 4.358549 2
## FLT3 -0.1260248 3.4701584 13.830714 2
## RNASE6 1.5742114 14.1748874 42.479856 1
## MYL12B 0.2044665 0.9006073 8.758852 2
## TCF4 1.6567226 5.9027751 9.998347 2
## APP 3.6408789 4.9336464 11.793986 2
## CSF2RA 0.2511451 3.0948585 13.830714 1
## mean.AUC min.AUC median.AUC max.AUC rank.AUC mean.logFC.detected
## BCL11A 0.9019988 0.7416813 0.9350649 0.9642857 13 1.4149321
## BARD1 0.6280138 0.2740506 0.6071429 1.0000000 1 0.5746046
## ITM2C 0.9663615 0.8392857 0.9801587 1.0000000 1 1.7100349
## JCHAIN 0.9674165 0.8896104 0.9732143 1.0000000 1 1.7058765
## RUNX2 0.9213730 0.8651489 0.9107143 0.9740260 21 1.7951997
## IRF7 0.9742683 0.9562172 0.9758491 1.0000000 1 1.9638433
## FLT3 0.7275427 0.4882883 0.7379913 1.0000000 1 1.2461015
## RNASE6 0.9578152 0.8623646 0.9649235 1.0000000 1 1.9874992
## MYL12B 0.7403881 0.5357143 0.7501887 1.0000000 1 0.8358841
## TCF4 0.9597523 0.8571429 0.9684764 1.0000000 1 1.2047328
## APP 0.9510964 0.8571429 0.9557762 0.9920635 3 1.6276777
## CSF2RA 0.8469413 0.5794224 0.8744541 1.0000000 1 1.8941064
## min.logFC.detected median.logFC.detected max.logFC.detected
## BCL11A 0.24871337 1.6479107 2.440553
## BARD1 -1.37423795 0.4494364 2.321928
## ITM2C 0.69262435 2.0166468 2.180713
## JCHAIN 0.49805622 1.7955241 2.473010
## RUNX2 1.05842119 1.8507540 2.519045
## IRF7 1.37769374 1.9375222 2.351252
## FLT3 -0.16083406 1.4545384 2.321928
## RNASE6 0.52794095 2.2015976 2.496296
## MYL12B 0.11267293 0.7188382 2.509810
## TCF4 0.07920895 1.4491427 2.344953
## APP 0.67305151 1.6311527 2.496296
## CSF2RA 0.37483908 2.1138467 2.326343
## rank.logFC.detected
## BCL11A 2
## BARD1 1
## ITM2C 22
## JCHAIN 5
## RUNX2 9
## IRF7 5
## FLT3 1
## RNASE6 1
## MYL12B 1
## TCF4 5
## APP 2
## CSF2RA 1
However, we can also see that its LFC goes from -0.1 to 13.8, which is a huge range!
c12_top_markers["FLT3", ] %>%
select(min.logFC.cohen, max.logFC.cohen)
## min.logFC.cohen max.logFC.cohen
## FLT3 -0.1260248 13.83071
Looking at its expression, we can see what might be going on:
plotExpression(sce,
features = "FLT3",
x = "label")
This gene has very low variation in expression in some clusters, and because Cohen’s d measures average differences scaled by variance, the gene comes up as having a high value for that metric in some comparisons.
To make our analysis more restrictive, we can instead indicate to the
scoreMarkers()
function what is the minimum LFC threshold
we want to use to consider a gene for ranking. For example, a LFC >
2:
markers_lfc <- scoreMarkers(sce,
groups = sce$label,
block = sce$SampleName,
lfc = 2)
FLT3 no longer appears in the candidate cluster marker genes list by min-rank of Cohen’s d.
c12_markers_lfc <- as.data.frame(markers_lfc[["12"]])
c12_markers_lfc %>%
select(contains("cohen")) %>%
filter(rank.logFC.cohen <= 2)
## mean.logFC.cohen min.logFC.cohen median.logFC.cohen max.logFC.cohen
## RPL31 -2.0770791 -4.8144787 -2.793087139 3.072737
## JCHAIN 1.9511846 0.5136757 2.149542943 3.348834
## PLAC8 1.1619955 -0.1321631 1.164217120 3.333530
## FHIP1A 0.5125335 -0.9692980 -0.006702181 3.639111
## FCHSD2 1.2318180 -0.4836114 1.347720886 3.601409
## TCF4 2.1504036 -0.6453323 2.398848237 4.639553
## RPS28 -1.9856597 -5.1160247 -2.552505189 3.983252
## APP 2.1427676 0.7898421 1.653588236 4.947973
## rank.logFC.cohen
## RPL31 2
## JCHAIN 1
## PLAC8 1
## FHIP1A 1
## FCHSD2 2
## TCF4 1
## RPS28 1
## APP 1
In fact it’s min-rank for Cohen’s d has dropped to:
c12_markers_lfc["FLT3", c("rank.logFC.cohen")]
## [1] 1623
From the OSCA book:
Given that scoreMarkers() already reports effect sizes, it is tempting to take the next step and obtain p-values for the pairwise comparisons. Unfortunately, the p-values from the relevant tests cannot be reliably used to reject the null hypothesis. This is because DE analysis is performed on the same data used to obtain the clusters, which represents “data dredging” (also known as fishing or data snooping). The hypothesis of interest - are there differences between clusters? - is formulated from the data, so we are more likely to get a positive result when we re-use the data set to test that hypothesis.
The main thing to remember is that, in practice, this is a valid approach to help us annotate groups of cells based on the expression of genes with known cell-specificity and to find new interesting genes for further experiments and validation (e.g. using microscopy or qPCR). In other words, identifying cluster marker genes should be taken as a way to generate new hypothesis from our data, rather than a valid statistical model to test for differential expression between cell types.
sessionInfo()
sessionInfo()
## R version 4.2.0 (2022-04-22)
## Platform: x86_64-apple-darwin17.0 (64-bit)
## Running under: macOS Big Sur/Monterey 10.16
##
## Matrix products: default
## BLAS: /Library/Frameworks/R.framework/Versions/4.2/Resources/lib/libRblas.0.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.2/Resources/lib/libRlapack.dylib
##
## locale:
## [1] en_GB.UTF-8/en_GB.UTF-8/en_GB.UTF-8/C/en_GB.UTF-8/en_GB.UTF-8
##
## attached base packages:
## [1] stats4 stats graphics grDevices utils datasets methods
## [8] base
##
## other attached packages:
## [1] patchwork_1.1.2 forcats_0.5.2
## [3] stringr_1.4.1 dplyr_1.0.10
## [5] purrr_0.3.4 readr_2.1.2
## [7] tidyr_1.2.1 tibble_3.1.8
## [9] tidyverse_1.3.2 pheatmap_1.0.12
## [11] scran_1.24.1 scater_1.24.0
## [13] ggplot2_3.3.6 scuttle_1.6.3
## [15] SingleCellExperiment_1.18.0 SummarizedExperiment_1.26.1
## [17] Biobase_2.56.0 GenomicRanges_1.48.0
## [19] GenomeInfoDb_1.32.4 IRanges_2.30.1
## [21] S4Vectors_0.34.0 BiocGenerics_0.42.0
## [23] MatrixGenerics_1.8.1 matrixStats_0.62.0
##
## loaded via a namespace (and not attached):
## [1] googledrive_2.0.0 ggbeeswarm_0.6.0
## [3] colorspace_2.0-3 ellipsis_0.3.2
## [5] bluster_1.6.0 XVector_0.36.0
## [7] BiocNeighbors_1.14.0 fs_1.5.2
## [9] rstudioapi_0.14 farver_2.1.1
## [11] ggrepel_0.9.1 fansi_1.0.3
## [13] lubridate_1.8.0 xml2_1.3.3
## [15] codetools_0.2-18 sparseMatrixStats_1.8.0
## [17] cachem_1.0.6 knitr_1.40
## [19] jsonlite_1.8.0 broom_1.0.1
## [21] cluster_2.1.4 dbplyr_2.2.1
## [23] compiler_4.2.0 httr_1.4.4
## [25] dqrng_0.3.0 backports_1.4.1
## [27] assertthat_0.2.1 Matrix_1.5-1
## [29] fastmap_1.1.0 gargle_1.2.1
## [31] limma_3.52.3 cli_3.4.0
## [33] BiocSingular_1.12.0 htmltools_0.5.3
## [35] tools_4.2.0 rsvd_1.0.5
## [37] igraph_1.3.4 gtable_0.3.1
## [39] glue_1.6.2 GenomeInfoDbData_1.2.8
## [41] Rcpp_1.0.9 cellranger_1.1.0
## [43] jquerylib_0.1.4 vctrs_0.4.1
## [45] DelayedMatrixStats_1.18.0 xfun_0.33
## [47] beachmat_2.12.0 rvest_1.0.3
## [49] lifecycle_1.0.2 irlba_2.3.5
## [51] statmod_1.4.37 googlesheets4_1.0.1
## [53] edgeR_3.38.4 zlibbioc_1.42.0
## [55] scales_1.2.1 hms_1.1.2
## [57] parallel_4.2.0 RColorBrewer_1.1-3
## [59] yaml_2.3.5 gridExtra_2.3
## [61] sass_0.4.2 stringi_1.7.8
## [63] highr_0.9 ScaledMatrix_1.4.1
## [65] BiocParallel_1.30.3 rlang_1.0.5
## [67] pkgconfig_2.0.3 bitops_1.0-7
## [69] evaluate_0.16 lattice_0.20-45
## [71] labeling_0.4.2 cowplot_1.1.1
## [73] tidyselect_1.1.2 magrittr_2.0.3
## [75] R6_2.5.1 generics_0.1.3
## [77] metapod_1.4.0 DelayedArray_0.22.0
## [79] DBI_1.1.3 pillar_1.8.1
## [81] haven_2.5.1 withr_2.5.0
## [83] RCurl_1.98-1.8 crayon_1.5.1
## [85] modelr_0.1.9 utf8_1.2.2
## [87] tzdb_0.3.0 rmarkdown_2.16
## [89] viridis_0.6.2 locfit_1.5-9.6
## [91] grid_4.2.0 readxl_1.4.1
## [93] reprex_2.0.2 digest_0.6.29
## [95] munsell_0.5.0 beeswarm_0.4.0
## [97] viridisLite_0.4.1 vipor_0.4.5
## [99] bslib_0.4.0