R - 如何在不同尺度上用两个 y 轴绘制 ggplot2 * 带有时间变量
R - How to plot ggplot2 with two y axes on different scales *with time variables
我可以用相同的 x 轴(比如,年份)但不同的 y 轴(在非常不同的尺度上)制作一个 ggplot2
图。是否可以使用 gganimate
来制作动画两条线,每条线对应自己的 y 轴?我已经能够使用相同的 y 轴创建两条线,但不知道如何使用两个轴。
我认为我的特定情况下的问题可能与我的 y 轴变量采用 POSIX 格式有关。
假设我按如下方式创建 a
数据集:
library(ggplot2)
library(gganimate)
library(htmltab)
library(lubridate)
#marathon
data0 <- htmltab("https://en.wikipedia.org/wiki/Marathon_world_record_progression",1)
data <- data0[,c(1,4)]
#remove ones that are ARRS only
data <- data[-c(9,12,13,22,27,33,34,35,36,51),]
#data <- data %>% mutate(time = Time %>% hms())
data$time2 <- as.POSIXct(data$Time, format = "%H:%M:%S")
data$date <- mdy(data$Date)
data$race <- "Marathon"
#mile
mile0 <- htmltab("https://en.wikipedia.org/wiki/Mile_run_world_record_progression",4)
mile <- mile0[,c(1,4)]
#mile <- mile0 %>% mutate(time = Time %>% ms())
mile$time2 <- as.POSIXct(mile$Time, format = "%M:%S")
mile$date <- dmy(mile$Date)
mile$race <- "Mile"
marathon <- data[,c(3,4)]
names(marathon)[1]<-"marathon"
mile2 <- mile[,c(3,4)]
names(mile2)[1]<-"mile"
a <- merge(marathon, mile2, by="date", all=TRUE)
然后我可以获得一个 gganimate
动画,如下所示:
ggplot(a) +
geom_point(aes(x=date, y=marathon, group=date, color="blue")) +
geom_point(aes(x=date, y=mile, group=date, color="red")) +
scale_y_continuous(sec.axis = sec_axis(~./152, name = "CDF"), breaks=seq(0,150,25))
transition_reveal(date)
问题在于两者的尺度非常不同(一个约为 2-3 小时,而另一个约为 2.5-3.5 分钟)。我怎样才能让他们处于相同的规模?如果它们是普通格式,我也许可以执行以下操作:
ggplot(a) +
geom_point(aes(x=date, y=marathon, group=date, color="blue")) +
geom_point(aes(x=date, y=mile*65, group=date, color="red")) +
scale_y_continuous(sec.axis = sec_axis(~./65, name = "Mile"), breaks=seq(0,150,25)) +
transition_reveal(date)
但是,由于 y 变量的 POSIX 格式,我收到错误消息。我该怎么办? (理想情况下,我希望将它们放在比例尺上,以便每个变量的垂直范围基本上填满垂直距离。)
作为参考,这是我要修复的情节的结果:
恐怕这不可能。见 https://ggplot2.tidyverse.org/reference/sec_axis.html:
"As of v3.1, date and datetime scales have limited secondary axis capabilities. Unlike other continuous scales, secondary axis transformations for date and datetime scales must respect their primary POSIX data structure. This means they may only be transformed via addition or subtraction, e.g. ~ . + hms::hms(days = 8), or ~ . - 8*60*60. Nonlinear transformations will return an error. To produce a time-since-event secondary axis in this context, users may consider adapting secondary axis labels."
一种方法是将时间转换为十进制小时(或分钟等)并调整刻度标签:
library(dplyr); library(lubridate)
a %>%
# tidyr::gather(type, time, -date) %>%
tidyr::pivot_longer(-date, "type", "time") %>% # Preferred syntax since tidyr 1.0.0
mutate(time_dec = hour(value) + minute(value)/60 + second(value)/3600,
time_scaled = time_dec * if_else(type == "mile", 30, 1)) %>%
ggplot() +
geom_point(aes(x=date, y=time_scaled, group=value, color = type)) +
scale_y_continuous(breaks = 0:3,
labels = c("0", "1:00", "2:00", "3:00"),
name = "Marathon",
sec.axis = sec_axis(~./30,
name = "Mile",
breaks = (1/60)*0:100,
labels = 0:100)) +
expand_limits(y = c(1.5,3)) +
transition_reveal(date)
我可以用相同的 x 轴(比如,年份)但不同的 y 轴(在非常不同的尺度上)制作一个 ggplot2
图。是否可以使用 gganimate
来制作动画两条线,每条线对应自己的 y 轴?我已经能够使用相同的 y 轴创建两条线,但不知道如何使用两个轴。
我认为我的特定情况下的问题可能与我的 y 轴变量采用 POSIX 格式有关。
假设我按如下方式创建 a
数据集:
library(ggplot2)
library(gganimate)
library(htmltab)
library(lubridate)
#marathon
data0 <- htmltab("https://en.wikipedia.org/wiki/Marathon_world_record_progression",1)
data <- data0[,c(1,4)]
#remove ones that are ARRS only
data <- data[-c(9,12,13,22,27,33,34,35,36,51),]
#data <- data %>% mutate(time = Time %>% hms())
data$time2 <- as.POSIXct(data$Time, format = "%H:%M:%S")
data$date <- mdy(data$Date)
data$race <- "Marathon"
#mile
mile0 <- htmltab("https://en.wikipedia.org/wiki/Mile_run_world_record_progression",4)
mile <- mile0[,c(1,4)]
#mile <- mile0 %>% mutate(time = Time %>% ms())
mile$time2 <- as.POSIXct(mile$Time, format = "%M:%S")
mile$date <- dmy(mile$Date)
mile$race <- "Mile"
marathon <- data[,c(3,4)]
names(marathon)[1]<-"marathon"
mile2 <- mile[,c(3,4)]
names(mile2)[1]<-"mile"
a <- merge(marathon, mile2, by="date", all=TRUE)
然后我可以获得一个 gganimate
动画,如下所示:
ggplot(a) +
geom_point(aes(x=date, y=marathon, group=date, color="blue")) +
geom_point(aes(x=date, y=mile, group=date, color="red")) +
scale_y_continuous(sec.axis = sec_axis(~./152, name = "CDF"), breaks=seq(0,150,25))
transition_reveal(date)
问题在于两者的尺度非常不同(一个约为 2-3 小时,而另一个约为 2.5-3.5 分钟)。我怎样才能让他们处于相同的规模?如果它们是普通格式,我也许可以执行以下操作:
ggplot(a) +
geom_point(aes(x=date, y=marathon, group=date, color="blue")) +
geom_point(aes(x=date, y=mile*65, group=date, color="red")) +
scale_y_continuous(sec.axis = sec_axis(~./65, name = "Mile"), breaks=seq(0,150,25)) +
transition_reveal(date)
但是,由于 y 变量的 POSIX 格式,我收到错误消息。我该怎么办? (理想情况下,我希望将它们放在比例尺上,以便每个变量的垂直范围基本上填满垂直距离。)
作为参考,这是我要修复的情节的结果:
恐怕这不可能。见 https://ggplot2.tidyverse.org/reference/sec_axis.html:
"As of v3.1, date and datetime scales have limited secondary axis capabilities. Unlike other continuous scales, secondary axis transformations for date and datetime scales must respect their primary POSIX data structure. This means they may only be transformed via addition or subtraction, e.g. ~ . + hms::hms(days = 8), or ~ . - 8*60*60. Nonlinear transformations will return an error. To produce a time-since-event secondary axis in this context, users may consider adapting secondary axis labels."
一种方法是将时间转换为十进制小时(或分钟等)并调整刻度标签:
library(dplyr); library(lubridate)
a %>%
# tidyr::gather(type, time, -date) %>%
tidyr::pivot_longer(-date, "type", "time") %>% # Preferred syntax since tidyr 1.0.0
mutate(time_dec = hour(value) + minute(value)/60 + second(value)/3600,
time_scaled = time_dec * if_else(type == "mile", 30, 1)) %>%
ggplot() +
geom_point(aes(x=date, y=time_scaled, group=value, color = type)) +
scale_y_continuous(breaks = 0:3,
labels = c("0", "1:00", "2:00", "3:00"),
name = "Marathon",
sec.axis = sec_axis(~./30,
name = "Mile",
breaks = (1/60)*0:100,
labels = 0:100)) +
expand_limits(y = c(1.5,3)) +
transition_reveal(date)