参数要点
| 参数 | 默认 | 说明 |
|---|---|---|
sort |
desc |
none/asc/desc,按数值排扇区 |
inner_radius |
0 | >0 变环形(中间可放注释) |
start_angle |
0 | 起始角度(度) |
label_min_share |
0.08 | 只给占比 ≥8% 的扇区打内部标签 |
plot58 · 代码 3 · 图 1 · 笔记 2 · 代码库专题
长表:label + value(可选 group 做堆叠玫瑰图)。
示例 polar bar plot示例_polar_bar_plot.png
图源:示例_polar_bar_plot.png
从专题 README 抽取;原文顺序保留,未跑过的部分照实标注。
类别多(8~30 个)时,用极坐标把有限版面装满,比横向条形图的信息密度高。
| 参数 | 默认 | 说明 |
|---|---|---|
sort |
desc |
none/asc/desc,按数值排扇区 |
inner_radius |
0 | >0 变环形(中间可放注释) |
start_angle |
0 | 起始角度(度) |
label_min_share |
0.08 | 只给占比 ≥8% 的扇区打内部标签 |
长表:label + value(可选 group 做堆叠玫瑰图)。
trait,value
Total root length,128.4
Root surface area,96.2
Tips,210.9render_plot method_id="plot58"
arguments: {"csv_path": "your.csv",
"columns": {"label": "trait", "value": "value"}}玫瑰图在 ggplot2 里必须同时满足三个条件,缺一个就只画出一段弧(实测反复踩):
limits 精确卡 [0.5, n+0.5]、expand = c(0,0)。coord_polar 会把每类映射到固定刻度,整圈只铺开约 180°。scale_y_continuous(limits = c(0, NA)) —— y 下限必须是 0。geom_col(width = 1) —— 扇区之间不能留缝。另外两个坑:
xpos 这一列必须在 ggplot() 之前创建:ggplot 会捕获数据框的当时状态,raw$xpos <- ... 不会进入图层数据。.xpos 这种带点的列名在 aes() 里裸写会被当成对象名,.data[["xpos"]] 也可能失效;直接用无点列名 xpos 最稳。类别 <5 个(普通条形图更好读)、量纲差异很大(对数或分面更合适)。
MsTt模板/241202_polar_plot 极坐标条形图/(circlize 手绘原稿)。
2 个源码文件,按目录顺序;本机绝对路径已替换为 ~。 代码可复制,但需要按自己的数据改路径与参数。
---
title: "code"
output: html_document
date: "2025-05-14"
editor_options:
chunk_output_type: console
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
SCI 复现 | 绝美极坐标条形图
请尊重原创劳动成果
未经允许,不得转载
今天来复现Journal of Hazardous Materials 文章中 (Yuxiao Chang. et al. Enhanced nitrogen fixation and Cd passivation in rhizosphere soil by biochar-loaded nitrogen-fixing bacteria: Chemisorption and microbial mechanism. Journal of Hazardous Materials, Volume 481, 2025, 136588, ISSN 0304-3894, https://doi.org/10.1016/j.jhazmat.2024.136588) 的 Fig.2c
原图
图片
这个图很好看、很清晰:
不仅展示了多个根系指标(如总根长、总根表面积、平均根直径等),还区分了不同的处理(KB, BC, BAc),另外还标记了多重比较的标签(a, b, c)。
采用极坐标形式,可以在有限的空间内展示大量信息,避免了过度占用页面空间。
复现图
图片
此图复现使用的是 R 语言,复现过程中学习到的技巧:
使用 circlize 包完成,虽然整体难度不大,但过程中需要注意很多细节。比如,背景刻度线的设置、多重比较标签的添加,这些细节的处理使得图表更加美观和易于理解。
加载R包,准备数
```{r}
# 设置工作目录
setwd("~/Downloads/MSTT 笔记/241202_polar_plot 极坐标条形图")
#清除环境变量
rm(list = ls())
# 加载必要的包
library(circlize)
# 读取数据
data = read.csv("data.csv")
data$category <- factor(data$category, levels = c("Forks", "Crossings", "Length", "SurfArea", "AvgDiam", "RootVolume", "Tips"))
# 定义颜色
category_colors <- c(
"Forks" = "#E41A1C", # 红色
"Crossings" = "#377EB8", # 蓝色
"Length" = "#4DAF4A", # 绿色
"SurfArea" = "#984EA3", # 紫色
"AvgDiam" = "#FF7F00", # 橙色
"RootVolume" = "#FFFF33", # 黄色
"Tips" = "#A65628" # 棕色
)
# 定义组颜色 - 修改为图片中的颜色
colors <- c(
"KB" = "#4292C6", # 蓝色
"BC" = "#6BAED6", # 浅蓝色
"BAc" = "#9ECAE1" # 最浅蓝色
)
```
处理一下数据:将category列转换为因子,并且指定因子的顺序。在极坐标图中,因子的顺序决定了扇形图的排列顺序。
绘图 - 定义画布
```{r}
# 初始化极坐标图
circos.clear()
# 修改参数以提供更多空间,并更好地匹配目标图像
circos.par(start.degree = 90,
gap.degree = 4, # 减小扇区间隙
track.margin = c(0, 0.02), # 减少轨道上下边距
cell.padding = c(0, 0, 0, 0),
track.height = 0.35 # 调整默认轨道高度
)
circos.initialize(factors = data$category, xlim = c(0, 1))
```
使用circos.clear()清除当前的图形设置,包括所有扇区和轨道的设置。
使用circos.par()设置一些全局参数。这些参数会影响整个图形的外观和布局。
start.degree = 90: 设置极坐标图的起始角度为 90 度。默认情况下,极坐标图从 0 度开始(即从正右方向开始),设置为 90 度意味着图形从正上方开始绘制。
gap.degree = 7: 设置扇区之间的间隙为 7 度。这个参数控制每个扇区之间的空白区域,使得每个扇区之间有一定的间隔。
track.margin = c(0, 0.12): 设置轨道的上下边距。c(0, 0.12)表示轨道的上边距为 0,下边距为 0.12。这个参数控制轨道之间的间距。
cell.padding = c(0, 0, 0, 0): 设置单元格内部的填充。c(0, 0, 0, 0)表示单元格的四个方向(上、右、下、左)都没有填充。这可以使得每个轨道的内容更紧密地填充在轨道内。
使用circos.initialize()初始化极坐标图。这个函数定义了每个扇区的基本参数,包括扇区的类别和每个扇区的 x 轴范围。
factors = data$category: 指定了扇区的类别。
xlim = c(0, 1): 定义了每个扇区的 x 轴范围。c(0, 1)表示每个扇区的 x 轴从 0 到 1。这个范围是标准化的,意味着无论实际数据的范围如何,都会被映射到 0 到 1 的范围内。
绘图 - 极坐标分类标签
```{r}
# 添加扇形分类标签和填充颜色
circos.track(
factors = data$category,
ylim = c(0, 1),
track.height = 0.05, # 增加高度以匹配图片
bg.col = category_colors,
panel.fun = function(x, y) {
circos.text(
CELL_META$xcenter,
CELL_META$ylim[2] - 0.5, # 调整文字位置
CELL_META$sector.index,
facing = "bending.inside",
cex = 0.9, # 减小字体以匹配图片
font = 2, # 粗体
adj = c(0.5, 0.5)
)
}
)
```
使用circos.track()函数添加一个新的轨道,并在轨道中绘制文本标签。
factors = data$category: 指定扇区的类别。每个类别将对应一个扇区。
ylim = c(0, 1):定义轨道的 y 轴范围。
track.height = 0.035: 定义轨道的高度。0.035 表示轨道高度为 3.5% 的圆环半径。
bg.col = category_colors: 指定每个扇区的背景颜色。
panel.fun = function(x, y):是一个自定义的绘图函数。
circos.text()函数用于在极坐标图中绘制文本标签。CELL_META是一个包含当前扇区的元数据的对象。xcenter表示当前扇区的 x 轴中心位置。ylim[2]表示当前扇区 y 轴的最大值(即上边界)。sector.index是当前扇区的名称。在这里,它被用作文本标签的内容。
图片
绘图 - 极坐标条形图
```{r}
# 设置极坐标图的背景和刻度线
circos.trackPlotRegion(
factors = data$category,
ylim = c(0, 1),
track.height = 0.45,
bg.col = adjustcolor(category_colors, alpha.f = 0.2), # 降低透明度以匹配图片
panel.fun = function(x, y) {
sector_data <- data[data$category == CELL_META$sector.index, ]
# 根据不同指标调整刻度范围
if (CELL_META$sector.index == "AvgDiam") {
max_value <- 0.5 # 为AvgDiam设置固定最大值
} else if (CELL_META$sector.index == "Length") {
max_value <- 1200 # 为Length设置固定最大值
} else if (CELL_META$sector.index == "RootVolume") {
max_value <- 30 # 为RootVolume设置固定最大值
} else if (max(sector_data$value) * 1.1 < 100) {
max_value <- ceiling(max(sector_data$value) * 1.1 / 10) * 10
} else if (max(sector_data$value) * 1.1 < 1000) {
max_value <- ceiling(max(sector_data$value) * 1.1 / 100) * 100
} else {
max_value <- ceiling(max(sector_data$value) * 1.1 / 400) * 400
}
# 生成3个刻度,符合图片
at <- seq(0, max_value, by = max_value / 3)
at <- at[-c(1, length(at))]
for (a in at) {
circos.lines(
CELL_META$xlim,
c(a, a) / max_value,
lty = 2, # 虚线
col = "grey60" # 浅灰色
)
circos.text(
CELL_META$cell.xlim[1] - mm_h(3),
a / max_value,
labels = ifelse(a >= 100, as.integer(a), round(a, 1)), # 大数去掉小数点
facing = "clockwise",
adj = c(0.5, 0),
cex = 0.8 # 减小字体
)
circos.lines(
CELL_META$cell.xlim[1] + c(-0.01, 0),
c(a, a) / max_value
)
}
# 添加坐标轴
circos.axis(
h = "top",
major.at = NULL,
labels = FALSE
)
}
)
```
使用circos.trackPlotRegion()函数添加一个新的轨道区域。
panel.fun():是一个自定义函数,在每个扇区中执行自定义绘图操作。
sector_data <- data[data$category == CELL_META$sector.index, ]:根据当前扇区的名称,从 data 数据框中提取相应的行数据。
确定最大值和刻度:根据每个扇区的最大值来确定绘制刻度线的最大值。最大值会稍微放大一些(乘以1.1),然后根据实际大小选择一个合适的刻度间隔(40 或 400)。
at <- seq(0, max_value, by = max_value / 4) 生成刻度线的位置。
at <- at[-c(1, length(at))]去掉第一个和最后一个刻度,以避免在图形边缘绘制刻度线。
for (a in at)循环遍历每个刻度位置,绘制刻度线和标签。
circos.lines()绘制水平刻度线。
circos.text()在刻度线的位置绘制刻度值标签。
circos.axis()添加坐标轴刻度,h = "top"指定添加在扇形的上边。
图片
```{r}
# 绘制极坐标的条形图
circos.trackPlotRegion(
factors = data$category,
ylim = c(0, 1),
track.height = 0.25,
bg.col = NA, # 不需要背景色
panel.fun = function(x, y) {
sector_data <- data[data$category == CELL_META$sector.index, ]
# 根据不同指标调整刻度范围
if (CELL_META$sector.index == "AvgDiam") {
max_value <- 0.5 # 为AvgDiam设置固定最大值
} else if (CELL_META$sector.index == "Length") {
max_value <- 1200 # 为Length设置固定最大值
} else if (CELL_META$sector.index == "RootVolume") {
max_value <- 30 # 为RootVolume设置固定最大值
} else if (max(sector_data$value) * 1.1 < 100) {
max_value <- ceiling(max(sector_data$value) * 1.1 / 10) * 10
} else if (max(sector_data$value) * 1.1 < 1000) {
max_value <- ceiling(max(sector_data$value) * 1.1 / 100) * 100
} else {
max_value <- ceiling(max(sector_data$value) * 1.1 / 400) * 400
}
# 调整条形宽度和间隔以匹配图片
bar_width <- 0.15
gap_width <- 0.05
# 调整条形起始位置,使其居中
start_pos <- 0.2
for (i in seq_len(nrow(sector_data))) {
xleft <- start_pos + (i - 1) * (bar_width + gap_width)
xright <- xleft + bar_width
circos.rect(
xleft = xleft,
ybottom = 0,
xright = xright,
ytop = sector_data$value[i] / max_value,
col = colors[sector_data$group[i]],
border = NA, # 移除边框以匹配图片
lwd = 1
)
}
}
)
```
for (i in 1:nrow(sector_data)) 循环遍历每个数据点,绘制条形图。
xleft和xright定义条形的左右边界位置。
circos.rect()用于绘制条形图。
ybottom定义条形的底部位置(这里设为 0)。
ytop定义条形的顶部位置,按比例缩放到 max_value。
col定义条形的填充颜色,colors[sector_data$group[i]]根据数据点的组别设置颜色。
图片
```{r}
# 添加显著性标记
circos.trackPlotRegion(
factors = data$category,
ylim = c(0, 1),
track.height = 0.2, # 减小轨道高度
bg.col = NA, # 不需要背景色
panel.fun = function(x, y) {
sector_data <- data[data$category == CELL_META$sector.index, ]
# 根据不同指标调整刻度范围
if (CELL_META$sector.index == "AvgDiam") {
max_value <- 0.5 # 为AvgDiam设置固定最大值
} else if (CELL_META$sector.index == "Length") {
max_value <- 1200 # 为Length设置固定最大值
} else if (CELL_META$sector.index == "RootVolume") {
max_value <- 30 # 为RootVolume设置固定最大值
} else if (max(sector_data$value) * 1.1 < 100) {
max_value <- ceiling(max(sector_data$value) * 1.1 / 10) * 10
} else if (max(sector_data$value) * 1.1 < 1000) {
max_value <- ceiling(max(sector_data$value) * 1.1 / 100) * 100
} else {
max_value <- ceiling(max(sector_data$value) * 1.1 / 400) * 400
}
# 计算柱子位置,与条形图保持一致
bar_width <- 0.15
gap_width <- 0.05
start_pos <- 0.2
for (i in seq_len(nrow(sector_data))) {
xleft <- start_pos + (i - 1) * (bar_width + gap_width)
xright <- xleft + bar_width
circos.text(
(xleft + xright) / 2,
sector_data$value[i] / max_value + 0.05, # 增加偏移量使标签更明显
labels = sector_data$significance[i],
col = "black",
cex = 0.8, # 减小字体大小
font = 2, # 使用粗体
facing = "inside",
adj = c(0.5, 0)
)
}
}
)
# 添加图例
legend("topright",
legend = c("KB", "BC", "BAc"),
fill = colors,
bty = "n",
cex = 0.8,
border = NA, # 移除边框
title = "Treatment")
```
使用circos.text()函数在每个条形的顶部绘制显著性标记:
x 位置:(xleft + xright) / 2取左右边界的中点,即条形的中间位置。
y 位置:sector_data$value[i] / max_value + 0.02计算条形的高度,再加上一个偏移量 0.02,以确保标记在柱子的顶部。
标签内容:labels = sector_data$significance[i]提取当前数据点的显著性标记。
图片
带误差棒的版本也已添加,获取以 RProject 形式保存的绘图代码和测试数据,后台回复关键词:241202_polar_plot
---
title: "241202_polar_plot 极坐标条形图"
output: html_document
date: "2025-04-10"
editor_options:
chunk_output_type: console
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
```{r}
#清除所有数据
rm(list = ls())
library(circlize)
library(readxl)
library(writexl)
# 读取CSV数据文件
data <- read.csv("data.csv", stringsAsFactors = FALSE)
data$category <- factor(data$category, levels = c("Forks", "Crossings", "Length", "SurfArea", "AvgDiam", "RootVolume", "Tips"))
```
```{r}
# 设置类别顺序
categories <- c("Forks", "Crossings", "Length", "SurfArea", "AvgDiam", "RootVolume", "Tips")
data$category <- factor(data$category, levels = categories)
# 定义颜色
category_colors <- c(
"Forks" = "#E41A1C", # 红色
"Crossings" = "#377EB8", # 蓝色
"Length" = "#4DAF4A", # 绿色
"SurfArea" = "#984EA3", # 紫色
"AvgDiam" = "#FF7F00", # 橙色
"RootVolume" = "#FFFF33", # 黄色
"Tips" = "#A65628" # 棕色
)
# 定义组颜色
colors <- c(
"KB" = "#66C2A5", # 青绿色
"BC" = "#FC8D62", # 橙色
"BAc" = "#8DA0CB" # 蓝紫色
)
```
```{r fig.width=10, fig.height=10, results='hide', message=FALSE, warning=FALSE}
# 确保图形设备初始化
par(mfrow=c(1,1))
# 清除之前的circos设置
circos.clear()
# 设置circos参数
circos.par(start.degree = 90,
gap.degree = 7,
track.margin = c(0, 0.05),
cell.padding = c(0, 0, 0, 0),
track.height = 0.1 # 减小默认跟踪高度
)
# 初始化扇区
circos.initialize(factors = data$category, xlim = c(0, 1))
# 添加扇形分类标签和填充颜色
circos.track(
factors = data$category,
ylim = c(0, 1),
track.height = 0.035,
bg.col = category_colors,
panel.fun = function(x, y) {
circos.text(
CELL_META$xcenter,
CELL_META$ylim[2] - 3.2,
CELL_META$sector.index,
facing = "bending.inside",
cex = 2,
adj = c(0.5, 0)
)
}
)
# 设置极坐标图的背景和刻度线
circos.trackPlotRegion(
factors = data$category,
ylim = c(0, 1),
track.height = 0.47,
bg.col = adjustcolor(category_colors, alpha.f = 0.4),
panel.fun = function(x, y) {
sector_data <- data[data$category == CELL_META$sector.index, ]
if (max(sector_data$value) * 1.1 < 1000) {
max_value <- ceiling(max(sector_data$value) * 1.1 / 40) * 40
} else if (max(sector_data$value) * 1.1 >= 1000) {
max_value <- ceiling(max(sector_data$value) * 1.1 / 400) * 400
}
at <- seq(0, max_value, by = max_value / 4)
at <- at[-c(1, length(at))]
for (a in at) {
circos.lines(
CELL_META$xlim,
c(a, a) / max_value,
lty = 5,
col = "grey40"
)
circos.text(
CELL_META$cell.xlim[1] - mm_h(2),
a / max_value, labels = round(a),
facing = "clockwise",
adj = c(0.5, 0),
cex = 1.1
)
circos.lines(
CELL_META$cell.xlim[1] + c(-0.02, 0),
c(a, a) / max_value
)
circos.axis(
h = "top",
major.at = seq(0, 1, by = 0.3),
major.tick.length = -0.05,
minor.ticks = 1,
labels = FALSE
)
}
}
)
# 绘制极坐标的条形图
circos.trackPlotRegion(
factors = data$category,
ylim = c(0, 1),
track.height = 0.47,
bg.col = adjustcolor(category_colors, alpha.f = 0.4),
panel.fun = function(x, y) {
sector_data <- data[data$category == CELL_META$sector.index, ]
# 获取当前扇区的最大值
if (max(sector_data$value) * 1.1 < 1000) {
max_value <- ceiling(max(sector_data$value) * 1.1 / 40) * 40
} else if (max(sector_data$value) * 1.1 >= 1000) {
max_value <- ceiling(max(sector_data$value) * 1.1 / 400) * 400
}
bar_width <- 0.2
gap_width <- 0.1
for (i in seq_len(nrow(sector_data))) {
xleft <- (i - 0.7) * (bar_width + gap_width)
xright <- xleft + bar_width
circos.rect(
xleft = xleft,
ybottom = 0,
xright = xright,
ytop = sector_data$value[i] / max_value,
col = colors[sector_data$group[i]],
border = "black",
lwd = 1.5
)
}
}
)
# 添加显著性标记
circos.trackPlotRegion(
factors = data$category,
ylim = c(0, 1),
track.height = 0.47,
bg.col = adjustcolor(category_colors, alpha.f = 0.4),
panel.fun = function(x, y) {
sector_data <- data[data$category == CELL_META$sector.index, ]
# 获取当前扇区的最大值
if (max(sector_data$value) * 1.1 < 1000) {
max_value <- ceiling(max(sector_data$value) * 1.1 / 40) * 40
} else if (max(sector_data$value) * 1.1 >= 1000) {
max_value <- ceiling(max(sector_data$value) * 1.1 / 400) * 400
}
bar_width <- 0.2
gap_width <- 0.1
for (i in seq_len(nrow(sector_data))) {
xleft <- (i - 0.7) * (bar_width + gap_width)
xright <- xleft + bar_width
circos.text(
(xleft + xright) / 2,
sector_data$value[i] / max_value + 0.02,
labels = sector_data$significance[i],
col = "black",
cex = 1.7,
facing = "inside",
adj = c(0.5, 0)
)
}
}
)
# 添加图例
legend("topright", legend = c("KB", "BC", "BAc"), fill = colors, bty = "n", cex = 0.8)
# 保存为png,背景为白色
png("polar_plot.png", width = 800, height = 800, res = 300, bg = "white")
# 重新绘制所有内容(直接在png设备上绘制)
circos.clear()
circos.par(start.degree = 90,
gap.degree = 7,
track.margin = c(0, 0.05),
cell.padding = c(0, 0, 0, 0),
track.height = 0.1 # 减小默认跟踪高度
)
circos.initialize(factors = data$category, xlim = c(0, 1))
# 添加扇形分类标签和填充颜色
circos.track(
factors = data$category, ylim = c(0, 1), track.height = 0.035, bg.col = category_colors,
panel.fun = function(x, y) {
circos.text(
CELL_META$xcenter, CELL_META$ylim[2] - 3.2, CELL_META$sector.index,
facing = "bending.inside", cex = 2, adj = c(0.5, 0)
)
}
)
# 设置极坐标图的背景和刻度线
circos.trackPlotRegion(
factors = data$category, ylim = c(0, 1), track.height = 0.47,
bg.col = adjustcolor(category_colors, alpha.f = 0.4),
panel.fun = function(x, y) {
sector_data <- data[data$category == CELL_META$sector.index, ]
if (max(sector_data$value) * 1.1 < 1000) {
max_value <- ceiling(max(sector_data$value) * 1.1 / 40) * 40
} else if (max(sector_data$value) * 1.1 >= 1000) {
max_value <- ceiling(max(sector_data$value) * 1.1 / 400) * 400
}
at <- seq(0, max_value, by = max_value / 4)
at <- at[-c(1, length(at))]
for (a in at) {
circos.lines(CELL_META$xlim, c(a, a) / max_value, lty = 5, col = "grey40")
circos.text(CELL_META$cell.xlim[1] - mm_h(2), a / max_value,
labels = round(a), facing = "clockwise", adj = c(0.5, 0), cex = 1.1)
circos.lines(CELL_META$cell.xlim[1] + c(-0.02, 0), c(a, a) / max_value)
circos.axis(h = "top", major.at = seq(0, 1, by = 0.3),
major.tick.length = -0.05, minor.ticks = 1, labels = FALSE)
}
}
)
# 绘制极坐标的条形图
circos.trackPlotRegion(
factors = data$category, ylim = c(0, 1), track.height = 0.47,
bg.col = adjustcolor(category_colors, alpha.f = 0.4),
panel.fun = function(x, y) {
sector_data <- data[data$category == CELL_META$sector.index, ]
if (max(sector_data$value) * 1.1 < 1000) {
max_value <- ceiling(max(sector_data$value) * 1.1 / 40) * 40
} else if (max(sector_data$value) * 1.1 >= 1000) {
max_value <- ceiling(max(sector_data$value) * 1.1 / 400) * 400
}
bar_width <- 0.2
gap_width <- 0.1
for (i in seq_len(nrow(sector_data))) {
xleft <- (i - 0.7) * (bar_width + gap_width)
xright <- xleft + bar_width
circos.rect(
xleft = xleft, ybottom = 0, xright = xright, ytop = sector_data$value[i] / max_value,
col = colors[sector_data$group[i]], border = "black", lwd = 1.5
)
}
}
)
# 添加显著性标记
circos.trackPlotRegion(
factors = data$category, ylim = c(0, 1), track.height = 0.47,
bg.col = adjustcolor(category_colors, alpha.f = 0.4),
panel.fun = function(x, y) {
sector_data <- data[data$category == CELL_META$sector.index, ]
if (max(sector_data$value) * 1.1 < 1000) {
max_value <- ceiling(max(sector_data$value) * 1.1 / 40) * 40
} else if (max(sector_data$value) * 1.1 >= 1000) {
max_value <- ceiling(max(sector_data$value) * 1.1 / 400) * 400
}
bar_width <- 0.2
gap_width <- 0.1
for (i in seq_len(nrow(sector_data))) {
xleft <- (i - 0.7) * (bar_width + gap_width)
xright <- xleft + bar_width
circos.text(
(xleft + xright) / 2, sector_data$value[i] / max_value + 0.02,
labels = sector_data$significance[i], col = "black", cex = 1.7,
facing = "inside", adj = c(0.5, 0)
)
}
}
)
# 添加图例
legend("topright", legend = c("KB", "BC", "BAc"), fill = colors, bty = "n", cex = 0.8)
# 关闭PNG设备
dev.off()
```
```
```
这个专题已经做成确定性工具,调用后直接返回图片, 不需要 AI 现写代码。