How to plot circular heatmap in R

created at 07-10-2021 views: 439

What is a circular heatmap

Circular heatmap, as the name suggests, is a form of heat map. According to my mentor, everything becomes a circle and it becomes cool, and so is the heat map. First, I will show you a few circular heat maps.

Circular heatmap example

Source: Cell (2021)

Circular heatmap

from: circular visualization

The advantage of the circular heat map is that it can display multiple aspects on one picture, which saves space, and is very suitable for multi-group or multi-omics research, because it can reveal the changing laws and connections of different omics. Of course, if you want to further explain the relationship of the data, then the ring heat map may be a bit "bells and whistles".

How to plot a circular heat map

Today we will talk about an interesting R package "circlize". Yes, it is a package that circularizes various graphs. Among them is a function called circos.heatmap(), which can be used to draw ring graphs. This function is dependent on the  ComplexHeatmap  package (this is also a very useful R package, those who are interested can try it). Therefore, we must first install these related packages.

data structure

Then let's take a look at the data format (because the subject data was recently used to make this picture, it is not convenient to display, so I will use the example that comes in the package~~).

mat1 = rbind(cbind(matrix(rnorm(50*5, mean = 1), nr = 50), 
                   matrix(rnorm(50*5, mean = -1), nr = 50)),
             cbind(matrix(rnorm(50*5, mean = -1), nr = 50), 
                   matrix(rnorm(50*5, mean = 1), nr = 50))
rownames(mat1) = paste0("R", 1:100)
colnames(mat1) = paste0("C", 1:10)
mat1 = mat1[sample(100, 100), ] # randomly permute rows

data structure:

data structure

The data format is actually very simple. Like most packages that make heatmaps, the matrix format is required. Each column is a group, and each row is a specific indicator.
Next we look at how to make a picture. It is very easy to make the most basic circular heat map.

simplest example

#Draw circoheatmap
col_fun1 = colorRamp2(c(-2, 0, 2), c("navy", "white", "firebrick3"))
circos.heatmap(mat1, col = col_fun1,dend.side = "inside",rownames.side = "outside")
#Used to draw legend
lgd = Legend(title = "mat1", col_fun = col_fun1)
  • circos.clear(): Be sure to add this to indicate that the heat map is drawn
  • (-2,0,2): is the value range in the corresponding legend, which can be further adjusted as needed. The following is naturally the color corresponding to the heat map.
  • dend.side is used to determine whether the clustering result is placed inside or outside the circle, and rownames.side is the same.

The following is the simplest heat map obtained by the above code:

simplest heat map

add group name

Of course, we can further add more information, such as the group name (C1-C10). We can use circos.text() and circos.track() to accomplish this. But you need to debug the parameters and add the label to the appropriate position.

col_fun1 = colorRamp2(c(-2, 0, 2), c("navy", "white", "firebrick3"))
circos.par(gap.after = c(10))#Empty a paragraph for adding label
circos.heatmap(mat1, col = col_fun1,dend.side = "inside",rownames.side = "outside",track.height = 0.4)
circos.track(track.index = get.current.track.index(), = function(x, y) {
  if(CELL_META$sector.numeric.index == 1) { # the last sector
    cn = colnames(mat1)
    n = length(cn)
    circos.text(rep(CELL_META$cell.xlim[2], n) + convert_x(0.1, "mm"), #x coordinate
                13+(1:n)*5,#y coordinate
                cn, #label
                cex = 0.5, adj = c(0, 1), facing = "inside")
}, bg.border = NA)
lgd = Legend(title = "mat1", col_fun = col_fun1)

adjusted circular heatmap

add a new heatmap

Of course, we can also add a new circular heat map (I am too lazy to adjust the position of the previous label and remove it, haha):

#Generate a new set of data
mat2 = mat1[sample(100, 100), ] 

col_fun1 = colorRamp2(c(-2, 0, 2), c("navy", "white", "firebrick3"))
col_fun2 = colorRamp2(c(-2, 0, 2), c("green", "white", "red"))

circos.par(gap.after = c(10))
circos.heatmap(mat1, col = col_fun1,rownames.side = "outside",track.height = 0.2)
circos.heatmap(mat2, col = col_fun2,dend.side = "inside",track.height = 0.2)

lgd = Legend(title = "mat1", col_fun = col_fun1)

final result

created at:07-10-2021
edited at: 07-10-2021: