R ggplot:facet_grid,每个方面都有不同的geom_rect问题

时间:2017-11-21 04:52:34

标签: r ggplot2

我有一个加速度计数据的时间序列数据集,我在其上运行了一些峰值检测以识别步态的不同阶段。我正在使用ggplot将左右腿数据绘制为facet_grid中的两个方面,现在我想重叠geom_rect来显示每条腿的步态的不同阶段。我可以添加rect图层确定,但我无法弄清楚如何将左geom_rect s保留在左腿小平面上,将右geom_rect s保持在右侧小平面上。例如,在步态周期中,当您的体重位于左腿(左侧的站立阶段)时,右腿向前摆动(右侧的摆动阶段),因此相位时间不同。您可以通过直观地比较左右槽的时间点来看到这一点。

Gait Cycle Testing chart

我已经用谷歌搜索了我的方式解决问题,我找不到答案。我发现最接近的是this,但作者在各个方面使用相同的geom_rect因此它不是我想要的。我附加了一个简化的Rscript,数据为csv。有人可以给我一些提示来制作这个情节吗?

facet_rects_test.zip (.csv and R Script)

谢谢!

2 个答案:

答案 0 :(得分:2)

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

您缺少的关键元素是faceting变量可以从多个数据参数中获取,只要它具有相同的名称和级别即可。下面的函数在您读取数据时使用数据(您可能希望在函数定义首次使用之前将其放在脚本中)。

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"))
}

答案 1 :(得分:1)

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

library(tidyverse) 

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

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

现在我们需要正确设置三个步态Phases以进行绘图。我们想要一个&#34; long&#34;数据框,以便我们可以对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"))

一旦我们正确设置了数据,该图就相对简单了。在下面的代码中,我们仅在data语句中输入aes参数和geom映射,以便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")

enter image description here