使用facet分面时,如何用geom_line连接geom_point的点?
问题描述
我遇到了一个未在网络上找到解决方案的问题,希望能得到相关提示。
我有一个数据集,其x轴为离散型,原本可以连接各点,但添加facet分面选项后,无法再跨分面连接点(例如周一夜班的最后一个点应连接到周二早班的点)。我找到了一个替代方案,但效果不佳。
可复现代码
# Create a simple dataset dat <- data.frame(Days = c(rep("Monday", 6), rep("Tuesday", 6), rep("Wednesday", 6)), Shift = rep(c("Morning", "Evening", "Night"), 6), Group = c(rep("Group1", 3), rep("Group2", 3), rep("Group1", 3), rep("Group2", 3), rep("Group1", 3), rep("Group2", 3)), Amount = c(6, 5, 6, 2, 3, 1, 5, 4, 6, 1, 2, 2, 5, 4, 7, 3, 1, 2)) # Change into factor to have the order I need dat$Days <- factor(dat$Days, levels = c("Monday", "Tuesday", "Wednesday")) dat$Shift <- factor(dat$Shift, levels = c("Morning", "Evening", "Night")) # The plot I am stuck with # The last dot of Monday night should be linked to Tuesday morning ggplot(data = dat, aes(x = Shift, y = Amount)) + geom_point() + geom_line(aes(group = Group)) + facet_grid(.~Days) + theme(panel.spacing = unit(0, "lines"))
当前效果示意图:
替代方案(效果不佳)
# This is the alternative I found, but clearly not great ggplot(data = dat, aes(x = interaction(Days, Shift, sep = "\n", lex.order = T), y = Amount)) + geom_point(aes(color = Group)) + geom_line(aes(group = Group)) + geom_vline(xintercept = c(3, 6, 9), color = "darkred", linetype = 2)
替代方案效果示意图:
解决方案
核心思路是将Days和Shift转换为连续的位置变量,让跨分面的点在连续轴上有对应位置,从而实现跨面板连线。
步骤1:构造连续位置变量
给每个Days-Shift组合分配连续数值,确保时间顺序正确:
# 生成所有Day-Shift的组合并按顺序排序 shift_order <- expand.grid(Days = levels(dat$Days), Shift = levels(dat$Shift)) shift_order <- shift_order[order(shift_order$Days, shift_order$Shift), ] # 给每个组合分配连续位置 shift_order$x_pos <- 1:nrow(shift_order) # 合并到原数据集 dat <- merge(dat, shift_order, by = c("Days", "Shift"))
步骤2:绘制带跨分面连线的图
利用连续的x_pos作为x轴,分面时设置scales="free_x"和space="free_x",同时手动调整x轴标签匹配原Shift名称:
library(ggplot2) ggplot(dat, aes(x = x_pos, y = Amount)) + geom_point() + geom_line(aes(group = Group)) + # 分面,每个Day一个面板,x轴自由缩放且空间匹配 facet_grid(. ~ Days, scales = "free_x", space = "free_x") + # 自定义x轴刻度和标签,仅显示当前面板对应Day的Shift scale_x_continuous( breaks = function(x) { current_day <- unique(dat$Days[dat$x_pos >= x[1] & dat$x_pos <= x[2]]) panel_shifts <- shift_order[shift_order$Days == current_day, ] panel_shifts$x_pos }, labels = function(x) { current_day <- unique(dat$Days[dat$x_pos >= x[1] & dat$x_pos <= x[2]]) panel_shifts <- shift_order[shift_order$Days == current_day, ] panel_shifts$Shift } ) + theme( panel.spacing = unit(0, "lines"), axis.title.x = element_blank() )
该方案既保留了分面布局,又实现了跨分面的连续连线,同时x轴标签仍显示为原Shift名称,视觉效果更贴合需求。
内容的提问来源于stack exchange,提问作者Robin.N.
相关产品推荐
相关产品推荐

