OSCR

An integrated single-cell and spatial proteotranscriptomics atlas of fibroblast-driven immunoregulation within the human adult oral cavity.

Code ↔ Paper

11 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 11 matches
  1. [1] § STAR★METHODS › METHOD DETAILS › Published scRNA-seq harmonization ↔ reprocess_public_10x.sh, lines 1–54 · score 0.82 · SRA tools, fastq dump, STARsolo, GEO, bamtofastq, ENA
  2. [2] § STAR★METHODS › METHOD DETAILS › AstroSuite for auto assignment of cell identities and states, TCNs, and MCIMs › Constellation for Tissue Cellular Neighborhood Assignment in Whole Slide Imaging. ↔ TCN/Demo/running_the_algo.ipynb, lines 103–157 · score 0.82 · collective unsupervised training, hot encoded, sub graph, loss, TCN, horizontal
  3. [3] § STAR★METHODS › METHOD DETAILS › AstroSuite for auto assignment of cell identities and states, TCNs, and MCIMs › Constellation for Tissue Cellular Neighborhood Assignment in Whole Slide Imaging. ↔ TCN/Algo/stage4-2_consensus_based_TCN_assignment.py, lines 82–166 · score 0.78 · majority voting, TCN assignment, consensus, horizontal, vertical, square
  4. [4] § STAR★METHODS › METHOD DETAILS › L-R analyses via Cellphone DB, CellChat, and MultiNicheNet ↔ R/pipeline.R, lines 1–97 · score 0.67 · MultiNicheNet, pipeline, receiver cell, target genes, cell communication, muscat
  5. [5] § RESULTS › An integrated single-cell transcriptomics atlas of human oral tissues ↔ Healthy vs Disease/healthy vs disease.R, lines 1788–1827 · score 0.60 · Langerhans cells, Epithelial cells, Merkel, myoepithelial, acinar, ductal
  6. [6] § RESULTS › An integrated single-cell transcriptomics atlas of human oral tissues ↔ Spatial analysis/MCIMs analysis.R, lines 1920–1959 · score 0.60 · Langerhans cells, Epithelial cells, Merkel, myoepithelial, acinar, ductal
  7. [7] § STAR★METHODS › METHOD DETAILS › Newly generated scRNA-seq data › Labial Mucosa (National Institutes of Health). ↔ scripts/generate_test_data.py, lines 128–239 · score 0.57 · cDNA, droplet, adapters, UMI, barcoded, cells
  8. [8] § STAR★METHODS › METHOD DETAILS › L-R analyses via Cellphone DB, CellChat, and MultiNicheNet ↔ README.Rmd, lines 7–92 · score 0.55 · intercellular communication, MultiNicheNet, single cell transcriptomics, receiver cell, target genes, cell communication
  9. [9] § RESULTS › Spatial proteotranscriptomics predicts fibroblast-driven interaction hubs ↔ Spatial analysis/MCIMs analysis.R, lines 1920–1959 · score 0.53 · dendritic cell, NK cells, monocytes, signatures, macrophages, COL
  10. [10] § RESULTS › Spatial proteotranscriptomics predicts fibroblast-driven interaction hubs ↔ Healthy vs Disease/healthy vs disease.R, lines 1788–1827 · score 0.53 · dendritic cell, NK cells, monocytes, signatures, macrophages, COL
  11. [11] § STAR★METHODS › QUANTIFICATION AND STATISTICAL ANALYSIS › General methods ↔ NatureProtocols2024_case_studies/CaseExample1_differentiation/analysis_method3_CellSign_microenvironments.ipynb, lines 38–64 · score 0.51 · Wilcoxon rank sum, biological questions, cell interaction, tailored, Seurat, genes

Paper

Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

