ggplot多子图公共图例缺失部分数据类别问题求解
解决公共图例缺失Model C的问题
问题场景
生成三个数据集并合并为mydata:
- mydata1(model=A)、mydata2(model=B)包含n=1-10的全部数据
- mydata3(model=C)仅包含n=6-10的数据
使用循环绘制每个n对应的子图,通过ggarrange组合后,n=6-10的子图正常显示Model C的曲线,但顶部公共图例里没有Model C的选项。
原代码如下:
mydata1 <- data.frame("model" = rep("A", 1000), "n" = sample.int(10, 1000, replace = T), "n1" = seq(1,1000), "values" = rnorm(1000)) mydata2 <- data.frame("model" = rep("B", 1000), "n" = sample.int(10, 1000, replace = T), "n1" = seq(1,1000), "values" = rnorm(1000)) mydata3 <- data.frame("model" = rep("C", 500), "n" = c(rep(6,100),rep(7,100),rep(8,100),rep(9,100),rep(10,100)), "n1" = seq(1,500), "values" = rnorm(500)) mydata <- rbind(mydata1, mydata2, mydata3) fig_list <- list() for(i in 1:length(sort(unique(mydata$n)))) { data <- mydata[which(mydata$n == sort(unique(mydata $n))[i]),] fig_list[[i]] <- ggplot2::ggplot(data , aes(x = n1, y = values, colour = model)) + geom_line(size = 0.6) + labs(title = paste0("n = ", sort(unique(mydata$n))[i]), x = "n1", y = "values") + theme(plot.title = element_text(hjust = 0.5, size = 10)) } fig_all <- ggpubr::ggarrange(plotlist = fig_list, ncol = 2, nrow = ceiling(length(fig_list)/2), common.legend = TRUE, legend = "top") ggpubr::annotate_figure(fig_all, top = text_grob(paste0("All the plots are here.")))
问题原因
ggarrange的common.legend参数会提取所有子图共同存在的图例元素。由于n=1-5的子图中没有Model C的数据,ggplot会自动丢弃该水平的图例,最终公共图例只保留了所有子图都有的A和B。
两种可行解决方案
方案一:提前将model转为包含全量水平的因子
在合并数据集后,把model列转为因子并指定所有可能的水平,确保每个子图都会识别到三个model的存在:
mydata <- rbind(mydata1, mydata2, mydata3) # 指定model的所有水平,强制保留C的图例项 mydata$model <- factor(mydata$model, levels = c("A", "B", "C"))
之后保持原绘图循环不变即可,ggarrange会提取到所有三个水平的图例。
方案二:在每个子图中禁用图例自动丢弃
在ggplot代码中添加scale_colour_discrete(drop = FALSE),强制保留所有存在过的model水平图例,即使当前子图没有对应数据:
fig_list[[i]] <- ggplot2::ggplot(data , aes(x = n1, y = values, colour = model)) + geom_line(size = 0.6) + labs(title = paste0("n = ", sort(unique(mydata$n))[i]), x = "n1", y = "values") + theme(plot.title = element_text(hjust = 0.5, size = 10)) + # 禁用自动丢弃不存在的图例水平 scale_colour_discrete(drop = FALSE)
两种方法都能让公共图例同时显示A、B、C三个model的选项,且不影响子图中曲线的正常显示。
内容的提问来源于stack exchange,提问作者Phoebe
相关产品推荐
相关产品推荐

