如何在 y 轴上排序时间

How to order time in y axis

我有一个像这样的数据框(小标题):

library(tidyverse)
library(lubridate)
x = tibble(date=c("2022-04-25 07:04:07", "2022-04-25 07:09:07", "2022-04-25 07:14:07", "2022-04-26 07:04:07"),
              value=c("on", "off", "on", "off"))
x$day<- as.factor(day(x$date))
x$time <- paste0(str_pad(hour(x$date),2,pad="0"),":",str_pad(minute(x$date),2,pad="0"))

当我绘制数据时:

x %>% ggplot() + geom_col(aes(x=day,y=time, fill=value))

y 轴上的时间不遵循条形。每次数据都应该与每个条形段并排。 我尝试使用 as.factor(time) 但没有解决。 我还尝试添加一个数字刻度:

x = tibble(date=c("2022-04-25 07:04:07", "2022-04-25 07:09:07", "2022-04-25 07:14:07", "2022-04-26 07:04:07"),
fake_y=c(1,1,1,1)
value=c("on", "off", "on", "off"))
x %>% ggplot() + geom_col(aes(x=day,y=fake_y, fill=value))

但是 on/off 柱的顺序丢失了。 我该如何解决这个问题?

由于您正在寻找时间线,因此最好使用 geom_segment 而不是 geom_col。原因是由于您可能在一天内有多个 'on' 或 'off' 值,因此很难将它们正确堆叠。您还需要 diff on-off 次才能让它们堆叠。此外,如果“off”表示从开启状态变为关闭状态的时间,那么使用列的标签将是错误的。

在 R 中处理时间时,通常最好以时间格式保存它们以便绘图。如果您在绘图前将时间转换为字符串,它们将被解释为因子水平,因此不会按比例正确间隔。

因为你想在一个轴上有一天,你需要相当多的数据操作来确保你记录每天开始和每天结束时的状态,但这是可以实现的通过做:

p <- x %>% 
  mutate(date = as.POSIXct(date)) %>%
  mutate(day = as.factor(day(date))) %>%
  group_by(day) %>%
  group_modify(~ add_row(.x,
          date = floor_date(as.POSIXct(first(.x$date)), 'day'), 
          value = ifelse(first(.x$value) == 'on', 'off', 'on'),
          .before = 1)) %>%
  group_modify(~ add_row(.x,
          date = ceiling_date(as.POSIXct(last(.x$date)), 'day') - 1,
          value = last(.x$value))) %>%
  mutate(ends = lead(date)) %>%
  filter(!is.na(ends)) %>%
  mutate(date = hms::as_hms(date), ends = hms::as_hms(ends)) %>%
  ggplot(aes(x = day, y = date)) +
  geom_segment(aes(xend = day, yend = ends, color = value),
               size = 20) +
  coord_cartesian(ylim = c(25120, 26500)) +
  labs(y = 'time') +
  guides(color = guide_legend(override.aes = list(size = 8)))

p

当然,如果您愿意,您可以轻松翻转co-ordinates,并应用主题元素使情节更吸引人:

p + coord_flip(ylim = c(25120, 26500)) +
  scale_color_manual(values = c('deepskyblue4', 'orange')) +
  theme_light(base_size = 16)