a b/docs/multiomic.Rmd
1
---
2
title: "Multi-omics"
3
output: 
4
  html_document:
5
    toc: true
6
    toc_depth: 4
7
    toc_float:
8
      collapsed: false
9
      smooth_scroll: false
10
---
11
12
<style>
13
.title{
14
  display: none;
15
}
16
body {
17
  text-align: justify
18
}
19
.center {
20
  display: block;
21
  margin-left: auto;
22
  margin-right: auto;
23
}
24
table, th, td {
25
  border-collapse: collapse;
26
  align-self: center;
27
  padding-right: 10px;
28
  padding-left: 10px;
29
}
30
</style>
31
32
```{css, echo=FALSE}
33
.watch-out {
34
  color: black;
35
}
36
```
37
38
```{r setup, include=FALSE}
39
# use rmarkdown::render_site(envir = knitr::knit_global())
40
knitr::opts_chunk$set(highlight = TRUE, echo = TRUE)
41
```
42
43
<br>
44
45
# Label Transfer via Registration
46
47
VoltRon is capable of analyzing molecule-level subcellular datasets independent of single cells, and specifically those that may also found outside of these cells. To demonstrate how VoltRon investigates extra-cellular molecules, we will make use of another Xenium in situ dataset where custom Xenium probes designed to hybridize distinct open reading frames of SARS-COV-2 virus molecules. These subcellular entities which then can be detected both within and outside of cells which allows to understand proliferation mechanics of the virus across the tissue.
48
49
In this use case, we analyse readouts of **eight tissue micro array (TMA) tissue sections** that were fitted into the scan area of a slide loaded on a Xenium in situ instrument. These sections were cut from **control and COVID-19 lung tissues** of donors categorized based on disease durations (acute and prolonged). You can download the standard Xenium output folder [here](https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Multiomics/Xenium_SARSCOV2.zip).  
50
51
For more information on the TMA blocks, see [GSE190732](https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE190732) for more information. 
52
53
<br>
54
55
## Single Cells and Molecules
56
57
Across these eight TMA section, we investigate a section of acute case which is originated from a lung with extreme number of detected open reading frames of virus molecules. For convenience, we load a VoltRon object where cells are already annotated. You can also find the RDS file  [here](https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Multiomics/acutecase1_annotated.rds).
58
59
```{r eval = FALSE, class.source="watch-out"}
60
vr2_merged_acute1 <- readRDS(file = "acutecase1_annotated.rds")
61
```
62
63
<br>
64
65
Lets visualize both the UMAP and Spatial plot of the annotated cells.
66
67
```{r eval = FALSE, class.source="watch-out"}
68
vrEmbeddingPlot(vr2_merged_acute1, assay = "Xenium", embedding = "umap", 
69
                group.by = "CellType", label = TRUE)
70
vrSpatialPlot(vr2_merged_acute1, assay = "Xenium", group.by = "CellType",
71
              plot.segments = TRUE)
72
```
73
74
<table>
75
<tbody>
76
  <tr style = "vertical-align: center">
77
  <td style = "width:45%; vertical-align: center"> <img src="https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Package/images/molecule_vrembeddingplot.png" class="center"></td>
78
  <td style = "width:55%; vertical-align: center"> <img src="https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Package/images/molecule_visualize_celltype.png" class="center"></td>
79
  </tr>
