Question 1: Please replicate the code and markdown provided in the readings for the mtcars dataset to visualize it using hierarchical cluster analysis heatmaps following the recommendations from the readings, including using uncentered correlation.

library(devtools)
## Loading required package: usethis
#install_github("jokergoo/ComplexHeatmap")
#install_github("cran/hopach")
#install.packages("circlize")
if (!requireNamespace("BiocManager", quietly = TRUE)) {
  install.packages("BiocManager")
}
BiocManager::install("hopach", update = FALSE, ask = FALSE)
## Bioconductor version 3.22 (BiocManager 1.30.27), R 4.5.3 (2026-03-11)
## Warning: package(s) not installed when version(s) same as or greater than current; use
##   `force = TRUE` to re-install: 'hopach'

load packages

library(ComplexHeatmap)
## Loading required package: grid
## ========================================
## ComplexHeatmap version 2.25.3
## Bioconductor page: http://bioconductor.org/packages/ComplexHeatmap/
## Github page: https://github.com/jokergoo/ComplexHeatmap
## Documentation: http://jokergoo.github.io/ComplexHeatmap-reference
## 
## If you use it in published research, please cite either one:
## - Gu, Z. Complex Heatmap Visualization. iMeta 2022.
## - Gu, Z. Complex heatmaps reveal patterns and correlations in multidimensional 
##     genomic data. Bioinformatics 2016.
## 
## 
## The new InteractiveComplexHeatmap package can directly export static 
## complex heatmaps into an interactive Shiny app with zero effort. Have a try!
## 
## This message can be suppressed by:
##   suppressPackageStartupMessages(library(ComplexHeatmap))
## ========================================
library(circlize)
## ========================================
## circlize version 0.4.18
## CRAN page: https://cran.r-project.org/package=circlize
## Github page: https://github.com/jokergoo/circlize
## Documentation: https://jokergoo.github.io/circlize_book/book/
## 
## If you use it in published research, please cite:
## Gu, Z. circlize implements and enhances circular visualization
##   in R. Bioinformatics 2014.
## 
## This message can be suppressed by:
##   suppressPackageStartupMessages(library(circlize))
## ========================================
library(hopach)
## Loading required package: cluster
## Loading required package: Biobase
## Loading required package: BiocGenerics
## Loading required package: generics
## 
## Attaching package: 'generics'
## The following objects are masked from 'package:base':
## 
##     as.difftime, as.factor, as.ordered, intersect, is.element, setdiff,
##     setequal, union
## 
## Attaching package: 'BiocGenerics'
## The following objects are masked from 'package:stats':
## 
##     IQR, mad, sd, var, xtabs
## The following objects are masked from 'package:base':
## 
##     anyDuplicated, aperm, append, as.data.frame, basename, cbind,
##     colnames, dirname, do.call, duplicated, eval, evalq, Filter, Find,
##     get, grep, grepl, is.unsorted, lapply, Map, mapply, match, mget,
##     order, paste, pmax, pmax.int, pmin, pmin.int, Position, rank,
##     rbind, Reduce, rownames, sapply, saveRDS, table, tapply, unique,
##     unsplit, which.max, which.min
## Welcome to Bioconductor
## 
##     Vignettes contain introductory material; view with
##     'browseVignettes()'. To cite Bioconductor, see
##     'citation("Biobase")', and for packages 'citation("pkgname")'.
## 
## Attaching package: 'hopach'
## The following object is masked from 'package:generics':
## 
##     prune

read the dataset

head(mtcars)
##                    mpg cyl disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
## Valiant           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1
data<-mtcars[, c(1:7)]

rescale the dataset

data.scale<-scale(data)
head(data.scale)
##                          mpg        cyl        disp         hp       drat
## Mazda RX4          0.1508848 -0.1049878 -0.57061982 -0.5350928  0.5675137
## Mazda RX4 Wag      0.1508848 -0.1049878 -0.57061982 -0.5350928  0.5675137
## Datsun 710         0.4495434 -1.2248578 -0.99018209 -0.7830405  0.4739996
## Hornet 4 Drive     0.2172534 -0.1049878  0.22009369 -0.5350928 -0.9661175
## Hornet Sportabout -0.2307345  1.0148821  1.04308123  0.4129422 -0.8351978
## Valiant           -0.3302874 -0.1049878 -0.04616698 -0.6080186 -1.5646078
##                             wt       qsec
## Mazda RX4         -0.610399567 -0.7771651
## Mazda RX4 Wag     -0.349785269 -0.4637808
## Datsun 710        -0.917004624  0.4260068
## Hornet 4 Drive    -0.002299538  0.8904872
## Hornet Sportabout  0.227654255 -0.4637808
## Valiant            0.248094592  1.3269868

heatmap 1

Heatmap(data.scale, name = "mtcars heatmap", 
        cluster_rows=FALSE , cluster_columns = FALSE)

cluster on rows

Heatmap(data.scale, name = "mtcars heatmap", 
        cluster_columns = FALSE)

# cluster on rows and columns

Heatmap(data.scale, name = "mtcars heatmap")

clustering using uncentered correlation and average linkage

uncenter.dist<-function(m) {
  as.dist(as.matrix(distancematrix(m, d="cosangle")))
}
row.clus<-hclust(uncenter.dist(data.scale), method = "ave")
col.clus<-hclust(uncenter.dist(t(data.scale)), method = "ave")

