如何在ggplot中重新排序并过滤夜间时段的时间格式数据?
问题
我拥有每晚21:00:00至次日5:59:59的录音数据,需制作以时间为x轴的柱状图。当前用ggplot生成的图表x轴按00:00:00至23:59:59排序,中间存在06:00:00-20:59:59的空白区域。需求是仅展示有数据的时段,将x轴调整为从21:00:00到06:00:00的夜间顺序。注:数据中的date字段为转换为dttm格式时的虚拟日期,实际录制时间跨数月的每晚。
数据样例:
> head(songs) Selection Begin.Time..s. End.Time..s. file date 1 1 0.0959375 0.4159375 Baldy-20240823_030000.WAV 2024-08-23 2 1 0.4799375 1.1199375 Baldy-20240825_030000.WAV 2024-08-25 3 2 1.1839375 1.5999375 Baldy-20240823_030000.WAV 2024-08-23 4 1 1.7599375 2.3359375 Quarry-20240905_030000.WAV 2024-09-05 5 3 2.1439375 2.8479375 Baldy-20240823_030000.WAV 2024-08-23 6 2 2.7199375 3.3919375 Baldy-20240825_030000.WAV 2024-08-25 Occupancy review overlap songs clock time 1 0.5 t t 21:00 2025-04-17 21:00:00 2 0.45 t t 21:00 2025-04-17 21:00:00 3 0.7692 t t 21:00 2025-04-17 21:00:00 4 0.5 overlap overlap 21:00 2025-04-17 21:00:00 5 0.6818 overlap overlap 21:00 2025-04-17 21:00:00 6 0.7619 overlap overlap 21:00 2025-04-17 21:00:00 > tail(songs) Selection Begin.Time..s. End.Time..s. file 205490 432 32394.59 32395.01 Quarry-20240907_030000.WAV 205491 671 32395.23 32395.78 Baldy-20240902_030000.WAV 205492 672 32396.42 32396.96 Baldy-20240902_030000.WAV 205493 673 32397.70 32398.27 Baldy-20240902_030000.WAV 205494 433 32397.73 32398.11 Quarry-20240907_030000.WAV 205495 674 32399.17 32399.62 Baldy-20240902_030000.WAV date Occupancy review overlap songs clock time 205490 2024-09-07 0.5385 t t 05:59 2025-04-17 05:59:00 205491 2024-09-02 0.8235 t t 05:59 2025-04-17 05:59:00 205492 2024-09-02 0.8824 t t 05:59 2025-04-17 05:59:00 205493 2024-09-02 0.7778 t t 05:59 2025-04-17 05:59:00 205494 2024-09-07 0.5833 t t 05:59 2025-04-17 05:59:00 205495 2024-09-02 0.9286 t t 05:59 2025-04-17 05:59:00
当前使用代码:
library(ggplot2) ostf1 = ggplot(songs,aes(x=time,fill=songs)) + geom_bar() + theme_classic() + labs(x="Time", y="Count") + theme(legend.title = element_blank()) + scale_fill_hue(labels = c("Overlapping", "Single")) + scale_y_continuous(breaks=seq(0,10000,by=100), expand = c(0,0)) + theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust=1)) + scale_x_datetime(date_breaks = "1 hours", date_labels = "%H:%M", expand = c(0,0))
生成的图表x轴按自然时间排序,中间存在大空白,如何调整以实现需求?
解决方案
核心思路是让x轴按照自定义的夜间时间顺序排列,避免展示无数据的时段,提供两种可行方案:
方案1:使用有序因子(推荐,简单直接)
利用数据中已有的clock字段,将其转换为有序因子,指定排序为21:00到次日06:00的顺序,ggplot会自动按该顺序渲染x轴,不会出现空白。
- 生成自定义排序的时间标签列表
# 按夜间顺序生成时间标签(21:00到次日05:00) time_order <- c(paste0(21:23, ":00"), paste0(0:5, ":00"))
- 将
clock字段转换为有序因子
如果clock包含非整点时间(如05:59),先统一为整点格式再转换:
# 统一clock为小时级格式(如05:59转为05:00) songs$clock_hour <- format(strptime(songs$clock, "%H:%M"), "%H:00") # 转换为有序因子,指定排序 songs$clock_ordered <- factor(songs$clock_hour, levels = time_order, ordered = TRUE)
- 修改ggplot代码
替换x轴为有序因子,调整x轴刻度设置:
library(ggplot2) ostf1 = ggplot(songs,aes(x=clock_ordered, fill=songs)) + geom_bar() + theme_classic() + labs(x="Time", y="Count") + theme(legend.title = element_blank()) + scale_fill_hue(labels = c("Overlapping", "Single")) + scale_y_continuous(breaks=seq(0,10000,by=100), expand = c(0,0)) + theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust=1)) + scale_x_discrete(expand = c(0,0)) # 移除x轴两端空白
方案2:调整datetime数值(保留连续时间类型)
如果需要保留x轴的连续时间属性,可将次日00:00-05:59的时间加上24小时,让其数值大于21:00-23:00,再修改x轴标签为原时间格式:
- 加载
lubridate包处理时间(若未安装先运行install.packages("lubridate"))
library(lubridate) # 调整时间:次日时间加24小时 songs$time_adjusted <- ifelse(hour(songs$time) < 6, songs$time + hours(24), songs$time)
- 修改ggplot代码
使用调整后的时间字段,自定义x轴标签:
library(ggplot2) ostf1 = ggplot(songs,aes(x=time_adjusted, fill=songs)) + geom_bar() + theme_classic() + labs(x="Time", y="Count") + theme(legend.title = element_blank()) + scale_fill_hue(labels = c("Overlapping", "Single")) + scale_y_continuous(breaks=seq(0,10000,by=100), expand = c(0,0)) + theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust=1)) + scale_x_datetime( breaks = seq(min(songs$time_adjusted), max(songs$time_adjusted), by = "1 hour"), labels = function(x) format(x, "%H:%M"), # 显示原时间格式 expand = c(0,0) )
两种方案都能实现需求,方案1操作更简单,适合按小时分组的场景;方案2保留了时间的连续性,适合需要更精细时间刻度的场景。
内容的提问来源于stack exchange,提问作者Cedar
相关产品推荐
相关产品推荐

