Skip to contents

Basics

If the matrix being plotted is symmetric it is possible to plot mixed layouts by giving two triangles (opposite each other) to the layout argument. Two modes must be provided, the default modes being heatmap for the first triangle and text for the second. The first triangle of layout gets the diagonal (if include_diag is TRUE).

plt1 <- ggcorrhm(mtcars, layout = c("tl", "br"))
plt2 <- ggcorrhm(mtcars, layout = c("tl", "br"), mode = c("21", "23"))

plt1 + plt2

Two mtcars correlation heatmaps. The first one is composed of a normal heatmap with filled cells for the top left triangle and cells with coloured text showing the correlation values in the bottom right triangle (the colour scaling with the correlation values). Names are written on the diagonal. The second heatmap has circles in the top left and diamonds in the bottom right, all filled with the same colours in the first heatmap and their sizes scaling with the absolute values of the correlations.

To add a grid for shape modes use ggplot2::theme and the panel.grid* arguments. If any part of the heatmap uses the ‘text’ or ‘none’ modes, the grid will be visible through the cells. The cell_bg_col and cell_bg_alpha arguments control the cell background colour and alpha parameter. By default, the cell colour is set to white and alpha to 0.

# Grid + default cell background
plt1 <- ggcorrhm(mtcars, layout = c("tl", "br"), mode = c("21", "text")) +
  labs(title = "cell_bg_alpha = 0") +
  # Add grid, make darker for demonstration
  theme(panel.grid.major = element_line(colour = "grey"))

plt2 <- ggcorrhm(mtcars, layout = c("tl", "br"), mode = c("21", "text"),
                 cell_bg_alpha = 1) +
  labs(title = "cell_bg_alpha = 1") +
  theme(panel.grid.major = element_line(colour = "grey"))

plt1 + plt2

Two mtcars correlation heatmaps with circles in the top left and cells with correlation labels (colour scaling with correlation value) in the bottom right. There is a major grid added to the plot, so that lines intersect at the middle points of each cell. In the first plot the grid is visible through the cells in the bottom right, making it hard to read the text. In the second plot the grid is not visible through cells.

Since mixed layouts consist of two triangular layout heatmaps, clustering can only be applied if both rows and columns are clustered (like for the simple triangular layouts).

ggcorrhm(mtcars, layout = c("tr", "bl"), cluster_rows = TRUE)
#> Warning: Cannot cluster only one dimension for triangular layouts, clustering both rows
#> and columns instead.

mtcars correlation heatmap with a normal heatmap in the top right and coloured text in the bottom left. Rows and columns have been clustered and dendrograms are shown on the right and below.

If return_data is TRUE there will be an extra column called layout, showing which triangle each cell belongs to.

head(ggcorrhm(mtcars, layout = c("tl", "br"), return_data = TRUE)$plot_data)
#>    row col      value layout
#> 1  mpg mpg  1.0000000     tl
#> 2  cyl mpg -0.8521620     tl
#> 3 disp mpg -0.8475514     tl
#> 4   hp mpg -0.7761684     tl
#> 5 drat mpg  0.6811719     tl
#> 6   wt mpg -0.8676594     tl

Parameter behaviour

When the layout is mixed, a few arguments can take vectors or lists of length two. If a vector, each element is applied to the whole corresponding triangle in layout. If a list is provided, the elements can be whatever values that would be applicable for non-mixed layouts, i.e. a single value to apply to the whole triangle, or a vector with one value for each cell.

The arguments that work like this are border_col, border_lwd, border_lty, cell_labels, cell_label_col, cell_label_size, cell_label_digits, cell_bg_col, cell_bg_alpha, and (for ggcorrhm) p_values and cell_label_p.

colr <- c("#70369D", "#59369D", "#4A44AB", "#486ED8", "#5B9892", "#79C314", "#C6DB28", "#FBDD2B", "#FEB30A", "#F56B08", "#E81416")