R · 2,854 lines · 94 KB · no license · 2 matches

  1. # Load required libraries
  2. library(readr)
  3. library(readxl)
  4. library(sf)
  5. library(dplyr)
  6. library(tidyr)
  7. library(ggplot2)
  8. library(MASS) # For kde2d function
  9. library(igraph)
  10. library(RColorBrewer)
  11. # Set working directory
  12. setwd("C:/Users/huynhk4/Documents/")
  13. #---------------------------------------------
  14. #cell_type=c("Fibroblasts")
  15. # Make change here
  16. # Read data
  17. ligands_list <- read_csv("C:/Users/huynhk4/Downloads/merscope_LR.csv")
  18. data2 <- read_csv("TACIT_annotate_MERSCOPE/cell_by_gene_Tongue_ID62_TACIT.csv") #Import datasets
  19. data2$Group="Tongue62"
  20. data2$Group_MG="Mucosal"
  21. data3 <- read_csv("TACIT_annotate_MERSCOPE/cell_by_gene_Tongue12_TACIT.csv") #Import datasets
  22. data3$Group="Tongue12"
  23. data3$Group_MG="Mucosal"
  24. data4 <- read_csv("TACIT_annotate_MERSCOPE/cell_by_gene_Gingiva_2_TACIT.csv") #Import datasets
  25. data4$Group="Gingiva2"
  26. data4$Group_MG="Mucosal"
  27. data5 <- read_csv("TACIT_annotate_MERSCOPE/cell_by_gene_Gingiva1_TACIT.csv") #Import datasets
  28. data5$Group="Gingiva1"
  29. data5$Group_MG="Mucosal"
  30. data6 <- read_csv("TACIT_annotate_MERSCOPE/cell_by_gene_BuccalMucosa_ID_5_TACIT.csv") #Import datasets
  31. data6$Group="BuccalMucosa"
  32. data6$Group_MG="Mucosal"
  33. data7 <- read_csv("TACIT_annotate_MERSCOPE/cell_by_geneBuccalMucosaMSG1_TACIT.csv") #Import datasets
  34. data7$Group="MSG1"
  35. data7$Group_MG="Glands"
  36. data8 <- read_csv("TACIT_annotate_MERSCOPE/cell_by_geneBuccalMucosaMSG8_TACIT.csv") #Import datasets
  37. data8$Group="MSG8"
  38. data8$Group_MG="Glands"
  39. data9 <- read_csv("TACIT_annotate_MERSCOPE/cell_by_geneBuccalMucosaMSG9_TACIT.csv") #Import datasets
  40. data9$Group="MSG9"
  41. data9$Group_MG="Glands"
  42. data10 <- read_csv("TACIT_annotate_MERSCOPE/cell_by_gene_Parotid_39_TACIT.csv") #Import datasets
  43. data10$Group="Parotid39"
  44. data10$Group_MG="Glands"
  45. data11<- read_csv("TACIT_annotate_MERSCOPE/cell_by_gene_Parotid_ID_35_TACIT.csv") #Import datasets
  46. data11$Group="Parotid35"
  47. data11$Group_MG="Glands"
  48. data12<- read_csv("TACIT_annotate_MERSCOPE/cell_by_geneParotid_20_TACIT.csv") #Import datasets
  49. data12$Group="Parotid20"
  50. data12$Group_MG="Glands"
  51. data13<- read_csv("TACIT_annotate_MERSCOPE/cell_by_geneParotid_40_TACIT.csv") #Import datasets
  52. data13$Group="Parotid40"
  53. data13$Group_MG="Glands"
  54. data14<- read_csv("TACIT_annotate_MERSCOPE/cell_by_geneSubmandibular_53_56.csv") #Import datasets
  55. data14$Group="Submandibular53_56"
  56. data14$Group_MG="Glands"
  57. data15<- read_csv("TACIT_annotate_MERSCOPE/data_final.csv") #Import datasets
  58. #data15$Group="Submandibular53_56"
  59. data15$Group_MG="Disease"
  60. standardize_and_offset <- function(data, x_offset = 0, y_offset = 0) {
  61. # Standardize column names
  62. common_columns <- intersect(colnames(data9), intersect(colnames(data2), colnames(data14)))
  63. data <- data[common_columns] # Reorder columns
  64. # Apply offset
  65. data <- data %>%
  66. mutate(X = X + x_offset, Y = Y + y_offset)
  67. return(data)
  68. }
  69. # List of datasets
  70. datasets <- list(data2,data3,data4,data5,data6,data7,data8,data9,data10,data11,data12,data13,data14)
  71. # Initialize offsets
  72. x_offset <- 0
  73. y_offset <- 0
  74. increment <- 10000 # Smaller increment to make the datasets closer
  75. # Standardize and combine datasets with offsets
  76. data1 <- datasets[[1]]
  77. for (i in 2:length(datasets)) {
  78. x_offset <- x_offset + increment
  79. y_offset <- y_offset + increment
  80. datasets[[i]] <- standardize_and_offset(datasets[[i]], x_offset, y_offset)
  81. data1 <- bind_rows(data1, datasets[[i]])
  82. }
  83. # View the combined data
  84. head(data1)
  85. # Filter data by cell type
  86. #data1 <- data1[data1$TACIT %in% "Fibroblasts",]
  87. # Find common columns between ligands/receptors and data1
  88. common <- intersect(c(ligands_list$Ligante, ligands_list$Receptores), colnames(data1))
  89. user_colors <- c(
  90. "Arterioles"="darkgrey",
  91. "B Cells"="#FFA500",
  92. "Capillaries"="#aa6e28",
  93. "CD4+ T Cells"="#FF0000",
  94. "T Helper"="#FF0000",
  95. "CD8+ Effector T Cells"="#CC0000",
  96. "CD8+ Exhausted T Cells"="#FF6347",
  97. "CD8+ T Cells exhausted"="#FF6347",
  98. "CD8+ T Cells"="#FF6347",
  99. "Dendritic Cells"="#FFD700",
  100. "Ductal Cells"="#00FF00",
  101. "Ductal Progenitors"="#008000",
  102. "Ductal Proliferating"="#008000",
  103. "Fibroblasts"="#f032e6",
  104. "Fibroblast Progen"="#f032e6",
  105. "IgA Plasma Cells"="#7B68EE",
  106. "IgG Plasma Cells"="purple",
  107. "Intermediate Epithelium"="powderblue",
  108. "Ionocytes"="lightgreen",
  109. "M1 Macrophages"="yellow3",
  110. "M2 Macrophages"="gold3",
  111. "Macrophage"="gold3",
  112. "Mucous Acinar Cells"="cyan",
  113. "Acinar Cells"="cyan",
  114. "Myoepithelium"="blue",
  115. "Myoepitelial Cells"="blue",
  116. "NK Cells"="darkred",
  117. "Adipocyte"="#FFC0CB",
  118. "Memory T cell"="brown3",
  119. "Regulatory T Cells"="brown2",
  120. "Treg"="brown2",
  121. "Seromucous Acinar Cells"="royalblue2",
  122. "Smooth Muscle"="azure3",
  123. "T Cell Progenitors"="brown3",
  124. "Venules"="orange3",
  125. "VEC"="orange3",
  126. "VEC Progen"="orange1",
  127. "LECs"="orange",
  128. "Others"="grey90",
  129. "Mast Cell"="gold",
  130. "Lymphoid"="darkcyan",
  131. "1"="green",
  132. "2"="red",
  133. "3"="blue",
  134. "4"="gold",
  135. "5"="darkcyan",
  136. "6"="brown3",
  137. "7"="royalblue2",
  138. "8"="cyan",
  139. "9"="lightgreen",
  140. "10"="yellow3",
  141. "11"="purple",
  142. "12"="powderblue",
  143. "13"="azure3",
  144. "14"="royalblue1",
  145. "15"="cyan3",
  146. "16"="#FFC0CB",
  147. "17"="yellow1",
  148. "18"="purple4",
  149. "19"="darkred",
  150. "20"="#f032e6"
  151. )
  152. data1=data1[!(data1$TACIT%in%c("Basal Keratincytes","Suprabasal Keratinocytes","Ductal Epithelial Cells","Acinar Cells")),]
  153. ggplot(data1, aes(x = X, y = Y, color = (TACIT))) +
  154. geom_point(size = 0.1) +
  155. scale_color_manual(values = user_colors) +
  156. theme_classic(base_size = 15)+ guides(color = guide_legend(override.aes = list(size = 3),title = "Cell type"))
  157. #---------------------------------------------
  158. # Do not change
  159. data_sub=data1[,c("X","Y","TACIT","Group",common)]
  160. data_sub=data.frame(cellID=1:nrow(data_sub),data_sub)
  161. selected_rows <- rowSums(data1[, common] > 0) > 2
  162. data_sub=data_sub[selected_rows,]
  163. library(sf)
  164. library(dplyr)
  165. # Assuming you have data in data_sub with columns X, Y, cellID, and Group
  166. # Convert data to an sf object without a CRS (non-geographic)
  167. data_sub_sf <- st_as_sf(data_sub, coords = c("X", "Y"), crs = NA)
  168. data_sub_sf$cell_id <- data_sub$cellID
  169. # Function to create a grid of windows
  170. create_windows <- function(data, window_size, step_size) {
  171. bbox <- st_bbox(data)
  172. x_breaks <- seq(bbox["xmin"], bbox["xmax"] - window_size, by = step_size)
  173. y_breaks <- seq(bbox["ymin"], bbox["ymax"] - window_size, by = step_size)
  174. return(expand.grid(x = x_breaks, y = y_breaks))
  175. }
  176. unique_neighbors <- function(results) {
  177. results %>%
  178. distinct() %>%
  179. rowwise() %>%
  180. mutate(neighbors = list(unique(neighbors)))
  181. }
  182. find_neighbors_in_window <- function(window, data, window_size, distance_cutoff) {
  183. xmin <- window$x
  184. xmax <- window$x + window_size
  185. ymin <- window$y
  186. ymax <- window$y + window_size
  187. window_data <- data %>%
  188. filter(st_coordinates(.)[,1] >= xmin & st_coordinates(.)[,1] < xmax &
  189. st_coordinates(.)[,2] >= ymin & st_coordinates(.)[,2] < ymax)
  190. if (nrow(window_data) < 2) {
  191. return(data.frame(cell_id = character(0), neighbors = I(list())))
  192. }
  193. distances <- st_distance(window_data)
  194. diag(distances) <- NA
  195. distances[distances > distance_cutoff] <- NA
  196. neighbors <- lapply(seq_len(nrow(window_data)), function(i) {
  197. near <- which(!is.na(distances[i, ]))
  198. if (length(near) > 0) as.character(window_data$cell_id[near]) else NA
  199. })
  200. return(data.frame(cell_id = window_data$cell_id, neighbors = I(neighbors)))
  201. }
  202. # Parameters
  203. window_size <- 500 # Size of the window
  204. step_size <- 400 # Step size for sliding window
  205. distance_cutoff <- 50 # Distance cutoff for neighbors
  206. # Create windows with overlap
  207. windows <- create_windows(data_sub_sf, window_size, step_size)
  208. # Find neighbors within each window and combine results
  209. results <- do.call(rbind, lapply(seq_len(nrow(windows)), function(i) {
  210. find_neighbors_in_window(windows[i, ], data_sub_sf, window_size, distance_cutoff)
  211. }))
  212. # Remove duplicates
  213. results <- unique_neighbors(results)
  214. # Combine results by group
  215. results_df <- results %>%
  216. group_by(cell_id) %>%
  217. summarise(neighbors = list(unique(unlist(neighbors))))
  218. # Display results
  219. print(results_df)
  220. # Assuming 'results_df' is already loaded and contains the neighbors column as lists
  221. results_df_expanded <- results_df %>%
  222. mutate(neighbors = ifelse(is.na(neighbors), list(NA), neighbors)) %>% # Ensure NA is handled as a list for consistency
  223. unnest(neighbors) %>%
  224. rename(Neighbor_ID = neighbors) # Rename the column for clarity
  225. results_df_expanded1=results_df_expanded
  226. data2_sub=data1[,c("X","Y","TACIT","Group",common)]
  227. results_df_sum=results_df_expanded1[which(results_df_expanded1$Neighbor_ID!="NA"),]
  228. data2_sub=data.frame(cell_id=1:nrow(data2_sub),data2_sub)
  229. # Function to check interactions using vectorized operations and pre-indexing
  230. check_interaction <- function(data, ligands, results) {
  231. # Initialize the interaction matrix
  232. interaction_matrix <- results
  233. interaction_names <- paste(ligands$Ligante, ligands$Receptores, sep = "_")
  234. interaction_matrix[interaction_names] <- 0
  235. # Create a data frame with only relevant columns for easier manipulation
  236. data_subset <- data[, c("cell_id", ligands$Ligante, ligands$Receptores)]
  237. # Pre-calculate which cells express each ligand and receptor
  238. ligand_expressed <- sapply(ligands$Ligante, function(l) data_subset[data_subset[[l]] > 0, "cell_id"])
  239. receptor_expressed <- sapply(ligands$Receptores, function(r) data_subset[data_subset[[r]] > 0, "cell_id"])
  240. # Vectorized comparison for each ligand-receptor pair
  241. for (i in seq_along(interaction_names)) {
  242. if(length(seq_along(interaction_names))==1){
  243. ligand_cells <- ligand_expressed
  244. receptor_cells <- receptor_expressed
  245. }else{
  246. ligand_cells <- ligand_expressed[[i]]
  247. receptor_cells <- receptor_expressed[[i]]
  248. }
  249. # Find matching cell_id and Neighbor_ID pairs
  250. interactions <- results$cell_id %in% ligand_cells & results$Neighbor_ID %in% receptor_cells
  251. interaction_matrix[interactions, interaction_names[i]] <- 1
  252. }
  253. return(interaction_matrix)
  254. }
  255. # ligands_list=ligands_list[which(ligands_list$Ligante%in%c("CXCL14",
  256. # "IL18",
  257. # "CXCL17",
  258. # "CXCL5",
  259. #
  260. # "CXCL6",
  261. # "CXCL13")),]
  262. ligands_list=ligands_list[which(ligands_list$Ligante%in%common),]
  263. ligands_list=ligands_list[which(ligands_list$Receptores%in%common),]
  264. # Apply the function
  265. interaction_matrix <- check_interaction(data2_sub, ligands_list, results_df_sum)
  266. table(interaction_matrix$CXCL12_CXCR4)
  267. unique_columns <- !duplicated(colnames(interaction_matrix))
  268. interaction_matrix <- interaction_matrix[, unique_columns]
  269. interaction_matrix <- interaction_matrix %>%
  270. mutate(across(where(is.list), ~ map_dbl(.x, ~ as.numeric(.x[[1]])), .names = "first_{col}"))
  271. # Add coordinates for cell_id
  272. interaction_matrix <- interaction_matrix %>%
  273. left_join(data2_sub %>% dplyr::select(cell_id, X, Y), by = "cell_id") %>%
  274. dplyr::rename(X_cell = X, Y_cell = Y)
  275. interaction_matrix$Neighbor_ID=as.integer(interaction_matrix$Neighbor_ID)
  276. # Add coordinates for Neighbor_ID
  277. interaction_matrix <- interaction_matrix %>%
  278. left_join(data2_sub %>% dplyr::select(cell_id, X, Y), by = c("Neighbor_ID" = "cell_id")) %>%
  279. dplyr::rename(X_neighbor = X, Y_neighbor = Y)
  280. TACIT_Ligands=data1$TACIT[interaction_matrix$cell_id]
  281. TACIT_Receptors=data1$TACIT[interaction_matrix$Neighbor_ID]
  282. interaction_matrix=interaction_matrix[which(rowSums(interaction_matrix[,3:53])>0),]
  283. count=interaction_matrix[,3:53]
  284. data1_sub_plot <- data.frame(
  285. X = interaction_matrix$X_cell,
  286. Y = interaction_matrix$Y_cell,
  287. ID = 1:nrow(interaction_matrix),
  288. count
  289. )
  290. library(dplyr)
  291. library(tidyr)
  292. # Assume data1_sub_plot is already defined and includes interaction counts
  293. # Define grid size and calculate dimensions of each grid cell
  294. grid_size <- 20000
  295. x_breaks <- seq(min(data1_sub_plot$X), max(data1_sub_plot$X), length.out = grid_size + 1)
  296. y_breaks <- seq(min(data1_sub_plot$Y), max(data1_sub_plot$Y), length.out = grid_size + 1)
  297. cell_width <- x_breaks[2] - x_breaks[1]
  298. cell_height <- y_breaks[2] - y_breaks[1]
  299. data1_sub_plot <- data1_sub_plot %>%
  300. mutate(
  301. grid_x = cut(X, breaks = x_breaks, include.lowest = TRUE, labels = FALSE),
  302. grid_y = cut(Y, breaks = y_breaks, include.lowest = TRUE, labels = FALSE),
  303. grid_id = interaction(grid_x, grid_y, drop = TRUE) # drop=TRUE to eliminate unused levels
  304. )
  305. process_chunk <- function(data_chunk, count_columns) {
  306. pivot_longer(
  307. data_chunk,
  308. cols = all_of(count_columns),
  309. names_to = "interaction_type",
  310. values_to = "count"
  311. )
  312. }
  313. split_data_into_chunks <- function(data, chunk_size) {
  314. split(data, (seq(nrow(data)) - 1) %/% chunk_size)
  315. }
  316. chunk_size <- 20000 # Define an appropriate chunk size
  317. data_chunks <- split_data_into_chunks(data1_sub_plot, chunk_size)
  318. # Assuming `count` is a vector of column names you want to pivot
  319. count_columns <- colnames(count)
  320. # Apply the process_chunk function to each chunk and combine results
  321. data_long_list <- lapply(data_chunks, process_chunk, count_columns = count_columns)
  322. data_long <- bind_rows(data_long_list)
  323. data_long <- pivot_longer(
  324. data1_sub_plot,
  325. cols = colnames(count), # Assuming you want to calculate density for columns starting with CCL2
  326. names_to = "interaction_type",
  327. values_to = "count"
  328. )
  329. # Aggregate data and calculate density
  330. grid_data <- data_long %>%
  331. group_by(grid_id, grid_x, grid_y, interaction_type) %>%
  332. summarise(
  333. Total = sum(count),
  334. Density = Total, # Adjust units as necessary
  335. .groups = 'drop'
  336. )
  337. # Pivot back to wide format if needed
  338. data_wide <- pivot_wider(
  339. grid_data,
  340. names_from = interaction_type,
  341. values_from = Density,
  342. names_prefix = ""
  343. )
  344. data_wide <- data1_sub_plot
  345. # Summarize the data by grid_id
  346. data_wide <- data1_sub_plot %>%
  347. group_by(grid_id) %>%
  348. summarize(
  349. avg_grid_x = mean(grid_x, na.rm = TRUE),
  350. avg_grid_y = mean(grid_y, na.rm = TRUE),
  351. across(all_of(colnames(count)), sum, na.rm = TRUE)
  352. )
  353. # View the data structure
  354. head(data_wide)
  355. library(MASS)
  356. library(dplyr)
  357. library(tidyr)
  358. library(fields)
  359. # Function to compute density for each ligand-receptor pair with adjustments
  360. compute_density_exact <- function(data, col, x_col, y_col) {
  361. data_sub <- data %>%
  362. filter(!!sym(col) == 1)
  363. if (nrow(data_sub) > 1) {
  364. density <- kde2d(data_sub[[x_col]], data_sub[[y_col]], h = c(10, 10), n = 200)
  365. # Interpolate the density at the given x and y coordinates
  366. density_values <- interp.surface(list(x = density$x, y = density$y, z = density$z),
  367. cbind(data[[x_col]], data[[y_col]]))
  368. density_df <- data.frame(X = data[[x_col]], Y = data[[y_col]])
  369. density_df[[col]] <- density_values
  370. density_df[[col]][is.na(density_df[[col]])] <- 0 # Handle NA values
  371. return(density_df)
  372. } else {
  373. density_df <- data.frame(X = data[[x_col]], Y = data[[y_col]])
  374. density_df[[col]] <- 0
  375. return(density_df)
  376. }
  377. }
  378. density_list <- data_wide
  379. i=1
  380. #interaction_matrix=interaction_matrix[,-1]
  381. lig_rec_cols=colnames(data_wide)[4:54]
  382. #data_wide=as.data.frame(data_wide)
  383. data_wide[is.na(data_wide)==T]=0
  384. #density_list=as.data.frame(density_list)
  385. #952,1143
  386. # Iterate over each ligand-receptor pair and compute the density matrix
  387. for (i in 1:length(lig_rec_cols)) {
  388. if(sum(data_wide[,lig_rec_cols[i]])>4){
  389. density_df <- compute_density_exact(data_wide, lig_rec_cols[i], "avg_grid_x", "avg_grid_y")
  390. density_list[,i+3]=density_df[,3]
  391. i=i+1
  392. }else{
  393. density_list[,i+3]=0
  394. i=i+1
  395. }
  396. print(i)
  397. }
  398. lig_rec_cols=colnames(density_list)[4:54]
  399. density_list_final=density_list#[order(density_list$ID),]
  400. #colnames(density_list_final)[1:51]=lig_rec_cols
  401. density_list_final$Adjusted_X=density_list$avg_grid_x
  402. density_list_final$Adjusted_Y=density_list$avg_grid_y
  403. #density_list_final$Group=interaction_matrix$Group
  404. data_wide
  405. # 3. Perform k-means clustering with an appropriate number of clusters (e.g., k = 3)
  406. set.seed(123)
  407. k <- 20 # Adjust based on the elbow method plot
  408. library(irlba)
  409. density_list_cluster=density_list[,4:54]
  410. library(Seurat)
  411. library(reticulate)
  412. reticulate::virtualenv_create("r-reticulate")
  413. reticulate::use_virtualenv("r-reticulate", required = TRUE)
  414. # Install leidenalg within the virtual environment
  415. reticulate::py_install("leidenalg", envname = "r-reticulate")
  416. reticulate::py_install("pandas", envname = "r-reticulate")
  417. # Test if leidenalg can be loaded
  418. py <- import("leidenalg")
  419. print(py)
  420. # Create a Seurat object from your data frame
  421. seurat_object <- CreateSeuratObject(counts = t(as.matrix(density_list_cluster)), project = "ClusterAnalysis")
  422. # Normalize the data
  423. seurat_object <- NormalizeData(seurat_object)
  424. # Find variable features
  425. seurat_object <- FindVariableFeatures(seurat_object, selection.method = "vst", nfeatures = 2000)
  426. # Scale the data
  427. seurat_object <- ScaleData(seurat_object)
  428. # Run PCA for dimensionality reduction
  429. seurat_object <- RunPCA(seurat_object, features = VariableFeatures(object = seurat_object))
  430. # Optionally, run UMAP or t-SNE
  431. seurat_object <- RunUMAP(seurat_object, dims = 1:10)
  432. # Alternatively, for t-SNE:
  433. # seurat_object <- RunTSNE(seurat_object, dims = 1:10)
  434. # Find neighbors
  435. seurat_object <- FindNeighbors(seurat_object, dims = 1:5)
  436. # Use Leiden algorithm for clustering
  437. seurat_object <- FindClusters(seurat_object, resolution = 0.005) # Algorithm 4 is Leiden
  438. pca_result <- prcomp(as.matrix(density_list_cluster[,which(colSums(density_list_cluster)>0)]), scale. = TRUE)
  439. #pca_result <- irlba(as.matrix(density_list_cluster[,which(colSums(density_list_cluster)>0)]), nv = 10, scale. = T)
  440. #pca_df <- pca_result$u[, 1:40] * pca_result$d[1:40]
  441. # Create a data frame with PCA results and cluster assignments
  442. pca_df <- as.data.frame(pca_result$x)
  443. #kmeans_result <- kmeans(pca_df[,c(1:41)], centers = k, nstart = 25)
  444. pca_df=as.data.frame(pca_df)
  445. pca_df$Cluster <- as.factor(seurat_object$seurat_clusters)
  446. colnames(pca_df)[c(1:2)]=c("PC1","PC2")
  447. # Plot the PCA results with cluster assignments
  448. ggplot(pca_df, aes(x = PC1, y = PC2, color = pca_df$Cluster)) +
  449. geom_point(size=0.1) +
  450. labs(title = "PCA Plot of Clusters",
  451. x = "Principal Component 1",
  452. y = "Principal Component 2") +
  453. theme_minimal()
  454. density_list_sub=density_list
  455. ggplot(density_list_sub, aes(x = avg_grid_x, y = avg_grid_y, color = as.factor(pca_df$Cluster))) +
  456. geom_point(size = 1) +
  457. theme_minimal()
  458. data_cluster=data.frame(grid_id=density_list_final$grid_id,Cluster=seurat_object$seurat_clusters)
  459. data_cluster=data_cluster[unique(data_cluster$grid_id),]
  460. data_final_sub=merge(data_cluster,data1_sub_plot,"grid_id")
  461. data_final_sub=data_final_sub[unique(data_final_sub$ID),]
  462. data_final_sub=data_final_sub[,c("ID","Cluster")]
  463. interaction_matrix$ID=1:nrow(interaction_matrix)
  464. data_final=merge(data_final_sub,interaction_matrix,"ID")
  465. #data_final_sub=data_final[which(data_final$Cluster%in%c("1","3","20")),]
  466. # Assuming 'user_colors' is a named vector with colors corresponding to each cluster
  467. library(ggplot2)
  468. # Correct ggplot with geom_segment
  469. ggplot() +
  470. geom_segment(data = data_final,
  471. aes(x = X_cell, y = Y_cell, xend = X_neighbor, yend = Y_neighbor,
  472. color = as.factor(Cluster)), # Correct reference to Cluster
  473. na.rm = TRUE, size = 0.1) +
  474. theme_classic(base_size = 15) +
  475. scale_color_manual(values = user_colors) + # Ensure user_colors matches the factors in Cluster
  476. labs(x = "X", y = "Y", title = "") +
  477. guides(color = guide_legend(override.aes = list(size = 3), title = "Cluster"))
  478. library(dplyr)
  479. # Group the data by the predicted label and calculate the mean for each column
  480. data_plot=data.frame(TACIT=as.numeric(seurat_object$seurat_clusters),density_list[,c(4:54)])
  481. mean_values_TACIT <- data_plot %>%
  482. group_by(TACIT) %>%
  483. summarise_all(~quantile(., 0.5))
  484. # mean_values_TACIT[ , -1][mean_values_TACIT[ , -1] > 0] <- 1
  485. mean_values_TACIT=as.data.frame(mean_values_TACIT)
  486. rownames(mean_values_TACIT)=mean_values_TACIT$TACIT
  487. mean_values_TACIT <- as.data.frame((mean_values_TACIT[,-1]))
  488. my.breaks <- c(seq(-2, 0, by=0.1),seq(0.1, 2, by=0.1))
  489. my.colors <- c(colorRampPalette(colors = c("blue", "white"))(length(my.breaks)/2), colorRampPalette(colors = c("white", "red"))(length(my.breaks)/2))
  490. aa=scale(mean_values_TACIT)
  491. aa <- as.data.frame(aa)
  492. aa <- aa %>%
  493. select_if(~ !all(is.na(.)))
  494. # Custom color palette from blue to white to red
  495. color_palette <- colorRampPalette(c("blue", "white", "red"))(100)
  496. # Define breaks for the color scale
  497. breaks <- seq(-3, 3, length.out = 101) # Adjust to match your data range
  498. library(pheatmap)
  499. pheatmap(aa,
  500. cluster_cols = T,
  501. cluster_rows = T,
  502. show_colnames = TRUE,
  503. fontsize_col = 15,
  504. fontsize_row = 15,scale = "none",clustering_method="ward.D2",color = my.colors,breaks = my.breaks)
  505. pheatmap(log10(aa+0.000000001),
  506. cluster_cols = T,
  507. cluster_rows = T,
  508. show_colnames = TRUE,
  509. fontsize_col = 15,
  510. fontsize_row = 15,scale = "none",clustering_method="ward.D2")
  511. library(umap) # or use library(uwot) if you installed it
  512. library(ggplot2)
  513. library(reticulate)
  514. use_virtualenv("r-reticulate", required = TRUE) # Adjust the name if your virtualenv is named differently
  515. # Prepare the data: Exclude non-numeric columns
  516. umap_data <-density_list[,c(4:54)]
  517. # Using the umap package
  518. py_install("umap-learn", envname = "r-reticulate")
  519. # If using the uwot package
  520. umap_result <- umap(scale(umap_data), n_neighbors = 15, min_dist = 0.1, metric = "correlation",method = "umap-learn")
  521. umap_df <- as.data.frame(umap_result$layout)
  522. colnames(umap_df) <- c("UMAP1", "UMAP2")
  523. umap_df$Group <- data_plot$TACIT # Assuming you want to color points by group
  524. ggplot(umap_df, aes(x = UMAP1, y = UMAP2, color = as.factor(Group))) +
  525. geom_point(alpha = 0.7, size = 1.5) +
  526. theme_minimal() +
  527. labs(title = "UMAP Projection", x = "UMAP1", y = "UMAP2") +
  528. scale_color_manual(values = user_colors)
  529. # Load necessary libraries
  530. library(dplyr)
  531. library(ggplot2)
  532. library(reshape2)
  533. data_final$Group=data1$Group[data_final$cell_id]
  534. data_final$Cluster=as.numeric(data_final$Cluster)
  535. data_final$GroupMG=data1$Group_MG[data_final$cell_id]
  536. data_final$GroupNICHES=ifelse(data_final$Group%in%c("Gingiva1","Gingiva1"),"Gingiva",data_final$Group)
  537. data_final$GroupNICHES=ifelse(data_final$GroupNICHES%in%c("MSG1","MSG8","MSG9"),"MSG",data_final$GroupNICHES)
  538. data_final$GroupNICHES=ifelse(data_final$GroupNICHES%in%c("Parotid20","Parotid35","Parotid39","Parotid40"),"Parotid",data_final$GroupNICHES)
  539. data_final$GroupNICHES=ifelse(data_final$GroupNICHES%in%c("Tongue12","Tongue62"),"Tongue",data_final$GroupNICHES)
  540. # List of neighbors to iterate over
  541. neighbors <- unique(data_final$Group)
  542. for (neighbor in neighbors) {
  543. data_final_sub = data_final[which(data_final$Group == neighbor),]
  544. library(ggplot2)
  545. # Ensure that `Cluster` is a factor in your data
  546. data_final_sub$Cluster <- as.factor(data_final_sub$Cluster)
  547. # Correct ggplot with geom_segment
  548. p=ggplot() +
  549. geom_segment(data = data_final_sub,
  550. aes(x = X_cell, y = Y_cell, xend = X_neighbor, yend = Y_neighbor,
  551. color = Cluster), # Use Cluster directly as a factor
  552. na.rm = TRUE, size = 0.1) +
  553. theme_classic(base_size = 15) +
  554. scale_color_manual(values = user_colors) + # Ensure `user_colors` aligns with Cluster levels
  555. labs(x = "X", y = "Y", title = "") +
  556. guides(color = guide_legend(override.aes = list(size = 3), title = "Cluster"))
  557. # Save the plot as an SVG file
  558. ggsave(paste0("C:/Users/huynhk4/Downloads/OCF_MERSCOPE_0409/Healthy/n=15/slide/", neighbor, "_LR_spatial.svg"), plot = p, width = 10, height = 8, dpi = 300)
  559. }
  560. data_plot=data.frame(Group=data_final$Group,Cluster=data_final$Cluster)
  561. # Load necessary library
  562. library(ggplot2)
  563. library(dplyr)
  564. # Calculate proportions of each Group within each Cluster
  565. data_plot_prop <- data_plot %>%
  566. group_by(Cluster, Group) %>%
  567. summarise(count = n()) %>%
  568. mutate(proportion = count / sum(count))
  569. # Define custom colors for groups based on your group labels
  570. group_colors <- c(
  571. "BuccalMucosa" = "#FF9999", "Gingiva1" = "blue", "Gingiva2" = "#99FF99",
  572. "MSG1" = "#FFCC99", "MSG8" = "#FFB266", "MSG9" = "#FF66B2",
  573. "Parotid20" = "#66FFB2", "Parotid35" = "#B266FF", "Parotid39" = "#66FF66",
  574. "Parotid40" = "#FF66FF", "Submandibular53_56" = "#6699FF",
  575. "Tongue12" = "red", "Tongue62" = "purple"
  576. )
  577. # Create the bar plot with custom colors
  578. ggplot(data_plot_prop, aes(x = factor(Cluster), y = proportion, fill = Group)) +
  579. geom_bar(stat = "identity", position = "stack") +
  580. scale_fill_manual(values = group_colors) +
  581. labs(x = "Cluster", y = "Proportion", title = "Proportion of Group in Each Slides in LR Cluster") +
  582. theme_classic(base_size = 15)+
  583. coord_flip() # This flips the coordinates
  584. data_plot=data.frame(Group=data_final$Group,Cluster=data_final$Cluster)
  585. data_plot$Group2=ifelse(data_plot$Group%in%c("Gingiva1","Gingiva2"),"Gingiva",data_plot$Group)
  586. data_plot$Group2=ifelse(data_plot$Group%in%c("MSG1","MSG8","MSG9"),"MSG",data_plot$Group2)
  587. data_plot$Group2=ifelse(data_plot$Group%in%c("Tongue12","Tongue62"),"Tongue",data_plot$Group2)
  588. data_plot$Group2=ifelse(data_plot$Group%in%c("Parotid20","Parotid35","Parotid39","Parotid40"),"Parotid",data_plot$Group2)
  589. # Load necessary library
  590. library(ggplot2)
  591. library(dplyr)
  592. # Calculate proportions of each Group within each Cluster
  593. data_plot_prop <- data_plot %>%
  594. group_by(Cluster, Group2) %>%
  595. summarise(count = n()) %>%
  596. mutate(proportion = count / sum(count))
  597. # Define custom colors for groups based on your group labels
  598. group_colors <- c(
  599. "BuccalMucosa" = "grey90", "Gingiva1" = "blue", "Gingiva" = "#99FF99",
  600. "MSG" = "#FFCC99", "MSG8" = "#FFB266", "MSG9" = "#FF66B2",
  601. "Parotid20" = "#66FFB2", "Parotid" = "#B266FF", "Parotid39" = "#66FF66",
  602. "Parotid40" = "#FF66FF", "Submandibular53_56" = "#6699FF",
  603. "Tongue" = "lightcoral", "Tongue62" = "purple"
  604. )
  605. # Create the bar plot with custom colors
  606. ggplot(data_plot_prop, aes(x = factor(Cluster), y = proportion, fill = Group2)) +
  607. geom_bar(stat = "identity", position = "stack") +
  608. scale_fill_manual(values = group_colors) +
  609. labs(x = "Cluster", y = "Proportion", title = "Proportion of Group in Each Niches in LR Cluster") +
  610. theme_classic(base_size = 15)+
  611. coord_flip() # This flips the coordinates
  612. library(dplyr)
  613. library(ggplot2)
  614. # Define the desired group order for plotting
  615. mucosal_groups <- c("Tongue", "BuccalMucosa", "Gingiva")
  616. gland_groups <- c("MSG", "Parotid", "Submandibular53_56")
  617. # Create a new column 'GroupOrder' to define the order
  618. data_plot_prop <- data_plot_prop %>%
  619. mutate(GroupOrder = case_when(
  620. Group2 %in% mucosal_groups ~ 1,
  621. Group2 %in% gland_groups ~ 2,
  622. TRUE ~ 3 # If any other groups are present, they will come last
  623. )) %>%
  624. arrange(GroupOrder, Group2, desc(proportion)) %>%
  625. mutate(Cluster = factor(Cluster, levels = unique(Cluster)))
  626. # Plot the data with the clusters ordered by the Group and proportion
  627. ggplot(data_plot_prop, aes(x = Cluster, y = proportion, fill = Group2)) +
  628. geom_bar(stat = "identity", position = "stack") +
  629. scale_fill_manual(values = group_colors) +
  630. labs(x = "Cluster", y = "Proportion", title = "Proportion of Group in Each Cluster") +
  631. theme_classic(base_size = 15) +
  632. coord_flip() # This flips the coordinates
  633. data_plot=data.frame(Group=data_final$Group,Cluster=data_final$Cluster)
  634. data_plot$Group2=ifelse(data_plot$Group%in%c("MSG1","MSG8","MSG9","Parotid20","Parotid35","Parotid39","Parotid40","Submandibular53_56"),"Glands","Mucosal")
  635. # Load necessary library
  636. library(ggplot2)
  637. library(dplyr)
  638. # Calculate proportions of each Group within each Cluster
  639. data_plot_prop <- data_plot %>%
  640. group_by(Cluster, Group2) %>%
  641. summarise(count = n()) %>%
  642. mutate(proportion = count / sum(count))
  643. # Define custom colors for groups based on your group labels
  644. group_colors <- c(
  645. "BuccalMucosa" = "#FF9999", "Glands" = "blue", "Gingiva" = "#99FF99",
  646. "MSG" = "#FFCC99", "MSG8" = "#FFB266", "MSG9" = "#FF66B2",
  647. "Parotid20" = "#66FFB2", "Parotid" = "#B266FF", "Parotid39" = "#66FF66",
  648. "Parotid40" = "#FF66FF", "Submandibular53_56" = "#6699FF",
  649. "Mucosal" = "red", "Tongue62" = "purple"
  650. )
  651. library(dplyr)
  652. library(ggplot2)
  653. # Calculate the Mucosal proportion for each Cluster and create a custom order
  654. data_plot_prop <- data_plot_prop %>%
  655. group_by(Cluster) %>%
  656. mutate(mucosal_proportion = sum(proportion[Group2 == "Mucosal"])) %>%
  657. ungroup() %>%
  658. mutate(Cluster = factor(Cluster, levels = unique(Cluster[order(mucosal_proportion, decreasing = F)])))
  659. # Plot the data with the clusters ordered by Mucosal group proportion
  660. ggplot(data_plot_prop, aes(x = Cluster, y = proportion, fill = Group2)) +
  661. geom_bar(stat = "identity", position = "stack") +
  662. scale_fill_manual(values = group_colors) +
  663. labs(x = "Cluster", y = "Proportion", title = "Proportion of Group in Each Group in LR Cluster") +
  664. theme_classic(base_size = 15) +
  665. coord_flip() # This flips the coordinates
  666. data_final
  667. # Convert data to an sf object without a CRS (non-geographic)
  668. data_sub_sf <- st_as_sf(data_final, coords = c("X_cell", "Y_cell"), crs = NA)
  669. data_sub_sf$cell_id <- data_final$ID
  670. # Function to create a grid of windows
  671. create_windows <- function(data, window_size, step_size) {
  672. bbox <- st_bbox(data)
  673. x_breaks <- seq(bbox["xmin"], bbox["xmax"] - window_size, by = step_size)
  674. y_breaks <- seq(bbox["ymin"], bbox["ymax"] - window_size, by = step_size)
  675. return(expand.grid(x = x_breaks, y = y_breaks))
  676. }
  677. # Function to find unique neighbors
  678. unique_neighbors <- function(results) {
  679. results %>%
  680. distinct() %>%
  681. rowwise() %>%
  682. mutate(neighbors = list(unique(neighbors)))
  683. }
  684. # Function to find neighbors in a sliding window
  685. find_neighbors_in_window <- function(window, data, window_size, distance_cutoff) {
  686. xmin <- window$x
  687. xmax <- window$x + window_size
  688. ymin <- window$y
  689. ymax <- window$y + window_size
  690. window_data <- data %>%
  691. filter(st_coordinates(.)[,1] >= xmin & st_coordinates(.)[,1] < xmax &
  692. st_coordinates(.)[,2] >= ymin & st_coordinates(.)[,2] < ymax)
  693. if (nrow(window_data) < 2) {
  694. return(data.frame(cell_id = character(0), neighbors = I(list())))
  695. }
  696. distances <- st_distance(window_data)
  697. diag(distances) <- NA
  698. distances[distances > distance_cutoff] <- NA
  699. neighbors <- lapply(seq_len(nrow(window_data)), function(i) {
  700. near <- which(!is.na(distances[i, ]))
  701. if (length(near) > 0) as.character(window_data$cell_id[near]) else NA
  702. })
  703. return(data.frame(cell_id = window_data$cell_id, neighbors = I(neighbors)))
  704. }
  705. # Parameters
  706. window_size <- 500 # Size of the window
  707. step_size <- 400 # Step size for sliding window
  708. distance_cutoff <- 20 # Distance cutoff for neighbors
  709. # Function to process each group
  710. process_group <- function(group_data) {
  711. # Create windows for the group
  712. windows <- create_windows(group_data, window_size, step_size)
  713. # Find neighbors within each window and combine results
  714. results <- do.call(rbind, lapply(seq_len(nrow(windows)), function(i) {
  715. find_neighbors_in_window(windows[i, ], group_data, window_size, distance_cutoff)
  716. }))
  717. # Remove duplicates and group neighbors
  718. results <- unique_neighbors(results)
  719. # Combine results by cell_id
  720. results_df <- results %>%
  721. group_by(cell_id) %>%
  722. summarise(neighbors = list(unique(unlist(neighbors))))
  723. return(results_df)
  724. }
  725. # Apply the process to each group and combine results
  726. all_results <- data_sub_sf %>%
  727. group_by(Group) %>%
  728. group_map(~ process_group(.x)) %>%
  729. bind_rows()
  730. # Display combined results
  731. print(all_results)
  732. all_results_glands_v2=all_results
  733. results_df=all_results_glands_v2
  734. # Filter out rows where the 'neighbors' column contains NA values
  735. results_df <- results_df %>%
  736. filter(!is.na(neighbors))
  737. table(is.na(results_df$cell_id))
  738. results_df <- results_df %>%
  739. filter(!is.na(cell_id))
  740. table(is.na(results_df$neighbors))
  741. results_df_expanded <- results_df %>%
  742. unnest(neighbors)
  743. # Check column names after unnesting
  744. colnames(results_df_expanded)[2]="Neighbor_ID"
  745. results_df_expanded$Neighbor_cell_id=data_final$Cluster[match(results_df_expanded$cell_id, data_final$ID)]
  746. results_df_expanded$Neighbor_Neigbor_ID=data_final$Cluster[match(results_df_expanded$Neighbor_ID, data_final$ID)]
  747. results_df_expanded$Group=data_final$Group[match(results_df_expanded$cell_id, data_final$ID)]
  748. # Load the required libraries
  749. library(dplyr)
  750. library(igraph)
  751. # Prepare the data
  752. # Filter out rows where Neighbor_cell_id is equal to Neighbor_Neigbor_ID
  753. filtered_data <- results_df_expanded %>%
  754. filter(Neighbor_cell_id != Neighbor_Neigbor_ID)
  755. table(filtered_data$Group)
  756. filtered_data=filtered_data[!(filtered_data$Group%in%c("Gingiva2","Tongue12","Tongue62")),]
  757. #filtered_data=filtered_data[which(filtered_data$Neighbor_cell_id!=11),]
  758. #filtered_data=filtered_data[which(filtered_data$Neighbor_Neigbor_ID!=11),]
  759. # Count the frequency of each Neighbor_Neigbor_ID for each Neighbor_cell_id
  760. connection_counts <- filtered_data %>%
  761. group_by(Neighbor_cell_id, Neighbor_Neigbor_ID) %>%
  762. summarise(count = n()) %>%
  763. ungroup()
  764. # Calculate the total connections for each Neighbor_cell_id
  765. total_connections <- connection_counts %>%
  766. group_by(Neighbor_cell_id) %>%
  767. summarise(total = sum(count))
  768. # Merge the total connections back to calculate the proportion
  769. connection_counts <- connection_counts %>%
  770. left_join(total_connections, by = "Neighbor_cell_id") %>%
  771. mutate(proportion = count / total)
  772. # For each Neighbor_cell_id, select the top connection by proportion
  773. top_connections <- connection_counts %>%
  774. group_by(Neighbor_cell_id) %>%
  775. slice_max(order_by = proportion, n = 3) %>%
  776. ungroup()
  777. # Create the edge list for the graph
  778. edges <- data.frame(from = top_connections$Neighbor_cell_id,
  779. to = top_connections$Neighbor_Neigbor_ID,
  780. weight = top_connections$proportion)
  781. # Create the graph object
  782. graph <- graph_from_data_frame(edges, directed = TRUE)
  783. vertex_labels <- V(graph)$name
  784. V(graph)$color <- user_colors[vertex_labels]
  785. plot(graph,
  786. edge.width = E(graph)$weight * 10, # Thickness of the edges proportional to the connection strength
  787. vertex.size = 15, # Size of the vertices
  788. vertex.label = V(graph)$name, # Label with the cell names
  789. vertex.color = V(graph)$color, # Color of the vertices
  790. edge.arrow.size = 0.5, # Arrow size for directed edges
  791. main = "Motif Glands")
  792. results_df_expanded$GroupNICHES=data_final$GroupNICHES[match(results_df_expanded$cell_id, data_final$ID)]
  793. # Load the required libraries
  794. library(dplyr)
  795. library(igraph)
  796. # Get unique groups
  797. groups <- unique(results_df_expanded$GroupNICHES)
  798. # Loop through each group and generate the graph
  799. for (group_name in groups) {
  800. # Filter the data for the current group
  801. group_data <- results_df_expanded %>%
  802. filter(GroupNICHES == group_name)
  803. # Prepare the data: Filter out rows where Neighbor_cell_id equals Neighbor_Neigbor_ID
  804. filtered_data <- group_data %>%
  805. filter(Neighbor_cell_id != Neighbor_Neigbor_ID)
  806. # filtered_data=filtered_data[which(filtered_data$Neighbor_cell_id!="11"),]
  807. # filtered_data=filtered_data[which(filtered_data$Neighbor_Neigbor_ID!="11"),]
  808. # Count the frequency of each Neighbor_Neigbor_ID for each Neighbor_cell_id
  809. connection_counts <- filtered_data %>%
  810. group_by(Neighbor_cell_id, Neighbor_Neigbor_ID) %>%
  811. summarise(count = n()) %>%
  812. ungroup()
  813. # Calculate the total connections for each Neighbor_cell_id
  814. total_connections <- connection_counts %>%
  815. group_by(Neighbor_cell_id) %>%
  816. summarise(total = sum(count))
  817. # Merge the total connections back to calculate the proportion
  818. connection_counts <- connection_counts %>%
  819. left_join(total_connections, by = "Neighbor_cell_id") %>%
  820. mutate(proportion = count / total)
  821. # For each Neighbor_cell_id, select the top connection by proportion
  822. top_connections <- connection_counts %>%
  823. group_by(Neighbor_cell_id) %>%
  824. slice_max(order_by = proportion, n =3) %>%
  825. ungroup()
  826. # Create the edge list for the graph
  827. edges <- data.frame(from = top_connections$Neighbor_cell_id,
  828. to = top_connections$Neighbor_Neigbor_ID,
  829. weight = top_connections$proportion)
  830. # Create the graph object
  831. graph <- graph_from_data_frame(edges, directed = TRUE)
  832. # Ensure that the vertex labels (V(graph)$name) are present in user_colors
  833. vertex_labels <- V(graph)$name
  834. # Assign colors to vertices based on the user_colors vector
  835. V(graph)$color <- user_colors[vertex_labels]
  836. # Handle any unmatched labels with a default color (e.g., "grey" if a label is not in user_colors)
  837. V(graph)$color[is.na(V(graph)$color)] <- "grey"
  838. # Plot the graph using igraph
  839. plot(graph,
  840. edge.width = E(graph)$weight * 10, # Thickness of the edges proportional to the connection strength
  841. vertex.size = 15, # Size of the vertices
  842. vertex.label = V(graph)$name, # Label with the cell names
  843. vertex.color = V(graph)$color, # Color of the vertices
  844. edge.arrow.size = 0.5, # Arrow size for directed edges
  845. main = paste("Motif for Group:", group_name))
  846. # Optionally save the plot as an image
  847. filename <- paste0("C:/Users/huynhk4/Downloads/OCF_MERSCOPE_0409/Healthy/n=15/niches/OCF_motif_", group_name, ".svg")
  848. svg(filename)
  849. plot(graph,
  850. edge.width = E(graph)$weight * 10, # Thickness of the edges proportional to the connection strength
  851. vertex.size = 15, # Size of the vertices
  852. vertex.label = V(graph)$name, # Label with the cell names
  853. vertex.color = V(graph)$color, # Color of the vertices
  854. edge.arrow.size = 0.5, # Arrow size for directed edges
  855. main = paste("Motif for Group:", group_name))
  856. dev.off()
  857. }
  858. data_cluster=data.frame(grid_id=density_list_final$grid_id,Cluster=seurat_object$seurat_clusters)
  859. data_cluster=data_cluster[unique(data_cluster$grid_id),]
  860. data_final_sub=merge(data_cluster,data1_sub_plot,"grid_id")
  861. data_final_sub=data_final_sub[unique(data_final_sub$ID),]
  862. data_final_sub=data_final_sub[,c("ID","Cluster","grid_id")]
  863. interaction_matrix$ID=1:nrow(interaction_matrix)
  864. data_final_heatmap=merge(data_final_sub,interaction_matrix,"ID")
  865. data_final_heatmap$Group=data1$Group[data_final_heatmap$cell_id]
  866. data_final_heatmap=data_final_heatmap[,c("grid_id","Group")]
  867. library(dplyr)
  868. # Group the data by the predicted label and calculate the mean for each column
  869. data_plot=data.frame(TACIT=as.numeric(seurat_object$seurat_clusters),grid_id=density_list$grid_id,density_list[,c(4:54)])
  870. mean_values_TACIT <- data_plot %>%
  871. group_by(TACIT) %>%
  872. summarise_all(~quantile(., 0.5))
  873. # mean_values_TACIT[ , -1][mean_values_TACIT[ , -1] > 0] <- 1
  874. mean_values_TACIT=as.data.frame(mean_values_TACIT)
  875. rownames(mean_values_TACIT)=mean_values_TACIT$TACIT
  876. mean_values_TACIT <- as.data.frame((mean_values_TACIT[,-1]))
  877. my.breaks <- c(seq(-2, 0, by=0.1),seq(0.1, 2, by=0.1))
  878. my.colors <- c(colorRampPalette(colors = c("blue", "white"))(length(my.breaks)/2), colorRampPalette(colors = c("white", "red"))(length(my.breaks)/2))
  879. aa=scale(mean_values_TACIT)
  880. aa <- as.data.frame(aa)
  881. aa <- aa %>%
  882. select_if(~ !all(is.na(.)))
  883. # Custom color palette from blue to white to red
  884. color_palette <- colorRampPalette(c("blue", "white", "red"))(100)
  885. # Define breaks for the color scale
  886. breaks <- seq(-3, 3, length.out = 101) # Adjust to match your data range
  887. library(pheatmap)
  888. pheatmap(aa,
  889. cluster_cols = T,
  890. cluster_rows = T,
  891. show_colnames = TRUE,
  892. fontsize_col = 15,
  893. fontsize_row = 15,scale = "row",clustering_method="ward.D2",color = my.colors,breaks = my.breaks)
  894. # Load necessary libraries
  895. library(dplyr)
  896. library(pheatmap)
  897. library(ggplot2)
  898. # Define custom colors and breaks for pheatmap
  899. my.breaks <- c(seq(-2, 0, by=0.1), seq(0.1, 2, by=0.1))
  900. my.colors <- c(colorRampPalette(colors = c("blue", "white"))(length(my.breaks)/2),
  901. colorRampPalette(colors = c("white", "red"))(length(my.breaks)/2))
  902. # Loop through each group in data_final_heatmap
  903. unique_groups <- unique(data_final_heatmap$Group)
  904. # Loop through each group in data_final_heatmap
  905. unique_groups <- unique(data_final_heatmap$Group)
  906. library(svglite)
  907. for (i in 13:length(unique_groups)) {
  908. # Filter grid_id for the current group
  909. grid_ids <- data_final_heatmap %>%
  910. filter(Group == unique_groups[i]) %>%
  911. pull(grid_id)
  912. grid_ids=unique(grid_ids)
  913. # Filter data_plot using the selected grid_ids
  914. filtered_data <- data_plot[data_plot$grid_id %in% grid_ids, ]
  915. # Remove non-numeric columns and calculate the mean for each numeric column
  916. numeric_columns <- sapply(filtered_data, is.numeric) # Identify numeric columns
  917. numeric_columns[c("TACIT", "grid_id")] <- FALSE # Exclude TACIT and grid_id specifically
  918. filtered_data=filtered_data[,-2]
  919. mean_values_TACIT <- filtered_data %>%
  920. group_by(TACIT) %>%
  921. summarise_all(~quantile(., 0.5))
  922. # mean_values_TACIT[ , -1][mean_values_TACIT[ , -1] > 0] <- 1
  923. mean_values_TACIT=as.data.frame(mean_values_TACIT)
  924. rownames(mean_values_TACIT)=mean_values_TACIT$TACIT
  925. mean_values_TACIT <- as.data.frame((mean_values_TACIT[,-1]))
  926. my.breaks <- c(seq(-2, 0, by=0.1),seq(0.1, 2, by=0.1))
  927. my.colors <- c(colorRampPalette(colors = c("blue", "white"))(length(my.breaks)/2), colorRampPalette(colors = c("white", "red"))(length(my.breaks)/2))
  928. aa=scale(mean_values_TACIT)
  929. aa <- as.data.frame(aa)
  930. aa <- aa %>%
  931. select_if(~ !all(is.na(.)))
  932. # Custom color palette from blue to white to red
  933. color_palette <- colorRampPalette(c("blue", "white", "red"))(100)
  934. # Define breaks for the color scale
  935. breaks <- seq(-3, 3, length.out = 101) # Adjust to match your data range
  936. library(pheatmap)
  937. p=pheatmap(aa,
  938. cluster_cols = T,
  939. cluster_rows = T,
  940. show_colnames = TRUE,
  941. fontsize_col = 15,
  942. fontsize_row = 15,scale = "row",clustering_method="ward.D2",color = my.colors,breaks = my.breaks,
  943. main = paste("Heatmap for Group:", unique_groups[i]))
  944. file_name <- paste0("C:/Users/huynhk4/Downloads/OCF_MERSCOPE_0409/Healthy/n=20/heatmap_", unique_groups[i], ".svg")
  945. # Use svglite to save the heatmap as an SVG
  946. svglite(file_name, width = 14, height = 8)
  947. grid::grid.draw(p$gtable) # Draw the pheatmap gtable to the SVG device
  948. dev.off() #
  949. }
  950. data1$Cell_ID=1:nrow(data1)
  951. LR=colnames(count)
  952. for (i in 1:length(LR)) {
  953. gene=strsplit(LR[i], "_")[[1]]
  954. # Match Cell_IDs from data1 to data_final_lung$cell_id
  955. gene1_col <- gene[1] # First gene column
  956. gene2_col <- gene[2] # Second gene column
  957. # Match Cell_IDs from data1 to data_final_lung$cell_id and extract gene1 column
  958. gene1_values <- data1[match(data_final$cell_id, data1$Cell_ID), gene1_col]
  959. # Match Neighbor_IDs from data1 to data_final_lung$Neighbor_ID and extract gene2 column
  960. gene2_values <- data1[match(data_final$Neighbor_ID, data1$Cell_ID), gene2_col]
  961. value=gene1_values*gene2_values
  962. data_final[,LR[i]]=value
  963. }
  964. library(Seurat)
  965. data = data_final[,colnames(count)]
  966. orig_values = as.matrix(data) # Consider only marker data
  967. rownames(orig_values) = 1:nrow(data)
  968. orig_values = t(orig_values)
  969. orig_values_metadata = data.frame("CellID" = 1:nrow(data))
  970. rownames(orig_values_metadata) = orig_values_metadata$CellID
  971. scfp = CreateSeuratObject(counts = orig_values, meta.data = orig_values_metadata)
  972. scfp = NormalizeData(scfp, normalization.method = "CLR", margin = 2)
  973. scfp = FindVariableFeatures(scfp, selection.method = "vst", nfeatures = 100)
  974. scfp = ScaleData(scfp, features = rownames(scfp))
  975. #scfp = RunPCA(scfp, features = VariableFeatures(object = scfp))
  976. #scfp = RunUMAP(scfp, reduction = "pca", dims = 1:10,metric = "correlation")
  977. #scfp = FindNeighbors(scfp, dims = 1:10)
  978. #scfp = FindClusters(scfp, resolution = 1.2)
  979. Idents(scfp)=data_final$Cluster
  980. scfp.markers = FindAllMarkers(scfp, only.pos = TRUE)
  981. top5 = scfp.markers %>%
  982. group_by(cluster) %>%
  983. ungroup() %>%
  984. as.data.frame()
  985. gene_pairs <- top5$gene[which(top5$cluster%in%c(15,13,12,11,8,6,7,4))]
  986. # Split the pairs and unlist into a vector of individual genes
  987. individual_genes <- unlist(strsplit(gene_pairs, "-"))
  988. library(clusterProfiler)
  989. library(org.Hs.eg.db)
  990. genes <-unique(individual_genes)
  991. # Convert gene symbols to Entrez IDs
  992. entrez_ids <- bitr(genes, fromType = "SYMBOL", toType = "ENTREZID", OrgDb = org.Hs.eg.db)
  993. # Check the conversion
  994. print(entrez_ids)
  995. # Perform KEGG pathway enrichment analysis
  996. kegg_enrichment <- enrichKEGG(gene = entrez_ids$ENTREZID, organism = 'hsa')
  997. # View the enrichment results
  998. head(kegg_enrichment)
  999. # Visualize top pathways in a barplot
  1000. barplot(kegg_enrichment, showCategory = 10, title = "KEGG Pathway Enrichment for Ligand-Receptor Pairs")
  1001. # Or a dotplot
  1002. dotplot(kegg_enrichment, showCategory = 10, title = "KEGG Pathway Enrichment for Ligand-Receptor Pairs")
  1003. gene_pairs <- top5$gene[!(top5$cluster%in%c(15,13,12,11,8,6,7,4))]
  1004. # Split the pairs and unlist into a vector of individual genes
  1005. individual_genes <- unlist(strsplit(gene_pairs, "-"))
  1006. library(clusterProfiler)
  1007. library(org.Hs.eg.db)
  1008. genes <-unique(individual_genes)
  1009. # Convert gene symbols to Entrez IDs
  1010. entrez_ids <- bitr(genes, fromType = "SYMBOL", toType = "ENTREZID", OrgDb = org.Hs.eg.db)
  1011. # Check the conversion
  1012. print(entrez_ids)
  1013. # Perform KEGG pathway enrichment analysis
  1014. kegg_enrichment <- enrichKEGG(gene = entrez_ids$ENTREZID, organism = 'hsa')
  1015. # View the enrichment results
  1016. head(kegg_enrichment)
  1017. # Visualize top pathways in a barplot
  1018. barplot(kegg_enrichment, showCategory = 10, title = "KEGG Pathway Enrichment for Ligand-Receptor Pairs")
  1019. # Or a dotplot
  1020. dotplot(kegg_enrichment, showCategory = 10, title = "KEGG Pathway Enrichment for Ligand-Receptor Pairs")
  1021. glands_gene_pairs <- top5$gene[which(top5$cluster%in%c(3,4,5,6,7,16,20))]
  1022. mucosal_gene_pairs <- top5$gene[which(top5$cluster%in%c(1,2,8,13,15,14,18))]
  1023. # Unique gene pairs for mucosal
  1024. unique_mucosal_gene_pairs <- setdiff(mucosal_gene_pairs, glands_gene_pairs)
  1025. # Unique gene pairs for glands
  1026. unique_glands_gene_pairs <- setdiff(glands_gene_pairs, mucosal_gene_pairs)
  1027. # Print the results
  1028. print("Unique gene pairs for mucosal:")
  1029. print(unique_mucosal_gene_pairs)
  1030. print("Unique gene pairs for glands:")
  1031. print(unique_glands_gene_pairs)
  1032. unique_gene=c(unique_glands_gene_pairs,unique_mucosal_gene_pairs)
  1033. data_final_sub=data_final[,c("Group",unique_gene)]
  1034. data_final_sub=data_final_sub[which(rowSums(data_final_sub[,-1])>0),]
  1035. data_final_sub$Group=ifelse(data_final_sub$Group%in%c("MSG1","MSG8","MSG9","Parotid20","Parotid35","Parotid39","Parotid40","Submandibular53_56"),"Glands","Mucosal")
  1036. # Load necessary libraries
  1037. library(dplyr)
  1038. library(pheatmap)
  1039. # Calculate the proportion of each column greater than 0 for each Group
  1040. data_proportions <- data_final_sub %>%
  1041. group_by(Group) %>%
  1042. summarise(across(everything(), ~mean(. > 0)))
  1043. # Convert the data to a matrix for heatmap plotting
  1044. data_matrix <- as.matrix(data_proportions[,-1]) # Remove the Group column for heatmap
  1045. rownames(data_matrix) <- data_proportions$Group # Set Group as rownames
  1046. # Plot the heatmap
  1047. pheatmap(data_matrix,
  1048. scale = "column",
  1049. cluster_rows = TRUE,
  1050. cluster_cols = TRUE,
  1051. main = "Proportion of Each Gene Pair > 0 Across Groups")
  1052. library(Seurat)
  1053. data = data_final[,colnames(count)]
  1054. orig_values = as.matrix(data) # Consider only marker data
  1055. rownames(orig_values) = 1:nrow(data)
  1056. orig_values = t(orig_values)
  1057. orig_values_metadata = data.frame("CellID" = 1:nrow(data))
  1058. rownames(orig_values_metadata) = orig_values_metadata$CellID
  1059. scfp = CreateSeuratObject(counts = orig_values, meta.data = orig_values_metadata)
  1060. scfp = NormalizeData(scfp, normalization.method = "CLR", margin = 2)
  1061. scfp = FindVariableFeatures(scfp, selection.method = "vst", nfeatures = 100)
  1062. scfp = ScaleData(scfp, features = rownames(scfp))
  1063. #scfp = RunPCA(scfp, features = VariableFeatures(object = scfp))
  1064. #scfp = RunUMAP(scfp, reduction = "pca", dims = 1:10,metric = "correlation")
  1065. #scfp = FindNeighbors(scfp, dims = 1:10)
  1066. #scfp = FindClusters(scfp, resolution = 1.2)
  1067. Idents(scfp)=ifelse(data_final$Group%in%c("MSG1","MSG8","MSG9","Parotid20","Parotid35","Parotid39","Parotid40","Submandibular53_56"),"Glands","Mucosal")
  1068. # Run differential expression analysis
  1069. markers <- FindMarkers(scfp, ident.1 = "Mucosal", ident.2 = "Glands", test.use = "wilcox")
  1070. # View the top markers
  1071. head(markers)
  1072. # Add a column for significance based on adjusted p-value and logFC threshold
  1073. markers$significance <- with(markers, ifelse(p_val_adj < 0.05 & abs(avg_log2FC) > 0.25,
  1074. ifelse(avg_log2FC > 0.25, "Up in Mucosal", "Up in Glands"),
  1075. "Not Significant"))
  1076. # View the updated markers table
  1077. head(markers)
  1078. # Set a minimum threshold for the p-values to avoid extreme values in the plot
  1079. markers$p_val_adj_plot <- pmax(markers$p_val_adj, 1e-300) # Set a lower bound for p-values
  1080. # Add the significance column again for classification if necessary
  1081. markers$significance <- with(markers, ifelse(p_val_adj < 0.05 & abs(avg_log2FC) > 0.25,
  1082. ifelse(avg_log2FC > 0.25, "Up in Mucosal", "Up in Glands"),
  1083. "Not Significant"))
  1084. # Load necessary libraries
  1085. library(ggplot2)
  1086. # Create the volcano plot with adjusted p-values
  1087. # Load necessary library
  1088. library(ggrepel)
  1089. # Add text labels for significant genes
  1090. ggplot(markers, aes(x = avg_log2FC, y = -log10(p_val_adj_plot), color = significance)) +
  1091. geom_point(alpha = 0.8, size = 3) +
  1092. geom_text_repel(data = subset(markers, significance != "Not Significant"),
  1093. aes(label = rownames(subset(markers, significance != "Not Significant"))),
  1094. size = 4, max.overlaps = 10) + # Adjust size and overlaps as needed
  1095. scale_color_manual(values = c("Up in Mucosal" = "red", "Up in Glands" = "blue", "Not Significant" = "gray")) +
  1096. labs(title = "Volcano Plot of Differentially LR pairs",
  1097. x = "Log2 Fold Change",
  1098. y = "-Log10 Adjusted P-Value") +
  1099. theme_classic(base_size = 15)
  1100. color_palette <- colorRampPalette(c("blue", "white", "red"))(100)
  1101. breaks <- seq(-2, 2, length.out = 101) # Adjust breaks for the color scale
  1102. data_final$TACIT_Ligands=data1$TACIT[data_final$cell_id]
  1103. data_final$TACIT_Receptors=data1$TACIT[data_final$Neighbor_ID]
  1104. TACIT_Ligands=data1$TACIT[interaction_matrix$cell_id]
  1105. TACIT_Receptors=data1$TACIT[interaction_matrix$Neighbor_ID]
  1106. data_plot=data.frame(TACIT_Ligands,TACIT_Receptors,count,Group=data_final$Group)
  1107. data_plot$Group=ifelse(data_plot$Group%in%c("MSG1","MSG8","MSG9","Parotid20","Parotid35","Parotid39","Parotid40","Submandibular53_56"),"Glands","Mucosal")
  1108. data_plot=data_plot[which(data_plot$Group=="Mucosal"),]
  1109. data_plot=data_plot[,-54]
  1110. # Function to calculate top interactions for each cell type
  1111. get_top_interactions <- function(cell_type, data_plot, top_n = 40) {
  1112. filtered_data <- data_plot %>%
  1113. filter(TACIT_Ligands == cell_type)
  1114. interaction_sums <- colSums(filtered_data[,-c(1,2)])
  1115. top_interactions <- sort(interaction_sums, decreasing = TRUE)[1:top_n]
  1116. top_df <- data.frame(
  1117. Interaction = names(top_interactions),
  1118. Count = as.numeric(top_interactions),
  1119. CellType = cell_type
  1120. )
  1121. return(top_df)
  1122. }
  1123. # Calculate top interactions for each cell type
  1124. cell_types <- unique(data_plot$TACIT_Ligands)
  1125. top_interactions_list <- lapply(cell_types, get_top_interactions, data_plot = data_plot)
  1126. top_interactions_df <- do.call(rbind, top_interactions_list)
  1127. # Convert to wide format for heatmap
  1128. heatmap_data <- dcast(top_interactions_df, Interaction ~ CellType, value.var = "Count", fill = 0)
  1129. rownames(heatmap_data) <- heatmap_data$Interaction
  1130. heatmap_matrix <- as.matrix(heatmap_data[,-1])
  1131. # Plot heatmap using pheatmap
  1132. library(pheatmap)
  1133. # Specify the desired order of the cell types
  1134. desired_order <- c(
  1135. "Ductal Epithelial Cells",
  1136. "Basal Keratincytes",
  1137. "Suprabasal Keratinocytes",
  1138. "Ionocytes",
  1139. "Merkel Cells",
  1140. "Acinar Cells",
  1141. "Fibroblasts",
  1142. "LECs",
  1143. "Mural Cells",
  1144. "VECs",
  1145. "Glial/Neuron",
  1146. "Skeletal Myocytes",
  1147. "B Cells",
  1148. "T Cells",
  1149. "CD4 T Cells",
  1150. "CD8 T Cells",
  1151. "gd T Cells",
  1152. "NK Cells",
  1153. "Dendritic Cells",
  1154. "Monocyte-Macrophage",
  1155. "Plasma Cells",
  1156. "Mast Cells",
  1157. "Langerhans Cells",
  1158. "Others"
  1159. )
  1160. # Identify the columns that are present in both `heatmap_matrix` and `desired_order`
  1161. common_columns <- intersect(desired_order, colnames(heatmap_matrix))
  1162. # Reorder `heatmap_matrix` based on `common_columns`
  1163. heatmap_matrix <- heatmap_matrix[, common_columns]
  1164. # Create the heatmap with a red-to-blue color palette
  1165. pheatmap(heatmap_matrix[which(rowSums(heatmap_matrix) > 0), ],
  1166. main = "Heatmap of Top Interactions for Each Cell Type in Mucosal",
  1167. cluster_rows = F,
  1168. cluster_cols = F,
  1169. scale = "row",
  1170. color = color_palette,
  1171. breaks = breaks)# Red-to-blue color gradient
  1172. data_plot=data.frame(TACIT_Ligands,TACIT_Receptors,count,Group=data_final$Group)
  1173. data_plot$Group=ifelse(data_plot$Group%in%c("MSG1","MSG8","MSG9","Parotid20","Parotid35","Parotid39","Parotid40","Submandibular53_56"),"Glands","Mucosal")
  1174. data_plot=data_plot[which(data_plot$Group=="Glands"),]
  1175. data_plot=data_plot[,-54]
  1176. # Function to calculate top interactions for each cell type
  1177. get_top_interactions <- function(cell_type, data_plot, top_n = 40) {
  1178. filtered_data <- data_plot %>%
  1179. filter(TACIT_Ligands == cell_type)
  1180. interaction_sums <- colSums(filtered_data[,-c(1,2)])
  1181. top_interactions <- sort(interaction_sums, decreasing = TRUE)[1:top_n]
  1182. top_df <- data.frame(
  1183. Interaction = names(top_interactions),
  1184. Count = as.numeric(top_interactions),
  1185. CellType = cell_type
  1186. )
  1187. return(top_df)
  1188. }
  1189. # Calculate top interactions for each cell type
  1190. cell_types <- unique(data_plot$TACIT_Ligands)
  1191. top_interactions_list <- lapply(cell_types, get_top_interactions, data_plot = data_plot)
  1192. top_interactions_df <- do.call(rbind, top_interactions_list)
  1193. # Convert to wide format for heatmap
  1194. heatmap_data <- dcast(top_interactions_df, Interaction ~ CellType, value.var = "Count", fill = 0)
  1195. rownames(heatmap_data) <- heatmap_data$Interaction
  1196. heatmap_matrix <- as.matrix(heatmap_data[,-1])
  1197. # Plot heatmap using pheatmap
  1198. library(pheatmap)
  1199. # Identify the columns that are present in both `heatmap_matrix` and `desired_order`
  1200. common_columns <- intersect(desired_order, colnames(heatmap_matrix))
  1201. # Reorder `heatmap_matrix` based on `common_columns`
  1202. heatmap_matrix <- heatmap_matrix[, common_columns]
  1203. # Create the heatmap with a red-to-blue color palette
  1204. pheatmap(heatmap_matrix[which(rowSums(heatmap_matrix) > 0), ],
  1205. main = "Heatmap of Top Interactions for Each Cell Type in Glands",
  1206. cluster_rows = F,
  1207. cluster_cols = F,
  1208. scale = "row",
  1209. color = color_palette,
  1210. breaks = breaks) # Red-to-blue color gradient
  1211. data_plot=data.frame(TACIT_Ligands,TACIT_Receptors,count,Group=data_final$Group)
  1212. data_plot$Group2=ifelse(data_plot$Group%in%c("Gingiva1","Gingiva2"),"Gingiva",data_plot$Group)
  1213. data_plot$Group2=ifelse(data_plot$Group%in%c("MSG1","MSG8","MSG9"),"MSG",data_plot$Group2)
  1214. data_plot$Group2=ifelse(data_plot$Group%in%c("Tongue12","Tongue62"),"Tongue",data_plot$Group2)
  1215. data_plot$Group2=ifelse(data_plot$Group%in%c("Parotid20","Parotid35","Parotid39","Parotid40"),"Parotid",data_plot$Group2)
  1216. data_plot=data_plot[which(data_plot$Group2%in%c("BuccalMucosa")),]
  1217. data_plot=data_plot[,-c(55,54)]
  1218. # Function to calculate top interactions for each cell type
  1219. get_top_interactions <- function(cell_type, data_plot, top_n = 40) {
  1220. filtered_data <- data_plot %>%
  1221. filter(TACIT_Ligands == cell_type)
  1222. interaction_sums <- colSums(filtered_data[,-c(1,2)])
  1223. top_interactions <- sort(interaction_sums, decreasing = TRUE)[1:top_n]
  1224. top_df <- data.frame(
  1225. Interaction = names(top_interactions),
  1226. Count = as.numeric(top_interactions),
  1227. CellType = cell_type
  1228. )
  1229. return(top_df)
  1230. }
  1231. # Calculate top interactions for each cell type
  1232. cell_types <- unique(data_plot$TACIT_Ligands)
  1233. top_interactions_list <- lapply(cell_types, get_top_interactions, data_plot = data_plot)
  1234. top_interactions_df <- do.call(rbind, top_interactions_list)
  1235. # Convert to wide format for heatmap
  1236. heatmap_data <- dcast(top_interactions_df, Interaction ~ CellType, value.var = "Count", fill = 0)
  1237. rownames(heatmap_data) <- heatmap_data$Interaction
  1238. heatmap_matrix <- as.matrix(heatmap_data[,-1])
  1239. # Plot heatmap using pheatmap
  1240. library(pheatmap)
  1241. # Identify the columns that are present in both `heatmap_matrix` and `desired_order`
  1242. common_columns <- intersect(desired_order, colnames(heatmap_matrix))
  1243. # Reorder `heatmap_matrix` based on `common_columns`
  1244. heatmap_matrix <- heatmap_matrix[, common_columns]
  1245. # Create the heatmap with a red-to-blue color palette
  1246. pheatmap(heatmap_matrix[which(rowSums(heatmap_matrix) > 0), ],
  1247. main = "Heatmap of Top Interactions for Each Cell Type in BuccalMucosa",
  1248. cluster_rows = F,
  1249. cluster_cols = F,
  1250. scale = "row",
  1251. color = color_palette,
  1252. breaks = breaks) # Specify breaks for the legend) # Red-to-blue color gradient
  1253. data_plot=data_final#[,c(21:33,56:60)]
  1254. data_plot$Group2=ifelse(data_plot$Group%in%c("Gingiva1","Gingiva2"),"Gingiva",data_plot$Group)
  1255. data_plot$Group2=ifelse(data_plot$Group%in%c("MSG1","MSG8","MSG9"),"MSG",data_plot$Group2)
  1256. data_plot$Group2=ifelse(data_plot$Group%in%c("Tongue12","Tongue62"),"Tongue",data_plot$Group2)
  1257. data_plot$Group2=ifelse(data_plot$Group%in%c("Parotid20","Parotid35","Parotid39","Parotid40"),"Parotid",data_plot$Group2)
  1258. data_plot$Group2=ifelse(data_plot$Group2%in%c("BuccalMucosa","Gingiva","Tongue"),"Mucosal","Glands")
  1259. # Load necessary libraries
  1260. library(dplyr)
  1261. # Calculate the proportion of non-zero values for each ligand-receptor pair by group
  1262. ligand_receptor_signature <- data_plot %>%
  1263. group_by(Group2) %>%
  1264. summarise(across(colnames(count), ~ mean(. > 0))) # Adjust if necessary for more columns
  1265. # View the results
  1266. head(ligand_receptor_signature)
  1267. # Convert to matrix for heatmap
  1268. signature_matrix <- as.matrix(ligand_receptor_signature[,-1]) # Remove the Group column for heatmap
  1269. rownames(signature_matrix) <- ligand_receptor_signature$Group2 # Set Group as row names
  1270. color_palette <- colorRampPalette(c("blue", "white", "red"))(100)
  1271. breaks <- seq(-2, 2, length.out = 101) # Adjust breaks for the color scale
  1272. # Plot heatmap
  1273. pheatmap(signature_matrix,
  1274. main = "Ligand-Receptor Signatures Across Groups",
  1275. cluster_rows = TRUE,
  1276. cluster_cols = TRUE,
  1277. scale = "row",
  1278. color = color_palette,
  1279. breaks = breaks) # Specify breaks for the legend)
  1280. # Load necessary libraries
  1281. library(ggplot2)
  1282. user_colors <- c(
  1283. "Acinar Cells"="cyan", "B Cells"="#FFA500", "Basal Keratincytes"="lightgrey",
  1284. "CD4 T Cells"="#FF0000", "CD8 T Cells"="#FF6347", "Dendritic Cells"="#FFD700",
  1285. "Ductal Epithelial Cells"="#00FF00", "Fibroblasts"="#f032e6", "gd T Cells"="#FF6347",
  1286. "Glial/Neuron"="lightgrey", "Ionocytes"="lightgreen", "Langerhans Cells"="#FFD700",
  1287. "LECs"="orange", "Mast Cells"="gold", "Merkel Cells"="lightgrey",
  1288. "Monocyte-Macrophage"="goldenrod", "Mural Cells"="lightgrey", "Myoepithelial Cells"="blue",
  1289. "NK Cells"="darkred", "Others"="lightgrey", "Plasma Cells"="purple",
  1290. "Skeletal Myocytes"="lightgrey", "Suprabasal Keratinocytes"="powderblue", "VECs"="orange3"
  1291. )
  1292. # Get unique groups
  1293. unique_groups <- unique(data1$Group)
  1294. # Loop through each group and generate the plot
  1295. for (group in unique_groups) {
  1296. # Subset the data for the current group
  1297. data_sub <- data1[which(data1$Group == group),]
  1298. # Create the plot
  1299. p <- ggplot(data_sub, aes(x = X, y = Y, color = as.factor(data_sub$TACIT))) +
  1300. geom_point(size = 0.1) +
  1301. scale_color_manual(values = user_colors) +
  1302. theme_classic(base_size = 15) +
  1303. guides(color = guide_legend(override.aes = list(size = 3), title = "Cell Type")) +
  1304. labs(title = paste("Plot for", group))
  1305. # Display the plot for the current group (optional)
  1306. print(p)
  1307. # Export the plot as an image (PNG format) for the current group
  1308. ggsave(paste0("C:/Users/huynhk4/Downloads/OCF_MERSCOPE_0409/Healthy/n=15/slide/",group, "_plot.png"), plot = p, width = 12, height = 8, dpi = 300)
  1309. }
  1310. top5$gene <- gsub("-", "_", top5$gene)
  1311. data_plot=data.frame(Cluster=data_final$Cluster,X_cell=data_final$X_cell,Y_cell=data_final$Y_cell,
  1312. X_neighbor=data_final$X_neighbor,Y_neighbor=data_final$Y_neighbor,data_final[,top5$gene])
  1313. # Define colors
  1314. user_colors2 <- c("0" = "grey90", "1" = "red")
  1315. library(dplyr)
  1316. # Loop through each cluster and generate the plot
  1317. for (cluster in unique(data_plot$Cluster)) {
  1318. # Subset data for the specific cluster
  1319. data_final_sub <- data_plot %>% filter(Cluster == cluster)
  1320. # Calculate the sums of the columns and select the top 6
  1321. final_results_sub=top5[which(top5$cluster==cluster),]
  1322. top_columns <- final_results_sub$gene
  1323. data_final_sub=as.data.frame(data_final_sub)
  1324. melted_data=data_final_sub[,c("Cluster", "X_cell", "Y_cell", "X_neighbor", "Y_neighbor",top_columns)]
  1325. # Melt the data for ggplot
  1326. melted_data <- melted_data%>%
  1327. pivot_longer(cols = top_columns, names_to = "Gene", values_to = "Value")
  1328. # Generate the plot
  1329. p <- ggplot(melted_data) +
  1330. geom_segment(aes(x = X_cell, y = Y_cell, xend = X_neighbor, yend = Y_neighbor, color = as.factor(Value)),
  1331. na.rm = TRUE, size = 0.1) +
  1332. facet_wrap(~ Gene) +
  1333. theme_classic(base_size = 15) +
  1334. scale_color_manual(values = user_colors2) +
  1335. labs(x = "X", y = "Y", title = paste("Cluster", cluster)) +
  1336. guides(color = guide_legend(override.aes = list(size = 3), title = "Value"))
  1337. # Save the plot to a file
  1338. ggsave(filename = paste0("TACIT_annotate_MERSCOPE/Gingiva_Fibroblast/","cluster_top_", cluster, ".png"), plot = p, width = 14, height = 8)
  1339. }
  1340. data_final$TACIT_Ligands=data1$TACIT[data_final$cell_id]
  1341. data_final$TACIT_Receptors=data1$TACIT[data_final$Neighbor_ID]
  1342. tail(colnames(interaction_matrix))
  1343. vec=colSums(interaction_matrix[,3:166])
  1344. df <- data.frame(ColumnSum = vec)
  1345. # Plot the density plot using ggplot2
  1346. ggplot(df, aes(x = ColumnSum)) +
  1347. geom_density(color = "blue", fill = "skyblue", alpha = 0.5) +
  1348. labs(
  1349. title = "Density Plot of LR",
  1350. x = "Sum of each LR",
  1351. y = "Density"
  1352. ) +
  1353. theme_minimal() +
  1354. theme(
  1355. plot.title = element_text(hjust = 0.5),
  1356. axis.title = element_text(face = "bold")
  1357. )+xlim(0,2000)
  1358. library(dplyr)
  1359. library(reshape2)
  1360. data_plot=data.frame(Cluster=data_final$Cluster,Ligands=data_final$TACIT_Ligands,Receptors=data_final$TACIT_Receptors)
  1361. # Calculate the proportion of Ligands for each cluster
  1362. ligands_proportion <- data_plot %>%
  1363. group_by(Cluster, Ligands) %>%
  1364. summarise(Count = n()) %>%
  1365. mutate(Proportion = Count / sum(Count)) %>%
  1366. ungroup()
  1367. # Normalize proportions by Ligands (cell type)
  1368. ligands_proportion <- ligands_proportion %>%
  1369. group_by(Ligands) %>%
  1370. mutate(Normalized_Proportion = Proportion / sum(Proportion)) %>%
  1371. ungroup()
  1372. # Convert to wide format for pheatmap
  1373. ligands_matrix <- dcast(ligands_proportion, Ligands ~ Cluster, value.var = "Normalized_Proportion", fill = 0)
  1374. ligands_matrix <- as.matrix(ligands_matrix[,-1]) # Remove the Ligands column to get only the matrix
  1375. # Set row names to Ligands
  1376. rownames(ligands_matrix) <- ligands_proportion$Ligands[!duplicated(ligands_proportion$Ligands)]
  1377. # Plot heatmap for Ligands using pheatmap
  1378. pheatmap(ligands_matrix,
  1379. main = "Heatmap of Normalized Ligands Proportion within Each Cluster",
  1380. cluster_rows = TRUE,
  1381. cluster_cols = TRUE)
  1382. # Calculate the proportion of Receptors for each cluster
  1383. receptors_proportion <- data_plot %>%
  1384. group_by(Cluster, Receptors) %>%
  1385. summarise(Count = n()) %>%
  1386. mutate(Proportion = Count / sum(Count)) %>%
  1387. ungroup()
  1388. # Normalize proportions by Receptors (cell type)
  1389. receptors_proportion <- receptors_proportion %>%
  1390. group_by(Receptors) %>%
  1391. mutate(Normalized_Proportion = Proportion / sum(Proportion)) %>%
  1392. ungroup()
  1393. # Convert to wide format for pheatmap
  1394. receptors_matrix <- dcast(receptors_proportion, Receptors ~ Cluster, value.var = "Normalized_Proportion", fill = 0)
  1395. receptors_matrix <- as.matrix(receptors_matrix[,-1]) # Remove the Receptors column to get only the matrix
  1396. # Set row names to Receptors
  1397. rownames(receptors_matrix) <- receptors_proportion$Receptors[!duplicated(receptors_proportion$Receptors)]
  1398. # Plot heatmap for Receptors using pheatmap
  1399. pheatmap(receptors_matrix,
  1400. main = "Heatmap of Normalized Receptors Proportion within Each Cluster",
  1401. cluster_rows = TRUE,
  1402. cluster_cols = TRUE)
  1403. data_final_sub=data_final[which(data_final$Cluster==16),]
  1404. ggplot() +
  1405. geom_point(data = data_final,size = 0.5,aes(x=X_cell,Y_cell,color=TACIT_Ligands))+
  1406. geom_point(data = data_final,size = 0.5,aes(x=X_neighbor,Y_neighbor,color=TACIT_Receptors))+
  1407. geom_segment(data = data_final_sub, aes(x = X_cell, y = Y_cell, xend = X_neighbor, yend = Y_neighbor,color = as.factor(t(data_final_sub$Cluster))), na.rm = TRUE,size=0.1) +
  1408. theme_classic(base_size = 15)+
  1409. scale_color_manual(values = user_colors) +
  1410. labs(x = "X", y = "Y", title = "") + guides(color = guide_legend(override.aes = list(size = 3),title = "Cluster"))
  1411. data_plot=data.frame(Cluster=data_final$Cluster,Ligands=data_final$TACIT_Ligands,Receptors=data_final$TACIT_Receptors)
  1412. data_plot=data_plot[which(data_plot$Ligands=="B Cells"),]
  1413. interaction_matrix_CX3CL1_CX3CR1_plot=data_plot[,c("Ligands","Receptors")]
  1414. # Calculate interaction counts
  1415. interaction_counts <- interaction_matrix_CX3CL1_CX3CR1_plot %>%
  1416. group_by(Ligands, Receptors) %>%
  1417. summarise(count = n(), .groups = 'drop') %>%
  1418. mutate(transformed_percentile = log10(count + 1))
  1419. top_5_interaction_counts <- interaction_counts %>%
  1420. slice_max(order_by = count, n = 20)
  1421. # Create a graph from the interaction data
  1422. g <- graph_from_data_frame(top_5_interaction_counts, directed = TRUE)
  1423. # Create a color palette
  1424. # Create a large color palette
  1425. color_palette_large <- c(brewer.pal(8, "Set1"), # Red, blue, green, etc.
  1426. brewer.pal(8, "Set2"), # Lighter and diverse colors
  1427. brewer.pal(8, "Set3"), # Mixed colors
  1428. brewer.pal(8, "Dark2"), # Dark colors
  1429. brewer.pal(8, "Pastel1"), # Pastel colors
  1430. brewer.pal(8, "Pastel2"), # More pastel colors
  1431. "red", "green", "blue", "orange", "purple", "cyan", "magenta") # Specific colors
  1432. # Function to get a specific number of random colors from the palette
  1433. get_random_colors <- function(number_of_colors) {
  1434. if (number_of_colors > length(color_palette_large)) {
  1435. stop("Requested number of colors exceeds the prepared palette size.")
  1436. }
  1437. sample(color_palette_large, number_of_colors)
  1438. }
  1439. unique_types <- unique(c(data_final$TACIT_Ligands, data_final$TACIT_Receptors))
  1440. # Example usage: Get 10 random colors
  1441. n <- length(unique_types) # Assume you have 10 types this time
  1442. color_palette <- get_random_colors(n)
  1443. names(color_palette) <- unique_types
  1444. # Assign colors to vertices based on cell type
  1445. V(g)$color <- color_palette[V(g)$name]
  1446. # Assign colors to edges based on interaction strength
  1447. # Use a continuous color scale or manually define breaks for clarity
  1448. E(g)$color <- ifelse(E(g)$transformed_percentile > median(E(g)$transformed_percentile, na.rm = TRUE), "grey90", "grey90")
  1449. #---------------------------------------------
  1450. # Graph cell type between ligands and receptors
  1451. # Plotting
  1452. plot(g, layout = layout_in_circle(g),
  1453. edge.width = E(g)$transformed_percentile * 5, # Scale edge width
  1454. edge.arrow.size = 0.5,
  1455. vertex.size = 15,
  1456. vertex.label.cex = 2,
  1457. vertex.color = V(g)$color,
  1458. edge.color = E(g)$color,
  1459. main = "Interaction Network")
  1460. interaction_matrix_pair=count[which(kmeans_result$cluster==4),]
  1461. # Convert the interaction matrix to a data frame of connection counts
  1462. interaction_counts_v2 <- interaction_matrix_pair %>%
  1463. summarise_all(sum) %>% # Sum the connections for each ligand-receptor pair
  1464. pivot_longer(everything(), names_to = "ligand_receptor", values_to = "count") %>%
  1465. separate(ligand_receptor, into = c("ligand", "receptor"), sep = "_") %>%
  1466. filter(count > 0) # Optional: filter out pairs with zero connections
  1467. # Assuming cell types are somehow encoded or need to be mapped:
  1468. # You will need additional data or logic to map ligands and receptors to specific cell types
  1469. # if you want to incorporate 'cell_type_ligands' and 'cell_type_receptors'
  1470. # For now, this code simply summarizes counts of connections for each ligand-receptor pair
  1471. # Optionally, add percentile transformation if needed:
  1472. interaction_counts_v2 <- interaction_counts_v2 %>%
  1473. mutate(transformed_percentile = log10(count + 1))
  1474. #---------------------------------------------
  1475. # Top ligands and receptor (n=5)
  1476. top_5_interaction_counts <- interaction_counts_v2 %>%
  1477. slice_max(order_by = count, n = 5)
  1478. # Create a graph from the interaction data
  1479. g <- graph_from_data_frame(top_5_interaction_counts, directed = TRUE)
  1480. # Create a color palette
  1481. # Create a large color palette
  1482. color_palette_large <- c(brewer.pal(8, "Set1"), # Red, blue, green, etc.
  1483. brewer.pal(8, "Set2"), # Lighter and diverse colors
  1484. brewer.pal(8, "Set3"), # Mixed colors
  1485. brewer.pal(8, "Dark2"), # Dark colors
  1486. brewer.pal(8, "Pastel1"), # Pastel colors
  1487. brewer.pal(8, "Pastel2"), # More pastel colors
  1488. "red", "green", "blue", "orange", "purple", "cyan", "magenta") # Specific colors
  1489. # Function to get a specific number of random colors from the palette
  1490. get_random_colors <- function(number_of_colors) {
  1491. if (number_of_colors > length(color_palette_large)) {
  1492. stop("Requested number of colors exceeds the prepared palette size.")
  1493. }
  1494. sample(color_palette_large, number_of_colors)
  1495. }
  1496. unique_types <- unique(c(data_final$TACIT_Ligands, data_final$TACIT_Receptors))
  1497. # Example usage: Get 10 random colors
  1498. n <- length(unique_types) # Assume you have 10 types this time
  1499. color_palette <- get_random_colors(n)
  1500. names(color_palette) <- unique_types
  1501. # Assign colors to vertices based on cell type
  1502. V(g)$color <- color_palette[V(g)$name]
  1503. # Assign colors to edges based on interaction strength
  1504. # Use a continuous color scale or manually define breaks for clarity
  1505. E(g)$color <- ifelse(E(g)$transformed_percentile > median(E(g)$transformed_percentile, na.rm = TRUE), "grey90", "grey90")
  1506. #---------------------------------------------
  1507. # Graph cell type between ligands and receptors
  1508. # Plotting
  1509. plot(g, layout = layout_in_circle(g),
  1510. edge.width = E(g)$transformed_percentile * 5, # Scale edge width
  1511. edge.arrow.size = 0.1,
  1512. vertex.size = 15,
  1513. vertex.label.cex = 0.8,
  1514. vertex.color = V(g)$color,
  1515. edge.color = E(g)$color,
  1516. main = "Top ligands and receptors")
  1517. TACIT_Ligands=data1$TACIT[interaction_matrix$cell_id]
  1518. TACIT_Receptors=data1$TACIT[interaction_matrix$Neighbor_ID]
  1519. data_plot=data.frame(TACIT_Ligands,TACIT_Receptors,count)
  1520. # Function to calculate top interactions for each cell type
  1521. get_top_interactions <- function(cell_type, data_plot, top_n = 40) {
  1522. filtered_data <- data_plot %>%
  1523. filter(TACIT_Ligands == cell_type)
  1524. interaction_sums <- colSums(filtered_data[,-c(1,2)])
  1525. top_interactions <- sort(interaction_sums, decreasing = TRUE)[1:top_n]
  1526. top_df <- data.frame(
  1527. Interaction = names(top_interactions),
  1528. Count = as.numeric(top_interactions),
  1529. CellType = cell_type
  1530. )
  1531. return(top_df)
  1532. }
  1533. # Calculate top interactions for each cell type
  1534. cell_types <- unique(data_plot$TACIT_Ligands)
  1535. top_interactions_list <- lapply(cell_types, get_top_interactions, data_plot = data_plot)
  1536. top_interactions_df <- do.call(rbind, top_interactions_list)
  1537. # Plot the top interactions using ggplot2
  1538. ggplot(top_interactions_df, aes(x = reorder(Interaction, -Count), y = Count, fill = CellType)) +
  1539. geom_bar(stat = "identity", position = "dodge") +
  1540. labs(
  1541. title = "Top Interactions for Each Cell Type",
  1542. x = "Interaction",
  1543. y = "Count"
  1544. ) +
  1545. theme_minimal() +
  1546. theme(
  1547. plot.title = element_text(hjust = 0.5),
  1548. axis.title = element_text(face = "bold"),
  1549. axis.text.x = element_text(angle = 45, hjust = 1)
  1550. ) +
  1551. scale_fill_manual(values = user_colors) # Customize colors as needed
  1552. # Convert to wide format for heatmap
  1553. heatmap_data <- dcast(top_interactions_df, Interaction ~ CellType, value.var = "Count", fill = 0)
  1554. rownames(heatmap_data) <- heatmap_data$Interaction
  1555. heatmap_matrix <- as.matrix(heatmap_data[,-1])
  1556. # Plot heatmap using pheatmap
  1557. library(pheatmap)
  1558. pheatmap(heatmap_matrix[which(rowSums(heatmap_matrix)>0),],
  1559. main = "Heatmap of Top Interactions for Each Cell Type",
  1560. cluster_rows = TRUE,
  1561. cluster_cols = TRUE,scale="row")
  1562. data_plot=data.frame(Cluster=data_final$Cluster,X_cell=data_final$X_cell,Y_cell=data_final$Y_cell,
  1563. X_neighbor=data_final$X_neighbor,Y_neighbor=data_final$Y_neighbor,data_final[,colnames(count)])
  1564. # Define colors
  1565. user_colors2 <- c("0" = "grey90", "1" = "red")
  1566. library(dplyr)
  1567. # Loop through each cluster and generate the plot
  1568. for (cluster in unique(data_plot$Cluster)) {
  1569. # Subset data for the specific cluster
  1570. data_final_sub <- data_plot %>% filter(Cluster == cluster)
  1571. # Calculate the sums of the columns and select the top 6
  1572. column_sums <- colSums(data_final_sub[, colnames(count)])
  1573. top_columns <- names(sort(column_sums, decreasing = TRUE))[1:6]
  1574. data_final_sub=as.data.frame(data_final_sub)
  1575. melted_data=data_final_sub[,c("Cluster", "X_cell", "Y_cell", "X_neighbor", "Y_neighbor",top_columns)]
  1576. # Melt the data for ggplot
  1577. melted_data <- melted_data%>%
  1578. pivot_longer(cols = top_columns, names_to = "Gene", values_to = "Value")
  1579. # Generate the plot
  1580. p <- ggplot(melted_data) +
  1581. geom_segment(aes(x = X_cell, y = Y_cell, xend = X_neighbor, yend = Y_neighbor, color = as.factor(Value)),
  1582. na.rm = TRUE, size = 0.1) +
  1583. facet_wrap(~ Gene) +
  1584. theme_classic(base_size = 15) +
  1585. scale_color_manual(values = user_colors2) +
  1586. labs(x = "X", y = "Y", title = paste("Cluster", cluster)) +
  1587. guides(color = guide_legend(override.aes = list(size = 3), title = "Value"))
  1588. # Save the plot to a file
  1589. ggsave(filename = paste0("cluster_xenium/","cluster_top_", cluster, ".png"), plot = p, width = 14, height = 8)
  1590. }
  1591. # Load necessary libraries
  1592. library(dplyr)
  1593. library(tidyr)
  1594. library(circlize)
  1595. library(pheatmap)
  1596. # Create the data_plot data frame
  1597. data_plot <- data.frame(TACIT_Ligands, TACIT_Receptors, Cluster = data_final$Cluster, data_final[, colnames(count)])
  1598. # Generate a proportion table for heatmap
  1599. proportion_table <- prop.table(table(data_plot$TACIT_Receptors, data_plot$Cluster), margin = 2)
  1600. pheatmap(proportion_table, scale = "row")
  1601. # Filter the data for Cluster 17
  1602. data_plot <- data_plot %>% filter(Cluster == 17)
  1603. final_results_sub <- top5 %>% filter(cluster == 17)
  1604. # Select the ligand-receptor columns
  1605. ligand_receptor_columns <- final_results_sub$gene
  1606. filtered_data <- data_plot
  1607. # Gather the ligand-receptor pairs and calculate their frequency
  1608. ligand_receptor_pairs <- filtered_data[,ligand_receptor_columns] %>%
  1609. summarise(across(everything(), sum)) %>%
  1610. pivot_longer(cols = everything(), names_to = "Ligand_Receptor", values_to = "Frequency") %>%
  1611. arrange(desc(Frequency))
  1612. # Select the top 10 ligand-receptor pairs
  1613. top10_ligand_receptor_pairs <- head(ligand_receptor_pairs, 10)
  1614. # Prepare data for circos plot
  1615. circos_data <- filtered_data %>%
  1616. gather(key = "Ligand_Receptor", value = "Value", -TACIT_Ligands, -TACIT_Receptors) %>%
  1617. filter(Value > 0 & Ligand_Receptor != "Cluster")
  1618. # Summarize the number of connections for each ligand-receptor pair between cell types
  1619. summarized_connections <- circos_data %>%
  1620. group_by(TACIT_Ligands, TACIT_Receptors, Ligand_Receptor) %>%
  1621. summarise(Value = sum(Value), .groups = 'drop') %>%
  1622. filter(Ligand_Receptor %in% top10_ligand_receptor_pairs$Ligand_Receptor) %>%
  1623. group_by(Ligand_Receptor) %>%
  1624. mutate(Proportion = Value / sum(Value)) %>%
  1625. ungroup()
  1626. # Keep only the top 5 connections for each Ligand_Receptor
  1627. summarized_connections <- summarized_connections %>%
  1628. group_by(Ligand_Receptor) %>%
  1629. slice_max(order_by = Value, n = 10) %>%
  1630. ungroup()
  1631. summarized_connections <- summarized_connections %>%
  1632. group_by(TACIT_Ligands) %>%
  1633. mutate(Total_Value_Ligands = sum(Value)) %>%
  1634. ungroup() %>%
  1635. mutate(Proportion_from_TACIT_Ligands = Value / Total_Value_Ligands)
  1636. summarized_connections <- summarized_connections %>%
  1637. group_by(TACIT_Receptors) %>%
  1638. mutate(Total_Value_Receptors = sum(Value)) %>%
  1639. ungroup() %>%
  1640. mutate(Proportion_from_TACIT_Receptors = Value / Total_Value_Receptors)
  1641. top_cell_types=data.frame(TACIT_Ligands=names(table((c(summarized_connections$TACIT_Ligands, summarized_connections$TACIT_Receptors)))),
  1642. count=as.numeric((table((c(summarized_connections$TACIT_Ligands, summarized_connections$TACIT_Receptors))))),
  1643. proportion=as.numeric((table((c(summarized_connections$TACIT_Ligands, summarized_connections$TACIT_Receptors)))))/sum(as.numeric((table((c(summarized_connections$TACIT_Ligands, summarized_connections$TACIT_Receptors)))))))
  1644. # Reassign cell types with proportions less than 0.02 to "Other"
  1645. top_cell_types$TACIT_Ligands[top_cell_types$proportion < 0.05] <- "Other"
  1646. # Sum up the counts and proportions for "Other"
  1647. other_count <- sum(top_cell_types$count[top_cell_types$TACIT_Ligands == "Other"])
  1648. other_proportion <- sum(top_cell_types$proportion[top_cell_types$TACIT_Ligands == "Other"])
  1649. # Remove individual rows with "Other" and add a single row
  1650. top_cell_types <- top_cell_types %>%
  1651. filter(TACIT_Ligands != "Other") %>%
  1652. bind_rows(tibble(TACIT_Ligands = "Other", count = other_count, proportion = other_proportion))
  1653. summarized_connections$TACIT_Ligands=ifelse(summarized_connections$TACIT_Ligands%in%top_cell_types$TACIT_Ligands,summarized_connections$TACIT_Ligands,"Other")
  1654. summarized_connections$TACIT_Receptors=ifelse(summarized_connections$TACIT_Receptors%in%top_cell_types$TACIT_Ligands,summarized_connections$TACIT_Receptors,"Other")
  1655. # Prepare the sector widths for circos plot
  1656. sector_widths <- top_cell_types %>%
  1657. mutate(sector = TACIT_Ligands)
  1658. # Initialize circos plot with sectors and their widths
  1659. circos.clear()
  1660. circos.par(gap.degree = 2)
  1661. circos.initialize(factors = sector_widths$TACIT_Ligands, xlim = c(0, 1), sector.width = sector_widths$proportion)
  1662. # Add segments for cell types with background colors to form a circle
  1663. circos.trackPlotRegion(ylim = c(0, 1), track.height = 0.1, bg.border = "black", bg.col = user_colors[sector_widths$TACIT_Ligands], panel.fun = function(x, y) {
  1664. circos.text(CELL_META$xcenter, CELL_META$ylim[1] + 0.5, CELL_META$sector.index, cex = 0.8, facing = "clockwise")
  1665. })
  1666. # Create a unique color for each ligand-receptor pair
  1667. ligand_receptor_colors <- setNames(rainbow(length(unique(summarized_connections$Ligand_Receptor))),
  1668. unique(summarized_connections$Ligand_Receptor))
  1669. # Draw the links between TACIT_Ligands and TACIT_Receptors
  1670. unique_ligands <- unique(summarized_connections$TACIT_Ligands)
  1671. for (ligand in unique_ligands) {
  1672. ligand_data <- summarized_connections %>% filter(TACIT_Ligands == ligand)
  1673. for (i in 1:nrow(ligand_data)) {
  1674. receptor <- ligand_data$TACIT_Receptors[i]
  1675. lig_rec <- ligand_data$Ligand_Receptor[i]
  1676. color <- ligand_receptor_colors[lig_rec]
  1677. width_L <- ligand_data$Proportion[i] / sum(ligand_data$Proportion)
  1678. receptor_data <- summarized_connections %>% filter(TACIT_Receptors == receptor)
  1679. width_R <- ligand_data$Proportion[i] / sum(receptor_data$Proportion)
  1680. circos.link(sector.index1 = ligand_data$TACIT_Ligands[i],
  1681. point1 = c((i-1)/nrow(ligand_data), i/nrow(ligand_data)),
  1682. sector.index2 = ligand_data$TACIT_Receptors[i],
  1683. point2 = c((i-1)/nrow(ligand_data), i/nrow(ligand_data)),
  1684. col = color, directional = 1)
  1685. }
  1686. }
  1687. # Add a legend
  1688. legend("topright", legend = names(ligand_receptor_colors), col = as.character(ligand_receptor_colors), pch = 19)
  1689. # Add a title
  1690. title(main = "Chord Diagram of Ligand-Receptor Interactions in Cluster 17")
  1691. TACIT_Ligands=data1$TACIT[data_final$cell_id]
  1692. TACIT_Receptors=data1$TACIT[data_final$Neighbor_ID]
  1693. # Load necessary libraries
  1694. library(dplyr)
  1695. library(tidyr)
  1696. library(circlize)
  1697. library(pheatmap)
  1698. library(ggplot2)
  1699. # Define a function to generate and save chord diagrams for each cluster
  1700. generate_chord_diagram <- function(cluster_id) {
  1701. # Filter the data for the current cluster
  1702. data_plot <- data.frame(TACIT_Ligands, TACIT_Receptors, Cluster = data_final$Cluster, data_final[, colnames(count)])
  1703. data_plot <- data_plot %>% filter(Cluster == cluster_id)
  1704. final_results_sub <- top5 %>% filter(cluster == cluster_id)
  1705. # Select the ligand-receptor columns
  1706. ligand_receptor_columns <- final_results_sub$gene
  1707. filtered_data <- data_plot
  1708. # Gather the ligand-receptor pairs and calculate their frequency
  1709. ligand_receptor_pairs <- filtered_data[,ligand_receptor_columns] %>%
  1710. summarise(across(everything(), sum)) %>%
  1711. pivot_longer(cols = everything(), names_to = "Ligand_Receptor", values_to = "Frequency") %>%
  1712. arrange(desc(Frequency))
  1713. # Select the top 10 ligand-receptor pairs
  1714. top10_ligand_receptor_pairs <- head(ligand_receptor_pairs, 5)
  1715. # Prepare data for circos plot
  1716. circos_data <- filtered_data %>%
  1717. gather(key = "Ligand_Receptor", value = "Value", -TACIT_Ligands, -TACIT_Receptors) %>%
  1718. filter(Value > 0 & Ligand_Receptor != "Cluster")
  1719. # Summarize the number of connections for each ligand-receptor pair between cell types
  1720. summarized_connections <- circos_data %>%
  1721. group_by(TACIT_Ligands, TACIT_Receptors, Ligand_Receptor) %>%
  1722. summarise(Value = sum(Value), .groups = 'drop') %>%
  1723. filter(Ligand_Receptor %in% top10_ligand_receptor_pairs$Ligand_Receptor) %>%
  1724. group_by(Ligand_Receptor) %>%
  1725. mutate(Proportion = Value / sum(Value)) %>%
  1726. ungroup()
  1727. # Keep only the top 5 connections for each Ligand_Receptor
  1728. summarized_connections <- summarized_connections %>%
  1729. group_by(Ligand_Receptor) %>%
  1730. slice_max(order_by = Value, n = 5) %>%
  1731. ungroup()
  1732. # Calculate proportions
  1733. summarized_connections <- summarized_connections %>%
  1734. group_by(TACIT_Ligands) %>%
  1735. mutate(Total_Value_Ligands = sum(Value)) %>%
  1736. ungroup() %>%
  1737. mutate(Proportion_from_TACIT_Ligands = Value / Total_Value_Ligands)
  1738. summarized_connections <- summarized_connections %>%
  1739. group_by(TACIT_Receptors) %>%
  1740. mutate(Total_Value_Receptors = sum(Value)) %>%
  1741. ungroup() %>%
  1742. mutate(Proportion_from_TACIT_Receptors = Value / Total_Value_Receptors)
  1743. top_cell_types <- data.frame(
  1744. TACIT_Ligands = names(table((c(summarized_connections$TACIT_Ligands, summarized_connections$TACIT_Receptors)))),
  1745. count = as.numeric((table((c(summarized_connections$TACIT_Ligands, summarized_connections$TACIT_Receptors))))),
  1746. proportion = as.numeric((table((c(summarized_connections$TACIT_Ligands, summarized_connections$TACIT_Receptors)))))/sum(as.numeric((table((c(summarized_connections$TACIT_Ligands, summarized_connections$TACIT_Receptors))))))
  1747. )
  1748. # Reassign cell types with proportions less than 0.02 to "Other"
  1749. top_cell_types$TACIT_Ligands[top_cell_types$proportion < 0.05] <- "Other"
  1750. # Sum up the counts and proportions for "Other"
  1751. other_count <- sum(top_cell_types$count[top_cell_types$TACIT_Ligands == "Other"])
  1752. other_proportion <- sum(top_cell_types$proportion[top_cell_types$TACIT_Ligands == "Other"])
  1753. # Remove individual rows with "Other" and add a single row
  1754. top_cell_types <- top_cell_types %>%
  1755. filter(TACIT_Ligands != "Other") %>%
  1756. bind_rows(tibble(TACIT_Ligands = "Other", count = other_count, proportion = other_proportion))
  1757. top_cell_types=top_cell_types[which(top_cell_types$proportion>0),]
  1758. summarized_connections$TACIT_Ligands <- ifelse(summarized_connections$TACIT_Ligands %in% top_cell_types$TACIT_Ligands, summarized_connections$TACIT_Ligands, "Other")
  1759. summarized_connections$TACIT_Receptors <- ifelse(summarized_connections$TACIT_Receptors %in% top_cell_types$TACIT_Ligands, summarized_connections$TACIT_Receptors, "Other")
  1760. # Prepare the sector widths for circos plot
  1761. sector_widths <- top_cell_types %>%
  1762. mutate(sector = TACIT_Ligands)
  1763. # file_name <- paste0("cluster_xenium/Chord_Diagram_Cluster_", cluster_id, ".png")
  1764. pdf(file = paste0("TACIT_annotate_MERSCOPE/Gingiva_Fibroblast/Chord_Diagram_Cluster_", cluster_id, ".pdf"), width = 8, height = 6)
  1765. # Initialize circos plot with sectors and their widths
  1766. circos.clear()
  1767. circos.par(gap.degree = 2)
  1768. circos.initialize(factors = sector_widths$TACIT_Ligands, xlim = c(0, 1), sector.width = sector_widths$proportion)
  1769. # Add segments for cell types with background colors to form a circle
  1770. circos.trackPlotRegion(ylim = c(0, 1), track.height = 0.1, bg.border = "black", bg.col = user_colors[sector_widths$TACIT_Ligands], panel.fun = function(x, y) {
  1771. circos.text(CELL_META$xcenter, CELL_META$ylim[1] + 0.5, CELL_META$sector.index, cex = 0.8, facing = "clockwise")
  1772. })
  1773. # Create a unique color for each ligand-receptor pair
  1774. ligand_receptor_colors <- setNames(rainbow(length(unique(summarized_connections$Ligand_Receptor))),
  1775. unique(summarized_connections$Ligand_Receptor))
  1776. # Draw the links between TACIT_Ligands and TACIT_Receptors
  1777. unique_ligands <- unique(summarized_connections$TACIT_Ligands)
  1778. for (ligand in unique_ligands) {
  1779. ligand_data <- summarized_connections %>% filter(TACIT_Ligands == ligand)
  1780. for (i in 1:nrow(ligand_data)) {
  1781. receptor <- ligand_data$TACIT_Receptors[i]
  1782. lig_rec <- ligand_data$Ligand_Receptor[i]
  1783. color <- ligand_receptor_colors[lig_rec]
  1784. width_L <- ligand_data$Proportion[i] / sum(ligand_data$Proportion)
  1785. receptor_data <- summarized_connections %>% filter(TACIT_Receptors == receptor)
  1786. width_R <- ligand_data$Proportion[i] / sum(receptor_data$Proportion)
  1787. circos.link(sector.index1 = ligand_data$TACIT_Ligands[i],
  1788. point1 = c((i-1)/nrow(ligand_data), i/nrow(ligand_data)),
  1789. sector.index2 = ligand_data$TACIT_Receptors[i],
  1790. point2 = c((i-1)/nrow(ligand_data), i/nrow(ligand_data)),
  1791. col = color, directional = 1)
  1792. }
  1793. }
  1794. # Add a legend
  1795. legend("topright", legend = names(ligand_receptor_colors), col = as.character(ligand_receptor_colors), pch = 19)
  1796. # Add a title
  1797. title(main = paste("Chord Diagram of Ligand-Receptor Interactions in Cluster", cluster_id))
  1798. # Save the plot
  1799. dev.off()
  1800. }
  1801. # Get all unique clusters
  1802. all_clusters <- unique(data_final$Cluster)
  1803. # Loop over all clusters and generate the chord diagrams
  1804. for (cluster_id in all_clusters[2:20]) {
  1805. generate_chord_diagram(cluster_id)
  1806. }
  1807. data_final_sub=data_final[which(data_final$TACIT_Ligands%in%c("T Cell Progenitors")|
  1808. data_final$TACIT_Receptors%in%c("T Cell Progenitors")),]
  1809. ggplot() +
  1810. geom_point(data = data_final_sub,size = 0.1,aes(x=X_cell,Y_cell,color=TACIT_Ligands))+
  1811. geom_point(data = data_final_sub,size = 0.1,aes(x=X_neighbor,Y_neighbor,color=TACIT_Receptors))+
  1812. geom_segment(data = data_final_sub, aes(x = X_cell, y = Y_cell, xend = X_neighbor, yend = Y_neighbor,color = as.factor(t(data_final_sub$Cluster))), na.rm = TRUE,size=0.1) +
  1813. theme_classic(base_size = 15)+
  1814. scale_color_manual(values = user_colors) +
  1815. labs(x = "X", y = "Y", title = "") + guides(color = guide_legend(override.aes = list(size = 3),title = "Cluster"))
  1816. data_cluster=data.frame(grid_id=density_list_final$grid_id,Cluster=kmeans_result$cluster)
  1817. data_cluster=data_cluster[unique(data_cluster$grid_id),]
  1818. data_final_sub=merge(data_cluster,data1_sub_plot,"grid_id")
  1819. data_final_sub=data_final_sub[unique(data_final_sub$ID),]
  1820. data_final_sub=data_final_sub[,c("ID","Cluster","grid_id")]
  1821. interaction_matrix$ID=1:nrow(interaction_matrix)
  1822. data_final=merge(data_final_sub,interaction_matrix,"ID")
  1823. data_final$Group=data1$Group[data_final$cell_id]
  1824. data_final=data_final[which(data_final$Cluster==11),]
  1825. data_final$Group2=ifelse(data_final$Group%in%c("Tongue12","Tongue62","MSG8","MSG9",
  1826. "Gingiva2","Parotid39","Submandibular53_56")&data_final$Cluster=="11","11_high_density",data_final$Cluster)
  1827. library(dplyr)
  1828. # Load necessary library
  1829. library(dplyr)
  1830. # Identify gene-related columns (all columns that contain an underscore)
  1831. gene_columns <- grep("_", names(data_final), value = TRUE)
  1832. # Check for and exclude 'grid_id' from gene columns if mistakenly included
  1833. gene_columns <- setdiff(gene_columns, "grid_id")
  1834. # Summarize data by grid_id: sum gene-related columns and handle Group2
  1835. summarized_data <- data_final %>%
  1836. group_by(grid_id) %>%
  1837. summarise(
  1838. across(all_of(gene_columns), sum, na.rm = TRUE), # Sum gene-related columns
  1839. Group2 = ifelse(length(unique(Group2)) == 1, unique(Group2), first(Group2)) # Handle non-unique Group2
  1840. )
  1841. # Print the summarized data
  1842. print(summarized_data)
  1843. # Print the summarized data
  1844. print(summarized_data)
  1845. library(dplyr)
  1846. # Group the data by the predicted label and calculate the mean for each column
  1847. data_plot=data.frame(TACIT=summarized_data$Group2,summarized_data[,c(4:54)])
  1848. mean_values_TACIT <- data_plot %>%
  1849. group_by(TACIT) %>%
  1850. summarise_all(~quantile(., 0.999))
  1851. # mean_values_TACIT[ , -1][mean_values_TACIT[ , -1] > 0] <- 1
  1852. mean_values_TACIT=as.data.frame(mean_values_TACIT)
  1853. rownames(mean_values_TACIT)=mean_values_TACIT$TACIT
  1854. mean_values_TACIT <- as.data.frame((mean_values_TACIT[,-1]))
  1855. my.breaks <- c(seq(-2, 0, by=0.1),seq(0.1, 2, by=0.1))
  1856. my.colors <- c(colorRampPalette(colors = c("blue", "white"))(length(my.breaks)/2), colorRampPalette(colors = c("white", "red"))(length(my.breaks)/2))
  1857. aa=scale(mean_values_TACIT)
  1858. aa <- as.data.frame(aa)
  1859. aa <- aa %>%
  1860. select_if(~ !all(is.na(.)))
  1861. # Custom color palette from blue to white to red
  1862. color_palette <- colorRampPalette(c("blue", "white", "red"))(100)
  1863. # Define breaks for the color scale
  1864. breaks <- seq(-3, 3, length.out = 101) # Adjust to match your data range
  1865. library(pheatmap)
  1866. aa=aa[c(3,4),]
  1867. pheatmap(aa,
  1868. cluster_cols = T,
  1869. cluster_rows = T,
  1870. show_colnames = TRUE,
  1871. fontsize_col = 15,
  1872. fontsize_row = 15,clustering_method="ward.D2",color = my.colors,breaks = my.breaks)
  1873. library(umap)
  1874. library(ggplot2)
  1875. # Run UMAP
  1876. umap_result <- umap(data_plot[,-1], n_neighbors = 15, min_dist = 0.1, metric = "euclidean")
  1877. # Convert UMAP result to a data frame
  1878. umap_df <- as.data.frame(umap_result$layout)
  1879. colnames(umap_df) <- c("UMAP1", "UMAP2")
  1880. # Add additional information, e.g., Group2
  1881. umap_df$Group2 <- data_final$Group2
  1882. data_plot=data.frame(Group=data_final$GroupMG,TACIT_Ligands=data_final$TACIT_Ligands,
  1883. TACIT_Receptors=data_final$TACIT_Receptors,Cluster=data_final$Cluster)
  1884. data_plot_subset=data_plot[which(data_plot$Group=="BuccalMucosa"),-1]
  1885. data_combined <- data_plot_subset %>%
  1886. pivot_longer(cols = c(TACIT_Ligands, TACIT_Receptors), names_to = "Type", values_to = "Cell_Type") %>%
  1887. group_by(Cluster, Cell_Type) %>%
  1888. summarise(Count = n(), .groups = 'drop')
  1889. # Calculate the proportion of each cell type within each cluster
  1890. data_prop <- data_combined %>%
  1891. group_by(Cluster) %>%
  1892. mutate(Proportion = Count / sum(Count)) %>%
  1893. ungroup()
  1894. data_prop=data_prop[,-3]
  1895. data_matrix <- data_prop %>%
  1896. pivot_wider(names_from = Cell_Type, values_from = Proportion, values_fill = list(Proportion = 0))
  1897. data_matrix=as.data.frame(data_matrix)
  1898. # Set row names to clusters for the heatmap
  1899. rownames(data_matrix) <- data_matrix$Cluster
  1900. data_matrix <- data_matrix %>% select(-Cluster) # Remove Cluster column after setting row names
  1901. data_matrix=data_matrix[,-1]
  1902. color_palette <- colorRampPalette(c("blue", "white", "red"))(100)
  1903. # Define breaks for the color scale
  1904. breaks <- seq(-2, 2, length.out = 101) # Adjust to match your data range
  1905. pheatmap(as.matrix(data_matrix),
  1906. cluster_rows = F,
  1907. cluster_cols = TRUE,
  1908. main = "Heatmap of Cell Type Proportions by BuccalMucosa",
  1909. border_color = NA,
  1910. scale = "row",color = color_palette,breaks = breaks) # Adjust scale if necessary
  1911. # Get unique groups
  1912. groups <- unique(data_plot$Group)
  1913. # Loop through each group to generate the heatmap
  1914. for (group in groups) {
  1915. # Subset the data for the current group
  1916. data_plot_subset <- data_plot[data_plot$Group == group, ]
  1917. data_plot_subset <- data_plot_subset[ , !(names(data_plot_subset) %in% "Group")] # Remove the 'Group' column
  1918. # Combine TACIT_Ligands and TACIT_Receptors into one column 'Cell_Type'
  1919. data_combined <- data_plot_subset %>%
  1920. pivot_longer(cols = c(TACIT_Ligands, TACIT_Receptors), names_to = "Type", values_to = "Cell_Type") %>%
  1921. group_by(Cluster, Cell_Type) %>%
  1922. summarise(Count = n(), .groups = 'drop')
  1923. # Calculate the proportion of each cell type within each cluster
  1924. data_prop <- data_combined %>%
  1925. group_by(Cluster) %>%
  1926. mutate(Proportion = Count / sum(Count)) %>%
  1927. ungroup()
  1928. # Remove the 'Count' column using base R
  1929. data_prop <- data_prop[ , !(names(data_prop) %in% "Count")]
  1930. # Pivot to create a matrix format for the heatmap
  1931. data_matrix <- data_prop %>%
  1932. pivot_wider(names_from = Cell_Type, values_from = Proportion, values_fill = list(Proportion = 0))
  1933. # Convert to data frame and set row names
  1934. data_matrix <- as.data.frame(data_matrix)
  1935. rownames(data_matrix) <- data_matrix$Cluster
  1936. data_matrix <- data_matrix[ , !(names(data_matrix) %in% "Cluster")] # Remove Cluster column after setting row names
  1937. # Define color palette and breaks for the heatmap
  1938. color_palette <- colorRampPalette(c("blue", "white", "red"))(100)
  1939. breaks <- seq(-2, 2, length.out = 101) # Adjust to match your data range
  1940. # Set the file name for the heatmap SVG output
  1941. heatmap_filename <- paste0("C:/Users/huynhk4/Downloads/OCF_MERSCOPE_0409/Healthy/Heatmap_of_Cell_Type_Proportions_", group, ".svg")
  1942. # Open SVG device
  1943. svg(filename = heatmap_filename, width = 8, height = 6)
  1944. # Plot heatmap
  1945. pheatmap(as.matrix(data_matrix),
  1946. cluster_rows = FALSE,
  1947. cluster_cols = TRUE,
  1948. main = paste("Heatmap of Cell Type Proportions by", group),
  1949. border_color = NA,
  1950. scale = "row", # Adjust scale if necessary
  1951. color = color_palette,
  1952. breaks = breaks)
  1953. # Close SVG device
  1954. dev.off()
  1955. }

