Learn R Programming

⚠️There's a newer version (1.11.6) of this package.Take me there.

tidyHeatmap

Citation

Mangiola et al., (2020). tidyHeatmap: an R package for modular heatmap production based on tidy principles. Journal of Open Source Software, 5(52), 2472, https://doi.org/10.21105/joss.02472

Please have a look also to

website: stemangiola.github.io/tidyHeatmap

tidyHeatmap is a package that introduces tidy principles to the creation of information-rich heatmaps. This package uses ComplexHeatmap as graphical engine.

Advantages:

  • Modular annotation with just specifying column names
  • Custom grouping of rows is easy to specify providing a grouped tbl. For example df |> group_by(...)
  • Labels size adjusted by row and column total number
  • Default use of Brewer and Viridis palettes

Functions/utilities available

FunctionDescription
heatmapPlots base heatmap
add_tileAdds tile annotation to the heatmap
add_pointAdds point annotation to the heatmap
add_barAdds bar annotation to the heatmap
add_lineAdds line annotation to the heatmap
layer_pointAdds layer of symbols on top of the heatmap
layer_squareAdds layer of symbols on top of the heatmap
layer_diamondAdds layer of symbols on top of the heatmap
layer_arrow_upAdds layer of symbols on top of the heatmap
layer_arrow_downAdd layer of symbols on top of the heatmap
split_rowsSplits the rows based on the dendogram
split_columnsSplits the columns based on the dendogram
save_pdfSaves the PDF of the heatmap

Installation

To install the most up-to-date version

devtools::install_github("stemangiola/tidyHeatmap")

To install the most stable version (however please keep in mind that this package is under a maturing lifecycle stage)

install.packages("tidyHeatmap")

Contribution

If you want to contribute to the software, report issues or problems with the software or seek support please open an issue here

Input data frame

The heatmaps visualise a multi-element, multi-feature dataset, annotated with independent variables. Each observation is a element-feature pair (e.g., person-physical characteristics).

elementfeaturevalueindependent_variables
chr or fctrchr or fctrnumeric

Let’s transform the mtcars dataset into a tidy “element-feature-independent variables” data frame. Where the independent variables in this case are ‘hp’ and ‘vs’.

mtcars_tidy <- 
    mtcars |> 
    as_tibble(rownames="Car name") |> 
    
    # Scale
    mutate_at(vars(-`Car name`, -hp, -vs), scale) |>
    
    # tidyfy
    pivot_longer(cols = -c(`Car name`, hp, vs), names_to = "Property", values_to = "Value")

mtcars_tidy
## # A tibble: 288 × 5
##    `Car name`       hp    vs Property Value[,1]
##    <chr>         <dbl> <dbl> <chr>        <dbl>
##  1 Mazda RX4       110     0 mpg          0.151
##  2 Mazda RX4       110     0 cyl         -0.105
##  3 Mazda RX4       110     0 disp        -0.571
##  4 Mazda RX4       110     0 drat         0.568
##  5 Mazda RX4       110     0 wt          -0.610
##  6 Mazda RX4       110     0 qsec        -0.777
##  7 Mazda RX4       110     0 am           1.19 
##  8 Mazda RX4       110     0 gear         0.424
##  9 Mazda RX4       110     0 carb         0.735
## 10 Mazda RX4 Wag   110     0 mpg          0.151
## # … with 278 more rows

Plotting

For plotting, you simply pipe the input data frame into heatmap, specifying:

  • The rows, cols relative column names (mandatory)
  • The value column name (mandatory)
  • The annotations column name(s)

mtcars

mtcars_heatmap <- 
    mtcars_tidy |> 
    heatmap(`Car name`, Property, Value,    scale = "row"   ) |>
    add_tile(hp)

mtcars_heatmap

Saving

mtcars_heatmap |> save_pdf("mtcars_heatmap.pdf")

Grouping and splitting

