【问题标题】:R ggplot: facet_grid with different geom_rects for each facet troubleR ggplot:facet_grid,每个方面的问题都有不同的geom_rects
【发布时间】:2017-11-21 04:52:34
【问题描述】:

我有一个加速度计数据的时间序列数据集,我在该数据集上运行了一些峰值检测来识别步态的不同阶段。我正在使用ggplot 将左右腿数据绘制为facet_grid 中的两个方面,现在我想覆盖geom_rects 以显示每条腿的不同步态阶段。我可以添加矩形层,但我不知道如何将左侧 geom_rects 保持在左腿刻面,将右侧 geom_rects 保留在右侧刻面。例如,在步态周期中,当您的体重在左腿上(左侧的站立阶段)时,右腿向前摆动(右侧的摆动阶段),因此阶段时间不同。您可以通过直观地比较左波谷和右波谷的时间点来看到这一点。

我已经用谷歌搜索并解决了这个问题,但我找不到答案。我发现的最接近的是this,但作者在各个方面使用了相同的geom_rect,所以这不是我想要的。我附上了一个简化的 Rscript 和 csv 的数据。谁能给我一些提示来制作这个情节?

facet_rects_test.zip (.csv and R Script)

谢谢!

【问题讨论】:

  • 如果您用来绘制矩形的数据框有一个side 列,标记哪些数据进入Left 构面,哪些数据进入Right,那么这应该足以获取在正确方面绘制的数据。
  • 第一遍我没能完全理解你的情节代码,但有一个突出的地方是像aes(xmin=acceldf$time_ms[swingStart], xmax=acceldf$time_ms[heelStrike]-1, ymin=-Inf, ymax=Inf, fill="Swing") 这样的结构。通常你不会在aes 中命名数据框(尤其是不同的数据框)或子集。您使用data 参数将数据框提供给ggplotgeom_rect,并在aes 中使用裸变量名。
  • 尝试在aes 中进行子集化或多次调用geom_rect 似乎表明您的数据应该被融合为“更长”格式,或者您需要一个额外的列来标记所需的分组,所以您可以调用geom_rect 一次,并使用fill 之类的美学映射来为不同的组获取不同颜色的矩形。

标签: r ggplot2


【解决方案1】:

answer 使用 tidyr 函数是一个很好的解决方案。当然,您可以使用您已经熟悉的 reshape2 包获得您想要的结果。

您缺少的关键元素是,可以从多个数据参数中获取分面变量,只要它具有相同的名称和级别。下面的函数在您读入数据时对其进行处理(不过,您可能希望将函数定义放在它第一次在脚本中使用之前!)。

plotAccelerometerDataWithPhasesSuperimposed <- function(acceldf, phasesdf) {

  # melt the rows for column left/right in order to facet_wrap on it
  acceldf_melted <- melt(acceldf[, c('time_ms', 'Ly', 'Ry')],
                         id.vars = 'time_ms')

  # make the facet variables identical
  phasesdf$variable <- factor(phasesdf$side, levels = c('Left', 'Right'),
                              labels = c('Ly', 'Ry'))

  ggplot(acceldf_melted, aes(x=time_ms, y=value)) +

    # Phases
    geom_rect(data = phasesdf, inherit.aes = FALSE, aes(
      xmin = acceldf$time_ms[swingStart],
      xmax = acceldf$time_ms[heelStrike] - 1,
      ymin = -Inf, ymax = Inf, fill = "Swing"), colour = NA, alpha = 0.3) +
    geom_rect(data = phasesdf, inherit.aes = FALSE, aes(
      xmin = acceldf$time_ms[toeOff],
      xmax = acceldf$time_ms[swingEnd] - 1,
      ymin = -Inf, ymax = Inf, fill = "Pre-swing"), colour = NA, alpha = 0.3) +
    geom_rect(data = phasesdf, inherit.aes = FALSE, aes(
      xmin = acceldf$time_ms[heelStrike],
      xmax = acceldf$time_ms[toeOff] - 1,
      ymin = -Inf, ymax = Inf, fill = "Stance"), colour = NA, alpha = 0.3) +

    # Lines
    facet_grid(variable~., labeller = labeller(
      variable = c(Ly = "Left", Ry = "Right"))) +
    labs(title = "Gait Phases by Accelerometer", x = "time (ms)",
         y = "Sensors Values") +
    geom_line() +
    scale_fill_manual('Phases',
      values = c('firebrick2', 'orange', 'steelblue2'),
      guide = guide_legend()) +
    guides(colour = FALSE) +
    theme(legend.direction = "horizontal", legend.position = "bottom",
          strip.text.y = element_text(size=16, colour = "blue"))
}

【讨论】:

    【解决方案2】:

    我认为这是将数据转换为正确形式的问题。

    library(tidyverse) 
    

    首先,让我们将gait_cycle 转换为长格式并正确命名。将LyRy 转换为LeftRight 并调用分组变量side 以匹配gaitPoints 数据框中的side 列。然后,两个数据框将具有相同的side 列,我们将用于分面,确保每个数据框的相应数据绘制在预期的分面中。 gather 函数将数据帧转换为长格式(它在tidyr 包中,旨在取代reshape2 中的melt)。

    gait_cycle_m = gait_cycle %>% 
      select(-X) %>% 
      rename(Left=Ly, Right=Ry) %>% 
      gather(side, value, -time_ms)
    

    现在我们需要正确设置三个步态Phases 以进行绘图。我们想要一个“长”数据框,以便我们可以对geom_rect 进行一次调用,并将数据列直接映射到美学。因此,我们创建了b(开始)和e(结束)列,它们将标记步态周期中每个阶段的开始和结束。然后我们创建一个Phases 列,它将成为fill 美学(也就是说,它将标记每个数据行代表的步态阶段)。

    gaitPoints_new = data.frame(swingStart=gait_cycle$time_ms[gaitPoints$swingStart],
                                heelStrike=gait_cycle$time_ms[gaitPoints$heelStrike],
                                toeOff=gait_cycle$time_ms[gaitPoints$toeOff],
                                swingEnd=gait_cycle$time_ms[gaitPoints$swingEnd],
                                side=gaitPoints$side)
    
    gaitPoints_new = bind_rows(gaitPoints_new %>% select(b=1,e=2,5) %>% mutate(Phases="Pre-swing"),
                               gaitPoints_new %>% select(b=2,e=3,5) %>% mutate(Phases="Stance"),
                               gaitPoints_new %>% select(b=3,e=4,5) %>% mutate(Phases="Swing"))
    

    一旦我们正确设置了数据,情节就相对简单了。在下面的代码中,我们只在geom 语句中输入data 参数和aes 映射,因此aes 继承没有问题。

    ggplot() +
      geom_rect(data=gaitPoints_new, aes(xmin=b, xmax=e, ymin=-Inf, max=Inf, fill=Phases), alpha=0.5) +
      geom_line(data=gait_cycle_m, aes(x=time_ms, y=value)) + 
      facet_grid(side ~ .) +
      scale_fill_manual(values=c('firebrick2','orange','steelblue2')) +
      theme_bw() +
      theme(legend.position = "bottom") +
      labs(x="Time (ms)", y="Sensor Values")
    

    【讨论】:

      猜你喜欢
      • 2019-06-12
      • 2013-06-29
      • 2012-11-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-04
      • 1970-01-01
      • 2020-03-09
      • 2011-08-14
      相关资源
      最近更新 更多