<- c("fs", "futile.logger", "configr", "stringr", "ggpubr", "ggthemes",
pkgs "SingleCellExperiment", "RColorBrewer", "vroom", "jhtools", "glue",
"jhuanglabHyperion", "openxlsx", "ggsci", "ggraph", "patchwork",
"cowplot", "tidyverse", "dplyr", "rstatix", "magrittr", "igraph",
"tidygraph", "ggtree", "aplot", "circlize")
suppressMessages(conflicted::conflict_scout())
for (pkg in pkgs){
suppressPackageStartupMessages(library(pkg, character.only = T))
}<- "./results/figure2" %>% checkdir
res_dir <- "./data" %>% checkdir
dat_dir <- "./config" %>% checkdir
config_dir
#colors config
<- glue::glue("{config_dir}/configs.yaml")
config_fn <- jhtools::show_me_the_colors(config_fn, "stype3")
stype3_cols <- jhtools::show_me_the_colors(config_fn, "cell_type_new")
ctype10_cols <- jhtools::show_me_the_colors(config_fn, "meta_color")
meta_cols
#read in coldata
<- readr::read_csv(glue::glue("{dat_dir}/sce_coldata.csv"))
coldat <- readxl::read_excel(glue::glue("{dat_dir}/meta_clu.xlsx")) %>% dplyr::select(-9) meta_clu
figure2
figure2b
# define cell groups
<- c("Epithelial tumor cell", "Normal epithelial cell", "Endothelial cell")
epiendo_cells <- c("DC", "MDSC", "Monocyte", "B cell", "CD8+ T cell", "CD4+ T cell",
immu_stroma_cells "HLA-DR-CD163- mp", "HLA-DR-CD163+ mp", "HLA-DR+CD163- mp",
"HLA-DR+CD163+ mp", "HLA-DR-CD163- MMT", "HLA-DR+CD163- MMT",
"HLA-DR+CD163+ MMT", "PSC", "myoCAF", "Col1+ CAF")
<- c("CCR6+ cell", "B7-H4+ cell", "Ki67+ cell", "Vim+ cell", "Unknown")
other_cells
<- data.frame(cell_type_new = c(epiendo_cells, immu_stroma_cells, other_cells),
grouping_celltype meta_celltype = c(rep("Epi-endo", 3), rep("Immune-stroma", 16), rep("Others", 5)))
# calculate fraction data
<- coldat %>% group_by(cluster_names, cell_type_new) %>% dplyr::mutate(cell_clu_count = n()) %>%
col_frac group_by(cluster_names) %>% dplyr::mutate(all_count = n(), frac = cell_clu_count / all_count) %>%
group_by(cell_type_new) %>% dplyr::mutate(all_c_count = n(), frac2 = cell_clu_count / all_c_count)
<- col_frac %>% select(cluster_names, cell_type_new, frac2, frac) %>%
col_frac_s na.omit() %>% unique() %>% as.data.frame()
<- col_frac_s %>% select(-frac) %>%
col_frac_wide pivot_wider(names_from = cell_type_new, values_from = frac2, values_fill = 0) %>%
as.data.frame() %>% column_to_rownames(var = "cluster_names") %>% as.matrix()
<- col_frac_wide[, c(epiendo_cells, immu_stroma_cells)]
col_frac_wide <- scale(t(col_frac_wide))
ht_mat
# grouped scale
<- function(x){
scale_this - mean(x, na.rm=TRUE)) / sd(x, na.rm=TRUE)
(x
}<- col_frac_s %>%
plot_data group_by(cluster_names) %>% dplyr::mutate(frac2_scaled = scale_this(frac2)) %>%
group_by(cell_type_new) %>% dplyr::mutate(frac_scaled_byrow = scale_this(frac))
<- left_join(plot_data, grouping_celltype) %>% ungroup() %>%
plot_data ::filter(meta_celltype != "Others")
dplyr
# calculate dendrogram
<- hclust(dist(ht_mat))
clust <- hclust(dist(t(ht_mat)))
v_clust <- as.dendrogram(v_clust)
ddgram_col <- ggtree(ddgram_col) + layout_dendrogram()
ggtree_plot_col <- as.dendrogram(clust)
ddgram <- ggtree::ggtree(ddgram)
ggtree_plot
# set colors and output location
= circlize::colorRamp2(c(-1, 0, 1, 2, 3), c("#5658A5", "#8BCDA3", "#FBF4AA", "#F16943", "#9D1A44"))
col_fun1 <- c("Epi-endo" = "#B61932", "Immune-stroma" = "#568AC2", "Others" = "#BEA278")
meta_colors <- data.frame(meta_colors, meta_celltype = names(meta_colors))
ctype_colors <- left_join(plot_data, ctype_colors, by = "meta_celltype")
plot_data
# main plot
<- plot_data %>%
dotplot3 ::mutate(`Enrichment\nin cell types` = frac2_scaled) %>%
dplyr::mutate(`Enrichment\nin clusters` = frac_scaled_byrow) %>%
dplyr::mutate(cell_type_new = factor(cell_type_new, levels = clust$labels[clust$order]),
dplyrcluster = factor(cluster_names, levels = v_clust$labels[v_clust$order])) %>%
ggplot(aes(x=cluster, y = cell_type_new, color = `Enrichment\nin clusters`, size = `Enrichment\nin cell types`)) +
geom_point() +
::theme_cowplot() +
cowplottheme(axis.line = element_blank()) +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)) +
xlab('') +
ylab('') +
theme(axis.ticks = element_blank()) +
theme(plot.margin = unit(c(0, 0, 0, 0), "cm")) +
scale_color_gradientn(colours = col_fun1(seq(-1, 4, by = 0.2))) +
scale_y_discrete(position = "right")
# handy function to alter the legend
<- function(myPlot, pointSize = 4, textSize = 8) {
addSmallLegend +
myPlot guides(shape = guide_legend(override.aes = list(size = pointSize))) +
theme(legend.title = element_text(size = textSize),
legend.text = element_text(size = textSize),
legend.position = c(1.1, -0.3), ## legend.justification does not work well
legend.direction = "horizontal")
}<- addSmallLegend(dotplot3)
dotplot3_s
# dendrograms
<- ggtree_plot + ylim2(dotplot3)
ggtree_plot <- ggtree_plot_col + xlim2(dotplot3)
ggtree_plot_col # row labels of cell metaclusters
<- ggplot(plot_data %>%
labels ::mutate(`Cell Categories` = meta_celltype,
dplyrcell_type_new = factor(cell_type_new, levels = clust$labels[clust$order])),
aes(y = cell_type_new, x = 3, fill = `Cell Categories`)) +
geom_tile() +
scale_fill_manual(values = meta_colors) +
ylim2(dotplot3)
# legend
<- plot_grid(ggpubr::get_legend(labels + theme(legend.position = "bottom")))
legend <- labels + theme_nothing() + theme(legend.position = "none") +
labels theme(plot.margin = unit(c(0, 0, 0, 0), "cm"))
# merged plot
<- plot_spacer() + plot_spacer() + plot_spacer() + plot_spacer() + ggtree_plot_col +
merged plot_spacer() + plot_spacer() + plot_spacer() + plot_spacer() + plot_spacer() +
+ plot_spacer() + labels + plot_spacer() + dotplot3_s +
ggtree_plot plot_spacer() + plot_spacer() + plot_spacer() + plot_spacer() + plot_spacer() +
plot_spacer() + plot_spacer() + plot_spacer() + plot_spacer() + legend +
plot_layout(ncol = 5, widths = c(0.7, -0.3, 0.2, -0.25, 4.2), heights = c(0.9, -0.4, 4, -0.5, 0.9))
ggsave(glue::glue("{res_dir}/fig2b_dotplot_main.pdf"), merged, height = 7, width = 9)
merged
figure2c
# use fast_tsne function
source("/cluster/apps/FIt-SNE/1.2.1/fast_tsne.R", chdir = T)
# set empty theme
<- function (font_size = 14, font_family = "", rel_small = 12/14) {
theme_no theme_void(base_size = font_size, base_family = font_family) %+replace%
theme(line = element_blank(), rect = element_blank(),
text = element_text(family = font_family, face = "plain",
color = "black", size = font_size, lineheight = 0.9,
hjust = 0.5, vjust = 0.5, angle = 0, margin = margin(),
debug = FALSE), axis.line = element_blank(),
axis.line.x = NULL, axis.line.y = NULL, axis.text = element_blank(),
axis.text.x = NULL, axis.text.x.top = NULL, axis.text.y = NULL,
axis.text.y.right = NULL, axis.ticks = element_blank(),
axis.ticks.length = unit(0, "pt"), axis.title = element_blank(),
axis.title.x = NULL, axis.title.x.top = NULL, axis.title.y = NULL,
axis.title.y.right = NULL, legend.background = element_blank(),
panel.background = element_blank(),
panel.border = element_blank(), panel.grid = element_blank(),
panel.grid.major = NULL, panel.grid.minor = NULL,
panel.spacing = unit(font_size/2, "pt"), panel.spacing.x = NULL,
panel.spacing.y = NULL, panel.ontop = FALSE, strip.background = element_blank(),
strip.text = element_blank(), strip.text.x = NULL,
strip.text.y = NULL, strip.placement = "inside",
strip.placement.x = NULL, strip.placement.y = NULL,
strip.switch.pad.grid = unit(0, "cm"), strip.switch.pad.wrap = unit(0, "cm"),
plot.background = element_blank(), plot.title = element_blank(),
plot.subtitle = element_blank(), plot.caption = element_blank(),
plot.tag = element_text(face = "bold", hjust = 0,
vjust = 0.7), plot.tag.position = c(0, 1),
plot.margin = margin(0,0, 0, 0), complete = TRUE)
}
<- distinct(coldat[, c("cluster_names", "community_name", "meta_cluster")])
df_com
# Option 3 fast_tsne & cell interaction data. for details of m_list, see
# ~/projects/hyperion/code/community/data_generation/1_community_clusters_generation.R
<- readr::read_rds(glue::glue("{dat_dir}/m_list_0.rds"))
m_list <- do.call(rbind, unname(m_list)) %>% as.matrix()
m <- m[!endsWith(rownames(m), "_NA"), ]
m <- fftRtsne(m)
res_tsne
<- data.frame(community_name = rownames(m),
tsne_result3 tsne_1 = res_tsne[, 1],
tsne_2 = res_tsne[, 2])
<- left_join(tsne_result3,
tsne_result3 by = "community_name")
df_com,
# plot and output
<- ggplot(tsne_result3,
tsne_plot_3 aes(x = tsne_1,
y = tsne_2,
color = meta_cluster,
fill = meta_cluster)) +
geom_point(size = 0.001, alpha = 0.5) +
scale_color_manual(values = meta_cols) +
scale_fill_manual(values = meta_cols) +
theme_no() +
labs(color = "Meta Clusters") +
theme(legend.position = "none")
#guides(color = guide_legend(override.aes = list(size = 2, alpha = 1)))
ggsave(glue::glue("{res_dir}/fig2c_tsne_community_meta_clusters.pdf"),
dpi=300, width = 6, height = 7, units = "cm")
tsne_plot_3, tsne_plot_3
figure2d
# circular stacked barplot of community and meta cluster fraction
## get the fraction data of both community and meta levels
<- coldat[, c("cell_id","cell_type_new", "cluster_names", "community_name", "meta_cluster")] %>%
dt na.omit()
<- dt %>% group_by(cluster_names) %>% mutate(comm_count = length(unique(community_name))) %>%
dt ::mutate(all_clu_cell_count = n()) %>% group_by(cluster_names, cell_type_new) %>%
dplyr::mutate(cell_allcount = n(), frac_cells_clu = cell_allcount / all_clu_cell_count)
dplyr
<- dt %>% group_by(meta_cluster) %>% dplyr::mutate(comm_count_meta = length(unique(community_name))) %>%
dt ::mutate(all_meta_cell_count = n()) %>% group_by(meta_cluster, cell_type_new) %>%
dplyr::mutate(cell_allcount_meta = n(), frac_cells_meta = cell_allcount_meta / all_meta_cell_count)
dplyr
$count_avg_meta <- dt$cell_allcount_meta / dt$comm_count_meta
dt$count_avg <- dt$cell_allcount / dt$comm_count
dt
$cell_type_new <- factor(dt$cell_type_new, levels = names(ctype10_cols))
dt
<- unique(dt[, c("cell_type_new", "cluster_names",
commu_data "count_avg", "comm_count", "frac_cells_clu")])
<- unique(dt[, c("cell_type_new", "meta_cluster",
meta_data "count_avg_meta", "comm_count_meta", "frac_cells_meta")])
<- commu_data[, c(1, 2, 5)] %>% gather(key = 'observation', value = 'value', -c(1, 2))
commu_dt <- meta_data[, c(1, 2, 5)] %>% gather(key = 'observation', value = 'value', -c(1, 2))
meta_dt <- commu_dt[, -3]
commu_dt <- meta_dt[, -3]
meta_dt ## convert the long matrix to wide matrix, with '0' filled in the missing cell
<- commu_dt %>% ungroup() %>%
mtx_commu_dt pivot_wider(id_cols = "cell_type_new", names_from = "cluster_names",
values_from = "value", values_fill = 0)
<- meta_dt %>% ungroup() %>%
mtx_meta_dt pivot_wider(id_cols = "cell_type_new", names_from = "meta_cluster",
values_from = "value", values_fill = 0)
## convert the wide matrices to the long ones
<- mtx_commu_dt %>% pivot_longer(cols = NL1:DC2, names_to = "names", values_to = "value")
long_mtx_commu_dt levels(long_mtx_commu_dt$names) <- c(
"TM1", "TB2", "TB1", "ST_MP2", "ST_MP1", "ST_mCAF2",
"ST_mCAF1", "ST_CAF3", "ST_CAF2", "ST_CAF1", "C2_MP2",
"C2_MP1", "C1_MP2", "C1_MP1", "IM_M", "IM_e2", "IM_e1",
"DC2", "DC1", "NL3", "NL2", "NL1"
)$group <- 'cluster'
long_mtx_commu_dt
<- mtx_meta_dt %>% pivot_longer(cols = "MC-normal":"MC-tumor-core", names_to = "names", values_to = "value")
long_mtx_meta_dt levels(long_mtx_meta_dt$names) <-
rev(c(
"MC-tumor-core",
"MC-tumor-frontline",
"MC-stroma-macro",
"MC-stroma-mCAF",
"MC-stroma-CAF",
"MC-macro-c2",
"MC-macro-c1",
"MC-immune-myeloid",
"MC-immune-enriched",
"MC-DC",
"MC-normal"
))$group <- 'metacluster'
long_mtx_meta_dt
## combine the 2 matrices
<- rbind(long_mtx_commu_dt, long_mtx_meta_dt)
data
## set the empty area
<- 2
empty_bar <- nlevels(as.factor(data$cell_type_new))
nObsType <-
to_add data.frame(matrix(
data = NA,
nrow = empty_bar * nlevels(as.factor(data$group)) * nObsType,
ncol(data)
))colnames(to_add) <- colnames(data)
$group <-
to_addrep(unique(data$group), each = empty_bar)
<- rbind(data, to_add)
data <- data %>% arrange(group, names)
data $id <-
datarep(seq(1, nrow(data) / nObsType) , each = nObsType)
## set the label data
<-
label_data %>% group_by(id, names) %>% summarize(tot = sum(value))
data <- nrow(label_data)
number_of_bar <-
angle 90 - 360 * (label_data$id - 0.5) / number_of_bar
# I substract 0.5 because the letter must have the angle of the center of the bars.
# Not extreme right(1) or extreme left (0)
$hjust <- ifelse(angle <= -90, 1, 0)
label_data$angle <- ifelse(angle <= -90, angle + 180, angle)
label_data
# prepare a data frame for base lines
<- data %>%
base_data group_by(group) %>%
summarize(start = min(id), end = max(id) - empty_bar) %>%
rowwise() %>%
mutate(title = mean(c(start, end)))
# prepare a data frame for grid (scales)
<- base_data
grid_data $end <-
grid_data$end[c(nrow(grid_data), 1:nrow(grid_data) - 1)] + .5
grid_data$start <- grid_data$start - .5
grid_data<- grid_data[-1,]
grid_data
<- ggplot(data) +
p # Add the stacked bar
geom_bar(
aes(x = as.factor(id), y = value, fill = cell_type_new),
stat = "identity",
position = 'fill',
alpha = 1
+
) scale_fill_manual(values = ctype10_cols) +
# Add a val=1/.75/.50/.25/0 lines. I do it at the beginning to make sur barplots are OVER it.
geom_segment(
data = grid_data,
aes(
x = end,
y = 0,
xend = start,
yend = 0
),colour = "grey",
alpha = 1,
size = 0.3 ,
inherit.aes = FALSE
+
) geom_segment(
data = grid_data,
aes(
x = end,
y = 0.25,
xend = start,
yend = .25
),colour = "grey",
alpha = 1,
size = 0.3 ,
inherit.aes = FALSE
+
) geom_segment(
data = grid_data,
aes(
x = end,
y = .5,
xend = start,
yend = .5
),colour = "grey",
alpha = 1,
size = 0.3 ,
inherit.aes = FALSE
+
) geom_segment(
data = grid_data,
aes(
x = end,
y = .75,
xend = start,
yend = .75
),colour = "grey",
alpha = 1,
size = 0.3 ,
inherit.aes = FALSE
+
) geom_segment(
data = grid_data,
aes(
x = end,
y = 1,
xend = start,
yend = 1
),colour = "grey",
alpha = 1,
size = 0.3 ,
inherit.aes = FALSE
+
) # Add text showing the value of each 1.00/.75/.50/.25/0 lines
::annotate(
ggplot2"text",
x = rep(max(data$id), 5),
y = c(0, .25, .5, .75, 1),
label = c("0", '0.25', '0.5', '0.75', '1.0') ,
color = "darkgray",
size = 3 ,
angle = 0,
fontface = "bold",
hjust = 1
+
) ylim(-.3, max(label_data$tot, na.rm = T) + .5) +
theme_minimal() +
theme(
legend.position = "none",
axis.text = element_blank(),
axis.title = element_blank(),
panel.grid = element_blank(),
plot.margin = unit(rep(-1, 4), "cm")
+
) coord_polar() +
# Add labels on top of each bar
geom_text(
data = label_data,
aes(
x = id,
y = tot + .04,
label = names,
hjust = hjust
),color = "black",
fontface = "bold",
alpha = 1,
size = 2.5,
angle = label_data$angle,
inherit.aes = FALSE
)ggsave(glue::glue("{res_dir}/fig2d_cell_type_prop_in_MCs_barplot_circle.pdf"), p, height = 7, width = 7)
p
figure2e
# read in and alter the data
<- readr::read_rds(glue::glue("{dat_dir}/ci_weighted_list.rds"))
ci_weighted <- data.table::rbindlist(ci_weighted)
ci_data dim(ci_data)
[1] 56905 10
# rename
<- meta_clu$cluster_names %>% `names<-`(meta_clu$old_cluster_name)
clu_new $from_cluster <- clu_new[ci_data$from_cluster]
ci_data$to_cluster <- clu_new[ci_data$to_cluster]
ci_data
<- meta_clu$meta_short_new %>% `names<-`(meta_clu$cluster_names)
meta_new $from_meta <- meta_new[ci_data$from_cluster]
ci_data$to_meta <- meta_new[ci_data$to_cluster]
ci_data
# meta-cluster interaction with self-interaction
<- ci_data %>% group_by(from_meta, to_meta) %>% summarise(count = n()) %>%
ci_matrix3 pivot_wider(names_from = from_meta, values_from = count, values_fill = 0) %>%
as.data.frame() %>% column_to_rownames(var = "to_meta") %>% as.matrix()
# cluster interaction without self-interaction
<- ci_matrix3
ci_matrix4 for (i in 1:nrow(ci_matrix4)) {
<- rownames(ci_matrix4)[i]
x <- 0
ci_matrix4[x, x]
}
<- ci_matrix4[c("MC-tumor-core",
ci_matrix4 "MC-tumor-frontline",
"MC-stroma-macro",
"MC-stroma-mCAF",
"MC-stroma-CAF",
"MC-macro-c2",
"MC-macro-c1",
"MC-immune-myeloid",
"MC-immune-enriched",
"MC-DC",
"MC-normal"),
c("MC-tumor-core",
"MC-tumor-frontline",
"MC-stroma-macro",
"MC-stroma-mCAF",
"MC-stroma-CAF",
"MC-macro-c2",
"MC-macro-c1",
"MC-immune-myeloid",
"MC-immune-enriched",
"MC-DC",
"MC-normal")]
# rotate labels
#pdf(glue::glue("{res_dir}/fig2e_metacluster_interaction_circ_noself_rotate.pdf"), width = 10, height = 10)
chordDiagram(ci_matrix4, grid.col = meta_cols, annotationTrack = c("grid", "axis"),
preAllocateTracks = list(track.height = max(strwidth(unlist(dimnames(ci_matrix4))))))
circos.track(track.index = 1, panel.fun = function(x, y) {
circos.text(CELL_META$xcenter, CELL_META$ylim[1], CELL_META$sector.index, cex = 0.7,
facing = "clockwise", niceFacing = TRUE, adj = c(-0.2, 0))
bg.border = NA) },