We can easily group the data (one group per dimension maximum, at the moment only the vertical dimension is supported) with dplyr, and the heatmap will be grouped accordingly

# Make up more groupings
mtcars_tidy_groupings = 
    mtcars_tidy |>
    mutate(property_group = if_else(Property %in% c("cyl", "disp"), "Engine", "Other"))

mtcars_tidy_groupings |> 
    group_by(vs, property_group) |>
    heatmap(`Car name`, Property, Value,    scale = "row"   ) |>
    add_tile(hp)

We can provide colour palettes to groupings

mtcars_tidy_groupings |> 
    group_by(vs, property_group) |>
    heatmap(
        `Car name`, Property, Value ,   
        scale = "row",
        palette_grouping = list(
            
            # For first grouping (vs)
            c("#66C2A5", "#FC8D62"), 
            
            # For second grouping (property_group)
            c("#b58b4c", "#74a6aa")
        )
    ) |>
    add_tile(hp)

We can split based on the cladogram

mtcars_tidy |> 
    heatmap(`Car name`, Property, Value,    scale = "row"   ) |>
    split_rows(2) |>
    split_columns(2)

We can split on kmean clustering (using ComplexHeatmap options, it is stochastic)

mtcars_tidy |> 
    heatmap(
        `Car name`, Property, Value,    
        scale = "row",
        row_km = 2,
        column_km = 2
    ) 

Custom palettes

We can easily use custom palette, using strings, hexadecimal color character vector,

mtcars_tidy |> 
    heatmap(
        `Car name`, 
        Property, 
        Value,  
        scale = "row",
        palette_value = c("red", "white", "blue")
    )

A better-looking blue-to-red palette

mtcars_tidy |> 
    heatmap(
        `Car name`, 
        Property, 
        Value,  
        scale = "row",
        palette_value = circlize::colorRamp2(
            seq(-2, 2, length.out = 11), 
            RColorBrewer::brewer.pal(11, "RdBu")
        )
    )

Or a grid::colorRamp2 function for higher flexibility

mtcars_tidy |> 
    heatmap(
        `Car name`, 
        Property, 
        Value,  
        scale = "row",
        palette_value = circlize::colorRamp2(c(-2, -1, 0, 1, 2), viridis::magma(5))
    )

We can use grid::colorRamp2 function for tile annotation too

mtcars_tidy |> 
    heatmap(
        `Car name`, 
        Property, 
        Value,  
        scale = "row"
    ) |>
    add_tile(
        hp, 
        palette = circlize::colorRamp2(c(0, 100, 200, 300), viridis::magma(4))
    )

Multiple groupings and annotations

tidyHeatmap::pasilla |>
    group_by(location, type) |>
    heatmap(
        .column = sample,
        .row = symbol,
        .value = `count normalised adjusted`,   
        scale = "row"
    ) |>
    add_tile(condition) |>
    add_tile(activation)

Remove legends, adding aesthetics to annotations in a modular fashion, using ComplexHeatmap arguments

tidyHeatmap::pasilla |>
    group_by(location, type) |>
    heatmap(
        .column = sample,
        .row = symbol,
        .value = `count normalised adjusted`,   
        scale = "row",
        show_heatmap_legend = FALSE
    ) |>
    add_tile(condition, show_legend = FALSE) |>
    add_tile(activation, show_legend = FALSE)

Annotation types

“tile”, “point”, “bar” and “line” are available

# Create some more data points
pasilla_plus <- 
    tidyHeatmap::pasilla |>
    dplyr::mutate(act = activation) |> 
    tidyr::nest(data = -sample) |>
    dplyr::mutate(size = rnorm(n(), 4,0.5)) |>
    dplyr::mutate(age = runif(n(), 50, 200)) |>
    tidyr::unnest(data) 

# Plot
pasilla_plus |>
    heatmap(
        .column = sample,
        .row = symbol,
        .value = `count normalised adjusted`,   
        scale = "row"
    ) |>
    add_tile(condition) |>
    add_point(activation) |>
    add_tile(act) |>
    add_bar(size) |>
    add_line(age)

