Answers.Body: <p>You can extract the necessary values and add them directly the plot as a second layer using <code>plot + geom_text()</code>. This is very similar to the inner workings of the <code>DimPlot</code> function with <code>label = TRUE</code> but allows you to use anything as label.</p>
  <pre><code># I use dplyr v1.0.2 for all data frame manipulations 
  # First the cluster annotation and the tsne embeddings are merged
  label.df &lt;- cbind(as.data.frame(seurat_object@meta.data), as.data.frame(seurat_object@reductions$tsne@cell.embeddings)) 
  
  # using dplyr across to calculate the mean mitochondrial percentage and 
  # the median tsne values per cluster
  label.df &lt;- label.df %&gt;% dplyr::group_by(seurat_clusters) %&gt;% dplyr::summarise(dplyr::across(percent.mito, ~ mean(.), .names = &quot;mean_{.col}&quot;), dplyr::across(contains(&quot;tSNE&quot;), ~ median(.)))
  
  # running FeaturePlot and adding the label layer
  FeaturePlot(seurat_object, reduction = &quot;tsne&quot;, features = &quot;percent.mito&quot;) + 
    geom_text(data = label.df, aes(x = tSNE_1, y = tSNE_2, label = mean_percent.mito))
  </code></pre>
  <p>The labels are positioned at the median position of the cells of a cluster. Typing <code>LabelClusters</code> (without brackets) in the R console will show you the labeling function used by Seurat that contains some additional ways of positioning the labels.<br />
  If you want to avoid overlapping labels you can use <code>geom_text_repel</code> from the <code>ggrepel</code> package.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-10-27T15:37:05.397Z
