在 geom_tile() 上将 x 轴标签更改为小时(时间)
Posted
技术标签:
【中文标题】在 geom_tile() 上将 x 轴标签更改为小时(时间)【英文标题】:Change x axis labels to hours (time) on geom_tile() 【发布时间】:2020-08-04 23:53:25 【问题描述】:这是一个 geom_tile
显示一周中的小时和天,如何让它显示每个小时(即 x 轴上的 00:00 到 23:00)?
library(tidyverse)
df %>%
ggplot(aes(hour, day, fill = value)) +
geom_tile(colour = "ivory")
目前它每五小时显示一次:
我尝试了很多不同的方法,并且更喜欢“最佳实践”方式(即不手动生成标签),但如果需要标签,这里有一种方法来生成它们hour_labs <- 0:23 %>% ifelse(nchar(.) == 1, paste0("0", .), .) %>% paste0(., ":00")
可重现示例的数据
df <- structure(list(day = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L,
3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L,
4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 5L, 5L,
5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L,
5L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L,
6L, 6L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L), .Label = c("Sunday",
"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
), class = c("ordered", "factor")), hour = c(0L, 2L, 3L, 5L,
6L, 7L, 8L, 10L, 11L, 12L, 13L, 18L, 21L, 22L, 23L, 0L, 1L, 2L,
3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 20L, 21L, 22L,
23L, 0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L,
20L, 21L, 22L, 23L, 0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L,
11L, 13L, 14L, 20L, 21L, 22L, 23L, 0L, 1L, 2L, 3L, 4L, 5L, 6L,
7L, 8L, 9L, 10L, 11L, 12L, 13L, 15L, 20L, 21L, 22L, 23L, 0L,
1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 11L, 13L, 14L, 15L, 16L,
19L, 21L, 0L, 1L, 2L, 3L, 7L, 8L, 10L, 13L, 14L, 22L, 23L), value = c(1L,
1L, 1L, 2L, 1L, 3L, 1L, 1L, 2L, 1L, 3L, 1L, 2L, 13L, 13L, 24L,
39L, 21L, 17L, 25L, 22L, 27L, 28L, 19L, 6L, 2L, 2L, 1L, 2L, 2L,
7L, 23L, 38L, 18L, 26L, 21L, 20L, 31L, 40L, 35L, 22L, 5L, 3L,
2L, 7L, 4L, 3L, 3L, 3L, 17L, 13L, 23L, 24L, 19L, 31L, 13L, 35L,
50L, 22L, 13L, 7L, 2L, 1L, 1L, 1L, 1L, 3L, 14L, 17L, 33L, 32L,
32L, 25L, 29L, 27L, 38L, 26L, 11L, 8L, 4L, 5L, 5L, 3L, 1L, 1L,
3L, 14L, 21L, 24L, 22L, 25L, 26L, 23L, 58L, 36L, 26L, 6L, 3L,
1L, 5L, 3L, 1L, 1L, 3L, 1L, 2L, 2L, 1L, 1L, 1L, 2L, 1L, 1L, 2L,
1L, 1L)), row.names = c(NA, -116L), groups = structure(list(day = structure(1:7, .Label = c("Sunday",
"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
), class = c("ordered", "factor")), .rows = structure(list(1:15,
16:33, 34:51, 52:69, 70:88, 89:105, 106:116), ptype = integer(0), class = c("vctrs_list_of",
"vctrs_vctr"))), row.names = c(NA, 7L), class = c("tbl_df", "tbl",
"data.frame"), .drop = TRUE), class = c("grouped_df", "tbl_df",
"tbl", "data.frame"))
【问题讨论】:
【参考方案1】:这是使用sprintf
构造标签的一种方法。
library(dplyr)
library(ggplot2)
df %>%
mutate(lab = sprintf('%02d:00', hour)) %>%
ggplot() + aes(lab, day, fill = value) +
geom_tile(colour = "ivory") +
theme(axis.text.x = element_text(angle = 90, hjust = 1))
除了@Eric Watt 的建议,我们还可以使用complete
来完成缺失的时间。
df %>%
mutate(lab = sprintf('%02d:00', hour)) %>%
tidyr::complete(lab = sprintf('%02d:00', 0:23)) %>%
ggplot() + aes(lab, day, fill = value) +
geom_tile(colour = "ivory") +
theme(axis.text.x = element_text(angle = 90, hjust = 1))
【讨论】:
快速问题:df
在这种情况下恰好包含所有小时 0 - 23。如果原始 df 没有 包含所有这些时间? (例如,如果它缺少凌晨 4 点的任何值,则不会生成该时间,但如果我们希望它出现在最终图中怎么办?)
或许你可以使用complete
。请注意,您的数据在dput
中分组,因此您可能需要先ungroup
。所以这样的事情可能会有所帮助。 df %>% ungroup() %>% complete(day, hour = 0:23) %>% mutate(lab = sprintf('%02d:00', hour)) %>% rest of ggplot code....
其实df
中没有17:00
的数据。在这个答案中使用sprintf
会跳过一个刻度线和17:00
位置的间隙。
@EricWatt 你是对的。事实上,我喜欢你的回答。我已经使用complete
更新了我的另一个替代方案。
如果这是我的数据并且我试图快速绘制,我可能会做一个简单的paste(hour, ":00", sep = "")
将其转换为我想要绘制的格式,然后可能会错过也缺少17:00
:) 我已经不止一次发生过这种情况,并且出于这个原因一直试图养成将时间/日期数据存储并绘制为正确类型的习惯。虽然有时肯定更痛苦。由于最初的问题是关于“最佳实践”...【参考方案2】:
我建议确保您的数据类型正确地表示您的数据。如果您的 hour
列以小时为单位表示时间,那么它应该是基于时间的结构。例如:
df$hour <- as.POSIXct(as.character(df$hour), format = "%H", tz = "UTC")
然后您可以使用scale_x_datetime
告诉ggplot x 轴是日期时间变量。
ggplot(df, aes(hour, day, fill = value)) +
geom_tile(colour = "ivory") +
scale_x_datetime(labels = date_format("%H:%M")) +
theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5))
如果您想每隔一小时休息一次,您可以将其输入为休息时间:
ggplot(df, aes(hour, day, fill = value)) +
geom_tile(colour = "ivory") +
scale_x_datetime(breaks = as.POSIXct(as.character(0:23), format = "%H", tz = "UTC"),
labels = date_format("%H:%M")) +
theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5))
您还可以使用scales
包,它具有方便的格式化选项,例如date_breaks
:
library(scales)
ggplot(df, aes(hour, day, fill = value)) +
geom_tile(colour = "ivory") +
scale_x_datetime(breaks = date_breaks("1 hour"),
labels = date_format("%H:%M")) +
theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5))
【讨论】:
请注意,您的数据集没有任何小时 = 17 的行。由于日期时间是基于数字的,即使那里没有数据,您也会在 17:00 获得 x 轴刻度。以上是关于在 geom_tile() 上将 x 轴标签更改为小时(时间)的主要内容,如果未能解决你的问题,请参考以下文章