healthy vs disease.R at commit e9e3866, no license · at the source

Overview

Authors: Bruno F. Matuck1,2, Khoa L.A. Huynh3,2, Diana Pereira4,2, Quinn T. Easter1, XiuYu Zhang3, Meik Kunz5, Nikhil Kumar6, Aditya Pratapa7, Brittany T. Rupp1, Ameer Ghodke8, Alexander V. Predeus9, Alexandre Fernandes4, Lili Szabó10,11, Stefan Hartmann12, Nadja Harnischfeger10,11, Zohreh Khavandgar13,14, Margaret Beach13,14, Paola Perez13, Benedikt Nilges15, Maria M. Moreno15
and 11 other authorsKang I. Ko16, Rohit Singh7, Purushothama Rao Tata7, Sarah A. Teichmann17,18, Adam Kimple8,19, Sarah Pringle20, Kai Kretzschmar10,11, Blake M. Warner13,14, Inês Sequeira4,21, Jinze Liu3,22,21, Kevin M. Byrd1,6,22,21,23
23 affiliations
  1. Department of Oral and Craniofacial Molecular Biology, Philips Institute for Oral Health Research, Virginia Commonwealth University, Richmond, VA, USA
  2. These authors contributed equally
  3. Department of Biostatistics, Virginia Commonwealth University, Richmond, VA, USA
  4. Center for Oral Immunobiology and Regenerative Medicine, Barts Centre for Squamous Cancer, Institute of Dentistry, Barts and the London School of Medicine and Dentistry, Queen Mary University of London, London, UK
  5. The Bioinformatics CRO, Sanford, FL, USA
  6. Division of Oral and Craniofacial Health Sciences, Adams School of Dentistry, University of North Carolina at Chapel Hill, Chapel Hill, NC, USA
  7. Department of Cell Biology, Duke University, Durham, NC, USA
  8. Department of Otolaryngology-Head and Neck Surgery, University of North Carolina School of Medicine, Chapel Hill, NC, USA
  9. Wellcome Sanger Institute, Wellcome Genome Campus, Hinxton, Cambridge, UK
  10. Mildred-Scheel Early Career Centre (MSNZ) for Cancer Research, University Hospital Wuerzburg, Wuerzburg, Germany
  11. Department of Biochemistry and Molecular Biology, Biocenter, University of Wuerzburg, Wuerzburg, Germany
  12. Department of Oral and Maxillofacial Plastic Surgery, University Hospital Würzburg, Würzburg, Germany
  13. Sjögren’s Clinical Investigations Team, National Institutes of Dental and Craniofacial Research, Bethesda, MD, USA
  14. Salivary Disorders Unit, National Institutes of Dental and Craniofacial Research, Bethesda, MD, USA
  15. OMAPiX, Inc, Leuven, Belgium
  16. Department of Periodontics, School of Dental Medicine, University of Pennsylvania, Philadelphia, PA 19104, USA
  17. Cambridge Stem Cell Institute, Jeffrey Cheah Biomedical Centre, Cambridge Biomedical Campus, University of Cambridge, Cambridge, UK
  18. Department of Medicine, University of Cambridge, Cambridge, UK
  19. Marsico Lung Institute, University of North Carolina at Chapel Hill, Chapel Hill, NC, USA
  20. University of Groningen and University Medical Center, Groningen, the Netherlands
  21. Senior author
  22. VCU Massey Comprehensive Cancer Center, Bioinformatics Shared Resource Core, Virginia Commonwealth University, Richmond, VA, USA
  23. Lead contact
Journal: Cell press blue, volume 1, issue 1, article 100007
Dates: published online 1 April 2026; in print 20 April 2026
Type: Research article · Language: English
License: CC BY-NC-ND
Identifiers: DOI 10.1016/j.cpblue.2026.100007 · PMID 42147490 · PMCID PMC13179517 · OpenAlex W7140104135
Open access: hybrid, a free copy (OpenAlex)
Status: code verified
Categories: human (organism)
Methods: Statistics, Smoothing, state filtering, decompositions, Machine learning, Connectivity
Topic: Single-cell and spatial transcriptomics (Molecular Biology, Biochemistry, Genetics and Molecular Biology), according to OpenAlex
Funding: European Research Council (101042738 /OralNiche, 101042738); National Heart Lung and Blood Institute (R01HL153375, R01HL146557, R01HL160939); Intramural NIH HHS (Z01 DE000704); NCI NIH HHS (P30 CA016059); British Skin Foundation (004/RA/23); Interdisziplinäres Zentrum für Klinische Forschung, Universitätsklinikum Würzburg (Z-6); National Institute of Dental and Craniofacial Research (DE000704, CA016059); Barts Charity (G-001524); Fundação para a Ciência e a Tecnologia (MGU045, 2020.08715); NHLBI NIH HHS (R01 HL160939, R01 HL146557, R01 HL153375); NIDCR NIH HHS (RM1 DE035338); Deutsche Krebshilfe (MSNZ W\u00FCrzburg/NG3); National Institutes of Health; Royal Society (RGS/R2/202291); Julius-Maximilians-Universität Würzburg
Citations: cited by 5 papers (Europe PMC); 70 references in the paper

