Chapter 9

Visualizing Dendrograms

data(USArrests)

dd <- dist(scale(USArrests), method = "euclidean")
hc <- hclust(dd, method = "ward.D2")

En el análisis de clúster, se utilizan algoritmos de agrupamiento para dividir un conjunto de datos en subconjuntos o clústeres basados en la similitud o proximidad entre los elementos. Estos algoritmos evalúan las similitudes o diferencias entre los datos utilizando medidas de distancia o similitud y agrupan los elementos en función de esas medidas.

suppressPackageStartupMessages(library(dendextend))

library(dendextend)

9.1 Visualizing dendrograms

Usaremos la función fviz_dend para crear un dendrograma basico usando el gráfico base R o ggplot2.

También proporciona una opción para dibujar dendrogramas circulares y árboles filogénicos.

suppressPackageStartupMessages(library(factoextra))
  
library(ggplot2)
library(factoextra)
fviz_dend(hc, cex = 0.5)
## Warning: The `<scale>` argument of `guides()` cannot be `FALSE`. Use "none" instead as
## of ggplot2 3.3.4.
## ℹ The deprecated feature was likely used in the factoextra package.
##   Please report the issue at <https://github.com/kassambara/factoextra/issues>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

Puede usar estos argumentos (main, sub, xlab,ylab) para cambiar los títulos del grafico y de los ejes:

fviz_dend (hc, cex = 0.5,
main = "Dendrogram - ward.D2" ,
xlab = "Objects" , ylab = "Distance" , sub= "")

Tambien pondemos presentarlo de manera horizontal:

fviz_dend(hc, cex = 0.5, horiz = TRUE)

Tambien podemos escoger la altura a la que deseamos que sean agrupados los datos, en este caso se describen 4 grupos que son:

  1. Murder: Tasa de asesinatos (por 100,000 habitantes).

  2. Assault: Tasa de asaltos (por 100,000 habitantes).

  3. UrbanPop: Porcentaje de población urbana.

  4. Rape: Tasa de violaciones (por 100,000 habitantes).

fviz_dend(hc, k = 4, # Cut in four groups
cex = 0.5, # label size
k_colors = c("#2E9FDF","#00AFBB", "#E7B800" ,"#FC4E07"),
color_labels_by_k = TRUE, # color labels by groups
ggtheme = theme_gray() # Change theme
)

fviz_dend(hc, cex = 0.5, k = 4, # Cut in four groups
k_colors = "jco" )

Aqui de manera horizontal y ya agrupada

fviz_dend(hc, k = 4, cex = 0.4, horiz = TRUE, k_colors = "jco",
rect = TRUE, rect_border = "jco", rect_fill = TRUE)

Tambien en diagrama circular con la opcion type = “circular”

fviz_dend(hc, cex = 0.5, k = 4,
k_colors = "jco", type = "circular")

Y en forma de filogenetica usamos las opciones type = “phylogenetic” y repel = TRUE, con esta ultima evitamos que las etiquetas de cada rama se superpongan una por encima de la otra

suppressPackageStartupMessages(require ("igraph"))

require ( "igraph")
fviz_dend(hc, k = 4, k_colors = "jco",
          type = "phylogenic", repel = TRUE
          )

require("igraph")
fviz_dend(hc, k = 4, # Cut in four groups
k_colors = "jco",
type = "phylogenic", repel = TRUE,
phylo_layout = "layout.gem")

9.2 Case of dendrogram with large data sets

9.2.1 Zooming in the dendrogram

si deseamos enfocar un/os grupo/s en especifico utilizaremos la funcion xlim y ylim para limitar el area que queremos enfocar.

fviz_dend(hc, xlim = c(1, 20), ylim = c(1, 8))

9.2.2 Plotting a sub-tree of dendrograms

para trazar un/os subarbol/es dentro de un dedrogramas es lo siguiente:

  1. Creamos el dendrograma usando fviz_dend , y Lo guardamos en un objeto, en este caso es dend_plot.
  2. Con la función cut.dendrogram cortamos el dendrograma a la altura h que deseamos en los subarbol/es
