3  Results: Heatmaps and Drug networks, based on barcode fingerprints

3.1 Reproducibility

I list below the R packages required to reproduce the analyses.

Code
## data wrangling
library(dplyr)
library(tidyr)
library(stringr)
library(purrr)

## plotting
library(ggplot2)
library(ComplexHeatmap)
library(cowplot)
library(grid)
library(RColorBrewer)
library(igraph)
library(magick)

## auxiliary functions
source("R/utils.R")
today_date <- "2025-04-28"
## today_date <- format(Sys.Date(), "%Y-%m-%d")

## set the seed, for fixing generation of ComplexHeatmaps (dendogram clustering)
set.seed(20)

3.2 Compute Compound Similarities

  • Correlation matrix computed with stats::cor.

  • Yet, we have to try other correlation methods on the continuous space, or consider other metrics if working on the discrete space. Unbalanced Wassertein distance, or relatives, for distinct input and output dimensions.

3.2.1 Compound Heatmaps

3.2.1.1 Heatmap with Pearson correlation score

  • Heatmap in Figure 3.1 is generated at the replicate level:
Code
## Read SummarizedExperiment object
se_normalised_replicate <- readRDS(paste0("./results/compounds/se_normalised_per_replicate_", today_date, ".rds"))
se_normalised_replicate_mat <- SummarizedExperiment::assay(se_normalised_replicate)
se_normalised_pheno_data_replicate <- SummarizedExperiment::colData(se_normalised_replicate)
se_normalised_pheno_data_replicate$log10Conc <- if_else(se_normalised_pheno_data_replicate$Concentrations==0, 
                                   0, 
                                   -log10(se_normalised_pheno_data_replicate$Concentrations))
## Compute global correlation score
cor_per_replicate <- cor(se_normalised_replicate_mat)

## Define clustering colours
col_heatmap_scale <- circlize::colorRamp2(c(min(cor_per_replicate), 0, 1),
                                      c("blue", "white", "red"))

## Define custom colour Heatmap annotation
## num_batches <- length(unique(se_normalised_pheno_data_replicate$Batch_ID))
## num_compounds <- length(unique(se_normalised_pheno_data_replicate$Compound))
## num_moa <- length(unique(se_normalised_pheno_data_replicate$MoA))
## 
## batch_col <- setNames(colorRampPalette(brewer.pal(8, "Dark2"))(num_batches), 
##                       unique(se_normalised_pheno_data_replicate$Batch_ID))
## compound_col <- setNames(colorRampPalette(brewer.pal(11, "Spectral"))(num_compounds), 
##                          unique(se_normalised_pheno_data_replicate$Compound))
## moa_col <- setNames(colorRampPalette(brewer.pal(12, "Set3"))(num_moa), 
##                     unique(se_normalised_pheno_data_replicate$MoA))


## Heatmap annotation
top_ha <- ComplexHeatmap::HeatmapAnnotation(df = se_normalised_pheno_data_replicate |> 
                                          as.data.frame() |> 
                                          dplyr::select(Batch_ID, MoA, Compound)) 
                                        ## col = list(Batch_ID = batch_col, 
                                        ##            MoA = moa_col, 
                                        ##            Compound = compound_col))

row_ha <- ComplexHeatmap::rowAnnotation(Concentration =
                                          ComplexHeatmap::anno_barplot(se_normalised_pheno_data_replicate$log10Conc), 
                                        Duration = paste0(se_normalised_pheno_data_replicate$Duration, "d"))

## 1) Generate HeatMap
heatmap_normalised_replicates <- ComplexHeatmap::Heatmap(cor_per_replicate, 
                                                         col=col_heatmap_scale, 
                                                         name = "CC for all Replicates", 
                                                         show_row_names = TRUE,
                                                         show_column_names = FALSE, 
                                                         row_dend_reorder = TRUE,
                                                         column_dend_reorder = TRUE, 
                                                         ## font size
                                                         row_names_gp = gpar(fontsize = 2),
                                                         column_names_gp = gpar(fontsize = 2),
                                                         column_names_rot = 45,
                                                         top_annotation = top_ha,
                                                         right_annotation = row_ha, 
                                                         ## matrix size
                                                         width = ncol(cor_per_replicate)*unit(1, "mm"),
                                                         height = nrow(cor_per_replicate)*unit(1, "mm")) 