ggcorrhm(mtcars, layout = c("bl", "tr"), mode = c("none", "hm"),
         # One value for the whole heatmap (border linewidth)
         border_lwd = 1.5,
         # Length two vector, each value being used for the whole corresponding triangle
         border_lty = c(1, 3),
         # A list with values for each triangle
         border_col = list(
           # The first triangle is 66 values (if the diagonal is drawn), second 55
           # If not known, can return the plotting data to see how many cells are in each triangle
           # Since the matrix must be symmetric the numbers can also be calculated
           # Total: ncol*ncol, triangle without diagonal: (total - ncol) / 2, with diagonal: without + ncol
           # First triangle, provide all values, moving down each column from the left
           rev(unlist(sapply(seq_along(colr), function(i) rep(colr[i], i)))),
           # Second triangle, recycle one value
           "white"
         ),
         # Also draw cell labels on the first triangle and set the same colours as the cells
         cell_labels = c(TRUE, FALSE),
         cell_label_col = list(
           # Provide the same values as for the cell border colours, but minus one as the diagonal
           # names are written instead of cell labels and are controlled differently
           rev(unlist(sapply(seq_along(colr), function(i) rep(colr[i], i - 1)))),
           1 # Anything as there are no labels
         ),
         names_diag_param = list(colour = rev(colr)))

mtcars correlation heatmap with filled cells with thick, grey, dotted borders on the top right. The bottom left, including the diagonal with names, has cells with coloured text and thick coloured borders with a rainbow scale.

As mentioned above, p-values can be added to only one half of the heatmap if desired. P-values in correlation matrices and mixed layouts are explored more in the correlation matrix article.

plt1 <- ggcorrhm(mtcars, layout = c("tl", "br"), p_values = TRUE,
                 cell_label_size = c(4, 2))
plt2 <- ggcorrhm(mtcars, layout = c("tl", "br"), p_values = c(FALSE, TRUE),
                 cell_label_size = 2)

plt1 + plt2

Two mtcars correlation heatmaps, filled cells on the top left and coloured text (showing correlation values) on the bottom right. The first plot has asterisks showing p-vaule thresholds in both triangles (added to the correlation values in the bottom right). The second plot retains the labels in the bottom right triangle but not the top left.

Mixed scales

In mixed layouts the two triangles can use different scales for colours by using the col_scale argument.

ggcorrhm(mtcars, layout = c("tr", "bl"),
         col_scale = c("G", "H"))

mtcars correlation heatmap with normal cells in the top right and coloured text in the bottom left triangle. The cells in the top right triangle use the viridis mako scale while the text in the bottom left use the viridis turbo scale. Each scale has a legend on the right (with the same name: Pearson r).

Just like the cell border and cell label arguments above, some scale-related arguments can also be applied in a triangle-wise manner. These arguments are bins, na_col, and limits and also, for ggcorrhm(), high, mid, low, midpoint, and size_range. Since limits and size_range are usually vectors of length two, so these must be in lists to apply different values to the two triangles.

# Make correlation data to plot (100x100)
plt_dat <- sapply(seq(-1, 0, length.out = 100), function(x) {
  seq(x, x + 1, length.out = 100)
})

# Using high, mid, low which only work if the default ggcorrhm scale is used
ggcorrhm(plt_dat, cor_in = TRUE, show_names_diag = FALSE, border_col = 0,
         layout = c("tl", "br"), mode = c("hm", "hm"),
         # Some arguments can be NULL to use the default
         # If using NULL, use a list as it disappears in atomic vectors
         limits = list(NULL, c(-0.75, 0.75)),
         bins = list(NULL, 5L),
         high = list("pink", NULL),
         mid = list(NULL, NULL),
         low = c("cyan", "purple"),
         # midpoint cannot take NULL
         midpoint = c(-0.25, 0))

A 100x100 heatmap with values in a gradient going from -1 in the bottom left to 1 in the top right. The top left triangle has a smooth gradient with cyan at -1, white at 0.25 and pink at 1. The bottom right triangle is purple at low values and red at high values and is divided into five discrete bins with the breaks at -0.45, -0.15, 0, 0.15, and -0.45 and the limits at -0.75 and 0.75. Values outside the limits take the colours at the extremes (purple, red).

# Different size ranges
ggcorrhm(mtcars, layout = c("tl", "br"), mode = c(21, 23),
         size_range = list(c(5, 10), c(1, 5)))

col_scale can also take a mix of NULL, character values, and scale objects in mixed layouts.

# Two fill scales
ggcorrhm(mtcars, layout = c("br", "tl"), mode = c("21", "hm"),
         show_names_diag = FALSE,
         col_scale = list(
           # When a scale object is passed, arguments of gghm/ggcorrhm
           # that modify legends will be ignored.
           # 'heatmap' mode and modes 20-25 use the fill aesthetic
           scale_fill_gradient2(high = "pink", mid = "white", low = "lightblue",
                                limits = c(-1, 1), name = "Bottom right"),
           "RdYlGn"
         ),
         # col_name can also take two values
         col_name = c("This name will be ignored", "Top left"))