# Create a plot of the whole dendrogram,
# and extract the dendrogram data
dend_plot <- fviz_dend(hc, k = 4, # Cut in four groups
cex = 0.5, # label size
k_colors = "jco"
)
dend_data <- attr(dend_plot, "dendrogram") # Extract dendrogram data
# Cut the dendrogram at height h = 10
dend_cuts <- cut(dend_data, h = 10)
# Visualize the truncated version containing
# two branches
fviz_dend(dend_cuts$upper)
## Warning in min(-diff(our_dend_heights)): ningún argumento finito para min;
## retornando Inf

Aquí ya vemos a versión de dendrograma divididos en subgrupos

# Plot the whole dendrogram
print(dend_plot)

y finalmente aquí vemos el dendrograma original cortado y dividido en dos subarboles, por lo general el subarbol es el principal (de izquierda a derecha)

# Plot subtree 1
fviz_dend(dend_cuts$lower[[1]], main = "Subtree 1")

# Plot subtree 2
fviz_dend(dend_cuts$lower[[2]], main = "Subtree 2")

Circular se presentaria de la siguiente forma:

fviz_dend(dend_cuts$lower[[1]], type = "circular")

fviz_dend(dend_cuts$lower[[2]], type = "circular")

9.2.3 Saving dendrograms into a large PDF page

Esto sirve para poder cuardar un dendrograma en caso tal que sea muy grande, grande en el sentido de muchos datos y tamaño

pdf("dendrogram.pdf", width=30, height=15)  
p <- fviz_dend(hc, k = 4, cex = 1, k_colors ="jco" )
print(p)
dev.off()
## png 
##   2

9.3 Manipulating dendrograms using dendextend

data <- scale(USArrests)
dist.res <- dist(data)
hc <- hclust(dist.res, method = "ward.D2")
dend <- as.dendrogram(hc)
plot(dend)

library(dendextend)
dend <- USArrests[1:5,] %>%#data
  scale %>% # Scale the data
  dist %>% # calculate a distance matrix,
  hclust(method = "ward.D2") %>% # Hierarchical clustering
  as.dendrogram # Turn the object into a dendrogram.
plot(dend)

#set(object, what, value)#
library(dendextend)
# 1. Create a customized dendrogram
mycols <- c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07")
dend <- as.dendrogram(hc) %>%
set("branches_lwd", 1) %>% # Branches line width
set("branches_k_color", mycols, k = 4) %>%#Color branches by groups
set("labels_colors", mycols, k = 4) %>% # Color labels by groups
set("labels_cex", 0.5) # Change Label size

# 2. Create plot
fviz_dend(dend)

9.4 Summary

Describimos funciones y paquetes para visualizar y personalizar dendrogramas, además, tambien aprendimos cómo cortar un subconjunto de dendrogramas grandes, por otro lado aprendimos a usar las funciones para la creación y personalización de los dendogramas:

  • fviz_dend y el paquete factoextra, que proporcionan soluciones convenientes para trazar fácilmente un dendrograma. Se puede utilizar para visualizar dendrogramas rectangulares y circulares, y en árbol filogénico.

Chapter 10

Heatmap: Static and lnteractive

Un mapa de calor, también conocido como mapa de color falso, es una forma de visualizar la agrupación jerárquica mediante una escala de color. Permite mostrar simultáneamente grupos de muestras y características.

El agrupamiento jerárquico se realiza tanto para las filas como para las columnas de la matriz de datos. Luego, se reordenan las columnas/filas de acuerdo con el resultado del agrupamiento, colocando las observaciones similares cerca unas de otras.

Los bloques de valores “altos” y “bajos” son adyacentes en la matriz de datos. Por último, se aplica un esquema de color para la visualización y se muestra la matriz de datos; aquí se demostrará cómo dibujar y organizar un mapa de calor.

10.1 R Packages/functions for drawing heatmaps

Para dibujar mapas de calor tenemos estas distintas funciones:

  • heatmap: Este dibuja un mapa de calor simple.

  • heatmap.2: Dibuja un mapa de calor mejorado en comparación con el base inicial heatmap.

  • pheatmap(): Presenta mapas de calor y proporciona más control para cambiar la apariencia .

  • d3heatmap(): Dibuja un mapa de calor interactivo en el que se puede hacer clic.

  • Heatmap(): Anota y organiza mapas de calor complejos, esto es muy útil para el análisis de datos genómicos.

10.2 Data preparation

Usamos datos de mtcars el cual es un conjunto de datos incorporado que contiene información sobre diferentes modelos de automóviles, y que contiene 32 filas (representando diferentes modelos de automóviles) y 11 variables o columnas que describen diferentes características de los automóviles como lo son:

  • `mpg`: Millas por galón (consumo de combustible).

  • `cyl`: Número de cilindros.

  • `disp`: Desplazamiento (en pulgadas cúbicas).

  • `hp`: Caballos de fuerza.

  • `drat`: Relación del eje trasero.

  • `wt`: Peso (en miles de libras).

  • `qsec`: Tiempo de cuarto de milla.

  • `vs`: Tipo de motor (0 = motor en V, 1 = motor en línea).

  • `am`: Tipo de transmisión (0 = automático, 1 = manual).

  • `gear`: Número de engranajes.

  • `carb`: Número de carburadores.

df <- scale(mtcars)

10.3 R base heatmap: heatmap()

Podemos usar la función R heatmap() un grafico simplificado, siendo:

  • x : una matrix numerica

  • Scale: Nos Indica si los valores deben estar centrados y escalados en la dirección de la fila o en la dirección de la columna, o ninguno. Los valores permitidos están en c(“row”, “column”, “none”). El valor predeterminado es “row”.

suppressPackageStartupMessages(library(gplots))

library(gplots)
x <- scale(df)
heatmap(x, scale = "row")

heatmap(df, scale = "none")

Podemos especificar una paleta de colores usando el argumento col.

col<- colorRampPalette(c("red", "white", "blue")) (256)
library("RColorBrewer")
col <- colorRampPalette (brewer.pal(10, "RdYlBu")) (256)

Además, puede usar el argumento RowSideColors y ColSideColors para anotar filas y columnas, respectivamente.

# Use RCoLorBrewer coLor paLette names
library("RColorBrewer")
col <- colorRampPalette (brewer.pal(10, "RdYlBu"))(256)

heatmap(df, scale = "none", col= col,
RowSideColors = rep(c("blue", "pink"), each = 16) ,
ColSideColors = c(rep("purple", 5), rep("orange", 6)))

10.4 Enhanced heat maps: heatmap.2()

library("gplots")
heatmap.2(df, scale = "none", col = bluered(100), 
          trace = "none", density.info = "none")

10.5 Pretty heat maps: pheatmap()

Cortamos el mapa de calor a la agrupación que deseamos, en este caso es de 4 filas, este valrlo lo podemos ir cambiando para ser mas especificos en las filas que queremos mostrar o en grupos.

library( "pheatmap")
pheatmap(df, cutree_rows = 4 )

10.6 Interactive heat maps: d3heatmap()

El paquete d3heatmap no sirve porque el paquete lo sacaron del repositorio CRAN.

Este paquete nos permite intecartuar mas con el mapa, en el sentido de acerle zoom a una area especifica, o dar click en alguna celda para ver la información de ella.

#install.packages("d3heatmap")#
#library("d3heatmap" )#
#d3heatmap(scale(mtcars), colors = "RdYlBu" ,#
#k_row = 4, # Number of groups in rows#
#k_col = 2 # Number of groups in columns#

10.7 Enhancing heatmaps using dendextend

Podemos usar tambien el paquete dendextend para mejorar lo que muestran los otros paquetes, para esto los datos que estamos utilizando que son los de mtcars le definiremos un orden a la apariecnia de las filas y las columnas usando el paquete de dendextend este primer paso lo haremos con el siguiente codigo:

library(dendextend)
# order for rows
Rowv  <- mtcars %>% scale %>% dist %>% hclust %>% as.dendrogram %>%
   set("branches_k_color", k = 3) %>% set("branches_lwd", 1.2) %>%
   ladderize
# Order for columns: We must transpose the data
Colv  <- mtcars %>% scale %>% t %>% dist %>% hclust %>% as.dendrogram %>%
   set("branches_k_color", k = 2, value = c("orange", "blue")) %>%
   set("branches_lwd", 1.2) %>%
   ladderize
  1. la función normal es el heatmap , esta agrupa en ramas las filas y las columnas, y esas ramas las agrupa en arboles como en el capitulo anterior; cambia el colors de los arboles y del mapa para poder distinguir a detalle cada celda y su valor.
heatmap(scale(mtcars), Rowv = Rowv, Colv = Colv,
        scale = "none")

  1. la funcion heatmap.2 mejora la presentación de la función base heatmap.