size_heatmap <- calc_ht_size(heatmap_normalised_replicates)
padding_heatmap <- unit(c(2, 15, 2, 2), "mm")

## 2) Save png and pdf outputs
png(paste0("figures/compounds/heatmap_normalised_replicates_", today_date,".png"),
    res = 200,
    width = size_heatmap$width, height = size_heatmap$height, units = c("in"))
heatmap_normalised_replicates |> ComplexHeatmap::draw(padding = padding_heatmap)
dev.off()
##  png 
##    2

knitr::include_graphics(paste0("figures/compounds/heatmap_normalised_replicates_", today_date,".png"),
                        auto_pdf = TRUE,
                        dpi = 100)

ggsave(paste0("figures/compounds/heatmap_normalised_replicates_", today_date,".pdf"),
       heatmap_normalised_replicates |>
         ComplexHeatmap::draw(padding = padding_heatmap) |>
         grid::grid.grabExpr(),
       dpi = 100,
       width = size_heatmap$width, height = size_heatmap$height, units = c("in"))
Figure 3.1: Heatmap of normalised replication scores, generated with the simple Pearson Correlation score.
  • Heatmap in Figure 3.2 is generated by averaging normalised barcode counts over replicates:
Code
## Read SummarizedExperiment object
se_normalised_compound_batch <- readRDS(paste0("./results/compounds/se_normalised_per_compound_by_batch_", today_date, ".rds"))
se_normalised_compound_batch_mat <- SummarizedExperiment::assay(se_normalised_compound_batch)
se_pheno_data_normalised_compound_batch <- SummarizedExperiment::colData(se_normalised_compound_batch)
## Compute global correlation score
cor_per_compound_by_batch <- cor(se_normalised_compound_batch_mat)

## Define clustering colours
col_heatmap_scale <- circlize::colorRamp2(c(min(cor_per_compound_by_batch), 0, 1),
                                      c("blue", "white", "red"))

## Heatmap annotation
ha <- ComplexHeatmap::HeatmapAnnotation(df = se_pheno_data_normalised_compound_batch |> 
                                          as.data.frame() |> 
                                          dplyr::select(Pathway))

## Define Heatmap
heatmap_normalised_compound_batch <- ComplexHeatmap::Heatmap(cor_per_compound_by_batch, 
                                                             col=col_heatmap_scale, 
                                                             name = "CC for all Compound", 
                                                             show_row_names = TRUE,
                                                             show_column_names = TRUE, 
                                                             row_dend_reorder = TRUE,
                                                             column_dend_reorder = TRUE, 
                                                             row_names_gp = gpar(fontsize = 6),
                                                             column_names_gp = gpar(fontsize = 3),
                                                             column_names_rot = 45,
                                                             top_annotation = ha,
                                                             ## matrix size
                                                             width = ncol(cor_per_compound_by_batch)*unit(2, "mm"),
                                                             height = nrow(cor_per_compound_by_batch)*unit(2, "mm"))



size_heatmap <- calc_ht_size(heatmap_normalised_compound_batch)
padding_heatmap <- unit(c(2, 15, 2, 2), "mm")

## 2) Save png and pdf outputs
png(paste0("figures/compounds/heatmap_normalised_compound_by_batch_", today_date,".png"),
    res = 200,
    width = size_heatmap$width, height = size_heatmap$height, units = c("in"))
heatmap_normalised_compound_batch |> ComplexHeatmap::draw(padding = padding_heatmap)
dev.off()
##  png 
##    2

knitr::include_graphics(paste0("figures/compounds/heatmap_normalised_compound_by_batch_", today_date,".png"),
                        auto_pdf = TRUE,
                        dpi = 200)

ggsave(paste0("figures/compounds/heatmap_normalised_compound_by_batch_", today_date,".pdf"),
       heatmap_normalised_compound_batch |>
         ComplexHeatmap::draw(padding = padding_heatmap) |>
         grid::grid.grabExpr(),
       dpi = 200,
       width = size_heatmap$width, height = size_heatmap$height, units = c("in"))
Figure 3.2: Heatmap of normalised compounds by batch(aggregated over replicates) with CC.
  • Heatmap in Figure 3.3 is generated at the compound level:
Code
## Read SummarizedExperiment object
se_normalised_compound <- readRDS(paste0("./results/compounds/se_normalised_per_compound_", today_date, ".rds"))
se_normalised_compound_mat <- SummarizedExperiment::assay(se_normalised_compound)
se_normalised_pheno_data_compound <- SummarizedExperiment::colData(se_normalised_compound)
## Compute global correlation score
cor_per_compound <- cor(se_normalised_compound_mat)

## Define clustering colours
col_heatmap_scale <- circlize::colorRamp2(c(min(cor_per_compound), 0, 1),
                                      c("blue", "white", "red"))

## Heatmap annotation
ha <- ComplexHeatmap::HeatmapAnnotation(df = se_normalised_pheno_data_compound |> 
                                          as.data.frame() |> 
                                          dplyr::select(Pathway))

## Define Heatmap
heatmap_normalised_compound <- ComplexHeatmap::Heatmap(cor_per_compound, 
                                                       col=col_heatmap_scale, 
                                                       name = "CC for all Compound", 
                                                       show_row_names = TRUE,
                                                       show_column_names = TRUE, 
                                                       row_dend_reorder = FALSE,
                                                       column_dend_reorder = TRUE, 
                                                       ## font size
                                                       row_names_gp = gpar(fontsize = 6),
                                                       column_names_gp = gpar(fontsize = 6),
                                                       column_names_rot = 45,
                                                       top_annotation = ha,
                                                       ## matrix size
                                                       width = ncol(cor_per_compound)*unit(3, "mm"),
                                                       height = nrow(cor_per_compound)*unit(3, "mm")) 

size_heatmap <- calc_ht_size(heatmap_normalised_compound)
padding_heatmap <- unit(c(2, 15, 2, 2), "mm")

## 2) Save png and pdf outputs
png(paste0("figures/compounds/heatmap_normalised_compound_", today_date,".png"),
    res = 300,
    width = size_heatmap$width, height = size_heatmap$height, units = c("in"))
heatmap_normalised_compound |> ComplexHeatmap::draw(padding = padding_heatmap)
dev.off()
##  png 
##    2

knitr::include_graphics(paste0("figures/compounds/heatmap_normalised_compound_", today_date,".png"),
                        auto_pdf = TRUE,
                        dpi = 300)

ggsave(paste0("figures/compounds/heatmap_normalised_compound_", today_date,".pdf"),
       heatmap_normalised_compound |>
         ComplexHeatmap::draw(padding = padding_heatmap) |>
         grid::grid.grabExpr(),
       dpi = 300,
       width = size_heatmap$width, height = size_heatmap$height, units = c("in"))
Figure 3.3: Heatmap generated with the simple Pearson Correlation score.

3.2.1.2 Heatmap with Pearson correlation and binarised values

Code
## Read SummarizedExperiment object
se_binarised_replicates <- readRDS(paste0("./results/compounds/se_discretised_per_replicate_", today_date, ".rds"))
se_binarised_replicates_mat <- SummarizedExperiment::assay(se_binarised_replicates)
se_binarised_pheno_data_replicate <- SummarizedExperiment::colData(se_binarised_replicates)
## Compute global correlation score
cor_per_replicates <- cor(se_binarised_replicates_mat)

## Define clustering colours
col_heatmap_scale <- circlize::colorRamp2(c(min(cor_per_replicates), 0, 1),
                                      c("blue", "white", "red"))

## Heatmap annotation
ha <- ComplexHeatmap::HeatmapAnnotation(df = se_binarised_pheno_data_replicate |> 
                                          as.data.frame() |> 
                                          dplyr::select(Pathway, Batch_ID, Compound))


heatmap_binarised_replicates <- ComplexHeatmap::Heatmap(cor_per_replicates, 
                                                        col=col_heatmap_scale, 
                                                        name = "CC at binarised Compound Level",
                                                        show_row_names = TRUE,
                                                        show_column_names = TRUE, 
                                                        row_dend_reorder = FALSE,
                                                        column_dend_reorder = TRUE, 
                                                        ## font size
                                                        row_names_gp = gpar(fontsize = 2),
                                                        column_names_gp = gpar(fontsize = 2),
                                                        column_names_rot = 45,
                                                        top_annotation = ha,
                                                        ## matrix size
                                                        width = ncol(cor_per_replicate)*unit(1, "mm"),
                                                        height = nrow(cor_per_replicate)*unit(1, "mm")) 

