針對近期多個粉絲咨詢環形圖的繪制,我意識到,我們似乎沒有真正介紹過circle圖,但這一類圖確是非常常用的圖,所以這里詳細學習一下circle的繪制,使用的是circlize包,功能很完善:安裝包,
#https://github.com/jokergoo/circlize/tree/master
#install package
install.packages("circlize")
#devtools::install_github("jokergoo/circlize")
library(circlize)
做環形熱圖使用circos.heatmap函數,我們看看具體的參數解析:
#了解下環形熱圖繪制circos.heatmap基本參數。
circos.heatmap(mat, #矩陣或者向量,矩陣就是和我們做hetamap的時候提供的一樣,例如行是基因,列是分組sample,向量的化會自動轉化為一個單列矩陣,說到底還是矩陣,適合于plot單組數值split = NULL, #環線熱圖分列,例如我們可以設置分組,讓熱圖分為多個扇形col, #熱圖顏色設置,參照colorRamp2,設置顏色和范圍,例如一般設置:colorRamp2(c(-2, 0, 2), c("blue", "white", "red"))cell.border = NA, #r熱圖格子邊框顏色,默認NA不設置cell.lwd = 1,#邊框線條寬度bg.border = NA, #cell.border設置的是每個單元格的邊框,bg.border設置的是整個熱圖外邊框顏色bg.lty = par("lty"),#整個熱圖邊框線條類型,可以直接設置數字,例如1,2,3等等,選擇是實線還是虛線類型的線條bg.lwd = par("lwd"),#整個熱圖邊框線條寬度,可直接設置數值cluster = TRUE, #熱圖行是否聚類。該值也可以是一個dendprogram /hclust對象或其他可以用as. dendprogram轉換為的對象。也就是所已經做好聚類的objectclustering.method = "complete", #聚類方法,參照hclust函數,可選"ward.D", "ward.D2", "single", "complete", "average" (= UPGMA), "mcquitty" (= WPGMA), "median" (= WPGMC) or "centroid" (= UPGMC).distance.method = "euclidean",#參照dist函數,method可選"euclidean", "maximum", "manhattan", "canberra", "binary" or "minkowski". # dend.callback = function(dend, m, si) reorder(dend, rowMeans(m)),dend.side = c("none", "outside", "inside"), #聚類樹位置,默認不展示。可選擇外圈或者內圈放置dend.track.height = 0.1,#聚類樹高度rownames.side = c("none", "outside", "inside"), #行名位置,默認不展示。可選擇外圈或者內圈放置rownames.cex = 0.5,#行名文字大小rownames.font = par("font"), #行名字體rownames.col = "black",#行名顏色cell_width = rep(1, nrow(mat)),#熱圖單元格寬度
準備作圖數據,這里我們使用轉錄組基因表達矩陣演示:
#prepare data
#這是一個轉錄組基因表達矩陣,也是我們常做pheatmap的輸入矩陣
#行是基因,列是分組,有兩個分組,HC,TL,分別有6個重復
df <- read.csv('./df_heat.csv', header = T, row.names = 1)
plot_df <- as.matrix(df)
#因為circos.heatmap沒有像pheatmap那樣,直接參數里面對數據進行scale
#所以我們plot之前需要對表達數據進行標準化,如果僅僅是想展示數值,那么數據并不用標準化
plot_df <- t(scale(t(plot_df)))#對數據進行標準化處理,按行z-score標準化
基礎plot:布局也是繪圖關鍵哦,了解下布局一些參數,可以調整:不可死板。
circos.par(start.degree,#數值,設置環形圖的起始角度。0是其實,位于3點鐘方向,數值增大,開口逆時針移動gap.degree,#數值或數值向量,設置扇區之間的間隔角度.單個數值設置表示多個扇區之間距離一致。向量可設置不一樣間隔gap.after, #設置圓環開口的大小,數值越大,開口越大track.margin,#數值向量,設置軌道的上下邊距cell.padding,#設置單元格的內邊距,扇形內格子之間的距離,一般設置為0track.height,#設置軌道的高度,也就是圓環的寬度,默認0.2clock.wise,#設置環形方向是否為順時針,默認Tlabels.cex,#設置文字大小labels.font,#設置文字字體,1=普通,2=粗體,3=斜體,4=粗斜體)unit.circle.segments,#設置繪制圓時的線段數量(影響圓形的平滑度),默認500big.gap,#設置兩個環形圖之間的間隔角度(用于多環形圖)circle.margin,#環形圖布局,圖形距離四邊的距離,數值向量設置。..., RESET = FALSE, READ.ONLY = NULL, LOCAL = FALSE, ADD = FALSE)
#布局設置
circos.clear()
circos.par(start.degree=30, gap.degree=30,track.height=0.3)circos.heatmap(plot_df,col = colorRamp2(c(-2,0,2),c("#003399","white","#cccc00")), cell.border = NA, cell.lwd = 1,bg.border = 'black', bg.lty = par("lty"),bg.lwd = par("lwd"),cluster = TRUE, clustering.method = "ward.D2", distance.method = "euclidean",dend.side = c("inside"), dend.track.height = 0.1,rownames.side = c("outside"),rownames.cex = 0.5,#行名文字大小rownames.font = par("font"), #行名字體rownames.col = "black")
基礎圖形出來了,感覺把平常的熱圖給掰彎了,現在還缺少legend和sample名:添加是比較麻煩的,需要為整個軌道創建繪圖區域,使用函數circos.track():添加文字使用circos.text,列名的位置需要根據自己的實際數據,調整x,y軸的坐標慢慢實現,如果感覺調整費時間,可以導出手動修飾,這也是circlize的一個不方便之處。
circos.track(track.index = get.current.track.index(), # 指定當前軌道的索引panel.fun = function(x, y) { #panel.fun,自定義繪制函數,用于在軌道中添加圖形或注釋if (CELL_META$sector.numeric.index == 1) { # 僅在第一個扇區執行cn = colnames(plot_df) # 獲取數據框的列名n = length(cn) # 列名的數量#添加文字注釋,參數需要設置文字位置xy坐標circos.text(x = CELL_META$cell.xlim[2] + convert_x(0.8, "mm"),#x坐標y = CELL_META$cell.ylim[2] + 4.5 * (1:n), # y 坐標,labels = rev(cn), # 文本內容(列名),這里需要注意,rev一下,保證標注正確cex = 0.4, # 字體大小facing = "inside" # 文本方向(朝內))}},bg.border = NA # 軌道背景無邊框
)
然而,我們前面也介紹了,circos.heatmap有一個參數,split,熱圖可以按照行的分組split,這里演示split以及添加分組注釋。其他和之前一致。我的數據并沒有分組,這里隨機設置的,沒有任何意義。將基因按照功能進行了分組。
annotation_row=data.frame(Pathway=c(rep("Wnt",20),rep("Inflammatory",32),rep("HIF",34)))#對行進行注釋,用于后續的熱圖分裂
row.names(annotation_row) <- rownames(df)
annotation_row <- as.matrix(annotation_row)#在circlize函數中,需要為matrix#plot,畫圖和之前一樣,需要注意的是布局設置的gap.degree
#這里我們有三組,也就是split時出現三組扇區,前面兩個扇區的gap設置小點
#最后一個設置大一點,便于添加列名
circos.clear()
circos.par(start.degree=30, gap.degree=c(2,2,30),track.height=0.3)
circos.heatmap(plot_df,split = annotation_row,col = colorRamp2(c(-2,0,2),c("#003399","white","#cccc00")), cell.border = NA, cell.lwd = 1,bg.border = 'black', bg.lty = par("lty"),bg.lwd = par("lwd"),cluster = TRUE, clustering.method = "ward.D2", distance.method = "euclidean",dend.side = c("inside"), dend.track.height = 0.05,rownames.side = c("outside"),rownames.cex = 0.5,#行名文字大小rownames.font = par("font"), #行名字體rownames.col = "black",dend.callback=function(dend,m,si){color_branches(dend,k=5,col=c("#E69253", "#EDB931", "#E4502E", "#4378A0", "#272A2A"))})#還可以對層次聚類添加顏色,按照聚類數#
circos.track(track.index = get.current.track.index(), # 指定當前軌道的索引panel.fun = function(x, y) { #panel.fun,自定義繪制函數,用于在軌道中添加圖形或注釋if (CELL_META$sector.numeric.index == 3) { # 僅在第一個扇區執行cn = colnames(plot_df) # 獲取數據框的列名n = length(cn) # 列名的數量#添加文字注釋,參數需要設置文字位置xy坐標circos.text(#這里我們將列名繪制在環形的尾部,我們前面參數里面解釋了,環形是默認順時針繪制的x = CELL_META$cell.xlim[2] + convert_x(0.8, "mm"),#前面的部分是獲取行的長度,也就是繪制文字的x坐標,后面convert_x是調整參數,0.5表示文本向右偏移0.5y = CELL_META$cell.ylim[2] + 12 * (1:n), # y 坐標,labels = rev(cn), # 文本內容(列名),這里需要注意,rev一下,保證標注正確cex = 0.4, # 字體大小facing = "inside" # 文本方向(朝內))}},bg.border = NA # 軌道背景無邊框
)#添加分組設置,我們直接接上一個圖層plot,這里沒有設置track.index,所以注釋在內圈
circos.track(ylim=c(0,1),track.height=0.081,#分組注釋環形高度,可以設置低一點bg.col=c("#FF0000", "#00A08A", "#F2AD00"),#分組注釋背景顏色panel.fun=function(x, y) {xlim = get.cell.meta.data("xlim")ylim = get.cell.meta.data("ylim")sector.index = CELL_META$sector.indexcircos.text(mean(xlim),mean(ylim),sector.index, col = "black", cex = 0.8, facing = 'bending.inside', niceFacing = TRUE)})