library(gplots)
heatmap.2(scale(mtcars), scale = "none", col = bluered(100), 
          Rowv = Rowv, Colv = Colv,
          trace = "none", density.info = "none")

10.8 Complex heatmap

Nos proporciona una solución para crear y visuRColorBrewer:alizar múltiples mapas de calor, también permite hacer la asociación entre diferentes datos de diferentes fuentes.

  • Mostramos un mapa de calor simple:
suppressPackageStartupMessages(library(ComplexHeatmap))

library(ComplexHeatmap)

Heatmap(df, 
        name = "mtcars", #title of legend
        column_title = "Variables", row_title = "Samples",
        row_names_gp = gpar(fontsize = 7) # Text size for row names
        )

  • Tambien podemos personalizar el color con la función colorRamp2 de la siguiente manera:
suppressPackageStartupMessages(library(circlize))

library(circlize)

mycols <- colorRamp2(breaks = c(-2, 0, 2), 
                    colors = c("green", "white", "red"))
Heatmap(df, name = "mtcars", col = mycols)

O cambiar la paleta de colores con la función RColorBrewer:

library("circlize")
library("RColorBrewer")
Heatmap(df, name = "mtcars",
        col = colorRamp2(c(-2, 0, 2), brewer.pal(n=3, name="RdBu")))

Y finalmente podemos cambiar la apariencia de los dendogramas para poder indentificarlos mejor:

library(dendextend)
row_dend = hclust(dist(df)) # row clustering
col_dend = hclust(dist(t(df))) # column clustering
Heatmap(df, name = "mtcars", 
        row_names_gp = gpar(fontsize = 6.5),
        cluster_rows = color_branches(row_dend, k = 4),
        cluster_columns = color_branches(col_dend, k = 2))

10.8.2 Splitting heatmap by rows

Podemos dividir el mapa de calor utilizando el algoritmo k-means o una variable de agrupación. Es importante que utilicemos la función set.seed para que los resultados obtenidos puedan reproducirse con precisión.

  • Dividiremos el dendograma usando el k-means , en este caso lo dividiremos en 2, pero tambien depende del usuario en cuantos filas quiere hacer visualizar a detalle.
# Divide into 2 groups
set.seed(2)
Heatmap(df, name = "mtcars", k = 2)

  • En caso para dividir una variables de agrupación utilizamos el argumento split
# split by a vector specifying rowgroups
Heatmap(df, name = "mtcars", split = mtcars$cyl,
        row_names_gp = gpar(fontsize = 7))

# Split by combining multiple variables
Heatmap(df, name ="mtcars", 
        split = data.frame(cyl = mtcars$cyl, am = mtcars$am),
        row_names_gp = gpar(fontsize = 7))

  • Si queremos utilizar otro metodo de aparte del K-meas, lo podemos hacer si asignamos un vector para esta partición, en este caso sería pam, este partirá los datos del cluster, se podría decir que es una versión mas constituida del k-means.

10.8.3 Heatmap annotation

La clase HeatmapAnnotation se utiliza para darle la anotación en una fila o columna, Un formato simplificado es:

#HeatmapAnnotation(df, col, show_legend)#
df <- t(df)

10.8.3.1 Simple annotation

Un vector en este caso tiene valores discretos o continuos y se utiliza para anotar filas o columnas. Vamos a utilizar las variables cualitativas cyl (niveles = “4”, “6” y “8”) y am (niveles = “0” y “1”), y la variable continua mpg para anotar columnas; estas 3 variables tienen colores personalizados para distinguirlas

# Define colors for each levels of qualitative variables
# Define gradient color for continuous variable (mpg)
col = list(cyl = c("4" = "green", "6" = "gray", "8" = "darkred"),
            am = c("0" = "yellow", "1" = "orange"),
            mpg = circlize::colorRamp2(c(17, 25), 
                                       c("lightblue", "purple")) )
# Create the heatmap annotation
ha <- HeatmapAnnotation(
  cyl = mtcars$cyl, am = mtcars$am, mpg = mtcars$mpg,
  col = col
)
# Combine the heatmap and the annotation
Heatmap(df, name = "mtcars",
        top_annotation = ha)

10.8.3.2 Complex annotation

