ggplot2绘图时为何忽略因子水平顺序?含双图例需求问询
我来帮你解决这两个ggplot图例的问题,咱们一步步来拆解:
问题1:控制图例项的顺序
你遇到的核心问题是子集化数据后,ggplot会默认根据子集中实际存在的因子水平生成图例,自动忽略了你全局设置的完整因子顺序。
解决思路很直接:在对应的颜色和形状刻度设置里,手动指定breaks参数,强制使用你想要的因子顺序。哪怕某个水平在当前子集中不存在,也能按你设定的逻辑排列(如果想隐藏不存在的水平,也可以针对性过滤breaks)。
结合你的代码,只需要在添加完点图层后,加上指定breaks的刻度设置:
# 基于你已经设置好的df$description因子水平,强制图例顺序 scale_shape_discrete(breaks = levels(df$description)) + scale_color_discrete(breaks = levels(df$description))
问题2:创建两个独立的图例(Motifs和PTM)
默认情况下,ggplot会把使用相同美学映射(比如shape和color)的元素合并到同一个图例里。要拆分出两个独立图例,最便捷的方法是用ggnewscale包——它允许在同一张图里重复使用相同的美学映射,生成多组独立的刻度和图例。
完整修改后代码
library(tidyverse) library(ggnewscale) # 先安装:install.packages("ggnewscale") df <- as.data.frame( type = as.factor(c("Chain", "PTM", "PTM", "Motif", "Motif", "PTM", "Motif", "Chain", "PTM", "PTM", "Motif", "Motif")), description = as.factor(c("seq", "methyl", "methyl", "RXL", "RXL", "amine", "CXXC", "seq", "amine", "methyl", "CXXC", "RXL")), begin = c(1, 20, 75, 150, 67, 289, 100, 1, 124, 89, 73, 6), order = c(1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2), length = c(300, 1, 1, 1, 1, 1, 1, 350, 1, 1, 1, 1) ) # 先设置好你想要的全局因子顺序 df$description <- factor(df$description, levels = c("amine", "methyl", "RXL", "seq", "CXXC")) plot_start <- -100 plot_end <- 500 dfplot <- ggplot() + xlim(plot_start, plot_end) + scale_y_continuous(expand = c(0,0), limits =c(0, 2.5)) + theme_bw() + theme( panel.grid.minor=element_blank(), panel.grid.major=element_blank(), axis.ticks = element_blank(), axis.text.y = element_blank(), panel.border = element_blank() ) # 绘制蛋白链 dfplot <- dfplot + geom_rect( data= df[df$type == "Chain",], mapping=aes(xmin=begin, xmax=length, ymin=order-0.2, ymax=order+0.2), colour = "blue", fill = "#C4D9E9" ) # 第一步:绘制Motifs并设置第一个图例 dfplot <- dfplot + geom_point( data = filter(df, type == "Motif"), aes(begin, order, shape = description, color = description), size = 3 ) + scale_shape_discrete(name = "Motifs", breaks = levels(df$description)) + scale_color_discrete(name = "Motifs", breaks = levels(df$description)) # 关键:重置shape和color的美学映射,为下一组图层准备独立图例 dfplot <- dfplot + new_scale("shape") + new_scale("color") # 第二步:绘制PTM并设置第二个独立图例 dfplot <- dfplot + geom_point( data = filter(df, type == "PTM"), aes(begin, (order + 0.25), shape = description, color = description), size = 3 ) + scale_shape_discrete(name = "PTM", breaks = levels(df$description)) + scale_color_discrete(name = "PTM", breaks = levels(df$description)) dfplot
代码说明
ggnewscale的new_scale()函数会重置指定的美学映射,让后面的图层使用全新的刻度设置,从而生成独立的图例。- 每个刻度的
name参数用来设置图例标题,分别指定为"Motifs"和"PTM"。 - 如果不想显示某个图例里不存在的水平,可以把
breaks改成对应子集的水平,比如针对PTM可以写breaks = unique(df$description[df$type=="PTM"])。
内容的提问来源于stack exchange,提问作者Alastair Skeffington
相关产品推荐
相关产品推荐