Abstract

The abstract is not reproduced here: the paper's license (CC BY-NC-ND) does not allow it. Read it in the paper, at the publisher or on Europe PMC.

Repositories

Its files are read in the Code ↔ Paper reader above, with 11 matches between paragraphs and lines of code.

cellgeni/reprocess_public_10x

License: GPL-3.0
State: the link answers, verified on 28 September 2026
Evidence: files inventoried
Commit: 500df21db8c0827746773e31f2e1a111f1300f4b, 13 May 2026
Languages: Shell (21)
Size: 81 files, 21 scripts
Software Heritage: not archived
Found in: the text, “Published scRNA-seq harmonization”
Holds: README, license file, environment (Dockerfile), tests, continuous integration
Not found: CITATION.cff, documentation
Availability: 1 check, the latest on 28 September 2026: the link answers
  • 28 September 2026: the link answers
23 files

cellgeni/STARsolo

License: GPL-3.0
State: the link answers, verified on 28 September 2026
Evidence: files inventoried
Commit: fbcd9ac360be3e5bdaad9b15bd4860537e6baff2, 3 September 2026
Languages: Shell (20), Python (1)
Size: 31 files, 21 scripts
Software Heritage: not archived
Found in: the text, “Published scRNA-seq harmonization”
Holds: README, license file, environment (Dockerfile), continuous integration
Not found: CITATION.cff, tests, documentation
Tools: STAR (6 files), SAMtools (1 file)
Availability: 1 check, the latest on 28 September 2026: the link answers
  • 28 September 2026: the link answers