Heatmap(data.scale, name = "mtcars heatmap", 
        cluster_rows=row.clus, cluster_columns=col.clus)

## dichtomous variables

ht_inline<-Heatmap(mtcars[, c(8)], name = "Cylinder Config",
                   col = colorRamp2(c(0,1),c("white", "black")),
                   heatmap_legend_param = list(at = c(0,1),
                         labels = c("V-shaped", "Inline")),
                   width = unit(0.5,"cm"))

ht_manual<-Heatmap(mtcars[, c(9)], name = "Transmission",
                   col = colorRamp2(c(0,1),c("white", "black")),
                   heatmap_legend_param = list(at = c(0,1),
                         labels = c("Automatic", "Manual")),
                   width = unit(0.5,"cm"))
ht_main = Heatmap(data.scale, name = "cluster rows",
                  cluster_rows=row.clus, cluster_columns = col.clus)

draw(ht_main+ht_manual+ht_inline, auto_adjust = FALSE) 

draw(ht_main+ht_manual+ht_inline) 

Question 2: Select at least three different options/alternatives from ComplexHeatmap’s first three chapters, and apply them to the mtcars dataset. For example, such as using different clustering algorithms (k-means, etc.), separation of heatmaps, stacking, different ways to annotate (columns and rows and different graphing options beyond black/white blocks), etc. Please provide some text in your markdown discussing what options/alternatives you selected, why this was interesting, and any challenges you experienced with running the visualizations. Provide a few sentences to interpret each new heatmap visualization.

Approach 1

what options selected, why this was interesting, any challenges, interpret each visualization

To make the clusters easier to distinguish, we split the heatmap into two labeled slices using Gestalt principles of proximity and visual grouping, while reducing the font size and tuning the margins to prevent car names from overlapping after setting auto_adjust = FALSE. The visualization reveals two distinct vehicle profiles: the “Fuel Efficient” cluster features high gas mileage (mpg), lighter weight (wt), and lower horsepower (hp) with smaller engine displacement, predominantly paired with manual transmissions and straight (in-line) engines; conversely, the “Fuel Inefficient” cluster consists of heavier, high-horsepower vehicles with lower mpg and larger engines, which are mostly equipped with automatic transmissions and V-shaped engines.

library(grid)
ht_main = Heatmap(data.scale, name = "cluster rows",
                  cluster_rows=row.clus, cluster_columns = col.clus,
                  row_split = 2, 
                  row_title = c("fuel efficient", "fuel inefficient"),
                  row_title_rot = 0,
                  row_names_gp = gpar(fontsize = 6),     
                  column_names_gp = gpar(fontsize = 9),  
                  row_title_gp = gpar(fontsize = 10))

draw(ht_main+ht_manual+ht_inline, auto_adjust = FALSE) 

Approach 2

Following Approach 1, the top boxplot annotation illustrates the distribution of column values across all 32 car models. The median line for each metric (hp, wt, cyl, disp, qsec, mpg, and drat) hovers near 0, with values spanning roughly between -2 and +2, confirming our prior standardization process (Z-score scaling). Additionally, mpg and drat exhibit longer upper whiskers and higher extreme values, highlighting the presence of notable high-end outliers in fuel efficiency and rear-axle gear ratios within the dataset.

anno <- HeatmapAnnotation(
  Distribution = anno_boxplot(
    data.scale,
    height = unit(2, "cm"),
    gp = gpar(fill = "#e0e0e0"),
    box_width = 0.9,
    outline = FALSE
  ),
  annotation_name_side = "left",
  annotation_name_gp = gpar(fontsize = 9)
)

ht_main = Heatmap(data.scale, name = "cluster rows",
                  top_annotation = anno,
                  cluster_rows=row.clus, cluster_columns = col.clus,
                  row_split = 2, 
                  row_title = c("fuel efficient", "fuel inefficient"),
                  row_title_rot = 0,
                  row_names_gp = gpar(fontsize = 6),     
                  column_names_gp = gpar(fontsize = 9),  
                  row_title_gp = gpar(fontsize = 10))
draw(ht_main+ht_manual+ht_inline, auto_adjust = FALSE) 

Approach 3

In Approach 3, we implemented k-means clustering by manually defining the cluster count k, in contrast to hierarchical clustering, which partitions data by slicing an existing tree topology via branch cuts (row_split and column_split). Interestingly, while both methods cleanly separated performance and engine metrics (hp, wt, cyl, disp) from efficiency and transmission metrics (mpg, drat, qsec), the cluster index assignment reversed between them: hierarchical clustering grouped the engine power metrics into Cluster 1 and the fuel efficiency metrics into Cluster 2, whereas k-means designated the fuel efficiency metrics as Cluster 1 and the engine power metrics as Cluster 2 due to the arbitrary nature of initial centroid labeling.

ht_main = Heatmap(data.scale, name = "cluster rows",
                  row_km = 2, row_km_repeats = 100,
                  column_km = 2, column_km_repeats = 100,
                  row_title = c("fuel efficient", "fuel inefficient"),
                  row_names_gp = gpar(fontsize = 6),     
                  column_names_gp = gpar(fontsize = 9),  
                  row_title_gp = gpar(fontsize = 10))

draw(ht_main+ht_manual+ht_inline, auto_adjust = FALSE)