Subset of genes used for plotting
astro.markers.subset <- astro.markers %>%
group_by(cluster) %>%
slice_max(n = 10, order_by = avg_logFC)
astro.markers.subset
astro.markers.subset %>%
select(gene, cluster) %>%
group_by(gene) %>%
slice_min(n = 1, order_by = cluster) %>%
ungroup() %>%
arrange(cluster)
# Expression matrix
cells_to_clusters <- data.frame(
cluster = so.astro$integrated_snn_res.0.2
) %>% rownames_to_column("cell")
geneset <- unique(astro.markers.subset$gene)
mat.scale.data <- so.astro@[email protected][geneset, cells_to_clusters$cell]
cluster_indices <- split(cells_to_clusters$cell, cells_to_clusters$cluster)
cluster_means <- sapply(cluster_indices, function(indices) {
Matrix::rowMeans(mat.scale.data[, indices, drop = FALSE])
})
rownames(cluster_means) <- word(rownames(cluster_means), 2, sep = "\\.")
# Gene cluster color bar annotation
# by cluster order
genes.clusters.cols <- astro.markers.subset %>%
select(gene, cluster) %>%
mutate(gene.full = gene,
gene = word(gene.full, 2, sep = "\\.")) %>%
group_by(gene) %>%
slice_min(n = 1, order_by = cluster) %>%
ungroup() %>%
arrange(cluster) %>%
left_join(., enframe(cluster.cols, name = "cluster", value = "colors"))
rownames(genes.clusters.cols) <- genes.clusters.cols$gene
genes.clusters.cols <- genes.clusters.cols[rownames(cluster_means), ]
# calculated via logFC
genes.clusters.cols.lfc <- astro.markers %>%
mutate(gene.full = gene,
gene = word(gene.full, 2, sep = "\\.")) %>%
filter(gene %in% rownames(cluster_means)) %>%
select(gene, gene.full, cluster, avg_logFC) %>%
arrange(gene, desc(avg_logFC), cluster) %>%
group_by(gene) %>%
slice_max(n = 1, order_by = avg_logFC) %>%
mutate(avg_logFC = NULL) %>%
left_join(., enframe(cluster.cols, name = "cluster", value = "colors")) %>%
as.data.frame()
rownames(genes.clusters.cols.lfc) <- genes.clusters.cols$gene
genes.clusters.cols.lfc <- genes.clusters.cols.lfc[rownames(cluster_means), ]
# calculated via scaled expression values
genes.clusters.cols.scaled <- cluster_means %>%
as.data.frame() %>%
rownames_to_column("gene") %>%
pivot_longer(names_to = "cluster", cols = as.character(clusters), values_to = "expression") %>%
group_by(gene) %>%
slice_max(n = 1, order_by = expression) %>%
select(-expression) %>%
left_join(., enframe(cluster.cols, name = "cluster", value = "colors")) %>%
as.data.frame()
rownames(genes.clusters.cols.scaled) <- genes.clusters.cols.scaled$gene
genes.clusters.cols.scaled <- genes.clusters.cols.scaled[rownames(cluster_means), ]
row.anno.genes <-
rowAnnotation("Cluster genes" = genes.clusters.cols$cluster,
col = list("Cluster genes" = cluster.cols),
show_annotation_name = FALSE
)
# Define the range and breaks
breaks <- seq(0, 1, length.out = 11) # This creates 11 points between 0 and 1
colors <- plasma(11)
# Create a color function that maps the range [0, 1] to the viridis palette
color_mapping <- colorRamp2(breaks, colors)
# Use the adjusted col argument
Heatmap(
cluster_means,
name = "Normal. expression",
col = color_mapping,
cluster_rows = FALSE,
show_row_dend = FALSE,
cluster_columns = FALSE,
column_names_side = "bottom",
row_names_side = "left",
column_names_rot = 0,
column_names_centered = TRUE,
row_names_gp = gpar(fontsize = 10),
left_annotation = row.anno.genes
)
GSM5026144.dgCM <- Read10X_h5("~/data/spatial/SpaceRanger_outputs/GSM5026144_S7_filtered_feature_bc_matrix.h5")
## Warning in sparseMatrix(i = indices[] + 1, p = indptr[], x = as.numeric(x =
## counts[]), : 'giveCsparse' is deprecated; setting repr="T" for you
## 'as(<dgTMatrix>, "dgCMatrix")' is deprecated.
## Use 'as(., "CsparseMatrix")' instead.
## See help("Deprecated") and help("Matrix-deprecated").
GSM5026144_S7_Seurat <- CreateSeuratObject(counts = GSM5026144.dgCM, project = "GSM5026144_S7_Spatial")
GSM5026144_S7_Seurat <- SCTransform(object = GSM5026144_S7_Seurat, return.only.var.genes = F, verbose = FALSE)
## Warning: The 'show_progress' argument is deprecated as of v0.3. Use 'verbosity'
## instead. (in sctransform::vst)
## Calculating cell attributes from input UMI matrix: log_umi
## Variance stabilizing transformation of count matrix of size 18288 by 2511
## Model formula is y ~ log_umi
## Get Negative Binomial regression parameters per gene
## Using 2000 genes, 2511 cells
## Found 90 outliers - those will be ignored in fitting/regularization step
## Second step: Get residuals using fitted parameters for 18288 genes
## Computing corrected count matrix for 18288 genes
## Calculating gene attributes
## Wall clock passed: Time difference of 1.154081 mins
astrocyte_markers <- c("Aldh1l1", "Slc1a2", "S100b", "Gfap", "Myoc")
cluster_0.module <- list(c("Gm42418", "Arhgap31", "Kcnq1ot1", "Rmst", "Cit", "Gli1", "Ttll3", "Neat1", "Gm26917"))
cluster_1.module <- list(c("Mfge8", "Igfbp2", "Btbd17"))
cluster_2.module <- list(c("Dbi", "Agt", "Nnat", "Ppia", "Tmsb4x", "Scrg1", "Mt3", "Gstm1", "Nkain4", "S100a1"))
cluster_3.module <- list(c("Thrsp", "Actb", "Chchd10", "Hint1", "Mrpl41", "Mpc1", "Camk2n1", "Ndufc2", "Nupr1", "Igfbp2"))
cluster_4.module <- list(c("Lcn2", "Ifitm3", "Timp1", "B2m", "Vim", "Gfap", "Psmb8", "Bst2"))
cluster_5.module <- list(c("Crym", "Prss56", "Slc43a3", "Mgst1", "Slc1a5", "Tuba1a", "Itm2b", "Chil1", "Ptn"))
cluster_6.module <- list(c("Thbs4", "Igfbp5", "Fxyd6", "Gsn", "Fxyd1", "Cd9", "Meg3"))
cluster_7.module <- list(c("Itih3", "Sparc", "Nkx6-2", "Etnppl", "Gria1", "Spon1", "5031439G07Rik"))
cluster_8.module <- list(c("Igtp", "Gm4951", "Ifit3", "Iigp1", "Irgm1", "Tap1", "Gbp2", "Ifit1", "Isg15", "Cxcl10"))
cluster_9.module <- list(c("Zic1", "Slc38a1", "Col1a2", "Kcnk2", "Luzp2", "Mgll", "Zic4", "Hopx"))
for (gene in astrocyte_markers) {
GSM5026144_S7_Seurat <- AddModuleScore(object = GSM5026144_S7_Seurat,
features = list(gene),
name = gene)
}
GSM5026144_S7_Seurat <- AddModuleScore(object = GSM5026144_S7_Seurat, features = cluster_0.module, name = 'Cluster0_ModuleScore')
GSM5026144_S7_Seurat <- AddModuleScore(object = GSM5026144_S7_Seurat, features = cluster_1.module, name = "Cluster1_ModuleScore")
GSM5026144_S7_Seurat <- AddModuleScore(object = GSM5026144_S7_Seurat, features = cluster_2.module, name = "Cluster2_ModuleScore")
GSM5026144_S7_Seurat <- AddModuleScore(object = GSM5026144_S7_Seurat, features = cluster_3.module, name = "Cluster3_ModuleScore")
GSM5026144_S7_Seurat <- AddModuleScore(object = GSM5026144_S7_Seurat, features = cluster_4.module, name = "Cluster4_ModuleScore")
GSM5026144_S7_Seurat <- AddModuleScore(object = GSM5026144_S7_Seurat, features = cluster_5.module, name = "Cluster5_ModuleScore")
GSM5026144_S7_Seurat <- AddModuleScore(object = GSM5026144_S7_Seurat, features = cluster_6.module, name = "Cluster6_ModuleScore")
GSM5026144_S7_Seurat <- AddModuleScore(object = GSM5026144_S7_Seurat, features = cluster_7.module, name = "Cluster7_ModuleScore")
GSM5026144_S7_Seurat <- AddModuleScore(object = GSM5026144_S7_Seurat, features = cluster_8.module, name = "Cluster8_ModuleScore")
GSM5026144_S7_Seurat <- AddModuleScore(object = GSM5026144_S7_Seurat, features = cluster_9.module, name = "Cluster9_ModuleScore")
#module_scores <- [email protected] %>%
# dplyr::select(starts_with("Cluster"))
module_scores <- [email protected] %>%
dplyr::select(starts_with("Cluster"), starts_with("Aldh1l1"), starts_with("Slc1a2"),
starts_with("S100b"), starts_with("Gfap"), starts_with("Myoc"))
# Create a new data frame with a column 'V1' for the row names
module_scores_new <- data.frame(V1 = rownames(module_scores), module_scores)
# Now check the result
head(module_scores_new)
spatial_coords <- read.csv("~/data/spatial/SpaceRanger_outputs/GSM5026144_tissue_positions_list.csv.gz", header = FALSE)
data <- dplyr::inner_join(spatial_coords, module_scores_new, by = "V1")
img <- imager::load.image("~/GSM5026144_S7_tissue_hires_image.png")
img_rotated <- imager::imrotate(img, -90) # Rotates the image 90 degrees counterclockwise
dim(img_rotated)
## [1] 2000 1865 1 3
# Create a raster grob with the rotated image
GSM5026144_S7_he_img <- rasterGrob(img_rotated, interpolate=TRUE)
# Extract the underlying matrix or array from the rasterGrob
img_data <- GSM5026144_S7_he_img$raster
# Get the dimensions
img_dims <- dim(img_data)
img_width <- img_dims[2] # The second element represents the width
img_height <- img_dims[1] # The first element represents the height
# Define the scale factor
scale_factor <- 0.54555374
# Adjust the coordinates
data$V5_scaled <- data$V5 * scale_factor
data$V6_scaled <- data$V6 * scale_factor
# Create the main plot
color_func <- colorRamp2(seq(0, 1, length.out = 5), c("#6256a8", "#8acda3", "#faf6c0", "#f48f54", "#a11944"))
legend_only <- ggplot(data, aes(x = V5_scaled, y = V6_scaled, fill = Myoc1)) +
geom_point(aes(fill = Myoc1), color = NA, stroke = 0.2, shape = 21) +
scale_fill_gradientn(colors = color_func(seq(0, 1, length.out = 100)),
breaks = c(min(data$Myoc1), max(data$Myoc1)),
labels = c("Lo", "Hi"),
guide = "colourbar") +
labs(fill = "") +
theme_minimal()
gt <- ggplotGrob(legend_only)
## Warning: Removed 2511 rows containing missing values (`geom_point()`).
# Extract the legend as its own gtable
legend_gtable <- gtable::gtable_filter(gt, "guide-box")
# Convert the gtable legend to a grob
legend_grob <- grid::grobTree(legend_gtable)
# List to store individual plots
plots <- list()
plots$Legend <- legend_grob
# Create an image-only ggplot
image_only <- ggplot(data, aes(x = V5_scaled, y = V6_scaled, fill = Myoc1)) +
# Use the defined image dimensions
annotation_custom(GSM5026144_S7_he_img,
xmin = 0, xmax = img_width,
ymin = 0, ymax = img_height) +
geom_point(aes(fill = Myoc1), color = NA, stroke = 0.2, shape = 21) +
scale_fill_gradientn(colors = color_func(seq(0, 1, length.out = 100)),
guide = FALSE) + # Removes the legend
theme_minimal() +
theme(
axis.title.x = element_blank(),
axis.title.y = element_blank(),
axis.text.x = element_blank(),
axis.text.y = element_blank(),
axis.ticks.x = element_blank(),
axis.ticks.y = element_blank(),
legend.title = element_blank()
) +
# Adding the "H&E" label to the top-left corner
annotate("text", x = min(data$V5_scaled), y = max(data$V6_scaled),
label = "H&E", hjust = 0, vjust = 1, fontface = "bold", size = 5)
# Add the image-only plot to the beginning of the plots list
plots[[length(plots) + 1]] <- image_only
label_list <- list(
"Aldh1l11" = "Aldh1l1",
"Slc1a21" = "Slc1a2",
"S100b1" = "S100b",
"Gfap1" = "Gfap",
"Myoc1" = "Myoc",
"Cluster0_ModuleScore1" = "0",
"Cluster1_ModuleScore1" = "1",
"Cluster2_ModuleScore1" = "2",
"Cluster3_ModuleScore1" = "3",
"Cluster4_ModuleScore1" = "4",
"Cluster5_ModuleScore1" = "5",
"Cluster6_ModuleScore1" = "6",
"Cluster7_ModuleScore1" = "7",
"Cluster8_ModuleScore1" = "8",
"Cluster9_ModuleScore1" = "9"
)
for (col in names(label_list)) {
p <- ggplot(data, aes(x = V5_scaled, y = V6_scaled, fill = !!sym(col))) +
annotation_custom(GSM5026144_S7_he_img,
xmin = 0, xmax = img_width,
ymin = 0, ymax = img_height) +
geom_point(color = "black", stroke = 0.2, shape = 21) +
scale_fill_gradientn(colors = color_func(seq(0, 1, length.out = 100))) +
theme_minimal() +
theme(
axis.title.x = element_blank(),
axis.title.y = element_blank(),
axis.text.x = element_blank(),
axis.text.y = element_blank(),
axis.ticks.x = element_blank(),
axis.ticks.y = element_blank(),
legend.position = "none"
) +
# Adding the label annotation to the top-left corner
annotate("text", x = min(data$V5_scaled), y = max(data$V6_scaled),
label = label_list[[col]], hjust = 0, vjust = 1, fontface = "bold", size = 5)
plots[[col]] <- p
}
# Arrange plots in a grid
grid.arrange(grobs = plots, ncol = 5)