23 files

ventolab/CellphoneDB

License: MIT
State: the link answers, verified on 28 September 2026
Evidence: files inventoried
Commit: dc8abd15b24e1d48c8862d54e8122603630a68ed, 6 June 2025
Languages: Python (52), Jupyter (12)
Size: 129 files, 64 scripts
Software Heritage: not archived
Found in: the text, “L-R analyses via Cellphone DB, CellChat, and Mul”
Holds: README, license file, environment (pyproject.toml, docs/requirements.txt), tests, continuous integration, documentation, 12 notebooks
Not found: CITATION.cff
Tools: pandas (29 files), NumPy (12 files), anndata (8 files), Matplotlib (5 files), SciPy (3 files), Seurat (2 files), ggplot2 (1 file), rpy2 (1 file), Scanpy (1 file), scikit-learn (1 file), seaborn (1 file)
Availability: 1 check, the latest on 28 September 2026: the link answers
  • 28 September 2026: the link answers
66 files

saeyslab/multinichenetr

License: GPL-3.0
State: the link answers, verified on 28 September 2026
Evidence: files inventoried
Commit: f1db92cf1ef72fee6edfa570d0bd6055d943a064, 12 August 2025
Languages: R (27)
Size: 727 files, 27 scripts
Software Heritage: not archived
Found in: the text, “L-R analyses via Cellphone DB, CellChat, and Mul”
Holds: README, license file, environment (DESCRIPTION), tests, continuous integration, documentation, 13 notebooks
Not found: CITATION.cff
Tools: tidyverse (25 files), ggplot2 (14 files), SingleCellExperiment (13 files), patchwork (2 files), circlize (1 file), ComplexHeatmap (1 file), edgeR (1 file), ggpubr (1 file), igraph (1 file), limma (1 file), Seurat (1 file)
Availability: 1 check, the latest on 28 September 2026: the link answers
  • 28 September 2026: the link answers
