You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

geom_segment()时间数据的坐标轴刻度调整问题

问题:ggplot2绘制时间差线段图时x轴刻度设置失败

我有一个包含多时间点测量数据的数据集,记录了测量的预期时间(exp)与实际发生时间(act)。尝试用geom_segment()展示每个受试者的预期时间与实际时间的差异,但x轴刻度无法清晰读取,手动设置刻度时还出现报错。

报错代码及信息

>  ggplot(df) + 
+    geom_segment(aes(x = exp, xend = act, y = subject_id, yend = subject_id, color = timef)) +
+    scale_x_continuous(name = "diff. in time", 
+                       breaks = c("14:30", "15:00", "15:30","16:00", "16:30","17:00","17:30"))
Error in `train_continuous()`:
! Discrete value supplied to a continuous scale

>  ggplot(df) + 
+    geom_segment(aes(x = exp, xend = act, y = subject_id, yend = subject_id, color = timef)) +
+    scale_x_continuous(name = "diff. in time", 
+                       breaks = strptime(c("14:30", "15:00", "15:30","16:00", "16:30","17:00","17:30"), "%H:%M"))
Error in `train_continuous()`:
! Discrete value supplied to a continuous scale
Run `rlang::last_trace()` to see where the error occurred.

>  ggplot(df) + 
+    geom_segment(aes(x = exp, xend = act, y = subject_id, yend = subject_id, color = timef)) +
+    scale_x_discrete(name = "diff. in time", 
+                       breaks = strptime(c("14:30", "15:00", "15:30","16:00", "16:30","17:00","17:30"), "%H:%M"))
Error in `mapped_discrete()`:
! Can't convert `x` <list> to <double>.
Run `rlang::last_trace()` to see where the error occurred

示例数据集

df <- structure(list(subject_id = c(102L, 166L, 123L, 152L, 173L, 151L, 
138L, 155L, 183L, 148L, 139L, 141L, 112L, 123L, 179L, 166L, 150L, 
183L, 155L, 172L), timef = c(5L, 5L, 10L, 2L, 2L, 2L, 3L, 7L, 
3L, 4L, 6L, 4L, 6L, 2L, 10L, 4L, 3L, 8L, 10L, 3L), exp = c("16:08", 
"15:31", "17:28", "15:08", "15:02", "15:08", "15:51", "16:16", 
"15:32", "16:16", "15:58", "15:28", "16:31", "15:39", "16:34", 
"15:21", "15:08", "16:37", "17:16", "15:38"), act = c("16:11", 
"15:28", "17:28", "15:07", "15:02", "15:06", "15:51", "16:14", 
"15:32", "16:17", "15:58", "15:27", "16:29", "15:39", "16:34", 
"15:21", "15:08", "16:37", "17:16", "15:41")), row.names = c("102.1.5", 
"166.2.5", "123.2.10", "152.1.2", "173.1.2", "151.2.2", "138.2.3", 
"155.1.7", "183.1.3", "148.2.4", "139.2.6", "141.2.4", "112.2.6", 
"123.1.2", "179.2.10", "166.1.4", "150.1.3", "183.1.8", "155.1.10", 
"172.1.3"), class = "data.frame")

解决方案

核心问题是你的exp和act列是字符类型,但错误使用了连续型/离散型比例尺处理时间数据。正确做法是先将时间列转换为时间类型,再用对应时间比例尺设置刻度。

方法1:用hms包处理纯时间格式

hms包专门适配小时:分钟格式的时间,ggplot支持良好:

library(ggplot2)
library(hms)

# 转换时间列为hms类型
df$exp <- parse_hms(df$exp)
df$act <- parse_hms(df$act)

# 绘制图表并设置自定义刻度
ggplot(df) + 
  geom_segment(aes(x = exp, xend = act, y = subject_id, yend = subject_id, color = timef)) +
  scale_x_time(
    name = "时间",
    breaks = parse_hms(c("14:30", "15:00", "15:30","16:00", "16:30","17:00","17:30")),
    labels = format(parse_hms(c("14:30", "15:00", "15:30","16:00", "16:30","17:00","17:30")), "%H:%M")
  ) +
  labs(y = "受试者ID", color = "时间组")

方法2:转换为POSIXct类型(带日期)

如果需要保留日期维度(可指定任意基础日期,仅用时间部分):

library(ggplot2)

# 转换为POSIXct类型,指定基础日期
df$exp <- as.POSIXct(paste("2024-01-01", df$exp), format = "%Y-%m-%d %H:%M")
df$act <- as.POSIXct(paste("2024-01-01", df$act), format = "%Y-%m-%d %H:%M")

# 定义刻度断点
break_times <- as.POSIXct(paste("2024-01-01", c("14:30", "15:00", "15:30","16:00", "16:30","17:00","17:30")), format = "%Y-%m-%d %H:%M")

ggplot(df) + 
  geom_segment(aes(x = exp, xend = act, y = subject_id, yend = subject_id, color = timef)) +
  scale_x_datetime(
    name = "时间",
    breaks = break_times,
    labels = format(break_times, "%H:%M"), # 仅显示小时:分钟
    date_labels = "%H:%M"
  ) +
  labs(y = "受试者ID", color = "时间组")

额外优化:自动减少刻度数量

无需手动指定所有断点,可用date_breaks自动设置间隔:

# 以hms类型为例
ggplot(df) + 
  geom_segment(aes(x = exp, xend = act, y = subject_id, yend = subject_id, color = timef)) +
  scale_x_time(
    name = "时间",
    date_breaks = "30 mins", # 每30分钟一个刻度
    date_labels = "%H:%M"
  )

内容的提问来源于stack exchange,提问作者Mia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 19:25:00