Frequently asked questions

Tal Galili

2024-11-15

Introduction

Questions are often taken from here the stackoverflow dendrogram tag.

How to colour the labels of a dendrogram by an additional factor variable

Asked (https://stackoverflow.com/questions/27485549/how-to-colour-the-labels-of-a-dendrogram-by-an-additional-factor-variable-in-r)[here].

Solution: use the labels_colors function.

# install.packages("dendextend")
library(dendextend)

dend <- as.dendrogram(hclust(dist(USArrests[1:5,])))
# Like: 
# dend <- USArrests[1:5,] %>% dist %>% hclust %>% as.dendrogram

# By default, the dend has no colors to the labels
labels_colors(dend)
## NULL
par(mfrow = c(1,2))
plot(dend, main = "Original dend")

# let's add some color:
labels_colors(dend) <- 1:5
# Now each state has a color
labels_colors(dend) 
##   Arkansas    Arizona California    Alabama     Alaska 
##          1          2          3          4          5
plot(dend, main = "A color for every state")

Instead of using 1:5, we can obviously use colors that are based on another factor (organized): the labels themselves. But in such a case, we want to map between the order of the labels and the order of the items in the original dataset. Here is another example based on the iris dataset:

# install.packages("dendextend")
library(dendextend)

small_iris <- iris[c(1, 51, 101, 2, 52, 102), ]
dend <- as.dendrogram(hclust(dist(small_iris[,-5])))
# Like: 
# dend <- small_iris[,-5] %>% dist %>% hclust %>% as.dendrogram

# By default, the dend has no colors to the labels
labels_colors(dend)
## NULL
par(mfrow = c(1,2))
plot(dend, main = "Original dend")

# Let's add some color:
colors_to_use <- as.numeric(small_iris[,5])
colors_to_use
## [1] 1 2 3 1 2 3
# But sort them based on their order in dend:
colors_to_use <- colors_to_use[order.dendrogram(dend)]
colors_to_use
## [1] 1 1 2 2 3 3
# Now we can use them
labels_colors(dend) <- colors_to_use
# Now each state has a color
labels_colors(dend) 
##   1   2  51  52 101 102 
##   1   1   2   2   3   3
plot(dend, main = "A color for every Species")

How to color a dendrogram’s labels according to defined groups? (in R)

Asked (https://stackoverflow.com/questions/31117849/how-to-color-a-dendrograms-labels-according-to-defined-groups-in-r)[here].

Solution: use the color_labels function.

I suspect the function you are looking for is either color_labels or get_leaves_branches_col. The first color your labels based on cutree (like color_branches do) and the second allows you to get the colors of the branch of each leaf, and then use it to color the labels of the tree (if you use unusual methods for coloring the branches (as happens when using branches_attr_by_labels). For example:

 # define dendrogram object to play with:
 hc <- hclust(dist(USArrests[1:5,]), "ave")
 dend <- as.dendrogram(hc)

 library(dendextend)
 par(mfrow = c(1,2), mar = c(5,2,1,0))
 dend <- dend %>%
          color_branches(k = 3) %>%
          set("branches_lwd", c(2,1,2)) %>%
          set("branches_lty", c(1,2,1))
 
 plot(dend)

 dend <- color_labels(dend, k = 3)
 # The same as:
 # labels_colors(dend)  <- get_leaves_branches_col(dend)
 plot(dend)

Either way, you should always have a look at the set function, for ideas on what can be done to your dendrogram (this saves the hassle of remembering all the different functions names).

How to color a dendrogram’s branches/labels based on cluster (i.e.: cutree result)

Use the color_branches and color_labels functions, with the k (orh) parameter:

# install.packages("dendextend")
library(dendextend)

dend <- as.dendrogram(hclust(dist(USArrests[1:5,])))
# Like: 
# dend <- USArrests[1:5,] %>% dist %>% hclust %>% as.dendrogram

dend1 <- color_branches(dend, k = 3)
dend2 <- color_labels(dend, k = 3)

par(mfrow = c(1,2))
plot(dend1, main = "Colored branches")
plot(dend2, main = "Colored labels")

Change dendrogram’s labels

Use the left assign labels<- function:

# install.packages("dendextend")
library(dendextend)

dend <- as.dendrogram(hclust(dist(USArrests[1:5,])))
# Like: 
# dend <- USArrests[1:5,] %>% dist %>% hclust %>% as.dendrogram

labels(dend)
## [1] "Arkansas"   "Arizona"    "California" "Alabama"    "Alaska"
labels(dend) <- 1:5
labels(dend)
## [1] 1 2 3 4 5

Larger font for leaves in a dendrogram

Asked (https://stackoverflow.com/questions/26965390/larger-font-and-spacing-between-leaves-in-r-dendrogram)[here].

Solution: use the set function, with the “labels_cex” parameter.

# install.packages("dendextend")
library(dendextend)

dend <- as.dendrogram(hclust(dist(USArrests[1:5,])))
# Like: 
# dend <- USArrests[1:5,] %>% dist %>% hclust %>% as.dendrogram

# By default, the dend has no text size to it (showing only the first leaf)
get_leaves_nodePar(dend)[[1]]
## [1] NA
par(mfrow = c(1,2), mar = c(10,4,4,2))
plot(dend, main = "Original dend")

# let's increase the size of the labels:
dend <- set(dend, "labels_cex", 2)
# Now each state has a larger label
get_leaves_nodePar(dend)[[1]]
## $lab.cex
## [1] 2
## 
## $pch
## [1] NA
plot(dend, main = "A larger font for labels")

(Note that changing the spacing between the labels is currently not implemented)

How to view attributes of a dendrogram

Asked (https://stackoverflow.com/questions/26240200/how-to-access-attributes-of-a-dendrogram-in-r)[here], and (https://stackoverflow.com/questions/25664911/r-hclust-height-of-final-merge)[here].

It generally depends on which attribute we want to view. For “midpoint” (or height) use the get_nodes_attr function, with the “midpoint” parameter.

# install.packages("dendextend")
library(dendextend)

dend <- as.dendrogram(hclust(dist(USArrests[1:5,])))
# Like: 
# dend <- USArrests[1:5,] %>% dist %>% hclust %>% as.dendrogram

# midpoint for all nodes
get_nodes_attr(dend, "midpoint")
## [1] 1.25   NA 1.50 0.50   NA   NA 0.50   NA   NA
# Perhaps also for the height:
get_nodes_attr(dend, "height")
## [1] 108.85192   0.00000  63.00833  23.19418   0.00000   0.00000  37.17701
## [8]   0.00000   0.00000

To also change an attribute, you can use the various assign functions from the package: assign_values_to_leaves_nodePar, assign_values_to_leaves_edgePar, assign_values_to_nodes_nodePar, assign_values_to_branches_edgePar, remove_branches_edgePar, remove_nodes_nodePar

How to color the branches in heatmap.2?

Asked (https://stackoverflow.com/questions/29265536/how-to-color-the-branches-and-tick-labels-in-the-heatmap-2?)[here].

Solution: use the color_branches function (or the set function, with the “branches_k_color”, “k”, and “value” parameters).

(Getting the data for this example is from the (https://stackoverflow.com/questions/29265536/how-to-color-the-branches-and-tick-labels-in-the-heatmap-2)[original SO question])

test <- test0
rnames <- test[,1] 
test <- data.matrix(test[,2:ncol(test)]) # to matrix
rownames(test) <- rnames                 
test <- scale(test, center=T, scale=T) # data standarization
test <- t(test) # transpose


## Creating a color palette & color breaks

my_palette <- colorRampPalette(c("forestgreen", "yellow", "red"))(n = 299)

col_breaks = c(seq(-1,-0.5,length=100),  # forestgreen
               seq(-0.5,0.5,length=100), # yellow
               seq(0.5,1,length=100))    # red

# distance & hierarchical clustering
distance = dist(test, method ="euclidean")    
hcluster = hclust(distance, method ="ward.D")


dend1 <- as.dendrogram(hcluster)

# Get the dendextend package
if(!require(dendextend)) install.packages("dendextend")
library(dendextend)
# get some colors
cols_branches <- c("darkred", "forestgreen", "orange", "blue")
# Set the colors of 4 branches
dend1 <- color_branches(dend1, k = 4, col = cols_branches)
# or with:
# dend1 <- set(dend1, "branches_k_color", k = 4, value = cols_branches)

# Get the colors of the tips of the dendrogram:
# col_labels <- cols_branches[cutree(dend1, k = 4)] # this may need tweaking in various cases - the following is a more general solution.

col_labels <- get_leaves_branches_col(dend1)
# But due to the way heatmap.2 works - we need to fix it to be in the 
# order of the data!   
col_labels <- col_labels[order(order.dendrogram(dend1))]

dend1
# plot(dend1)
# a <- heights_per_k.dendrogram(dend1)
# a2 <- heights_per_k.dendrogram(dend1)
# nleaves(dend1)


# Creating Heat Map
# if(!require(gplots)) install.packages("gplots")
library(gplots)
heatmap.2(test,  
    main = paste( "test"),  
        trace="none",          
        margins =c(5,7),      
        col=my_palette,        
        breaks=col_breaks,     
        dendrogram="row",      
        Rowv = dend1,  
        Colv = "NA", 
        key.xlab = "Concentration (index)",
        cexRow =0.6,
        cexCol = 0.8,
        na.rm = TRUE,
        RowSideColors = col_labels # to add nice colored strips     
      # colRow = col_labels # to add nice colored labels - only for qplots 2.17.0 and higher
        ) 

For package developers - how to call imported calls from dendextend 0.18.3?

If you are developing a package and you wish to use dendextend as an imported package, that is - without loading it to the search path, you should run:

dendextend::assign_dendextend_options()
# This populates the dendextend::dendextend_options() space

Before using any of its function (for example: dendextend::color_branches ). As of dendextend version 1.0.0, this is no longer required.

How to plot a fan (Polar) Dendrogram in R?

Asked (https://stats.stackexchange.com/questions/4062/how-to-plot-a-fan-polar-dendrogram-in-r)[here].

Solution: use the circlize_dendrogram function.

# install.packages("dendextend")
# install.packages("circlize")
library(dendextend)
library(circlize)

# create a dendrogram
hc <- hclust(dist(datasets::mtcars))
dend <- as.dendrogram(hc)

# modify the dendrogram to have some colors in the branches and labels
dend <- dend %>% 
   color_branches(k=4) %>% 
   color_labels

# plot the radial plot
par(mar = rep(0,4))
# circlize_dendrogram(dend, dend_track_height = 0.8) 
circlize_dendrogram(dend, labels_track_height = NA, dend_track_height = .3) 

A way to calculate lowest value of h in cut that produces groupings of a given minimum size?

Asked (https://stackoverflow.com/questions/31124810/r-cut-dendrogram-into-groups-with-minimum-size/)[here].

Solution: use the heights_per_k.dendrogram function.

This feature is available in the dendextend package with the heights_per_k.dendrogram function (which also has a faster C++ implementation when loading the dendextendRcpp function).

hc <- hclust(dist(USArrests[1:4,]), "ave")
dend <- as.dendrogram(hc)
heights_per_k.dendrogram(dend)
##        1        2        3        4 
## 86.47086 68.84745 45.98871 28.36531

As a sidenote, the dendextend package has a cutree.dendrogram S3 method for dendrograms (which works very similarly to cutree for hclust objects).

Coloring dendrogram’s end branches (or leaves) based on column number of data frame in R

Asked (https://stackoverflow.com/questions/30062187/coloring-dendrogram-s-end-branches-or-leaves-based-on-column-number-of-data-fr)[here].

Solution: use the assign_values_to_leaves_edgePar function.

aa1 <- c(2,4,6,8)
bb1 <- c(1,3,7,11)
aa2 <- c(3,6,9,12)
bb2 <- c(3,5,7,9)
data.main <- data.frame(aa1,bb1,aa2,bb2)
d1 <- dist(t(data.main))
hcl1 <- hclust(d1)
# plot(hcl1)

dend <- as.dendrogram(hcl1)
col_aa_red <- ifelse(grepl("aa", labels(dend)), "red", "blue")
dend2 <- assign_values_to_leaves_edgePar(dend=dend, value = col_aa_red, edgePar = "col")
plot(dend2)

Color side bar dendrogram plot

Asked (https://stackoverflow.com/questions/34539746/color-side-bar-dendrogram-plot/)[here].

Solution: use the color_branches function.

Example using mtcars:

## mtcars example

# Create the dend:
dend <- as.dendrogram(hclust(dist(mtcars)))

# Create a vector giving a color for each car to which company it belongs to
car_type <- rep("Other", length(rownames(mtcars)))
is_x <- grepl("Merc", rownames(mtcars))
car_type[is_x] <- "Mercedes"
is_x <- grepl("Mazda", rownames(mtcars))
car_type[is_x] <- "Mazda"
is_x <- grepl("Toyota", rownames(mtcars))
car_type[is_x] <- "Toyota"
car_type <- factor(car_type)
n_car_types <- length(unique(car_type))
cols_4 <- colorspace::rainbow_hcl(n_car_types, c = 70, l  = 50)
col_car_type <- cols_4[car_type]

# extra: showing the various clusters cuts 
k234 <- cutree(dend, k = 2:4)

# color labels by car company:
labels_colors(dend) <- col_car_type[order.dendrogram(dend)]
# color branches based on cutting the tree into 4 clusters:
dend <- color_branches(dend, k = 4)

### plots
par(mar = c(12,4,1,1))
plot(dend)
colored_bars(cbind(k234[,3:1], col_car_type), dend, rowLabels = c(paste0("k = ", 4:2), "Car Type"))

# horiz version:
# dend <- sort(dend)
par(mar = c(4,1,1,12))
plot(dend, horiz = TRUE)
colored_bars(cbind(k234[,3:1], col_car_type), dend, rowLabels = c(paste0("k = ", 4:2), "Car Type"), horiz = TRUE)
legend("topleft", legend = levels(car_type), fill = cols_4)

Plot a “mirror” (labels on the left) horizontal dendrogram

Asked (https://github.com/talgalili/dendextend/issues/29)[here].

Solution: use the plot_horiz.dendrogram function.

Example using USArrests:

# Create the dend:
hc <- hclust(dist(USArrests), "ave")
d <- as.dendrogram(hc)
library(dendextend)
d <- d %>% color_branches(k=3) %>% color_labels

# horiz normal version
par(mar = c(3,1,1,7))
plot(d, horiz  = TRUE)

# horiz mirror version
par(mar = c(3,7,1,1))
plot_horiz.dendrogram(d, side = TRUE)