29 files

Loci-lab/Oral-Craniofacial-Atlas

License: none: the authors keep all their rights
State: the link answers, verified on 28 September 2026
Evidence: files inventoried
Commit: e9e3866dfa3a5e0fa2ff9ff8508236c1b8c692ab, 13 February 2026
Languages: Python (9), R (8), Jupyter (2)
Size: 20 files, 19 scripts
Software Heritage: not archived
Found in: “Data and code availability”
Holds: README, 2 notebooks
Not found: license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: pandas (10 files), ggplot2 (8 files), tidyverse (8 files), NumPy (7 files), PyTorch Geometric (6 files), PyTorch (6 files), pheatmap (5 files), Seurat (4 files), igraph (3 files), circlize (2 files), reshape2 (2 files), reticulate (2 files), scikit-learn (2 files), UMAP (2 files), clusterProfiler (1 file), data.table (1 file), ggpubr (1 file), Matplotlib (1 file), Scanpy (1 file)
Availability: 1 check, the latest on 28 September 2026: the link answers
  • 28 September 2026: the link answers
20 files

Zenodo 18474758

License: CC-BY-4.0
State: the link answers, verified on 28 September 2026
Evidence: files inventoried
Size: 1 file
Software Heritage: not checked
Found in: “Data and code availability”
Not found: README, license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: pandas (10 files), ggplot2 (8 files), tidyverse (8 files), NumPy (7 files), PyTorch Geometric (6 files), PyTorch (6 files), pheatmap (5 files), Seurat (4 files), igraph (3 files), circlize (2 files), reshape2 (2 files), reticulate (2 files), scikit-learn (2 files), UMAP (2 files), clusterProfiler (1 file), data.table (1 file), ggpubr (1 file), Matplotlib (1 file), Scanpy (1 file)
Availability: 1 check, the latest on 28 September 2026: the link answers (HTTP 200)
  • 28 September 2026: the link answers (HTTP 200)