size_heatmap <- calc_ht_size(heatmap_binarised_replicates)
padding_heatmap <- unit(c(2, 15, 2, 2), "mm")

## 2) Save png and pdf outputs
png(paste0("figures/compounds/heatmap_binarised_replicates_", today_date,".png"),
    res = 100,
    width = size_heatmap$width, height = size_heatmap$height, units = c("in"))
heatmap_binarised_replicates |> ComplexHeatmap::draw(padding = padding_heatmap)
dev.off()
##  png 
##    2

knitr::include_graphics(paste0("figures/compounds/heatmap_binarised_replicates_", today_date,".png"),
                        auto_pdf = TRUE,
                        dpi = 100)

ggsave(paste0("figures/compounds/heatmap_binarised_replicates_", today_date,".pdf"),
       heatmap_binarised_replicates |>
         ComplexHeatmap::draw(padding = padding_heatmap) |>
         grid::grid.grabExpr(),
       dpi = 100,
       width = size_heatmap$width, height = size_heatmap$height, units = c("in"))
Figure 3.4: Heatmaps at the replicates level.
  • Heatmap at the compound by batch level in Figure 3.5 (aggregated over technical replicates):
Code
## Read SummarizedExperiment object
se_binarised_compound_batch <- readRDS(paste0("./results/compounds/se_discretised_per_compound_by_batch_", today_date, ".rds"))
se_binarised_compound_batch_mat <- SummarizedExperiment::assay(se_binarised_compound_batch)
se_binarised_pheno_data_compound_batch <- SummarizedExperiment::colData(se_binarised_compound_batch)
## Compute global correlation score
cor_per_compound_by_batch <- cor(se_binarised_compound_batch_mat)

## Define clustering colours
col_heatmap_scale <- circlize::colorRamp2(c(min(cor_per_compound_by_batch), 0, 1),
                                      c("blue", "white", "red"))

## Heatmap annotation
ha <- ComplexHeatmap::HeatmapAnnotation(df = se_binarised_pheno_data_compound_batch |> 
                                          as.data.frame() |> 
                                          dplyr::select(Pathway, MoA))


heatmap_binarised_compound_batch <- ComplexHeatmap::Heatmap(cor_per_compound_by_batch, 
                                                            col=col_heatmap_scale, 
                                                            name = "CC at binarised Compound Level",
                                                            show_row_names = TRUE,
                                                            show_column_names = TRUE, 
                                                            row_dend_reorder = FALSE,
                                                            column_dend_reorder = TRUE, 
                                                            ## font size
                                                            row_names_gp = gpar(fontsize = 6),
                                                            column_names_gp = gpar(fontsize = 3),
                                                            column_names_rot = 45,
                                                            top_annotation = ha,
                                                            ## matrix size
                                                            width = ncol(cor_per_compound_by_batch)*unit(2, "mm"),
                                                            height = nrow(cor_per_compound_by_batch)*unit(2, "mm"))



size_heatmap <- calc_ht_size(heatmap_binarised_compound_batch)
padding_heatmap <- unit(c(2, 15, 2, 2), "mm")

## 2) Save png and pdf outputs
png(paste0("figures/compounds/heatmap_binarised_compound_by_batch_", today_date,".png"),
    res = 200,
    width = size_heatmap$width, height = size_heatmap$height, units = c("in"))
heatmap_binarised_compound_batch |> ComplexHeatmap::draw(padding = padding_heatmap)
dev.off()
##  png 
##    2

knitr::include_graphics(paste0("figures/compounds/heatmap_binarised_compound_by_batch_", today_date,".png"),
                        auto_pdf = TRUE,
                        dpi = 200)

ggsave(paste0("figures/compounds/heatmap_binarised_compound_by_batch_", today_date,".pdf"),
       heatmap_binarised_compound_batch |>
         ComplexHeatmap::draw(padding = padding_heatmap) |>
         grid::grid.grabExpr(),
       dpi = 200,
       width = size_heatmap$width, height = size_heatmap$height, units = c("in"))                              
