# Calculating average mito.percentage for each cluster (seurat)

I have a tricky data set with cells that will have a higher percent of mitochondria genes than "typical" data sets. I would like to look at the mito percentage in each cluster without any filtering (e.g., subset(seurat_object, subset = nFeature_RNA > 200 & nFeature_RNA < 3000 & percent.mito < 10))

FeaturePlot(seurat_object, features=c('percent.mito'), cols = c("gold", "firebrick4"), pt.size=0.5, label=TRUE, repel=TRUE)


Done!

I would also like to calculate the average percent.mito for each cluster and place the value on the FeaturePlot/TSNE plots. I have no idea how to manipulate a Seurat object to calculate these values but I can probably figure out how to place those values on the graph -- probably with geom_text.

My Hail Mary approach is below:

p3 <- FeaturePlot(seurat_object, features=c('percent.mito'), cols = c("gold", "firebrick4"), pt.size=0.5, label=TRUE, repel=TRUE)
p3 <- lapply(X = p3, FUN = function(x) mean(p3))
CombinePlots(plots = p3)


My attempts yield the error below; I don't know if my approach is close to correct and therefore, I have spent little time working through the error message.

In mean.default(p3) : argument is not numeric or logical: returning NA
Execution halted


and

p3 <- FeaturePlot(seurat_object, features=c('percent.mito'), cols = c("gold", "firebrick4"), pt.size=0.5, label=TRUE, repel=TRUE)
p3 <- lapply(X = p3, FUN = function(x) mean(seurat_object$meta.data$seurat_clusters))
CombinePlots(plots = p3)

Error in [[.Seurat(x, i, drop = TRUE) :
Cannot find 'meta.data' in this Seurat object
Calls: lapply ... lapply -> FUN -> mean -> $->$.Seurat -> [[ -> [[.Seurat


and

p3 <- FeaturePlot(seurat_object, features=c('percent.mito'), cols = c("gold", "firebrick4"), pt.size=0.5, label=TRUE, repel=TRUE)
p3 <- lapply(X = seurat_object, FUN = function(x) mean(seurat_object$meta.data$seurat_clusters))
CombinePlots(plots = p3)

Error in as.list.default(X) :
no method for coercing this S4 class to a vector
Calls: lapply -> lapply -> as.list -> as.list.default


If anyone can provide some guidance -- you will be inducted into my personal hall of fame. :)

P.S. I am using Seurat 3.1

Update:

md = [email protected]
md_mean <- ddply(md, .(seurat_clusters), summarize, mean_mito_per=mean(percent.mito))


This was not the approach I was hoping for but I have the values -- which when expanded to the length of the original df, I can insert it into a free slot in the seurat_object.

If anyone has a better approach I would love to hear it.

UPDATE: Using @PPK's approach

# First the cluster annotation and the tsne embeddings are merged
label.df <- cbind(as.data.frame([email protected]), as.data.frame(seurat_object@[email protected]))

# using dplyr across to calculate the mean mitochondrial percentage and
# the median tsne values per cluster
label.df <- label.df %>% dplyr::group_by(seurat_clusters) %>% dplyr::summarise(dplyr::across(percent.mito, ~ mean(.), .names = "mean_{.col}"), dplyr::across(contains("tSNE"), ~ median(.)))

# running FeaturePlot and adding the label layer
FeaturePlot(seurat_object, reduction = "tsne", features = "percent.mito") +
geom_text(data = label.df, aes(x = tSNE_1, y = tSNE_2, label = mean_percent.mito))


Error:

* object '.col' is a function.
ℹ Input ..1 is dplyr::across(percent.mito, ~mean(.), .names = "mean_{.col}").
ℹ The error occured in group 1: seurat_clusters = "0".
Backtrace:
█
1. └─global::initial_clustering(BM0H, "BM0H")
2.   └─%>%(...)
3.     ├─base::withVisible(eval(quote(_fseq(_lhs)), env, env))
4.     └─base::eval(quote(_fseq(_lhs)), env, env)
5.       └─base::eval(quote(_fseq(_lhs)), env, env)
6.         └─_fseq(_lhs)
7.           └─magrittr::freduce(value, _function_list)
8.             ├─base::withVisible(function_list[[k]](value))
9.             └─function_list[[k]](value)
10.               ├─dplyr::summarise(...)
11.               └


You can extract the necessary values and add them directly the plot as a second layer using plot + geom_text(). This is very similar to the inner workings of the DimPlot function with label = TRUE but allows you to use anything as label.

# I use dplyr v1.0.2 for all data frame manipulations
# First the cluster annotation and the tsne embeddings are merged
label.df <- cbind(as.data.frame([email protected]), as.data.frame(seurat_object@[email protected]))

# using dplyr across to calculate the mean mitochondrial percentage and
# the median tsne values per cluster
label.df <- label.df %>% dplyr::group_by(seurat_clusters) %>% dplyr::summarise(dplyr::across(percent.mito, ~ mean(.), .names = "mean_{.col}"), dplyr::across(contains("tSNE"), ~ median(.)))

# running FeaturePlot and adding the label layer
FeaturePlot(seurat_object, reduction = "tsne", features = "percent.mito") +
geom_text(data = label.df, aes(x = tSNE_1, y = tSNE_2, label = mean_percent.mito))


The labels are positioned at the median position of the cells of a cluster. Typing LabelClusters (without brackets) in the R console will show you the labeling function used by Seurat that contains some additional ways of positioning the labels.
If you want to avoid overlapping labels you can use geom_text_repel from the ggrepel package.

• I think this is exactly what I need @PPK. As the code is written, I get the following error: Error: unexpected ',' in: label.df <- label.df %>% group_by(seurat_clusters) %>% summarise(across(percent.mito, ~ mean(.), .names = "mean_{.col}"))," Execution halted. I believe summarise should hold both of the across items??? I have tinkered with it at bit, but have yet to resolve the error.
– cer
Commented Oct 27, 2020 at 15:37
• label.df <- label.df %>% group_by(seurat_clusters) %>% summarise(across(percent.mito, ~ mean(.), .names = "mean_{.col}"), across(contains(" tSNE"), ~ median(.))) Yields this error: Error: across() must only be used inside dplyr verbs. ... └─dplyr::across(percent.mito, ~mean(.), .names = "mean_{.col}") -- any tips?
– cer
Commented Oct 27, 2020 at 15:42
• Sorry for the typo in the answer. As you correctly determined the summarise function was closed too early. I modified the answer accordingly.
– PPK
Commented Oct 27, 2020 at 16:44
• The second problem seems to be with some other package you are using overwriting some dplyr function. This happens pretty frequently because the functions have such generic names. I updated the answer with explicit calls to dplyr::group:by, dplyr::summarise and dplyr::across to circumvent this kind of problem. Hope this helps
– PPK
Commented Oct 27, 2020 at 16:48
• There is still some issue. I will post the error at the end of my post to preserve the format.
– cer
Commented Oct 27, 2020 at 21:28