20 files
At the source:

The paper's code and data availability statement is in the Data section.

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 6 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 171 scripts, each with its path and the digest of its content;
  • 11 matches between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

Datasets cited

Code and data availability statement

The paper has a code and data availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:

Read it in the paper: doi.org/10.1016/j.cpblue.2026.100007.

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 2, 28 September 2026

  • Publisher: n/a → Elsevier BV
  • Authors: added Bruno F. Matuck (0000-0002-2132-3402); removed Bruno F. Matuck

Version 1, 28 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 31 authors, 15 funders, 68 references.

Cite

This paper

Matuck, B. F., Huynh, K. L., Pereira, D., Easter, Q. T., Zhang, X., Kunz, M., Kumar, N., Pratapa, A., Rupp, B. T., Ghodke, A., Predeus, A. V., Fernandes, A., Szabó, L., Hartmann, S., Harnischfeger, N., Khavandgar, Z., Beach, M., Perez, P., Nilges, B., . . . Byrd, K. M. (2026). An integrated single-cell and spatial proteotranscriptomics atlas of fibroblast-driven immunoregulation within the human adult oral cavity. Cell press blue, 1(1), 100007. https://doi.org/10.1016/j.cpblue.2026.100007

BibTeX

@article{matuck2026integrated,
author = {Matuck, Bruno F. and Huynh, Khoa L.A. and Pereira, Diana and Easter, Quinn T. and Zhang, XiuYu and Kunz, Meik and Kumar, Nikhil and Pratapa, Aditya and Rupp, Brittany T. and Ghodke, Ameer and Predeus, Alexander V. and Fernandes, Alexandre and Szabó, Lili and Hartmann, Stefan and Harnischfeger, Nadja and Khavandgar, Zohreh and Beach, Margaret and Perez, Paola and Nilges, Benedikt and Moreno, Maria M. and Ko, Kang I. and Singh, Rohit and Tata, Purushothama Rao and Teichmann, Sarah A. and Kimple, Adam and Pringle, Sarah and Kretzschmar, Kai and Warner, Blake M. and Sequeira, Inês and Liu, Jinze and Byrd, Kevin M.},
title = {{An integrated single-cell and spatial proteotranscriptomics atlas of fibroblast-driven immunoregulation within the human adult oral cavity}},
journal = {Cell press blue},
year = {2026},
month = apr,
volume = {1},
number = {1},
pages = {100007},
publisher = {Elsevier BV},
issn = {3051-3839},
doi = {10.1016/j.cpblue.2026.100007},
url = {https://doi.org/10.1016/j.cpblue.2026.100007},
pmid = {42147490},
pmcid = {PMC13179517}
}

RIS

TY - JOUR
AU - Matuck, Bruno F.
AU - Huynh, Khoa L.A.
AU - Pereira, Diana
AU - Easter, Quinn T.
AU - Zhang, XiuYu
AU - Kunz, Meik
AU - Kumar, Nikhil
AU - Pratapa, Aditya
AU - Rupp, Brittany T.
AU - Ghodke, Ameer
AU - Predeus, Alexander V.
AU - Fernandes, Alexandre
AU - Szabó, Lili
AU - Hartmann, Stefan
AU - Harnischfeger, Nadja
AU - Khavandgar, Zohreh
AU - Beach, Margaret
AU - Perez, Paola
AU - Nilges, Benedikt
AU - Moreno, Maria M.
AU - Ko, Kang I.
AU - Singh, Rohit
AU - Tata, Purushothama Rao
AU - Teichmann, Sarah A.
AU - Kimple, Adam
AU - Pringle, Sarah
AU - Kretzschmar, Kai
AU - Warner, Blake M.
AU - Sequeira, Inês
AU - Liu, Jinze
AU - Byrd, Kevin M.
TI - An integrated single-cell and spatial proteotranscriptomics atlas of fibroblast-driven immunoregulation within the human adult oral cavity
T2 - Cell press blue
J2 - Cell Press Blue
PY - 2026
DA - 2026/04/01
VL - 1
IS - 1
SP - 100007
SN - 3051-3839
PB - Elsevier BV
DO - 10.1016/j.cpblue.2026.100007
UR - https://doi.org/10.1016/j.cpblue.2026.100007
LA - en
ER -

CSL-JSON

{
"id": "10.1016/j.cpblue.2026.100007",
"type": "article-journal",
"title": "An integrated single-cell and spatial proteotranscriptomics atlas of fibroblast-driven immunoregulation within the human adult oral cavity",
"container-title": "Cell press blue",
"author": [
{
"family": "Matuck",
"given": "Bruno F."
},
{
"family": "Huynh",
"given": "Khoa L.A."
},
{
"family": "Pereira",
"given": "Diana"
},
{
"family": "Easter",
"given": "Quinn T."
},
{
"family": "Zhang",
"given": "XiuYu"
},
{
"family": "Kunz",
"given": "Meik"
},
{
"family": "Kumar",
"given": "Nikhil"
},
{
"family": "Pratapa",
"given": "Aditya"
},
{
"family": "Rupp",
"given": "Brittany T."
},
{
"family": "Ghodke",
"given": "Ameer"
},
{
"family": "Predeus",
"given": "Alexander V."
},
{
"family": "Fernandes",
"given": "Alexandre"
},
{
"family": "Szabó",
"given": "Lili"
},
{
"family": "Hartmann",
"given": "Stefan"
},
{
"family": "Harnischfeger",
"given": "Nadja"
},
{
"family": "Khavandgar",
"given": "Zohreh"
},
{
"family": "Beach",
"given": "Margaret"
},
{
"family": "Perez",
"given": "Paola"
},
{
"family": "Nilges",
"given": "Benedikt"
},
{
"family": "Moreno",
"given": "Maria M."
},
{
"family": "Ko",
"given": "Kang I."
},
{
"family": "Singh",
"given": "Rohit"
},
{
"family": "Tata",
"given": "Purushothama Rao"
},
{
"family": "Teichmann",
"given": "Sarah A."
},
{
"family": "Kimple",
"given": "Adam"
},
{
"family": "Pringle",
"given": "Sarah"
},
{
"family": "Kretzschmar",
"given": "Kai"
},
{
"family": "Warner",
"given": "Blake M."
},
{
"family": "Sequeira",
"given": "Inês"
},
{
"family": "Liu",
"given": "Jinze"
},
{
"family": "Byrd",
"given": "Kevin M."
}
],
"container-title-short": "Cell Press Blue",
"volume": "1",
"issue": "1",
"page": "100007",
"DOI": "10.1016/j.cpblue.2026.100007",
"PMID": "42147490",
"PMCID": "PMC13179517",
"ISSN": "3051-3839",
"publisher": "Elsevier BV",
"URL": "https://doi.org/10.1016/j.cpblue.2026.100007",
"language": "en",
"issued": {
"date-parts": [
[
2026,
4,
1
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.1016/j.xcrm.2026.102766 [code]
A longitudinal single-cell and spatial multiomic atlas of pediatric high-grade glioma.
Journal: Cell reports. Medicine
In common: rpy2, SingleCellExperiment, edgeR, 22 other tools, 2 references
[2] doi:10.1038/s42003-026-10957-8 [code]
Brain defence by the extracellular matrix protein Cochlin.
Journal: Communications biology
In common: SAMtools, edgeR, reticulate, 21 other tools
[3] doi:10.1093/bioinformatics/btag592 [code]
Network-based stratification of allele-specific expression reveals patient subgroups in Huntington's disease.
Journal: Bioinformatics (Oxford, England)
In common: STAR, SAMtools, edgeR, 20 other tools
[4] doi:10.1038/s41586-026-10214-2 [code]
Multidimensional profiling of heterogeneity in supratentorial ependymomas.
Journal: Nature
In common: SingleCellExperiment, edgeR, reticulate, 20 other tools
[5] doi:10.1002/imt2.70163 [code]
Spatial multi-omics unveils sphingolipid metabolic reprogramming within the retinal pathological niche.
Journal: iMeta
In common: SingleCellExperiment, edgeR, limma, 20 other tools
[6] doi:10.1038/s41467-026-76675-1 [code]
Long-read proteogenomic atlas of human neuronal differentiation reveals isoform diversity informing neurodevelopmental risk mechanisms.
Journal: Nature communications
In common: STAR, SAMtools, edgeR, 19 other tools
[7] doi:10.1038/s41592-026-03194-8 [code]
Beyond benchmarking: an expert-guided consensus approach to spatially aware clustering.
Journal: Nature methods
In common: rpy2, PyTorch Geometric, SingleCellExperiment, 18 other tools, 1 reference
[8] doi:10.1186/s13059-026-04177-w [code]
Genomic sequence evolution underlying human neocortical interareal diversification.
Journal: Genome biology
In common: SAMtools, reticulate, UMAP, 18 other tools
[9] doi:10.1016/j.xcrm.2026.102651 [code]
Integrative CSF profiling identifies disease-specific immune responses in leptomeningeal disease.
Journal: Cell reports. Medicine
In common: SingleCellExperiment, reticulate, UMAP, 18 other tools
[10] doi:10.1038/s41593-026-02300-5 [code]
Integrated single-cell and spatial transcriptomic profiling in ALS uncovers peripheral-to-central immune infiltration and reprogramming.
Journal: Nature neuroscience
In common: SAMtools, edgeR, anndata, 18 other tools

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

Request its removal

To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).

Discussion, reproductions, activity

Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.

Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.