|
a |
|
b/docs/conversion.Rmd |
|
|
1 |
--- |
|
|
2 |
title: "Conversion" |
|
|
3 |
output: |
|
|
4 |
html_document: |
|
|
5 |
toc: true |
|
|
6 |
toc_float: |
|
|
7 |
collapsed: false |
|
|
8 |
smooth_scroll: false |
|
|
9 |
--- |
|
|
10 |
|
|
|
11 |
<style> |
|
|
12 |
.title{ |
|
|
13 |
display: none; |
|
|
14 |
} |
|
|
15 |
body { |
|
|
16 |
text-align: justify |
|
|
17 |
} |
|
|
18 |
.center { |
|
|
19 |
display: block; |
|
|
20 |
margin-left: auto; |
|
|
21 |
margin-right: auto; |
|
|
22 |
} |
|
|
23 |
</style> |
|
|
24 |
|
|
|
25 |
```{css, echo=FALSE} |
|
|
26 |
.watch-out { |
|
|
27 |
color: black; |
|
|
28 |
} |
|
|
29 |
``` |
|
|
30 |
|
|
|
31 |
```{r setup, include=FALSE} |
|
|
32 |
# use rmarkdown::render_site(envir = knitr::knit_global()) |
|
|
33 |
knitr::opts_chunk$set(highlight = TRUE, echo = TRUE) |
|
|
34 |
``` |
|
|
35 |
|
|
|
36 |
<br> |
|
|
37 |
|
|
|
38 |
# Conversion to Other Platforms |
|
|
39 |
|
|
|
40 |
VoltRon is capable of end-to-end spatial data analysis for all levels of spatial resolutions, including those of single cell resolution. However, VoltRon provides a ecosystem friendly infrastructure where VoltRon objects could be transformed into data structures used by popular computational platforms such as [Seurat](https://satijalab.org/seurat/), [Squidpy](https://squidpy.readthedocs.io/en/stable/) and even [Zarr](http://vitessce.io/docs/data-file-types/#anndata-zarr) for interactive spatial data visualizatiob with [Vitessce](http://vitessce.io/). |
|
|
41 |
|
|
|
42 |
For both **Seurat (R)** and **Squidpy (Python)**, we analyse readouts of the experiments conducted on example tissue sections analysed by the [Xenium In Situ](https://www.10xgenomics.com/platforms/xenium) platform. For more information on processing and analyzing Xenium datasets, check the [Cell/Spot Analysis](spotanalysis.html) tutorial. |
|
|
43 |
|
|
|
44 |
<br> |
|
|
45 |
|
|
|
46 |
## Seurat |
|
|
47 |
|
|
|
48 |
We will first see how we can transform VoltRon objects into Seurat object and use built-in functions such as **FindAllMarkers** to visualize marker genes of clusters found by VoltRon. You can find the clustered Xenium data using VoltRon [here](https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Cellanalysis/Xenium/Xenium_data_clustered.rds). |
|
|
49 |
|
|
|
50 |
```{r class.source="watch-out", eval = FALSE} |
|
|
51 |
Xen_data <- readRDS("Xenium_data_clustered.rds") |
|
|
52 |
SampleMetadata(Xen_data) |
|
|
53 |
``` |
|
|
54 |
|
|
|
55 |
``` |
|
|
56 |
Assay Layer Sample |
|
|
57 |
Assay1 Xenium Section1 XeniumR1 |
|
|
58 |
Assay3 Xenium Section1 XeniumR2 |
|
|
59 |
``` |
|
|
60 |
|
|
|
61 |
<br> |
|
|
62 |
|
|
|
63 |
We use the **as.Seurat** function to convert spatial assays of VoltRon into Seurat objects. Here, a Seurat object defines spatial components of cellular and subcellular assays as **FOV** objects, and we use the **type = "image"** argument to convert spatial coordinates of cells and molecules into individual FOV objects for each Xenium assay/layer in the VoltRon object. |
|
|
64 |
|
|
|
65 |
Please check the [Analysis of Image-based Spatial Data in Seurat](https://satijalab.org/seurat/articles/seurat5_spatial_vignette_2) tutorial for more information on analyzing FOV-based spatial data sets with Seurat. |
|
|
66 |
|
|
|
67 |
note: Use VoltRon::as.Seurat to avoid conflict with Seurat package's as.Seurat function |
|
|
68 |
|
|
|
69 |
|
|
|
70 |
```{r class.source="watch-out", eval = FALSE} |
|
|
71 |
library(Seurat) |
|
|
72 |
Xen_data_seu <- VoltRon::as.Seurat(Xen_data, cell.assay = "Xenium", type = "image") |
|
|
73 |
Xen_data_seu <- NormalizeData(Xen_data_seu) |
|
|
74 |
Xen_data_seu |
|
|
75 |
``` |
|
|
76 |
|
|
|
77 |
``` |
|
|
78 |
An object of class Seurat |
|
|
79 |
313 features across 283298 samples within 1 assay |
|
|
80 |
Active assay: Xenium (313 features, 0 variable features) |
|
|
81 |
1 layers present: counts |
|
|
82 |
2 dimensional reductions calculated: pca, umap |
|
|
83 |
2 spatial fields of view present: fov_Assay1 fov_Assay3 |
|
|
84 |
``` |
|
|
85 |
|
|
|
86 |
<br> |
|
|
87 |
|
|
|
88 |
### Marker Analysis |
|
|
89 |
|
|
|
90 |
Now that we converted VoltRon into a Seurat object, we can pick the **Clusters** metadata column indicating the clustering of cells and test for marker genes of each individual cluster. |
|
|
91 |
|
|
|
92 |
```{r class.source="watch-out", eval = FALSE} |
|
|
93 |
Idents(Xen_data_seu) <- "Clusters" |
|
|
94 |
markers <- FindAllMarkers(Xen_data_seu) |
|
|
95 |
head(markers[order(markers$avg_log2FC, decreasing = TRUE),]) |
|
|
96 |
``` |
|
|
97 |
|
|
|
98 |
<div><pre><code style="font-size: 13px;"> p_val avg_log2FC pct.1 pct.2 p_val_adj cluster gene |
|
|
99 |
CPA3 0 7.343881 0.977 0.029 0 16 CPA3 |
|
|
100 |
CTSG 0 7.114698 0.878 0.011 0 16 CTSG |
|
|
101 |
LILRA4.1 0 6.992717 0.939 0.015 0 19 LILRA4 |
|
|
102 |
ADIPOQ 0 6.860190 0.974 0.025 0 5 ADIPOQ |
|
|
103 |
MS4A1 0 6.763083 0.919 0.027 0 17 MS4A1 |
|
|
104 |
BANK1 0 6.082192 0.889 0.037 0 17 BANK1</code></pre></div> |
|
|
105 |
|
|
|
106 |
<br> |
|
|
107 |
|
|
|
108 |
### Visualization |
|
|
109 |
|
|
|
110 |
We can now pick top positive markers from each of these clusters prior to visualization. |
|
|
111 |
|
|
|
112 |
```{r class.source="watch-out", eval = FALSE} |
|
|
113 |
library(dplyr) |
|
|
114 |
topmarkers <- markers %>% |
|
|
115 |
group_by(cluster) %>% |
|
|
116 |
top_n(n = 5, wt = avg_log2FC) |
|
|
117 |
``` |
|
|
118 |
|
|
|
119 |
Here, VoltRon incorporates the unique markers learned by the **FindAllMarkers** function from Seurat and uses them to visualize the expression of these markers on heatmaps, and now we can also use these markers for annotating the clusters. |
|
|
120 |
|
|
|
121 |
```{r class.source="watch-out", eval = FALSE} |
|
|
122 |
library(ComplexHeatmap) |
|
|
123 |
marker_features <- unique(topmarkers$gene) |
|
|
124 |
vrHeatmapPlot(Xen_data, features = marker_features, group.by = "Clusters", |
|
|
125 |
show_row_names = TRUE, font.size = 10) |
|
|
126 |
``` |
|
|
127 |
|
|
|
128 |
<img width="100%" height="100%" src="https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Package/images/conversions_seurat_heatmap.png" class="center"> |
|
|
129 |
|
|
|
130 |
<br> |
|
|
131 |
|
|
|
132 |
### Convert with Molecule Data |
|
|
133 |
|
|
|
134 |
If defined, the **as.Seurat** function may also convert the molecule assay of the VoltRon object into a Seurat FOV object and allow visualizing molecules. You can find the Xenium VoltRon object with the molecule assay [here](https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Cellanalysis/Xenium/Xen_R1.rds). |
|
|
135 |
|
|
|
136 |
```{r class.source="watch-out", eval = FALSE} |
|
|
137 |
Xen_R1 <- readRDS("Xen_R1.rds") |
|
|
138 |
SampleMetadata(Xen_R1) |
|
|
139 |
``` |
|
|
140 |
|
|
|
141 |
``` |
|
|
142 |
Assay Layer Sample |
|
|
143 |
Assay1 Xenium Section1 XeniumR1 |
|
|
144 |
Assay2 Xenium_mol Section1 XeniumR1 |
|
|
145 |
``` |
|
|
146 |
|
|
|
147 |
<br> |
|
|
148 |
|
|
|
149 |
We define both the cell level assay and the molecule level assay. |
|
|
150 |
|
|
|
151 |
```{r class.source="watch-out", eval = FALSE} |
|
|
152 |
Xen_R1_seu <- as.Seurat(Xen_R1, cell.assay = "Xenium", molecule.assay = "Xenium_mol", type = "image") |
|
|
153 |
``` |
|
|
154 |
|
|
|
155 |
<br> |
|
|
156 |
|
|
|
157 |
Now we can visualize molecules alongside with cells. |
|
|
158 |
|
|
|
159 |
```{r class.source="watch-out", eval = FALSE} |
|
|
160 |
ImageDimPlot(Xen_R1_seu, fov = "fovAssay1", molecules = "PGR", group.by = "orig.ident", cols = "lightgrey", mols.size = 1) |
|
|
161 |
``` |
|
|
162 |
|
|
|
163 |
<img width="60%" height="60%" src="https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Package/images/conversions_seurat_imagedimplot.png" class="center"> |
|
|
164 |
|
|
|
165 |
<br> |
|
|
166 |
|
|
|
167 |
## SpatialExperiment |
|
|
168 |
|
|
|
169 |
VoltRon can also convert objects in [SpatialExperiment](https://www.bioconductor.org/packages/release/bioc/html/SpatialExperiment.html) objects. We are going to use the Xenium data clustered using VoltRon [here](https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Cellanalysis/Xenium/Xenium_data_clustered.rds). |
|
|
170 |
|
|
|
171 |
```{r class.source="watch-out", eval = FALSE} |
|
|
172 |
Xen_data <- readRDS("Xenium_data_clustered.rds") |
|
|
173 |
SampleMetadata(Xen_data) |
|
|
174 |
``` |
|
|
175 |
|
|
|
176 |
We use the **as.SpatialExperiment** function to convert spatial assays of VoltRon into SpatialExperiment objects. Please check the [Introduction to the SpatialExperiment class](https://www.bioconductor.org/packages/release/bioc/vignettes/SpatialExperiment/inst/doc/SpatialExperiment.html) tutorial for more information. |
|
|
177 |
|
|
|
178 |
```{r class.source="watch-out", eval = FALSE} |
|
|
179 |
library(SpatialExperiment) |
|
|
180 |
spe <- as.SpatialExperiment(Xen_data, assay = "Xenium") |
|
|
181 |
``` |
|
|
182 |
|
|
|
183 |
Here we can parse the image and visualize. |
|
|
184 |
|
|
|
185 |
```{r class.source="watch-out", eval = FALSE} |
|
|
186 |
img <- imgRaster(spe, |
|
|
187 |
sample_id = "Assay1", |
|
|
188 |
image_id = "main") |
|
|
189 |
plot(img) |
|
|
190 |
``` |
|
|
191 |
|
|
|
192 |
<br> |
|
|
193 |
|
|
|
194 |
## Squidpy (Anndata, h5ad) |
|
|
195 |
|
|
|
196 |
A true ecosystem friendly computational platform should support data types across multiple computing environments. By allowing users to convert VoltRon objects into annotated data matrix formats such as [anndata](https://github.com/scverse/anndata), we can use built-in spatial data analysis methods available on [squidpy](https://squidpy.readthedocs.io/en/stable/). |
|
|
197 |
|
|
|
198 |
You can find the clustered and the annotated Xenium data using VoltRon [here](https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Cellanalysis/Xenium/Xenium_data_clustered_annotated.rds). |
|
|
199 |
|
|
|
200 |
Anndata objects wrapped on h5ad files are commonly used by the [scverse](https://www.nature.com/articles/s41587-023-01733-8) ecosystem for single cell analysis which bring together numeruous tools maintained and distributed by a large community effort. Both squidpy and [scanpy](https://scanpy.readthedocs.io/en/stable/) are currently available on scverse. |
|
|
201 |
|
|
|
202 |
```{r class.source="watch-out", eval = FALSE} |
|
|
203 |
Xen_data <- readRDS("Xenium_data_clustered_annotated.rds") |
|
|
204 |
as.AnnData(Xen_data, assay = "Xenium", file = "Xen_adata_annotated.h5ad") |
|
|
205 |
``` |
|
|
206 |
|
|
|
207 |
<br> |
|
|
208 |
|
|
|
209 |
### Configure Squidpy (scverse) |
|
|
210 |
|
|
|
211 |
Here, we use the [reticulate](https://rstudio.github.io/reticulate/) package to call **scverse** module in Python through a prebuilt anaconda environment. However, any python installation with the scverse module can be incorporated by reticulate. |
|
|
212 |
|
|
|
213 |
```{r class.source="watch-out", eval = FALSE} |
|
|
214 |
library(reticulate) |
|
|
215 |
use_condaenv("scverse", required = T) |
|
|
216 |
``` |
|
|
217 |
|
|
|
218 |
We import some other necessary modules such as pandas, scanpy and squidpy. |
|
|
219 |
|
|
|
220 |
```{python class.source="watch-out", eval = FALSE} |
|
|
221 |
from pathlib import Path |
|
|
222 |
import numpy as np |
|
|
223 |
import pandas as pd |
|
|
224 |
import matplotlib.pyplot as plt |
|
|
225 |
import seaborn as sns |
|
|
226 |
import scanpy as sc |
|
|
227 |
import squidpy as sq |
|
|
228 |
sc.logging.print_header() |
|
|
229 |
``` |
|
|
230 |
|
|
|
231 |
<br> |
|
|
232 |
|
|
|
233 |
### Filter and Normalize |
|
|
234 |
|
|
|
235 |
We read the annotated Xenium object that was saved as an h5ad file using the **as.Anndata** function in VoltRon, and process before analysis. For more information using scanpy and squidpy on Xenium datasets, check the [Analyzing Xenium data](https://squidpy.readthedocs.io/en/stable/notebooks/tutorials/tutorial_xenium.html) tutorial at squidpy webpage. |
|
|
236 |
|
|
|
237 |
```{python class.source="watch-out", eval = FALSE} |
|
|
238 |
adata = sc.read_h5ad("Xen_adata_annotated.h5ad") |
|
|
239 |
adata.layers["counts"] = adata.X.copy() |
|
|
240 |
sc.pp.normalize_total(adata, inplace=True) |
|
|
241 |
sc.pp.log1p(adata) |
|
|
242 |
``` |
|
|
243 |
|
|
|
244 |
<br> |
|
|
245 |
|
|
|
246 |
### Visualize |
|
|
247 |
|
|
|
248 |
We use the **squidpy.pl.spatial_scatter** functions available in squidpy to visualize the spatial localization of cell types of both Xenium replicates. |
|
|
249 |
|
|
|
250 |
```{python class.source="watch-out", eval = FALSE} |
|
|
251 |
fig, ax = plt.subplots(1, 2, figsize=(10, 7)) |
|
|
252 |
sq.pl.spatial_scatter(adata, library_key = "library_id", library_id = "Assay1", |
|
|
253 |
color=["CellType"], shape=None, size=1, img = False, ax=ax[0]) |
|
|
254 |
sq.pl.spatial_scatter(adata, library_key = "library_id", library_id = "Assay3", |
|
|
255 |
color=["CellType"], shape=None, size=1, img = False, ax=ax[1]) |
|
|
256 |
plt.show(ax) |
|
|
257 |
``` |
|
|
258 |
|
|
|
259 |
<img width="100%" height="100%" src="https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Package/images/conversions_anndata_spatial_scatter.png" class="center"> |
|
|
260 |
|
|
|
261 |
<br> |
|
|
262 |
|
|
|
263 |
### Neighborhood Enrichment |
|
|
264 |
|
|
|
265 |
We can now use high level spatially-aware functions available in squidpy. We first establish spatial neighbors using the delaunay graphs. The spatial graph and distances will be stored under **.obsp** attribute/matrix. |
|
|
266 |
|
|
|
267 |
```{python class.source="watch-out", eval = FALSE} |
|
|
268 |
sq.gr.spatial_neighbors(adata, coord_type="generic", delaunay=True) |
|
|
269 |
adata |
|
|
270 |
``` |
|
|
271 |
|
|
|
272 |
``` |
|
|
273 |
AnnData object with n_obs × n_vars = 283298 × 313 |
|
|
274 |
obs: 'Count', 'Assay', 'Layer', 'Sample', 'Clusters', 'CellType', 'library_id' |
|
|
275 |
uns: 'log1p', 'spatial_neighbors' |
|
|
276 |
obsm: 'spatial' |
|
|
277 |
layers: 'counts' |
|
|
278 |
obsp: 'spatial_connectivities', 'spatial_distances' |
|
|
279 |
``` |
|
|
280 |
|
|
|
281 |
We can now conduct the permutation test for neighborhood enrichment across cell type pairs. |
|
|
282 |
|
|
|
283 |
```{python class.source="watch-out", eval = FALSE} |
|
|
284 |
sq.gr.nhood_enrichment(adata, cluster_key="CellType") |
|
|
285 |
``` |
|
|
286 |
|
|
|
287 |
```{python class.source="watch-out", eval = FALSE} |
|
|
288 |
fig, ax = plt.subplots(1, 2, figsize=(13, 7)) |
|
|
289 |
sq.pl.nhood_enrichment(adata, cluster_key="CellType", figsize=(8, 8), |
|
|
290 |
title="Neighborhood enrichment adata", ax=ax[0]) |
|
|
291 |
sq.pl.spatial_scatter(adata, color="CellType", library_key = "library_id", |
|
|
292 |
library_id = "Assay1", shape=None, size=2, ax=ax[1]) |
|
|
293 |
plt.show(ax) |
|
|
294 |
``` |
|
|
295 |
|
|
|
296 |
<img width="100%" height="100%" src="https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Package/images/conversions_anndata_neighborhood.png" class="center"> |
|
|
297 |
|
|
|
298 |
<br> |
|
|
299 |
|
|
|
300 |
## Vitessce (Anndata, zarr) |
|
|
301 |
|
|
|
302 |
In this section, we will transform VoltRon objects of Xenium data into zarr arrays, and use them for interactive visualization in [Vitessce](http://vitessce.io/). We should first download the vitessceR package which incorporates wrapper function to visualize zarr arrays interactively in R. |
|
|
303 |
|
|
|
304 |
```{r class.source="watch-out", eval = FALSE} |
|
|
305 |
install.packages("devtools") |
|
|
306 |
devtools::install_github("vitessce/vitessceR") |
|
|
307 |
``` |
|
|
308 |
|
|
|
309 |
<br> |
|
|
310 |
|
|
|
311 |
You can find the clustered and annotated Xenium data using VoltRon [here](https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Cellanalysis/Xenium/Xenium_data_clustered_annotated.rds). |
|
|
312 |
|
|
|
313 |
```{r class.source="watch-out", eval = FALSE} |
|
|
314 |
Xen_data <- readRDS("Xenium_data_clustered_annotated.rds") |
|
|
315 |
SampleMetadata(Xen_data) |
|
|
316 |
``` |
|
|
317 |
|
|
|
318 |
``` |
|
|
319 |
Assay Layer Sample |
|
|
320 |
Assay1 Xenium Section1 XeniumR1 |
|
|
321 |
Assay2 Xenium Section1 XeniumR2 |
|
|
322 |
``` |
|
|
323 |
|
|
|
324 |
<br> |
|
|
325 |
|
|
|
326 |
### Interactive Visualization |
|
|
327 |
|
|
|
328 |
Now we can convert the VoltRon object into a zarr array using the **as.Zarr** function which will create the array in a specified location. |
|
|
329 |
|
|
|
330 |
```{r class.source="watch-out", eval = FALSE} |
|
|
331 |
as.AnnData(Xen_data, assays = "Assay1", |
|
|
332 |
file = "xendata_clustered_annotated.zarr", flip_coordinates = TRUE) |
|
|
333 |
``` |
|
|
334 |
|
|
|
335 |
We can use the zarr file directly in the **vrSpatialPlot** function to visualize the zarr array interactively in Rstudio viewer. The **reduction** arguement allows the umap of the Xenium data to be visualized alongside with the spatial coordinates of the Xenium cells. |
|
|
336 |
|
|
|
337 |
```{r class.source="watch-out", eval = FALSE} |
|
|
338 |
vrSpatialPlot("xendata_clustered_annotated.zarr", group.by = "CellType", reduction = "umap") |
|
|
339 |
``` |
|
|
340 |
|
|
|
341 |
<img width="100%" height="100%" src="https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Package/images/conversions_interactive.png" class="center"> |
|
|
342 |
<br> |
|
|
343 |
<img width="100%" height="100%" src="https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Package/images/conversions_interactive_zoom.png" class="center"> |