ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

使用ComplexHeatmap与circlize包复现文献中的圆形热图

使用ComplexHeatmap与circlize包复现文献中的圆形热图 在实际生物信息学或数据可视化项目中我们经常需要复现高水平学术文献中的图表这不仅是对分析结果的验证也是提升自身绘图技能的重要途径。R语言的ComplexHeatmap包以其强大的灵活性和定制化能力成为绘制复杂热图的首选工具。然而当文献中出现一张设计精巧、布局独特的圆形热图Circular Heatmap时许多开发者会感到无从下手因为标准的矩形热图与圆形布局在数据映射、坐标转换和美学控制上存在显著差异。本文将聚焦于一个具体目标使用ComplexHeatmap包完整复现一篇文献中出现的圆形热图。我们将从理解圆形热图的数据结构开始逐步拆解其视觉元素如环形分区、径向轴、扇形标签、颜色映射并利用ComplexHeatmap的底层绘图单元和circlize包提供的环形布局框架进行实现。无论你是正在尝试重现特定论文结果的研究生还是希望将环形热图应用于自己多组学数据整合展示的生物信息分析师本文提供的步骤和代码都将为你提供一个清晰、可复现的解决方案。最终你将掌握如何将矩阵数据转化为一个信息丰富、视觉吸引力强的环形热图并理解其中每个自定义参数的控制逻辑。1. 理解圆形热图从数据到视觉的环形映射在开始编码之前必须厘清圆形热图与普通热图的核心区别这决定了我们后续所有代码的设计思路。普通热图在笛卡尔坐标系下工作行和列在二维平面上正交排布。而圆形热图将数据映射到极坐标系下行或列沿着圆周排列数据值则通过扇形的径向长度或扇区内的颜色块来呈现。1.1 圆形热图的数据与视觉元素解构假设文献中的热图展示了10个样本Sample1-Sample10在5条通路PathwayA-PathwayE上的活性得分矩阵。在圆形布局中常见的呈现方式是扇区每个样本或每条通路占据圆周上的一个扇形区域。这通常通过将矩阵的行或列映射到圆周角度来实现。径向轴从圆心向外辐射的轴线用于表示数值的大小。数值可以映射为扇形的径向长度类似于条形图或者在固定半径的环形带内用颜色块表示更常见于热图。环形带如果热图包含多层信息例如同时展示基因表达、突变状态和临床分组每一层信息会占据一个同心圆环。颜色映射每个数据单元格的颜色由数值和指定的颜色梯度函数决定这与普通热图一致。ComplexHeatmap包本身主要处理矩形热图但它可以与circlize包无缝协作。circlize包专为环形可视化设计提供了初始化画布circos.initialize、创建轨道circos.track和在轨道上绘图如circos.heatmap的函数。我们的策略是利用circlize搭建环形框架和轨道然后使用ComplexHeatmap的Heatmap对象或低层函数来绘制每个轨道内的热图区块并精细控制其样式。1.2 环境准备与依赖安装首先确保你的R环境已就绪。我们将主要依赖ComplexHeatmap、circlize以及用于数据处理的dplyr和色彩处理的circlize它也包含颜色函数。如果尚未安装请在R控制台执行以下命令# 安装CRAN上的稳定版本 install.packages(ComplexHeatmap) install.packages(circlize) install.packages(dplyr) # 或者从Bioconductor安装ComplexHeatmap通常更新更快 if (!require(BiocManager, quietly TRUE)) install.packages(BiocManager) BiocManager::install(ComplexHeatmap)安装完成后加载必要的库library(ComplexHeatmap) library(circlize) library(dplyr)2. 构建示例数据与复现目标定义为了模拟真实的复现过程我们创建一个与文献描述相似的模拟数据集。假设我们要复现的图展示了8个肿瘤样本在6个关键信号通路上的富集分数。# 设置随机种子保证结果可重现 set.seed(123) # 创建样本和通路名称 samples - paste0(Sample, sprintf(%02d, 1:8)) pathways - c(Wnt/Beta-catenin, PI3K/AKT/mTOR, MAPK, JAK/STAT, TGF-Beta, Hippo) # 生成一个8行样本x 6列通路的矩阵数值范围在-2到2之间模拟富集分数 data_matrix - matrix(rnorm(8*6, mean0, sd1), nrow8, ncol6) rownames(data_matrix) - samples colnames(data_matrix) - pathways # 查看数据矩阵前几行 print(head(data_matrix))接下来我们需要定义复现的视觉目标。假设文献中的圆形热图具有以下特征这是我们需要通过代码实现的整体布局热图呈现在一个完整的圆环上样本位于圆周通路形成同心圆环。颜色映射数值从-2蓝色到0白色再到2红色使用连续型颜色梯度。轨道分割每个样本占据的扇形区域有细线分隔。标签显示样本标签显示在圆环外侧通路标签显示在圆环内侧或末端。图例在图形一侧有一个连续型颜色图例。3. 使用circlize构建环形画布与轨道circlize是绘制环形图的基础。我们首先需要初始化环形画布并定义扇区这里对应我们的样本。# 1. 初始化环形画布 # 参数‘sectors‘定义了扇区这里用样本名。‘xlim‘定义了每个扇区在径向的起始范围这里我们暂时设为c(0,1)后续在轨道中具体定义。 circos.clear() # 清除之前的环形布局避免叠加 circos.initialize(factors samples, xlim c(0, 1)) # 2. 创建第一个轨道Track用于放置通路热图。 # ‘track.height‘控制轨道高度占整个半径的比例‘bg.border‘设置轨道背景边框颜色。 circos.track(ylim c(0, ncol(data_matrix)), track.height 0.3, bg.border NA, # 无背景边框 panel.fun function(x, y) { # 当前扇区的名称 sector.index - CELL_META$sector.index # 获取当前扇区对应的数据一行 data_row - data_matrix[sector.index, ] # 我们需要在这个扇区内沿着径向y轴方向为每个通路绘制一个颜色块。 # 由于panel.fun在每个扇区内独立运行我们循环每个通路列 nr ncol(data_matrix) for (i in 1:nr) { # 计算当前颜色块在径向的起始和结束位置 y_start nr - i y_end nr - i 1 # 根据数值定义颜色 value data_row[i] color_fun - colorRamp2(c(-2, 0, 2), c(blue, white, red)) cell_color - color_fun(value) # 绘制矩形颜色块 circos.rect(xleft 0, xright 1, ybottom y_start, ytop y_end, col cell_color, border black) } }) # 添加样本标签到圆环外侧 circos.trackText(factors samples, x rep(0.5, length(samples)), y rep(-0.1, length(samples)), labels samples, facing clockwise, niceFacing TRUE, adj c(0.5, 1), cex 0.8) # 添加通路标签需要更精细的控制通常放在另一个轨道或使用自定义方式 # 这里先绘制一个简单的内圈文本作为示意 for(i in 1:length(pathways)) { circos.text(x 1.1, y ncol(data_matrix) - i 0.5, labels pathways[i], sector.index samples[1], track.index 1, facing inside, cex 0.7) } # 清除环形布局为后续使用ComplexHeatmap高级功能做准备 circos.clear()上述代码使用circlize的基础函数绘制了一个简易的圆形热图但它有几个明显缺点颜色映射逻辑分散在循环中、标签布局难以精确控制、缺乏ComplexHeatmap提供的丰富注释和自动图例。对于复现复杂文献图表我们通常需要结合两者优势。4. 整合ComplexHeatmap与circlize绘制高级圆形热图ComplexHeatmap的Heatmap类对象本身不能直接绘制在环形画布上。但是我们可以利用ComplexHeatmap的grid图形系统兼容性以及circlize的circos.heatmap函数它内部支持类似热图的绘制。更高级的方法是将矩阵数据视为一个特殊的“轨道”用ComplexHeatmap生成热图对象后将其“分解”为图形元素再逐一绘制到circlize定义的扇区和轨道中。这里介绍一种更直接、功能更强大的方法使用ComplexHeatmap的Heatmap函数结合circos.heatmap的思维。实际上circlize包提供了一个名为circos.heatmap的专用函数它简化了在环形轨道上绘制热图的过程。我们可以这样操作# 重新初始化画布这次为circos.heatmap准备 circos.clear() # 设置全局图形参数如边距 par(mar c(1, 1, 1, 1)) # 初始化扇区样本并设置每个扇区的大小比例这里等分 circos.initialize(samples, xlim c(0, 1)) # 定义颜色映射函数与ComplexHeatmap的colorRamp2一致 col_fun - colorRamp2(c(-2, 0, 2), c(blue, white, red)) # 使用circos.heatmap绘制热图轨道 # 注意circos.heatmap期望数据矩阵的行名与扇区名匹配。 # 我们需要将矩阵转置因为circos.heatmap默认将矩阵的列映射到扇区行映射到径向位置。 # 我们的目标是扇区样本径向位置通路。因此原始矩阵的行是样本列是通路正好符合。 circos.heatmap(data_matrix, col col_fun, track.height 0.4, # 轨道高度 dend.side inside, # 聚类树显示在内侧如果有 rownames.side outside, # 行名样本显示在外侧 rownames.cex 0.8, # 行名字体 cluster FALSE) # 暂时不聚类 # 添加快通路标签。circos.heatmap没有直接提供列名标签参数需要手动添加。 # 我们可以在热图轨道内侧添加一个文本轨道。 circos.track(ylim c(0, ncol(data_matrix)), track.height 0.05, bg.border NA, panel.fun function(x, y) { for(i in 1:ncol(data_matrix)) { circos.text(x 0.5, y ncol(data_matrix) - i 0.5, labels colnames(data_matrix)[i], cex 0.7, facing bending.inside, adj c(0.5, 0.5)) } }) # 添加图例 # 首先跳出环形绘图区域在图形右侧添加图例 legend_x - 1.05 legend_y - 0.5 color_bar_height - 0.3 color_bar_width - 0.03 # 绘制颜色条 for (i in 1:100) { y_val - (i-1)/100 * color_bar_height rect(legend_x, legend_y y_val, legend_x color_bar_width, legend_y y_val color_bar_height/100, col col_fun(-2 (i-1)/99 * 4), border NA) } # 添加图例标签 text(legend_x color_bar_width*1.5, legend_y, -2, adj c(0, 0.5), cex0.7) text(legend_x color_bar_width*1.5, legend_y color_bar_height/2, 0, adj c(0, 0.5), cex0.7) text(legend_x color_bar_width*1.5, legend_y color_bar_height, 2, adj c(0, 0.5), cex0.7) text(legend_x, legend_y color_bar_height*1.1, Enrichment Score, adj c(0.5, 0), cex0.8) # 最终清除布局 circos.clear()这段代码生成了一个更接近文献风格的圆形热图。circos.heatmap自动处理了每个扇区内的颜色块绘制和行标签。我们手动添加了通路标签轨道和图例。5. 高级定制复现文献中的复杂细节文献中的图表往往包含更多细节如样本分组信息、显著性标记、缺失值处理等。这需要更精细地控制circlize的绘图函数和ComplexHeatmap的注释功能。以下是一些常见需求的实现思路5.1 添加样本分组注释环假设样本分为“GroupA”和“GroupB”我们需要在热图外层添加一个分组注释环。# 创建分组信息 sample_groups - rep(c(GroupA, GroupB), each4) names(sample_groups) - samples group_colors - c(GroupA darkorange, GroupB steelblue) circos.clear() circos.initialize(samples, xlim c(0, 1)) # 首先绘制分组轨道在最外层 circos.track(ylim c(0, 1), track.height 0.05, bg.border NA, panel.fun function(x, y) { sector.index - CELL_META$sector.index group - sample_groups[sector.index] circos.rect(0, 0, 1, 1, col group_colors[group], border NA) }) # 然后绘制热图轨道在内层 circos.heatmap(data_matrix, col col_fun, track.height 0.3, dend.side inside, cluster FALSE) # ... (添加通路标签和图例的代码与之前类似)5.2 在热图单元格中添加文本或符号如果需要在特定单元格如p值0.05上添加星号(*)可以在circos.heatmap之后遍历每个扇区和单元格进行绘制。# 假设我们有一个与data_matrix同样大小的逻辑矩阵标记显著项 significant_matrix - matrix(runif(8*6) 0.2, nrow8, ncol6) circos.track(ylim c(0, ncol(data_matrix)), track.height 0.3, bg.border NA, panel.fun function(x, y) { sector.index - CELL_META$sector.index data_row_idx - which(rownames(data_matrix) sector.index) for (i in 1:ncol(data_matrix)) { if(significant_matrix[data_row_idx, i]) { # 计算当前单元格的中心坐标 cell_center_y ncol(data_matrix) - i 0.5 # 在单元格中心绘制星号 circos.text(x 0.5, y cell_center_y, labels *, cex 1.2, col black, adj c(0.5, 0.5)) } } })5.3 控制扇区顺序与聚类circos.heatmap支持通过cluster参数对行样本进行聚类。你也可以通过预定义的顺序来初始化扇区。# 方法1使用聚类结果重新排序样本 row_dend - hclust(dist(data_matrix)) # 对样本进行层次聚类 sample_order - rownames(data_matrix)[row_dend$order] # 按照聚类顺序初始化扇区 circos.clear() circos.initialize(sample_order, xlim c(0, 1)) circos.heatmap(data_matrix[sample_order, ], col col_fun, cluster FALSE) # 关闭内部聚类因为我们已经排好序 # 方法2手动指定顺序例如按某个通路的值降序 manual_order - rownames(data_matrix)[order(data_matrix[, PI3K/AKT/mTOR], decreasing TRUE)] circos.initialize(manual_order, xlim c(0, 1))6. 常见问题排查与调试在复现过程中你可能会遇到以下典型问题问题现象可能原因检查与解决方式图形空白或只有部分扇区circos.clear()未调用导致新旧布局冲突。在开始新的环形图之前务必先运行circos.clear()。标签重叠或显示不全扇区太窄或标签太长、字体太大。调整track.height增加轨道空间减小cex参数使用facing参数调整标签方向如“clockwise”,“bending.inside”。颜色映射不正确colorRamp2的断点breaks与数据范围不匹配。使用range(data_matrix)检查数据实际范围确保颜色断点能覆盖它。对于不对称数据可能需要调整断点位置。热图单元格错位circos.heatmap的数据行名与circos.initialize的扇区因子不匹配或顺序不一致。确保data_matrix的行名完全包含且顺序与初始化扇区的因子一致。使用rownames(data_matrix)和samples进行比对。图例不显示或位置错误图例是在环形绘图区域外用基础图形函数绘制的坐标系统不同。使用par(usr)获取当前图形区域的坐标范围根据此范围计算图例的绝对位置。或者考虑使用ComplexHeatmap::Legend函数生成图例对象再用grid系统绘制到特定位置。运行后图形设备混乱多次绘图未正确关闭或清理。在脚本最后使用dev.off()关闭图形设备或使用pdf(“filename.pdf”)等函数将图形直接输出到文件。一个关键的调试技巧是分步绘制。不要试图一次性写出完美的最终代码。先初始化画布并绘制一个简单的轨道确认扇区和坐标正确。然后逐步添加热图、标签、注释环。每添加一个元素都运行一次查看中间结果。7. 生产环境最佳实践与扩展建议当你需要将复现的图形用于论文或报告时以下几点至关重要图形输出与分辨率使用pdf(),png(),tiff()等函数指定输出文件、尺寸和分辨率。对于出版级图片DPI通常需要300或更高。png(circular_heatmap.png, width2000, height2000, res300) # ... 你的绘图代码 ... dev.off()代码模块化与可重用性将绘制圆形热图的代码封装成一个函数。这样只需更换输入数据、颜色方案和标签即可快速生成新的图形。draw_circular_heatmap - function(data_mat, row_colors NULL, col_colors NULL, main_title , filename NULL, ...) { # 参数检查、默认值设置 # 初始化图形设备 # 核心绘图流程 # 关闭设备如果指定了文件名 # 返回图形对象或保存文件 }颜色方案的可访问性考虑色盲友好配色。避免使用红-绿对比。可以使用viridis或RColorBrewer包中的配色。library(RColorBrewer) col_fun - colorRamp2(breaks c(-2, 0, 2), colors brewer.pal(11, RdBu)[c(9,6,3)]) # 蓝-白-红 # 或者使用viridis library(viridis) col_fun - colorRamp2(c(-2, 2), viridis(10))数据验证在绘图函数开头检查输入矩阵是否包含NA或Inf并决定处理方式如设为灰色或跳过。确保行名和列名存在且唯一。扩展方向交互式圆形热图探索circlize与plotly或ggiraph的结合创建可悬停查看数值的交互式环形热图。多层多组学数据整合利用多个同心圆轨道同时展示基因表达、DNA甲基化、拷贝数变异等多组学数据用ComplexHeatmap的HeatmapAnnotation思想管理每层的注释。与Shiny集成构建一个Shiny应用允许用户上传自己的矩阵数据动态调整颜色方案、聚类方法、标签显示等参数实时生成圆形热图。复现文献图表是提升数据可视化能力的绝佳练习。通过拆解目标、理解circlize的环形坐标系和ComplexHeatmap的美学控制你不仅能够重现特定的图形更能获得定制任何复杂环形可视化需求的能力。核心在于将全局的环形布局思维与局部的单元格绘图命令相结合并充分利用R图形系统的可组合性。
返回列表