Annotation size

We can customise annotation sizes using the grid::unit(), and the size of their names using in-built ComplexHeatmap arguments

pasilla_plus |>
    heatmap(
        .column = sample,
        .row = symbol,
        .value = `count normalised adjusted`,   
        scale = "row"
    ) |>
    add_tile(condition, size = unit(0.3, "cm"), annotation_name_gp= gpar(fontsize = 8)) |>
    add_point(activation, size = unit(0.3, "cm"),   annotation_name_gp= gpar(fontsize = 8)) |>
    add_tile(act, size = unit(0.3, "cm"),   annotation_name_gp= gpar(fontsize = 8)) |>
    add_bar(size, size = unit(0.3, "cm"),   annotation_name_gp= gpar(fontsize = 8)) |>
    add_line(age, size = unit(0.3, "cm"),   annotation_name_gp= gpar(fontsize = 8))

Layer symbol

Add a layer on top of the heatmap

tidyHeatmap::pasilla |>
    
    # filter
    filter(symbol %in% head(unique(tidyHeatmap::pasilla$symbol), n = 10)) |>
    
    heatmap(
        .column = sample,
        .row = symbol,
        .value = `count normalised adjusted`,   
        scale = "row"
    ) |> 
    layer_point(
        `count normalised adjusted log` > 6 & sample == "untreated3" 
    )

Adding heatmap side-by-side

p_heatmap = heatmap(mtcars_tidy, `Car name`, Property, Value, scale = "row") 

p_heatmap + p_heatmap

ComplexHeatmap further styling

Add cell borders

mtcars_tidy |> 
    heatmap(
        `Car name`, Property, Value,    
        scale = "row", 
        rect_gp = grid::gpar(col = "#161616", lwd = 0.5)
    ) 

Drop row clustering

mtcars_tidy |> 
    heatmap(
        `Car name`, Property, Value,    
        scale = "row", 
        cluster_rows = FALSE
    ) 

Reorder rows elements

library(forcats)
mtcars_tidy |> 
    mutate(`Car name` = fct_reorder(`Car name`, `Car name`, .desc = TRUE)) %>% 
    heatmap(
        `Car name`, Property, Value,    
        scale = "row", 
        cluster_rows = FALSE
    ) 

Size of dendrograms

mtcars_tidy |> 
    mutate(`Car name` = fct_reorder(`Car name`, `Car name`, .desc = TRUE)) %>% 
    heatmap(
        `Car name`, Property, Value,    
        scale = "row", 
        column_dend_height = unit(0.2, "cm"), 
        row_dend_width = unit(0.2, "cm")
    ) 

Size of rows/columns titles and names

mtcars_tidy |> 
    mutate(`Car name` = fct_reorder(`Car name`, `Car name`, .desc = TRUE)) %>% 
    heatmap(
        `Car name`, Property, Value,    
        scale = "row", 
        row_names_gp = gpar(fontsize = 7),
        column_names_gp = gpar(fontsize = 7),
        column_title_gp = gpar(fontsize = 7),
        row_title_gp = gpar(fontsize = 7)
    ) 

External ComplexHeatmap functionalities

ComplexHeatmap has some graphical functionalities that are not included in the standard functional framework

Chainging side of legends

heatmap(mtcars_tidy, `Car name`, Property, Value, scale = "row" ) %>%
    as_ComplexHeatmap() %>%
    ComplexHeatmap::draw(heatmap_legend_side = "left"   )

Using patchwork to integrate heatmaps

library(ggplot2)
library(patchwork)

p_heatmap =
    mtcars_tidy |> 
    heatmap(
        `Car name`, Property, Value,    
        scale = "row", 
            show_heatmap_legend = FALSE,
        row_names_gp = gpar(fontsize = 7)
    ) 