Aquí se combina el mapa de color con graficos basicos que muestran la distribición de los datos, las funciones para esto son las siguientes: anno_pointsanno_barplotanno_boxplotanno_densityanno_histogram.

# Define some graphics to display the distribution of columns
.hist = anno_histogram(df, gp = gpar(fill = "lightblue"))
.density = anno_density(df, type = "line", gp = gpar(col = "blue"))
ha_mix_top = HeatmapAnnotation(
  hist = .hist, density = .density,
  height = unit(3.8, "cm")
  )

# Define some graphics to display the distribution of rows
.violin = anno_density(df, type = "violin", 
                       gp = gpar(fill = "lightblue"), which = "row")
.boxplot = anno_boxplot(df, which = "row")
ha_mix_right = HeatmapAnnotation(violin = .violin, bxplt = .boxplot,
                              which = "row", width = unit(4, "cm"))

# Combine annotation with heatmap
Heatmap(df, name = "mtcars", 
        column_names_gp = gpar(fontsize = 8),
        top_annotation = ha_mix_top) + ha_mix_right

  • Los histogramas muestran la distribución de los valores en cada columna del dataframe df, y representan la frecuencia de los valores en un rango específico.

  • Las curvas de densidad representan la distribución de la probabilidad de los valores en cada columna del dataframe df, y muestran la forma de la distribución en que podemos identificar picos, asimetrías o colas largas.

  • Los diagramas de violín muestran información sobre la mediana, los cuartiles, los valores atípicos y la forma de la distribución en cada fila.

  • Los diagramas de caja muestran la mediana, los cuartiles y los valores atípicos, lo que permite tener una idea de la dispersión y la simetría de los datos en cada fila.

10.8.3.3 Combining multiple heatmaps

Organizamos los mapas de la siguiente manera:

# Heatmap 1
ht1 = Heatmap(df, name = "ht1", km = 2,
              column_names_gp = gpar(fontsize = 9))
# Heatmap 2
ht2 = Heatmap(df, name = "ht2", 
        col = circlize::colorRamp2(c(-2, 0, 2), c("green", "white", "red")),
        column_names_gp = gpar(fontsize = 9))
# Combine the two heatmaps
ht1 + ht2

hay que tener en cuenta que cuando combinamos varios mapas de calor, el primer mapa se considera el principal, el mapa restante en ocasiones se ajusta automaticamente a la configuración del mapa principal y es posible que se eliminen grupos de filas.

10.9 Application to gene expression matrix

En los datos de expresión génica, las filas son genes y las columnas son muestras, los graficos muesran más información sobre los genes después del mapa de calor , la longitud del gen y el tipo de genes.

expr <- readRDS(paste0(system.file(package = "ComplexHeatmap"),
                      "/extdata/gene_expression.rds"))
mat <- as.matrix(expr[, grep("cell", colnames(expr))])
type <- gsub("s\\d+_", "", colnames(mat))
ha = HeatmapAnnotation(
  df = data.frame(type = type),
   annotation_height = unit(4, "mm")
  )

Heatmap(mat, name = "expression", km = 5, top_annotation = ha,
    show_row_names = FALSE, show_column_names = FALSE) +
Heatmap(expr$length, name = "length", width = unit(5, "mm"),
    col = circlize::colorRamp2(c(0, 100000), c("white", "orange"))) +
Heatmap(expr$type, name = "type", width = unit(5, "mm")) +
Heatmap(expr$chr, name = "chr", width = unit(5, "mm"),
    col = circlize::rand_color(length(unique(expr$chr))))
## There are 23 unique colors in the vector `col` and 23 unique values in
## `matrix`. `Heatmap()` will treat it as an exact discrete one-to-one
## mapping. If this is not what you want, slightly change the number of
## colors, e.g. by adding one more color or removing a color.

10.10 Summary

Usamos muchas funciones para dibujar mapas de calor (desde mapas de calor básicos hasta complejos). Se puede representar un mapa de calor básico utilizando la función heatmap o la función heatmap.2.
La función pheatmap, en el paquete del mismo nombre se usa para crear mapas de calor mas interactivos, donde uno tiene un mejor control sobre algunos parámetros gráficos como el tamaño de la celda.

y finalmente la función Heatmap nos permite dibujar, anotar y organizar fácilmente mapas de calor complejos.