80
</tbody>
81
</table>
82
83
<br>
84
85
We incorporate two open reading frames (ORFs), named **S2_N** and **S2_orf1ab**, which represent unreplicated and replicated virus molecules, respectively. We can visualize again tile the count of these virus expressions by specifically selecting these two ORFs.
86
87
```{r eval = FALSE, class.source="watch-out"}
88
vrSpatialPlot(vr2_merged_acute1, assay = "Xenium_mol", group.by = "gene", 
89
              group.ids = c("S2_N", "S2_orf1ab"), n.tile = 500)
90
```
91
92
<img width="70%" height="70%" src="https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Package/images/molecule_visualize_virus.png" class="center">
93
94
<br>
95
96
We can even zoom into specific locations at the tissue to investigate virus particles more closely by droping the **n.tile** argument and calling interactive visualization.
97
98
```{r eval = FALSE, class.source="watch-out"}
99
vrSpatialPlot(vr2_merged_acute1, assay = "Xenium_mol", group.by = "gene", 
100
              group.ids = c("S2_N", "S2_orf1ab"), interactive = TRUE, pt.size = 0.1)
101
```
102
103
<img width="70%" height="70%" src="https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Package/images/molecules_visualize_virus_zoom.png" class="center">
104
105
<br>
106
107
In the following sections, we will integrate pathological images and annotations with Xenium datasets to further understand the spatial localization of virus ORF types over the tissue.  
108
109
<br>
110
111
## Hot Spot Analysis
112
113
VoltRon platform allows users to find hot spots of several types of spatial entities, for spots, cells, and even molecules. We first learn spatial neighborhoods from molecules of interests, in this case, the extracellular virus particles and their ORFs.
114
115
```{r eval = FALSE, class.source="watch-out"}
116
vr2_merged_acute1
117
```
118
119
```
120
VoltRon Object 
121
acute case 1: 
122
  Layers: Section1 
123
Assays: Xenium(Main) Xenium_mol 
124
```
125
126
We switch to the molecule assay of the VoltRon object, and select virus ORFs. We also look for other virus ORFs that are 50 pixel distance from each virus molecule to pin point neighborhoods that are rich in virus.
127
128
```{r eval = FALSE, class.source="watch-out"}
129
vr2_merged_acute1 <- getSpatialNeighbors(vr2_merged_acute1, assay = "Xenium_mol", 
130
                                         group.by = "gene", group.ids = c("S2_N", "S2_orf1ab"), 
131
                                         method = "radius", radius = 50)
132
```
133
134
We can now observe the new spatial neighborhood graph saved in the VoltRon object with name **radius**.
135
136
```{r eval = FALSE, class.source="watch-out"}
137
vrGraphNames(vr2_merged_acute1)
138
```
139
140
```
141
[1] "radius"
142
```
143
144
We now select the feature type and graph name to run an hot spot analysis which will label each molecule if their neighborhood are dense in other virus molecules.
145
146
```{r eval = FALSE, class.source="watch-out"}
147
vr2_merged_acute1 <- getHotSpotAnalysis(vr2_merged_acute1, assay = "Xenium_mol", 
148
                                        features = "gene", graph.type = "radius")
149
vrSpatialPlot(vr2_merged_acute1, assay = "Xenium_mol", 
150
              group.by = "gene_hotspot_flag", group.ids = c("cold", "hot"), 
151
              alpha = 1, background.color = "white")
152
```
153
154
<img width="70%" height="70%" src="https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Package/images/molecule_visualize_virus_hotspot.png" class="center">
155
156
## Automated H&E Registration
157
158
VoltRon can analyze and also integrate information from distinct spatial data types such as images, annotations (as regions of interests, i.e. ROIs) and molecules independently. Using such advanced utilities, we can make use of histological information and generate new metadata level information for molecule datasets.
159
160
We will first import both histological images and manual annotations using the **importImageData** function which accepts both images to generate tile/pixel level datasets but also allows one to import either a list of segments or [GeoJSON](https://geojson.org/) objects for create ROI-level datasets as separate assays in a single VoltRon layer. The .geojson file was generated using [QuPath](https://qupath.github.io/) on the same section H&E image of one Xenium section with the acute COVID-19 case. We also have to flip the coordinates of ROI annotations also for they were directly imported from QuPath which incorporates a reverse coordinate system on the y-axis.
161
162
Once imported, the resulting VoltRon object will have two assays in a single layer, one for tile dataset of the H&E image and the other for ROI based annotations of again the same image. You can download the H&E image from [here](https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Multiomics/acutecase1_HE.jpg), and download the json file from [here](https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Multiomics/acutecase1_membrane.geojson).
163
164
```{r eval = FALSE, class.source="watch-out"}
165
# get image
166
imgdata <- importImageData("acutecase1_HE.jpg", 
167
                           segments = "acutecase1_membrane.geojson", 
168
                           sample_name = "acute case 1 (HE)")
169
imgdata <- flipCoordinates(imgdata, assay = "ROIAnnotation")
170
imgdata
171
```
172
173
```
174
VoltRon Object 
175
acute case 1 (HE): 
176
  Layers: Section1 
177
Assays: ImageData(Main) ROIAnnotation 
178
Features: main(Main) 
179
```
180
181
By visualizing these annotations interactively, we can see that the ROIs point to the hyaline membranes. Here, we likely find extra-cellular SARS-COV-2 molecules mostly outside of any single cell.
182
183
```{r eval = FALSE, class.source="watch-out"}
184
vrSpatialPlot(imgdata, assay = "ROIAnnotation", group.by = "Sample", 
185
              alpha = 0.7, interactive = TRUE)
186
```
187
188
<img width="60%" height="60%" src="https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Package/images/molecule_Covid_HE_zoom.png" class="center">
189
190
<br>
191
192
At a first glance, although the Xenium (DAPI) and H&E images are associated with the same TMA core, they were captured in a different perspective; that is, one image is almost the 90 degree rotated version of the other. We will account for this rotation when we (automatically) align the Xenium data with the H&E image. 
193
194
```{r eval = FALSE, class.source="watch-out"}
195
vr2_merged_acute1 <- modulateImage(vr2_merged_acute1, brightness = 300, channel = "DAPI")
196
vrImages(vr2_merged_acute1, assay = "Assay7", scale.perc = 20)
197
vrImages(imgdata, assay = "Assay1", scale.perc = 20)
198
```
199
200
<img width="90%" height="90%" src="https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Package/images/multiomic_twoimages.png" class="center">
201
202
<br>
203
204
We now register the H&E image and annotations to the DAPI image of Xenium section using the **registerSpatialData** function. We select FLANN (with "Homography" method) automated registration mode, negate the DAPI image of the Xenium slide, turn 90 degrees to the left and set the scale parameter of both images to **width = 1859**. See [Spatial Data Alignment](registration.html) tutorial for more information. 
205
206
```{r eval = FALSE, class.source="watch-out"}
207
xen_reg <- registerSpatialData(object_list = list(vr2_merged_acute1, imgdata))
208
```
209
210
<img width="90%" height="90%" src="https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Package/images/molecule_HE_registration.png" class="center">
211
212
<br>
213
214
Once registered, we can isolate the registered H&E data and use it further analysis. We can transfer images and their channels across assays of one or multiple VoltRon objects. Here, we save the registered image of the H&E data as an additional channel of Xenium section of the acuse case 1 sample with molecule data.
215
216
```{r eval = FALSE, class.source="watch-out"}
217
imgdata_reg <- xen_reg$registered_spat[[2]]
218
vrImages(vr2_merged_acute1[["Assay7"]], name = "main", channel = "H&E") <- 
219
  vrImages(imgdata_reg, assay = "Assay1", name = "main_reg")
220
vrImages(vr2_merged_acute1[["Assay8"]], name = "main", channel = "H&E") <- 
221
  vrImages(imgdata_reg, assay = "Assay1", name = "main_reg")
222
```
223
224
We can now observe the new channels available for the both molecule and cell-level assays of Xenium data. 
225
226
```{r eval = FALSE, class.source="watch-out"}
227
vrImageChannelNames(vr2_merged_acute1)
228
```
229
230
```
231
               Assay    Layer       Sample  Spatial Channels
232
Assay7        Xenium Section1 acute case 1     main DAPI,H&E
233
Assay8    Xenium_mol Section1 acute case 1     main DAPI,H&E
234
```
235
236
<br>
237
238
You can also add the VoltRon object of H&E data as an additional assay of the Xenium section such that one layer includes cell, molecules, ROI Annotations and images in the same time. Specifically, we add the ROI annotation to the Xenium VoltRon object using the **addAssay** function where we choose the destination sample/block and the layer of the assay. 
239
240
```{r eval = FALSE, class.source="watch-out"}
241
vr2_merged_acute1 <- addAssay(vr2_merged_acute1,
242
                              assay = imgdata_reg[["Assay2"]],
243
                              metadata = Metadata(imgdata_reg, assay = "ROIAnnotation"),
244
                              assay_name = "ROIAnnotation",
245
                              sample = "acute case 1", layer = "Section1")
246
vr2_merged_acute1
247
```
248
249
```
250
VoltRon Object 
251
acute case 1: 
252
  Layers: Section1 
253
Assays: ROIAnnotation(Main) Xenium_mol Xenium 
254
```
255
256
<br>
257
258
## Interactive Visualization
259
260
Once the H&E image is registered and transfered to the Xenium data, we can convert the VoltRon object into an Anndata object (h5ad file) and use [TissUUmaps](https://tissuumaps.github.io/) tool for interactive visualization.
261
262
```{r eval = FALSE, class.source="watch-out"}
263
# convert VoltRon object to h5ad
264
as.AnnData(vr2_merged_acute1, assay = "Xenium", file = "vr2_merged_acute1.h5ad", 
265
           flip_coordinates = TRUE, name = "main", channel = "H&E")
266
```
267
268
To run TissUUmaps please follow installation instructions [here](https://tissuumaps.github.io/installation/), then you can simply drag and drop both the h5ad file and png file to the application.
269
270
<img width="90%" height="90%" src="https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Package/images/multiomic_interactivevisualization.png" class="center">
271
272
<br>
273
274
## Label transfer
275
276
Now we can transfer ROI annotations as additional metadata features of the molecule assay. We will refer the new metadata column as "Region" which will indicate if the molecule is within any annotated ROI in the same layer.
277
278
```{r eval = FALSE, class.source="watch-out"}
279
vrMainAssay(vr2_merged_acute1) <- "ROIAnnotation"
280
vr2_merged_acute1$Region <- vrSpatialPoints(vr2_merged_acute1)
281
282
# set the spatial coordinate system of ROI Annotations assay
283
vrMainSpatial(vr2_merged_acute1[["Assay9"]]) <- "main_reg"
284
285
# transfer ROI annotations to molecules
286
vr2_merged_acute1 <- transferData(object = vr2_merged_acute1, from = "Assay9", to = "Assay8", 
287
                                  features = "Region")
288
289
# Metadata of molecules
290
Metadata(vr2_merged_acute1, assay = "Xenium_mol")
291
```
292
293
<div><pre><code style="font-size: 11px;">                            id assay_id overlaps_nucleus   gene       qv      Assay    Layer       Sample    Region
294
                        &lt;char&gt;   &lt;char&gt;            &lt;int&gt; &lt;char&gt;    &lt;num&gt;     &lt;char&gt;   &lt;char&gt;       &lt;char&gt;    &lt;char&gt;
295
     1: 281651070371256_cb791e   Assay8                0   ENAH 40.00000 Xenium_mol Section1 acute case 1 undefined
296
     2: 281651070371258_cb791e   Assay8                1  CD274 40.00000 Xenium_mol Section1 acute case 1 undefined
297
     3: 281651070372515_cb791e   Assay8                0  CD163 40.00000 Xenium_mol Section1 acute case 1 undefined
298
     4: 281651070374059_cb791e   Assay8                1   CTSL 33.97290 Xenium_mol Section1 acute case 1 undefined
299
     5: 281651070374411_cb791e   Assay8                0    C1S 40.00000 Xenium_mol Section1 acute case 1 undefined
300
    ---                                                                                                            
301
785787: 281874408669584_cb791e   Assay8                0  SFRP2 40.00000 Xenium_mol Section1 acute case 1 undefined
302
785788: 281874408671410_cb791e   Assay8                0   S2_N 40.00000 Xenium_mol Section1 acute case 1 undefined
303
785789: 281874408672438_cb791e   Assay8                0 S100A8 40.00000 Xenium_mol Section1 acute case 1 undefined
304
785790: 281874408673446_cb791e   Assay8                0  TIMP1 29.86642 Xenium_mol Section1 acute case 1 undefined
305
785791: 281874408673882_cb791e   Assay8                0   S2_N 40.00000 Xenium_mol Section1 acute case 1 undefined</code></pre></div>
306
<br>
307
308
This annotations can be accessed from the default molecule level metadata of the VoltRon object.
309
310
```{r eval = FALSE, class.source="watch-out"}
311
vrMainAssay(vr2_merged_acute1) <- "Xenium_mol"
312
head(table(vr2_merged_acute1$Region))
313
```
314
315
```
316
  ROI1_Assay9  ROI10_Assay9 ROI100_Assay9 ROI101_Assay9 ROI102_Assay9 ROI103_Assay9 
317
          583           624           784           357           215           200 
318
```
319
320
<br>
321
322
Now we will grab these annotations from molecule metadata and calculate the ratio of N to orf1ab frequency of SARS-COV-2 particles across all annotated molecules.
323
324
```{r eval = FALSE, class.source="watch-out"}
325
library(dplyr)
326
s2_summary_hyaline <- 
327
  Metadata(vr2_merged_acute1, assay = "Xenium_mol") %>%
328
  filter(gene %in% c("S2_N", "S2_orf1ab"), 
329
         Region != "undefined") %>% 
330
  summarise(S2_N = sum(gene == "S2_N"), 
331
            S2_orf1ab = sum(gene == "S2_orf1ab"), 
332
            ratio = sum(gene == "S2_N")/sum(gene == "S2_orf1ab")) %>% 
333
  as.matrix()
334
s2_summary_hyaline
335
```
336
337
```
338
      S2_N S2_orf1ab    ratio
339
[1,] 50977     33532 1.520249
340
```
341
342
<br>
343
344
## Manual annotation
345
346
To compare the proportion of **S2_N** and **S2_orf1ab** molecules in hyaline membranes with tissue sites of possible infection. We focus on another tissue niche where a large accumulation of cells with high **S2_N** and **S2_orf1ab** counts. 
347
348
By visualizing and zooming on a spatial plot with annotated cells, we can detect a site of cells with high infection which are also accompanied by a group of T cells.
349
350
```{r eval = FALSE, class.source="watch-out"}
351
vrSpatialPlot(vr2_merged_acute1, assay = "Xenium", group.by = "CellType", 
352
              group.ids = c("H.I. Cells", "T cells"), plot.segments = TRUE, 
353
              alpha = 0.6, spatial = "main", channel = "H&E", interactive = TRUE)
354
```
355
356
<img width="80%" height="80%" src="https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Package/images/molecule_spatialplot_infected.png" class="center">
357
358
<br>
359
360
Now we use the **annotateSpatialData** function to create an additional annotation of Xenium molecules directly. By selecting this region of infection we can directly annotate the 'Xenium_mol' assay and the metadata of molecules. We use the H&E image as the background again, and generate a new molecule-level metadata column called "Infected".
361
362
```{r eval = FALSE, class.source="watch-out"}
363
vr2_merged_acute1 <- annotateSpatialData(vr2_merged_acute1, assay = "Xenium_mol", 
364
                                         label = "Region", use.image = TRUE, 
365
                                         channel = "H&E", annotation_assay = "ROIAnnotation1")
366
```
367
368
<img width="80%" height="80%" src="https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Package/images/molecule_annotation_infected.png" class="center">
369
370
<br>
371
372
## Visualize annotations
373
374
Before visualizing the annotations and molecule localizations in the same time, lets make some changes to the metadata. 
375
We basically wanna change the annotation of all ROIs originated from the GeoJson file to have the label **Hyaline Membrane**.
376
377
```{r eval = FALSE, class.source="watch-out"}
378
# update molecule metadata
379
vrMainAssay(vr2_merged_acute1_infected) <- "Xenium_mol"
380
vr2_merged_acute1_infected$Region <- gsub("ROI[0-9]+", "Hyaline Membrane", 
381
                                          vr2_merged_acute1_infected$Region)
382
383
# update ROI metadata
384
vrMainAssay(vr2_merged_acute1_infected) <- "ROIAnnotation"
385
vr2_merged_acute1_infected$Region <- gsub("ROI[0-9]+", "Hyaline Membrane", 
386
                                          vr2_merged_acute1_infected$Region)
387
```
388
389
Now we can visualize two assays together. We use the **addSpatialLayer** function to overlay molecule locations with both the Hyaline Membrane and the infected region annotations.
390
391
```{r eval = FALSE, class.source="watch-out"}
392
vrSpatialPlot(vr2_merged_acute1_infected, assay = "Xenium_mol", group.by = "gene", 
393
              group.ids = c("S2_N", "S2_orf1ab"), n.tile = 500) |>
394
  addSpatialLayer(vr2_merged_acute1_infected, assay = "ROIAnnotation", 
395
                  group.by = "Region", alpha = 0.3, 
396
                  colors = list(`Hyaline Membrane` = "blue", `Infected` = "yellow"))
397
```
398
399
<img width="70%" height="70%" src="https://bimsbstatic.mdc-berlin.de/landthaler/VoltRon/Package/images/molecule_visualize_virus_overlay.png" class="center">
400
401
402
## Comparison of annotations
403
404
By using the newly annotated infection-associated virus molecules, we can do a comparison of infected regions versus the hyaline membranes. 
405
406
```{r eval = FALSE, class.source="watch-out"}
407
library(dplyr)
408
s2_summary_infected <- 
409
  Metadata(vr2_merged_acute1, assay = "Xenium_mol") %>%
410
  filter(gene %in% c("S2_N", "S2_orf1ab"), 
411
         Region == "Infected") %>% 
412
  summarise(S2_N = sum(gene == "S2_N"), 
413
            S2_orf1ab = sum(gene == "S2_orf1ab"), 
414
            ratio = sum(gene == "S2_N")/sum(gene == "S2_orf1ab")) %>% 
415
  as.matrix()
416
s2_summary_infected
417
```
418
419
```
420
     S2_N S2_orf1ab    ratio
421
[1,] 6376      2372 2.688027
422
```
423
424
Comparison of both the ratio between the infected region and the hyaline membranes show a considerable difference of the population of **S2_N** and **S2_orf1ab** molecules.
425
426
```{r eval = FALSE, class.source="watch-out"}
427
S2_table <- matrix(c(s2_summary_hyaline[,1:2], 
428
                     s2_summary_infected[,1:2]), 
429
                   dimnames = list(Region = c("Hyaline", "Infected"), 
430
                                   S2 = c("N", "orf1ab")),
431
                   ncol = 2,  byrow = TRUE)
432
S2_table
433
```
434
435
```
436
          S2
437
Region     N     orf1ab
438
  Hyaline  50977 33532 
439
  Infected 6376  2372
440
```
441
442
A quick test of independance on this contingency table show a significant difference of ratios across Hyaline and Infected regions.
443
444
```{r eval = FALSE, class.source="watch-out"}
445
fisher.test(S2_table, alternative = "two.sided")
446
```
447
448
```
449
450
    Fisher's Exact Test for Count Data
451
452
data:  S2_table
453
p-value < 2.2e-16
454
alternative hypothesis: true odds ratio is not equal to 1
455
95 percent confidence interval:
456
 0.5382305 0.5941683
457
sample estimates:
458
odds ratio 
459
 0.5655696 
460
```
461