You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ggplot:添加不同数据框数据为额外分面网格并分离图例

问题描述

现有以下R数据与代码,用于生成分面的时间轴色块图:

# 第一个数据集
channel <- c("Channel 1", "Channel 1", "Channel 1", "Channel 2", "Channel 2", "Channel 2", "Channel 2", "Channel 3", "Channel 3", "Channel 3")
start_time <- c(0.000, 9.719, 11.735, 14.183, 16.554, 18.482, 0.000, 11.693, 12.310, 13.912)
stop_time <- c(9.719, 11.735, 14.183, 16.554, 18.482, 19.553, 11.693, 12.310, 13.912, 15.406)
character <- c("A", "B", "C", "C", "B", "A", "A", "B", "C", "B")

df1 <- data.frame(channel, start_time, stop_time, character)

library(ggplot2)
ggplot(df1, aes(fill = character, color = character)) +
  geom_rect(color = NA, aes(xmin = start_time, xmax = stop_time, ymin = -0.5, ymax = 0.5)) +
  scale_x_continuous(name = "Time (sec)", breaks = scales::pretty_breaks(n = 10)) +
  facet_grid(channel ~ .) +
  theme(axis.text.y=element_blank(),
        axis.ticks.y=element_blank() ) + 
  theme(legend.position="bottom") 

该代码生成的分面网格中,每个Channel对应一行,展示不同角色的时间色块。

现在需要添加一行标签为“Episode”的分面,对应第二个数据集:

# 第二个数据集
start_time_ep <- c(0, 5, 10, 15)
stop_time_ep <- c(5, 10, 15, 20)
episode <- c("episode 1", "episode 2", "episode 3", "episode 4")

df2 <- data.frame(start_time_ep, stop_time_ep, episode)

最初尝试合并两个数据框,给df2的channel统一设为“Episode”,但生成的图表中Episode和Character的图例被混在一起,需要让二者拥有独立的图例。

解决方案

核心思路是不合并数据框,分别为两个数据集调用geom_rect,使用不同的美学映射区分两类色块,再手动配置独立图例。

具体代码如下:

library(ggplot2)
library(scales)
library(dplyr)

# 预处理第二个数据集:统一列名并添加channel标识
df2 <- df2 %>% 
  rename(start_time = start_time_ep, stop_time = stop_time_ep) %>% 
  mutate(channel = "Episode")

# 为两类元素分配独立色系,避免视觉混淆
char_colors <- c("A" = "#1f77b4", "B" = "#ff7f0e", "C" = "#2ca02c")
ep_colors <- c("episode 1" = "#9467bd", "episode 2" = "#8c564b", "episode 3" = "#e377c2", "episode 4" = "#7f7f7f")

ggplot() +
  # 绘制Channel角色色块,使用fill映射
  geom_rect(data = df1, 
            aes(xmin = start_time, xmax = stop_time, ymin = -0.5, ymax = 0.5, 
                fill = character), 
            color = NA) +
  # 绘制Episode色块,使用自定义的fill2映射
  geom_rect(data = df2, 
            aes(xmin = start_time, xmax = stop_time, ymin = -0.5, ymax = 0.5, 
                fill2 = episode), 
            color = NA) +
  # 配置x轴
  scale_x_continuous(name = "Time (sec)", breaks = pretty_breaks(n = 10)) +
  # 分别配置两个图例的名称与颜色
  scale_fill_manual(name = "Character", values = char_colors) +
  scale_fill_manual(name = "Episode", values = ep_colors, aesthetics = "fill2") +
  # 生成包含所有分面的网格
  facet_grid(channel ~ .) +
  # 调整主题样式
  theme(axis.text.y = element_blank(),
        axis.ticks.y = element_blank(),
        legend.position = "bottom",
        legend.box = "horizontal") # 让两个图例横向排列

代码说明

  1. 数据预处理:为df2统一时间列名并添加channel字段,确保分面逻辑一致。
  2. 独立美学映射:用fill对应角色、fill2对应剧集,从根源避免图例混淆。
  3. 自定义色系:为两类元素分配不同色系,提升视觉区分度。
  4. 图例配置:通过scale_fill_manual分别定义两个图例的名称和颜色,再用legend.box让图例横向排列,优化布局。

内容的提问来源于stack exchange,提问作者Wangana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 19:07:35