Answers.Text: 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.
Answers.UserDisplayName: cer
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-10-27T15:42:36.097Z
Answers.Text: `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?
Answers.UserDisplayName: cer
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-10-27T16:44:11.680Z
Answers.Text: Sorry for the typo in the answer. As you correctly determined the summarise function was closed too early. I modified the answer accordingly.
Answers.UserDisplayName: PPK
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-10-27T16:48:53.600Z
Answers.Text: 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
Answers.UserDisplayName: PPK
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-10-27T21:28:19.483Z
Answers.Text: There is still some issue. I will post the error at the end of my post to preserve the format.
Answers.UserDisplayName: cer
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-10-27T21:34:12.697Z
Answers.Text: Is your code expecting seurat_clusters to be integers rather than characters?
Answers.UserDisplayName: cer
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-10-28T11:47:24.400Z
Answers.Text: The code should work for both integers and characters.
Answers.UserDisplayName: PPK
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-10-28T11:51:51.310Z
Answers.Text: I looked for solutions and it may be that the error is caused by the expressions `~ mean(.)` and `~ median(.)`. You could try to replace this with simply `mean` and `median`.  For me both work equally well but after reading more documentation the second version may be more correct. If this solves your problem I will update the code in the answer again
Answers.UserDisplayName: PPK
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-10-28T13:18:23.290Z
Answers.Text: Let us [continue this discussion in chat](https://chat.stackexchange.com/rooms/115609/discussion-between-cer-and-ppk).
Answers.UserDisplayName: cer
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-10-26T15:27:51.103Z
Answers.LastActivityDate: 2020-10-27T16:48:17.967Z
Answers.LastEditDate: 2020-10-27T16:48:17.967Z
Answers.UserDisplayName: PPK
Body: <p>I have a tricky data set with cells that will have a higher percent of mitochondria genes than &quot;typical&quot; data sets. I would like to look at the mito percentage in each cluster without any filtering (<em>e.g.</em>, <code>subset(seurat_object, subset = nFeature_RNA &gt; 200 &amp; nFeature_RNA &lt; 3000 &amp; percent.mito &lt; 10)</code>)</p>
  <pre><code>FeaturePlot(seurat_object, features=c('percent.mito'), cols = c(&quot;gold&quot;, &quot;firebrick4&quot;), pt.size=0.5, label=TRUE, repel=TRUE)
  </code></pre>
  <p>Done!</p>
  <p>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 <code>geom_text</code>.</p>
  <p>My Hail Mary approach is below:</p>
  <pre><code>p3 &lt;- FeaturePlot(seurat_object, features=c('percent.mito'), cols = c(&quot;gold&quot;, &quot;firebrick4&quot;), pt.size=0.5, label=TRUE, repel=TRUE)
  p3 &lt;- lapply(X = p3, FUN = function(x) mean(p3))
  CombinePlots(plots = p3)
  </code></pre>
  <p>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.</p>
  <pre><code>In mean.default(p3) : argument is not numeric or logical: returning NA
  Execution halted
  </code></pre>
  <p>and</p>
  <pre><code>p3 &lt;- FeaturePlot(seurat_object, features=c('percent.mito'), cols = c(&quot;gold&quot;, &quot;firebrick4&quot;), pt.size=0.5, label=TRUE, repel=TRUE)
  p3 &lt;- lapply(X = p3, FUN = function(x) mean(seurat_object$meta.data$seurat_clusters))
  CombinePlots(plots = p3)
  </code></pre>
  <pre><code>Error in `[[.Seurat`(x, i, drop = TRUE) :
    Cannot find 'meta.data' in this Seurat object
  Calls: lapply ... lapply -&gt; FUN -&gt; mean -&gt; $ -&gt; $.Seurat -&gt; [[ -&gt; [[.Seurat
  </code></pre>
  <p>and</p>
  <pre><code>p3 &lt;- FeaturePlot(seurat_object, features=c('percent.mito'), cols = c(&quot;gold&quot;, &quot;firebrick4&quot;), pt.size=0.5, label=TRUE, repel=TRUE)
  p3 &lt;- lapply(X = seurat_object, FUN = function(x) mean(seurat_object$meta.data$seurat_clusters))
  CombinePlots(plots = p3)
  </code></pre>
  <pre><code>Error in as.list.default(X) : 
    no method for coercing this S4 class to a vector
  Calls: lapply -&gt; lapply -&gt; as.list -&gt; as.list.default```
  </code></pre>
  <p>If anyone can provide some guidance -- you will be inducted into my personal hall of fame. :)</p>
  <p>Thank you for your time.</p>
  <p>P.S. I am using Seurat 3.1</p>
  <p>Update:</p>
  <pre><code>md = surate_object@meta.data 
  md_mean &lt;- ddply(md, .(seurat_clusters), summarize, mean_mito_per=mean(percent.mito))
  </code></pre>
  <p>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.</p>
  <p>If anyone has a better approach I would love to hear it.</p>
  <p>UPDATE:
  Using @PPK's approach</p>
  <pre><code># First the cluster annotation and the tsne embeddings are merged
  label.df &lt;- cbind(as.data.frame(seurat_object@meta.data), as.data.frame(seurat_object@reductions$tsne@cell.embeddings)) 
  
  # using dplyr across to calculate the mean mitochondrial percentage and 
  # the median tsne values per cluster
  label.df &lt;- label.df %&gt;% dplyr::group_by(seurat_clusters) %&gt;% dplyr::summarise(dplyr::across(percent.mito, ~ mean(.), .names = &quot;mean_{.col}&quot;), dplyr::across(contains(&quot;tSNE&quot;), ~ median(.)))
  
  # running FeaturePlot and adding the label layer
  FeaturePlot(seurat_object, reduction = &quot;tsne&quot;, features = &quot;percent.mito&quot;) + 
    geom_text(data = label.df, aes(x = tSNE_1, y = tSNE_2, label = mean_percent.mito))
  </code></pre>
  <p>Error:</p>
  <pre><code>* object '.col' is a function.
  ℹ Input `..1` is `dplyr::across(percent.mito, ~mean(.), .names = &quot;mean_{.col}&quot;)`.
  ℹ The error occured in group 1: seurat_clusters = &quot;0&quot;.
  Backtrace:
       █
    1. └─global::initial_clustering(BM0H, &quot;BM0H&quot;)
    2.   └─`%&gt;%`(...)
    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.               └
  </code></pre>
  
Tags: <seurat><single-cell><clustering>
Title: Calculating average mito.percentage for each cluster (seurat)
ThreadText: # Calculating average mito.percentage for each cluster (seurat)
  
  (Asked by: username_0 on 2020-10-25)
  
  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. :)
  
  Thank you for your time.
  
  P.S. I am using Seurat 3.1
  
  Update:
  
  ```
  md = surate_object@meta.data 
  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 @username_1's approach
  
  ```
  # First the cluster annotation and the tsne embeddings are merged
  label.df <- cbind(as.data.frame(seurat_object@meta.data), as.data.frame(seurat_object@reductions$tsne@cell.embeddings)) 
  
  # 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.               └
  
  ```
  
  **Tags:** seurat, single-cell, clustering
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2020-10-26. Score: 2 | Accepted answer
  
  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(seurat_object@meta.data), as.data.frame(seurat_object@reductions$tsne@cell.embeddings)) 
  
  # 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.
  
  > **Comments:**
  > **username_0**: I think this is exactly what I need @username_1. 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.  
  > **username_0**: `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?  
  > **username_1**: Sorry for the typo in the answer. As you correctly determined the summarise function was closed too early. I modified the answer accordingly.  
  > **username_1**: 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  
  > **username_0**: There is still some issue. I will post the error at the end of my post to preserve the format.  
  > **username_0**: Is your code expecting seurat_clusters to be integers rather than characters?  
  > **username_1**: The code should work for both integers and characters.  
  > **username_1**: I looked for solutions and it may be that the error is caused by the expressions `~ mean(.)` and `~ median(.)`. You could try to replace this with simply `mean` and `median`.  For me both work equally well but after reading more documentation the second version may be more correct. If this solves your problem I will update the code in the answer again  
  > **username_0**: Let us [continue this discussion in chat](https://chat.stackexchange.com/rooms/115609/discussion-between-cer-and-ppk).  
  
  ---
  
  