ggplot实现非均匀断点的等间距图例刻度
问题
使用geom_point绘制频率(Frequency)和倍数变化(FC)两个变量:点大小对应Frequency,颜色对应FC(FC<1.5为绿色,>1.5为红色)。为区分FC小于1的部分设置了更多断点,绘图效果符合预期,但希望让刻度c(0, 0.25, 0.5, 0.75, 1, 2, 3, 4, 5, 6)在图例颜色条中呈现等间距,求实现方法。
原绘图代码及可复现样本数据如下:
原绘图代码
p <- ggplot(mainG, aes(x = Allele, y = Cohort, size = Freq, color = FC)) + geom_point() + scale_y_discrete(limits = rev(levels(mainG$Cohort)), position = "right") + scale_size_continuous(limits = c(0, 0.5), breaks = c(0, 0.05, 0.10, 0.20, 0.40)) + # Underrepresented: FC < 1.5 ; overrepresented: FC > 1.5 scale_colour_gradientn( colours = c('darkgreen', 'forestgreen', 'darkseagreen3', 'darkseagreen2', 'indianred1', 'indianred2', 'indianred3', 'darkred'), values = c(0, 0.25, 0.5, 0.75, 1, 2, 3, 4, 5, 6)/6, breaks = c(0, 0.25, 0.5, 0.75, 1, 2, 3, 4, 5, 6)) + xlab("") + ylab("") + theme(axis.text = element_text(size = 7), axis.text.x = element_text(angle = 45, vjust = 1, hjust=1), axis.ticks.y = element_blank(), panel.border = element_rect(fill = NA), panel.background = element_blank(), axis.line = element_line(), legend.title = element_text(size = 7), legend.text = element_text(size = 7), legend.key = element_blank(), legend.position = "right", panel.spacing = unit(0.2, "lines"), strip.background =element_rect(colour = "black", fill = NA), strip.text = element_text(size = 7, face = "bold", margin = margin(0.1,5,0.1,5, "cm")) ) + facet_grid(.~ Gene, scales = "free", space = "free") p + guides(colour = guide_colourbar(barwidth = unit(0.5, "cm"), barheight = unit(5, "cm"), direction = "vertical"), size = guide_legend(title = "Frequency", reverse = T))
可复现样本数据
Cohort Gene Allele Freq FC Cohort1 B *08:01 0.027 0.24 Cohort2 A *01:01 0.103 0.63 Cohort2 A *68:01 0.103 3.63 Cohort2 B *07:02 0.207 1.59 Cohort2 B *08:01 0.034 0.31 Cohort2 B *51:01 0.121 2.44 Cohort3 A *02:01 0.407 1.51 Cohort3 A *03:01 0 NA Cohort3 B *07:02 0.037 0.28 Cohort3 B *08:01 0.019 0.17 Cohort3 B *44:03 0.148 3.15 Cohort4 A *02:01 0.17 0.63 Cohort4 A *24:02 0.17 2.01 Cohort4 B *07:02 0.05 0.38 Cohort4 B *18:01 0.11 2.41 Cohort5 B *07:02 0.053 0.4 Cohort5 B *18:01 0.105 2.31 Cohort6 B *07:02 0.041 0.31 Cohort6 B *18:01 0.122 2.69 Cohort6 B *51:01 0.102 2.06 Control A *01:01 0.163 NA Control A *02:01 0.269 NA Control A *03:01 0.14 NA Control A *24:02 0.085 NA Control A *26:01 0.035 NA Control A *29:02 0.035 NA Control A *32:01 0.037 NA Control A *68:01 0.029 NA Control B *07:02 0.13 NA Control B *08:01 0.11 NA Control B *18:01 0.046 NA Control B *44:02 0.087 NA Control B *44:03 0.047 NA Control B *51:01 0.05 NA
解决方案
要实现指定刻度在颜色条中等间距显示,核心是对FC值做自定义非线性变换,让目标断点对应到颜色条的等间距位置,同时保留原有颜色映射逻辑。
修改后的完整代码
library(ggplot2) # 读取样本数据 mainG <- read.table(text = "Cohort Gene Allele Freq FC Cohort1 B *08:01 0.027 0.24 Cohort2 A *01:01 0.103 0.63 Cohort2 A *68:01 0.103 3.63 Cohort2 B *07:02 0.207 1.59 Cohort2 B *08:01 0.034 0.31 Cohort2 B *51:01 0.121 2.44 Cohort3 A *02:01 0.407 1.51 Cohort3 A *03:01 0 NA Cohort3 B *07:02 0.037 0.28 Cohort3 B *08:01 0.019 0.17 Cohort3 B *44:03 0.148 3.15 Cohort4 A *02:01 0.17 0.63 Cohort4 A *24:02 0.17 2.01 Cohort4 B *07:02 0.05 0.38 Cohort4 B *18:01 0.11 2.41 Cohort5 B *07:02 0.053 0.4 Cohort5 B *18:01 0.105 2.31 Cohort6 B *07:02 0.041 0.31 Cohort6 B *18:01 0.122 2.69 Cohort6 B *51:01 0.102 2.06 Control A *01:01 0.163 NA Control A *02:01 0.269 NA Control A *03:01 0.14 NA Control A *24:02 0.085 NA Control A *26:01 0.035 NA Control A *29:02 0.035 NA Control A *32:01 0.037 NA Control A *68:01 0.029 NA Control B *07:02 0.13 NA Control B *08:01 0.11 NA Control B *18:01 0.046 NA Control B *44:02 0.087 NA Control B *44:03 0.047 NA Control B *51:01 0.05 NA", header = TRUE, stringsAsFactors = FALSE) # 定义自定义变换:将目标断点映射到等间距的0-1区间 fc_breaks <- c(0, 0.25, 0.5, 0.75, 1, 2, 3, 4, 5, 6) fc_trans <- scales::trans_new( name = "fc_custom", transform = function(x) { idx <- findInterval(x, fc_breaks) ifelse(idx == 0, 0, ifelse(idx == length(fc_breaks), 1, (idx - 1 + (x - fc_breaks[idx])/(fc_breaks[idx+1]-fc_breaks[idx]))/(length(fc_breaks)-1)) ) }, inverse = function(x) { idx <- floor(x*(length(fc_breaks)-1)) + 1 if(idx >= length(fc_breaks)) return(fc_breaks[length(fc_breaks)]) fc_breaks[idx] + (x*(length(fc_breaks)-1) - (idx-1))*(fc_breaks[idx+1]-fc_breaks[idx]) } ) # 绘制图形 p <- ggplot(mainG, aes(x = Allele, y = Cohort, size = Freq, color = FC)) + geom_point() + scale_y_discrete(limits = rev(levels(factor(mainG$Cohort))), position = "right") + scale_size_continuous(limits = c(0, 0.5), breaks = c(0, 0.05, 0.10, 0.20, 0.40)) + # 调整颜色映射,使用自定义变换 scale_colour_gradientn( colours = c('darkgreen', 'forestgreen', 'darkseagreen3', 'darkseagreen2', 'indianred1', 'indianred2', 'indianred3', 'darkred'), values = seq(0, 1, length.out = length(fc_breaks)), # 等间距颜色位置 breaks = fc_breaks, # 指定目标断点 trans = fc_trans # 应用自定义变换 ) + xlab("") + ylab("") + theme(axis.text = element_text(size = 7), axis.text.x = element_text(angle = 45, vjust = 1, hjust=1), axis.ticks.y = element_blank(), panel.border = element_rect(fill = NA), panel.background = element_blank(), axis.line = element_line(), legend.title = element_text(size = 7), legend.text = element_text(size = 7), legend.key = element_blank(), legend.position = "right", panel.spacing = unit(0.2, "lines"), strip.background =element_rect(colour = "black", fill = NA), strip.text = element_text(size = 7, face = "bold", margin = margin(0.1,5,0.1,5, "cm")) ) + facet_grid(.~ Gene, scales = "free", space = "free") # 调整颜色条指南,确保刻度显示正确 p + guides(colour = guide_colourbar(barwidth = unit(0.5, "cm"), barheight = unit(5, "cm"), direction = "vertical", breaks = fc_breaks), size = guide_legend(title = "Frequency", reverse = TRUE))
关键说明
- 自定义变换函数:
fc_trans将FC值映射到0-1的等间距区间,让目标断点在颜色条上均匀分布,逆变换则负责将映射后的值还原为原始FC刻度。 - 颜色映射调整:
values设置为等间距的0-1序列,确保每个颜色对应到刻度的等间距位置,和断点一一匹配。 - 保留原有逻辑:完全保留了FC<1.5用绿色系、>1.5用红色系的颜色规则,同时让小值刻度占据更多视觉空间,满足区分需求。
内容的提问来源于stack exchange,提问作者jennwl
相关产品推荐
相关产品推荐