Figure 3.5: Heatmaps at the compound by batch level.
Code
## Read SummarizedExperiment object
se_binarised_compound <- readRDS(paste0("./results/compounds/se_discretised_per_compound_", today_date, ".rds"))
se_binarised_compound_mat <- SummarizedExperiment::assay(se_binarised_compound)
se_binarised_pheno_data_compound <- SummarizedExperiment::colData(se_binarised_compound)
## Compute global correlation score
cor_per_compound <- cor(se_binarised_compound_mat)

## Define clustering colours
col_heatmap_scale <- circlize::colorRamp2(c(min(cor_per_compound), 0, 1),
                                      c("blue", "white", "red"))

## Heatmap annotation
ha <- ComplexHeatmap::HeatmapAnnotation(df = se_binarised_pheno_data_compound |> 
                                          as.data.frame() |> 
                                          dplyr::select(Pathway, MoA))


heatmap_binarised_compound <- ComplexHeatmap::Heatmap(cor_per_compound, 
                                                      col=col_heatmap_scale, 
                                                      name = "CC at binarised Compound Level",
                                                      show_row_names = TRUE,
                                                      show_column_names = TRUE, 
                                                      row_dend_reorder = TRUE,
                                                      column_dend_reorder = TRUE, 
                                                      row_names_gp = gpar(fontsize = 8),
                                                      column_names_gp = gpar(fontsize = 8),
                                                      column_names_rot = 45,
                                                      top_annotation = ha,
                                                      ## matrix size
                                                      width = ncol(cor_per_compound)*unit(4, "mm"),
                                                      height = nrow(cor_per_compound)*unit(4, "mm")) 

size_heatmap <- calc_ht_size(heatmap_binarised_compound)
padding_heatmap <- unit(c(2, 10, 2, 2), "mm")

## 2) Save png and pdf outputs
png(paste0("figures/compounds/heatmap_binarised_compound_", today_date,".png"),
    res = 300,
    width = size_heatmap$width, height = size_heatmap$height, units = c("in"))
heatmap_binarised_compound |> ComplexHeatmap::draw(padding = padding_heatmap)
dev.off()
##  png 
##    2

knitr::include_graphics(paste0("figures/compounds/heatmap_binarised_compound_", today_date,".png"),
                        auto_pdf = TRUE,
                        dpi = 300)

ggsave(paste0("figures/compounds/heatmap_binarised_compound_", today_date,".pdf"),
       heatmap_binarised_compound |>
         ComplexHeatmap::draw(padding = padding_heatmap) |>
         grid::grid.grabExpr(),
       dpi = 300,
       width = size_heatmap$width, height = size_heatmap$height, units = c("in"))                            
Figure 3.6: Heamaps at the compound level.

3.2.2 Compound Networks

  • Plot weighted undirected compound graphs with igraph::graph_from_adjacency_matrix in Figure 3.7, filtering out pairwise connections between 2 drugs if the \(p\)-value is not significant and absolute correlation score is below 0.8:
Code
#| label: fig-igraph-drug

## 1) Compute correlation matrix and p-values ----
cor_res <- Hmisc::rcorr(se_binarised_compound_mat, type = "pearson")
cor_binarised_compound <- cor_res$r
pval_binarised_compound <- cor_res$P

adj_mat <- cor_binarised_compound
adj_mat[pval_binarised_compound > 0.05/ncol(cor_res)] <- 0

## 2) build igraph adjacency matrix ----
compound_graph <- igraph::graph_from_adjacency_matrix(adjmatrix=adj_mat, 
                                          weighted = TRUE,
                                          diag = FALSE, 
                                          mode = "undirected")
## 3) igraph customisation ----
compound_graph$date <- today_date
E(compound_graph)$color <- if_else(E(compound_graph)$weight >0, "red", "blue")
E(compound_graph)$weight <- abs(E(compound_graph)$weight)

layout_graph <- igraph::layout_with_fr(compound_graph,
                                       niter = 500)
# graph dimension sizes
graph_width <- range(layout_graph[,1]) |> diff()
graph_height <- range(layout_graph[,2]) |> diff()
aspect_ratio <- graph_width / graph_height

vertex_structure <- se_binarised_pheno_data_compound |> 
  as.data.frame() |> 
  dplyr::mutate(color = if_else(Pathway=="EGFR", "green", "yellow"))

igraph::V(compound_graph)$color <- vertex_structure$color

