figure2

pkgs <- c("fs", "futile.logger", "configr", "stringr", "ggpubr", "ggthemes",
          "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))
}
res_dir <- "./results/figure2" %>% checkdir
dat_dir <- "./data" %>% checkdir
config_dir <- "./config" %>% checkdir

#colors config
config_fn <- glue::glue("{config_dir}/configs.yaml")
stype3_cols <- jhtools::show_me_the_colors(config_fn, "stype3")
ctype10_cols <- jhtools::show_me_the_colors(config_fn, "cell_type_new")
meta_cols <- jhtools::show_me_the_colors(config_fn, "meta_color")

#read in coldata
coldat <- readr::read_csv(glue::glue("{dat_dir}/sce_coldata.csv"))
meta_clu <- readxl::read_excel(glue::glue("{dat_dir}/meta_clu.xlsx")) %>% dplyr::select(-9)

figure2b

# define cell groups
epiendo_cells <- c("Epithelial tumor cell", "Normal epithelial cell", "Endothelial cell")
immu_stroma_cells <- c("DC", "MDSC", "Monocyte", "B cell", "CD8+ T cell", "CD4+ T cell",
                 "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")
other_cells <- c("CCR6+ cell", "B7-H4+ cell", "Ki67+ cell", "Vim+ cell", "Unknown")

grouping_celltype <- data.frame(cell_type_new = c(epiendo_cells, immu_stroma_cells, other_cells),
                                meta_celltype = c(rep("Epi-endo", 3), rep("Immune-stroma", 16), rep("Others", 5)))

# calculate fraction data
col_frac <- coldat %>% group_by(cluster_names, cell_type_new) %>% dplyr::mutate(cell_clu_count = n()) %>%
  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_s <- col_frac %>% select(cluster_names, cell_type_new, frac2, frac) %>%
  na.omit() %>% unique() %>% as.data.frame()
col_frac_wide <- col_frac_s %>% select(-frac) %>%
  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 <- col_frac_wide[, c(epiendo_cells, immu_stroma_cells)]
ht_mat <- scale(t(col_frac_wide))

# grouped scale 
scale_this <- function(x){
  (x - mean(x, na.rm=TRUE)) / sd(x, na.rm=TRUE)
}
plot_data <- col_frac_s %>%
  group_by(cluster_names) %>% dplyr::mutate(frac2_scaled = scale_this(frac2)) %>%
  group_by(cell_type_new) %>% dplyr::mutate(frac_scaled_byrow = scale_this(frac))
plot_data <- left_join(plot_data, grouping_celltype) %>% ungroup() %>%
  dplyr::filter(meta_celltype != "Others")

# calculate dendrogram
clust <- hclust(dist(ht_mat))
v_clust <- hclust(dist(t(ht_mat)))
ddgram_col <- as.dendrogram(v_clust)
ggtree_plot_col <- ggtree(ddgram_col) + layout_dendrogram()
ddgram <- as.dendrogram(clust)
ggtree_plot <- ggtree::ggtree(ddgram)

# set colors and output location
col_fun1 = circlize::colorRamp2(c(-1, 0, 1, 2, 3), c("#5658A5", "#8BCDA3", "#FBF4AA", "#F16943", "#9D1A44"))
meta_colors <- c("Epi-endo" = "#B61932", "Immune-stroma" = "#568AC2", "Others" = "#BEA278")
ctype_colors <- data.frame(meta_colors, meta_celltype = names(meta_colors))
plot_data <- left_join(plot_data, ctype_colors, by = "meta_celltype")

# main plot
dotplot3 <- plot_data %>%
  dplyr::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]),
         cluster = 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() +
  cowplot::theme_cowplot() +
  theme(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
addSmallLegend <- function(myPlot, pointSize = 4, textSize = 8) {
  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")
}
dotplot3_s <- addSmallLegend(dotplot3)

# dendrograms
ggtree_plot <- ggtree_plot + ylim2(dotplot3)
ggtree_plot_col <- ggtree_plot_col + xlim2(dotplot3)
# row labels of cell metaclusters
labels <- ggplot(plot_data %>%
                   dplyr::mutate(`Cell Categories` = meta_celltype,
                          cell_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
legend <- plot_grid(ggpubr::get_legend(labels + theme(legend.position = "bottom")))
labels <- labels + theme_nothing() + theme(legend.position = "none")  +
  theme(plot.margin = unit(c(0, 0, 0, 0), "cm"))
# merged plot
merged <- plot_spacer() + plot_spacer() + plot_spacer() + plot_spacer() + ggtree_plot_col +
  plot_spacer() + plot_spacer() + plot_spacer() + plot_spacer() + plot_spacer() +
  ggtree_plot + plot_spacer() + labels + plot_spacer() + dotplot3_s +
  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
theme_no <- function (font_size = 14, font_family = "", rel_small = 12/14) {
  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)
}

df_com <- distinct(coldat[, c("cluster_names", "community_name", "meta_cluster")]) 

# Option 3 fast_tsne & cell interaction data. for details of m_list, see
# ~/projects/hyperion/code/community/data_generation/1_community_clusters_generation.R
m_list <- readr::read_rds(glue::glue("{dat_dir}/m_list_0.rds"))
m <- do.call(rbind, unname(m_list)) %>% as.matrix()
m <- m[!endsWith(rownames(m), "_NA"), ]
res_tsne <- fftRtsne(m)

tsne_result3 <- data.frame(community_name = rownames(m),
                           tsne_1 = res_tsne[, 1],
                           tsne_2 = res_tsne[, 2])

tsne_result3 <- left_join(tsne_result3,
                          df_com, by = "community_name")

# plot and output
tsne_plot_3 <- ggplot(tsne_result3,
                      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"),
       tsne_plot_3, dpi=300, width = 6, height = 7, units = "cm")
tsne_plot_3

figure2d

# circular stacked barplot of community and meta cluster fraction
## get the fraction data of both community and meta levels
dt <- coldat[, c("cell_id","cell_type_new", "cluster_names", "community_name", "meta_cluster")] %>%
  na.omit()

dt <- dt %>% group_by(cluster_names) %>% mutate(comm_count = length(unique(community_name))) %>%
  dplyr::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)

dt <- dt %>% group_by(meta_cluster) %>% dplyr::mutate(comm_count_meta = length(unique(community_name))) %>%
  dplyr::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)

