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'
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
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)]
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(data.scale, name = "mtcars heatmap",
cluster_rows=FALSE , cluster_columns = FALSE)
Heatmap(data.scale, name = "mtcars heatmap",
cluster_columns = FALSE)
# cluster on rows and columns
Heatmap(data.scale, name = "mtcars heatmap")
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)
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)
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)
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)