10X Visium captures spatially resolved transcriptomic profiles in spots containing multiple cells. In this vignette, we will use the gene expression information from Visium data to infer pathway activity and investigate spatial relationships between some pathways and ligand expression.
Load the necessary packages:
# MISTy library(mistyR) library(future) #Seurat library(Seurat) library(SeuratObject) # Data manipulation library(tidyverse) # Pathways and annotation library(decoupleR) library(OmnipathR) library(progeny) # Cleaning names library(janitor)
For this showcase, we use a 10X Visium spatial slide from Kuppe et al., 2022, where they created a spatial multi-omic map of human myocardial infarction. The tissue example data comes from the human heart of patient 14, which is in a later state after myocardial infarction. The Seurat object contains, among other things, the normalized and raw gene counts. First, we have to download and extract the file:
download.file("https://zenodo.org/records/6580069/files/10X_Visium_ACH005.tar.gz?download=1", destfile = "10X_Visium_ACH005.tar.gz", method = "curl") untar("10X_Visium_ACH005.tar.gz")
The next step is to load the data, extract the normalized gene counts, names of genes expressed in at least 5% of the spots, and pixel coordinates. It is recommended to use pixel coordinates instead of row and column numbers since the rows are shifted and therefore do not express the real distance between the spots.
seurat_vs <- readRDS("ACH005/ACH005.rds") expression <- as.matrix(GetAssayData(seurat_vs, layer = "counts", assay = "SCT")) gene_names <- rownames(expression[(rowSums(expression > 0) / ncol(expression)) >= 0.05,]) geometry <- GetTissueCoordinates(seurat_vs, scale = NULL)
Now we create a Seurat object with pathway activities inferred from PROGENy
. We delete the PROGENy assay done by Kuppe et al. and load a model matrix with the top 1000 significant genes for each of the 14 available pathways. We then extract the genes that are both common to the PROGENy model and the snRNA-seq assay from the Seurat object. We estimate the pathway activity with a multivariate linear model using decoupleR
. We save the result in a Seurat assay and clean the row names to handle problematic variables.
seurat_vs[['progeny']] <- NULL # Matrix with important genes for each pathway model <- get_progeny(organism = "human", top = 1000) # Use multivariate linear model to estimate activity est_path_act <- run_mlm(expression, model,.mor = NULL) # Put estimated pathway activities object into the correct format est_path_act_wide <- est_path_act %>% pivot_wider(id_cols = condition, names_from = source, values_from = score) %>% column_to_rownames("condition") # Clean names colnames(est_path_act_wide) <- est_path_act_wide %>% clean_names(parsing_option = 0) %>% colnames(.) # Create a Seurat object seurat_vs[['progeny']] <- CreateAssayObject(counts = t(est_path_act_wide)) # Format for running MISTy later pathway_activity <- t(as.matrix(GetAssayData(seurat_vs, "progeny")))
To annotate the expressed ligands found in the tissue slide, we import an intercellular network of ligands and receptors from Omnipath. We extract the ligands that are expressed in the tissue slide and get their count data. We again clean the row names to handle problematic variables.
# Get ligands lig_rec <- import_intercell_network(interactions_param = list(datasets = c('ligrecextra', 'omnipath', 'pathwayextra')), transmitter_param = list(parent = 'ligand'), receiver_param = list(parent = 'receptor')) # Get unique ligands ligands <- unique(lig_rec$source_genesymbol) # Get expression of ligands in slide slide_markers <- ligands[ligands %in% gene_names] ligand_expr <- t(as.matrix(expression[slide_markers,])) %>% clean_names() #clean names rownames(seurat_vs@assays$SCT@data) <- seurat_vs@assays$SCT@data %>% clean_names(parsing_option = 0) %>% rownames(.)
Before continuing with creating the MISTy view, we can look at the slide itself and some of the pathway activities.
#Slide SpatialPlot(seurat_vs, alpha = 0) # Pathway activity examples DefaultAssay(seurat_vs) <- "progeny" SpatialFeaturePlot(seurat_vs, feature = c("mapk", "p53"), keep.scale = NULL)
Now we need to create the MISTy views of interest. We are interested in the relationship of the pathway activity in the same spot (intraview) and the ten closest spots (paraview). Therefore we choose the family `constant` and set l to ten, which will select the ten nearest neighbors. Depending on the goal of the analysis, different families can be applied.
We are also intrigued about the relationship of ligand expression and pathway activity in the broader tissue. For this, we again create an intra- and paraview, this time for the expression of the ligands, but from this view, we only need the paraview. In the next step, we add it to the pathway activity views to achieve our intended view composition.
pathway_act_view <- create_initial_view(as_tibble(pathway_activity) ) %>% add_paraview(geometry, l = 10, family = "constant") ligand_view <- create_initial_view(as_tibble(ligand_expr) %>% clean_names()) %>% add_paraview(geometry, l = 10, family = "constant") combined_views <- pathway_act_view %>% add_views(create_view("paraview.ligand.10", ligand_view[["paraview.10"]]$data, "para.ligand.10"))
Then run MISTy and collect the results:
run_misty(combined_views, "result/functional_ligand") misty_results <- collect_results("result/functional_ligand/")
With the collected results, we can now answer the following questions:
Here we can look at two different statistics: multi.R2
shows the total variance explained by the multiview model. gain.R2
shows the increase in explainable variance from the paraviews.
misty_results %>% plot_improvement_stats("multi.R2") %>% plot_improvement_stats("gain.R2")
The paraviews particularly increase the explained variance for TGFb and PI3K. In general, the significant gain in R2 can be interpreted as the following:
"We can better explain the expression of marker X when we consider additional views other than the intrinsic view."
To see the individual contributions of the views we can use:
misty_results %>% plot_view_contributions()
The importance of the markers from each viewpoint as predictors of the spot intrinsic pathway activity can be shown individually to explain the contributions.
First, for the intrinsic view. To set an importance threshold we apply cutoff
:
misty_results %>% plot_interaction_heatmap("intra", clean = TRUE, cutoff = 1.5)
We can observe that TNFa is a significant predictor for the activity of the NFkB pathway when in the same spot. Let's take a look at the spatial distribution of these pathway activities in the tissue slide:
SpatialFeaturePlot(seurat_vs, features = c("tnfa", "nfkb"), image.alpha = 0)
We can observe a correlation between high TNFa activity and high NFkB activity.
Now we repeat this analysis with the pathway activity paraview. With trim
we display only targets with a value above 0.5% for gain.R2
.
misty_results %>% plot_interaction_heatmap(view = "para.10", clean = TRUE, trim = 0.5, trim.measure = "gain.R2", cutoff = 1.25)
From the gain.R2
we know that the paraview contributes a lot to explaining the TGFb pathway activity. Let's visualize it and its most important predictor, androgen pathway activity:
SpatialFeaturePlot(seurat_vs, features = c("androgen", "tgfb"), image.alpha = 0)
The plots show us an anticorrelation of these pathways.
Now we will analyze the last view, the ligand expression paraview:
misty_results %>% plot_interaction_heatmap(view = "para.ligand.10", clean = TRUE, trim = 0.5, trim.measure = "gain.R2", cutoff=3)
The ligand SERPINF1 is a predictor of both PI3K and VEGF:
SpatialFeaturePlot(seurat_vs, features = c("pi3k"), image.alpha = 0) SpatialFeaturePlot(seurat_vs, features = c("vegf"), image.alpha = 0) DefaultAssay(seurat_vs) <- "SCT" SpatialFeaturePlot(seurat_vs, features = c("serpinf1"), image.alpha = 0)
From the slides we can see that SERPINF1 correlates positive with PI3K and negative with VEGF
browseVignettes("mistyR")
Here is the output of sessionInfo()
at the point when this document was compiled.
sessionInfo()
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.