dt$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))

commu_data <- unique(dt[, c("cell_type_new", "cluster_names",
                            "count_avg", "comm_count", "frac_cells_clu")])
meta_data <- unique(dt[, c("cell_type_new", "meta_cluster",
                           "count_avg_meta", "comm_count_meta", "frac_cells_meta")])

commu_dt <- commu_data[, c(1, 2, 5)] %>% gather(key = 'observation', value = 'value', -c(1, 2))
meta_dt <- meta_data[, c(1, 2, 5)] %>% gather(key = 'observation', value = 'value', -c(1, 2))
commu_dt <- commu_dt[, -3]
meta_dt <- meta_dt[, -3]
## convert the long matrix to wide matrix, with '0' filled in the missing cell
mtx_commu_dt <- commu_dt %>% ungroup() %>%
  pivot_wider(id_cols = "cell_type_new", names_from = "cluster_names",
              values_from = "value", values_fill = 0)
mtx_meta_dt <- meta_dt %>% ungroup() %>%
  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
long_mtx_commu_dt <- mtx_commu_dt %>% pivot_longer(cols = NL1:DC2, names_to = "names", values_to = "value")
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"
)
long_mtx_commu_dt$group <- 'cluster'

long_mtx_meta_dt <- mtx_meta_dt %>% pivot_longer(cols = "MC-normal":"MC-tumor-core", names_to = "names", values_to = "value")
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"
  ))
long_mtx_meta_dt$group <- 'metacluster'

## combine the 2 matrices
data <- rbind(long_mtx_commu_dt, long_mtx_meta_dt)

## set the empty area
empty_bar <- 2
nObsType <- nlevels(as.factor(data$cell_type_new))
to_add <-
  data.frame(matrix(
    data = NA,
    nrow = empty_bar * nlevels(as.factor(data$group)) * nObsType,
    ncol(data)
  ))
colnames(to_add) <- colnames(data)
to_add$group <-
  rep(unique(data$group), each = empty_bar)
data <- rbind(data, to_add)
data <- data %>% arrange(group, names)
data$id <-
  rep(seq(1, nrow(data) / nObsType) , each = nObsType)

## set the label data
label_data <-
  data %>% group_by(id, names) %>% summarize(tot = sum(value))
number_of_bar <- nrow(label_data)
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)
label_data$hjust <- ifelse(angle <= -90, 1, 0)
label_data$angle <- ifelse(angle <= -90, angle + 180, angle)

# prepare a data frame for base lines
base_data <- 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)
grid_data <- 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,]

p <- ggplot(data) +
  # 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
  ggplot2::annotate(
    "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
ci_weighted <- readr::read_rds(glue::glue("{dat_dir}/ci_weighted_list.rds"))
ci_data <- data.table::rbindlist(ci_weighted)
dim(ci_data)
[1] 56905    10
# rename
clu_new <- meta_clu$cluster_names %>% `names<-`(meta_clu$old_cluster_name)
ci_data$from_cluster <- clu_new[ci_data$from_cluster]
ci_data$to_cluster <- clu_new[ci_data$to_cluster]

meta_new <- meta_clu$meta_short_new %>% `names<-`(meta_clu$cluster_names)
ci_data$from_meta <- meta_new[ci_data$from_cluster]
ci_data$to_meta <- meta_new[ci_data$to_cluster]

# meta-cluster interaction with self-interaction
ci_matrix3 <- ci_data %>% group_by(from_meta, to_meta) %>% summarise(count = n()) %>%
  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_matrix4 <- ci_matrix3
for (i in 1:nrow(ci_matrix4)) {
  x <- rownames(ci_matrix4)[i]
  ci_matrix4[x, x] <- 0
}


ci_matrix4 <- ci_matrix4[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"),
                         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)