p_ggplot = tibble(value = 1:10) %>% ggplot(aes(value)) + geom_density()

wrap_heatmap(p_heatmap) + 
    p_ggplot +
    wrap_heatmap(p_heatmap) + 
    plot_layout(width = c(1, 0.3, 1))

Copy Link

Version

Install

install.packages('tidyHeatmap')

Monthly Downloads

1,611

Version

1.8.1

License

GPL-3

Issues

Pull Requests

Stars

Forks

Maintainer

Stefano Mangiola

Last Published

May 20th, 2022

Functions in tidyHeatmap (1.8.1)

add_bar

Adds a bar annotation layer to a `InputHeatmap`, that on evaluation creates a `ComplexHeatmap`
check_if_counts_is_na

Check whether there are NA counts
ifelse2_pipe

This is a generalisation of ifelse that accepts an object and return an objects
parse_formula

.formula parser
heatmap

Creates a `InputHeatmap` object from `tbl_df` on evaluation creates a `ComplexHeatmap`
as_matrix

Get matrix from tibble
layer_square

Adds a layers of symbols above the heatmap tiles to a `InputHeatmap`, that on evaluation creates a `ComplexHeatmap`
drop_class

Remove class to abject
get_sample_transcript_counts

Get column names either from user or from attributes
error_if_log_transformed

Check whether a numeric vector has been log transformed
check_if_duplicated_genes

Check whether there are duplicated genes/transcripts
get_abundance_norm_if_exists

Get column names either from user or from attributes
layer_diamond

Adds a layers of symbols above the heatmap tiles to a `InputHeatmap`, that on evaluation creates a `ComplexHeatmap`
get_x_y_annotation_columns

get_x_y_annotation_columns
get_elements

Get column names either from user or from attributes
scale_robust

Scale counts in a robust way against sd == 0
get_sample_transcript

Get column names either from user or from attributes
save_pdf

Save plot on PDF file
get_sample_counts

Get column names either from user or from attributes
scale_design

Scale design matrix
save_pdf,InputHeatmap-method

save_pdf
layer_point

Adds a layers of symbols above the heatmap tiles to a `InputHeatmap`, that on evaluation creates a `ComplexHeatmap`
wrap_heatmap

Wrap tidyHeatmap (ComplexHeatmap) in a patchwork-compliant patch
layer_arrow_down

Adds a layers of symbols above the heatmap tiles to a `InputHeatmap`, that on evaluation creates a `ComplexHeatmap`
check_if_wrong_input

Check whether there are NA counts
layer_arrow_up

Adds a layers of symbols above the heatmap tiles to a `InputHeatmap`, that on evaluation creates a `ComplexHeatmap`
ifelse_pipe

This is a generalisation of ifelse that accepts an object and return an objects
prepend

From rlang deprecated
pasilla

Example data set Pasilla
input_heatmap

input_heatmap
get_elements_features

Get column names either from user or from attributes
quo_names

Convert array of quosure (e.g. c(col_a, col_b)) into character vector
get_elements_features_abundance

Get column names either from user or from attributes
save_pdf,Heatmap-method

save_pdf
select_closest_pairs

Sub function of remove_redundancy_elements_though_reduced_dimensions
split_rows

Split the heatmap row-wise depending on the biggest branches in the cladogram.
add_point

Adds a point annotation layer to a `InputHeatmap`, that on evaluation creates a `ComplexHeatmap`
as_ComplexHeatmap

Creates a `ComplexHeatmap` object for less standard plot manipulation (e.g. changing legend position)
add_attr

Add attribute to abject
add_annotation

add_annotation
add_tile

Adds a tile annotation layer to a `InputHeatmap`, that on evaluation creates a `ComplexHeatmap`
annot_to_list

annot_to_list
N52

Example data set N52
add_class

Add class to abject
add_line

Adds a line annotation layer to a `InputHeatmap`, that on evaluation creates a `ComplexHeatmap`