pdf(paste0("figures/compounds/compound_graph_", today_date, ".pdf"), 
    width = 14 * aspect_ratio, height = 14, 
    useDingbats = TRUE, compress = FALSE)
plot(compound_graph, layout = layout_graph, vertex.size = 10,
     ## vertex.label.dist= 2,
     main = "Compound network interaction.
     In green, drugs related with the EGFR mechanism,
     and in yellow other pathways.
     Edge widths are proportional to the coefficient of correlation.", 
     edge.width = igraph::E(compound_graph)$weight * 20,
     vertex.label.cex = 0.9, curved = 0.2)
dev.off()
##  png 
##    2

## 4) export PNG and readable graph formats for Neo4J
png(paste0("figures/compounds/compound_graph_", today_date, ".png"), 
    width = 14 * aspect_ratio, height = 14, 
    res = 200, units = c("in"))
plot(compound_graph, layout = layout_graph, vertex.size = 10,
     ## vertex.label.dist= 2,
     main = "Compound network interaction.
     In green, drugs related with the EGFR mechanism,
     and in yellow other pathways.
     Edge widths are proportional to the coefficient of correlation.", 
     edge.width = igraph::E(compound_graph)$weight * 20,
     vertex.label.cex = 0.9, curved = 0.2)
dev.off()
##  png 
##    2
knitr::include_graphics(paste0("figures/compounds/compound_graph_", today_date, ".png"),
                        dpi = 200, auto_pdf = TRUE)

igraph::write_graph(graph = compound_graph, 
                    file = paste0("./results/compounds/compound_network_", today_date, ".graphml"),
                    format = "graphml")
Figure 3.7: Drug-drug network interactions, at the compound level.

3.3 Compute Cell Lines Similarities

3.3.1 Cell Line by Compound

Code
se_binarised_compound_batch_fac <- apply(se_binarised_compound_batch_mat, 2, as.character)

## Heatmap annotation
ha <- ComplexHeatmap::HeatmapAnnotation(df = se_binarised_pheno_data_compound_batch |> 
                                          as.data.frame() |> 
                                          dplyr::select(Batch_ID, Pathway, Compound))

heatmap_cell_lines_by_sample <- ComplexHeatmap::Heatmap(se_binarised_compound_batch_fac, 
                                                        col = c("TRUE" = "red", "FALSE" = "blue"), 
                                                        name = "Heatmap: cell-line by sample",
                                                        show_row_names = FALSE,
                                                        row_dend_reorder = TRUE,
                                                        ## clustering_distance_rows = "pearson",
                                                        show_row_dend = FALSE,
                                                        column_dend_reorder = TRUE, 
                                                        show_column_names = TRUE, 
                                                        column_names_gp = gpar(fontsize = 6),
                                                        column_names_rot = 45,
                                                        top_annotation = ha,
                                                        ## matrix size
                                                        width = ncol(se_binarised_compound_batch_fac)*unit(3, "mm"),
                                                        height = nrow(se_binarised_compound_batch_fac)*unit(0.3, "mm"),
                                                        use_raster = TRUE) 

size_heatmap <- calc_ht_size(heatmap_cell_lines_by_sample)
padding_heatmap <- unit(c(2, 10, 2, 2), "mm")

## 2) Save png and pdf outputs
png(paste0("figures/cell_lines/heatmap_cell_lines_by_samples_", today_date,".png"),
    res = 50,
    width = size_heatmap$width, height = size_heatmap$height, units = c("in"))
heatmap_cell_lines_by_sample |> ComplexHeatmap::draw(padding = padding_heatmap)
dev.off()
##  png 
##    2

knitr::include_graphics(paste0("figures/cell_lines/heatmap_cell_lines_by_samples_", today_date,".png"),
                        auto_pdf = TRUE,
                        dpi = 50)

ggsave(paste0("figures/cell_lines/heatmap_cell_lines_by_samples_", today_date,".pdf"),
       heatmap_cell_lines_by_sample |>
         ComplexHeatmap::draw(padding = padding_heatmap) |>
         grid::grid.grabExpr(),
       dpi = 200, limitsize = FALSE,
       width = size_heatmap$width, height = size_heatmap$height, units = c("in"))                                  
Figure 3.8: Heatmap cell lines by samples, averaging over replicates.