mtcars correlation heatmap with cells in the top left and circles in the bottom right. The cells use the Brewer RdYlGn palette (going from green (low) to yellow to red (high)), while the circles use a custom scale with light blue for low values, white for middle values and pink for high values. The two legends on the right are named Bottom right (blue-pink) and Top left (RdYlGn).

Use the guide argument in the ggplot2 scale functions to set the order or hide legends if a scale object is passed in the col_scale argument.

# Two colour scales
ggcorrhm(mtcars, layout = c("tr", "bl"), mode = c("19", "text"),
         col_scale = list(
           # 'text' mode and modes 1-20 use the colour aesthetic and need colour scales
           scale_colour_gradient(high = "lightsalmon4", low = "white", limits = c(-1, 1),
                                 # Can use the guide argument to change order of legends (or hide them)
                                 guide = guide_colourbar(order = 1),
                                 name = "First legend"),
           scale_colour_distiller(palette = "Spectral", limits = c(-1, 1),
                                  name = "Second legend")
         ), cell_label_size = 4,
         col_name = c("Names that will", "be ignored"))

mtcars correlation heatmap with circles in the top right and text labels in empty cells in the bottom left. The circles use a scale going from white at low values to brown at high values while the text in the cells uses the Brewer Spectral palette. The legends are named First legend (brown) and Second legend (Spectral).

If one of the scales is NULL, the default scale is used instead (and can be customised with the high, mid, low etc arguments).

# NULL uses the default that changes with high, mid, low etc
ggcorrhm(mtcars, layout = c("tl", "br"), mode = c("hm", "hm"),
         col_scale = list(
           NULL,
           # Scale object will not be affected by the default scale arguments
           scale_fill_distiller(palette = "PRGn", limits = c(-1, 1))
         ), bins = 5L, high = "pink", mid = "beige", low = "lightblue")

mtcars correlation heatmap. The cells in the top left triangle use a divergent colour scale going from light blue to beige to pink, while the bottom right cells use a binned scale with the Brewer PrGn palette, going from green to white to purple.

It’s also possible to use different scales for the sizes with the size_scale argument.

ggcorrhm(mtcars, layout = c("tr", "bl"), mode = c(23, 23),
         size_scale = list(
           # Can make a binned size scale
           scale_size_binned(n.breaks = 6, range = c(1, 5),
                             # Absolute value transform but legend loses meaning
                             transform = scales::trans_new("abs", abs, abs),
                             name = "scale_size_binned", guide = guide_bins(order = 1)),
           scale_size_continuous(range = c(5, 10), name = "scale_size_continuous")
         ), border_lwd = 1, legend_order = NA)

mtcars correlation heatmap with diamonds instead of cells in both triangles. The diamonds in the top right are smaller than those in the bottom left. Two legends can be seen to the right, one called scale_size_binned with a binned scale with breaks from 0.2 to 0.8 and the other called scale_size_continuous with breaks from -0.5 to 0.5.

Some extra plots

When using triangular layouts, annotations and dendrograms are moved to the non-empty sides of the heatmap for convenience. Using mixed layouts with mode “none” it is possible to “hack” annotations and dendrograms onto the empty sides of triangular layouts.

annot <- data.frame(.names = colnames(mtcars), a = 1:11)
ggcorrhm(mtcars, layout = c("tl", "br"), mode = c("hm", "none"),
         annot_rows_df = annot, annot_cols_df = annot,
         cluster_rows = TRUE, cluster_cols = TRUE,
         # Hide cell borders only in the 'none' triangle
         border_lwd = c(0.1, 0))

A mtcars correlation heatmap showing only the top left triangle. On the right and below are row and column annotations, leaving a large triangular gap in the bottom right.

Finally, the default full layout reverses the y axis levels so that the rows are in the same order as in the input and the diagonal runs from top left to bottom right. If the opposite layout is desired it can be made using a mixed layout of a top left and a bottom right triangle, like the plot below.

plt1 <- ggcorrhm(mtcars, layout = "f")
plt2 <- ggcorrhm(mtcars, layout = c("tl", "br"), mode = c("hm", "hm"))

plt1 + plt2

Two mtcars correlation heatmaps, both showing the whole heatmap with names along the diagonal. The first one has the diagonal running from top left to bottom right, while the second one has the diagonal between the bottom left and top right (the row order is reversed).