Skip to content

Instantly share code, notes, and snippets.

@moodymudskipper
Last active November 13, 2019 15:02
Show Gist options
  • Save moodymudskipper/455d9001bb22645d986535e6aad3395c to your computer and use it in GitHub Desktop.
Save moodymudskipper/455d9001bb22645d986535e6aad3395c to your computer and use it in GitHub Desktop.
scale_y_duration displays time in sec, min, hour or day depending on max value
library(ggplot2)
scale_y_duration <- function(..., units = c("s","min","h","day")){
units <- match.arg(units, c("ms","seconds","minutes","hours","days", "weeks", "months", "years"),
several.ok = TRUE)
# to get them in the right order
units <- intersect(c("ms","seconds","minutes","hours","days", "weeks", "months", "years"), units)
ms <- 1/1000
min <- 60
h <- 60 *min
day <- 24 *h
week <- 7 * day
year <- 365.25 * day
month <- year / 12
labels <- function(x){
max_x <- max(x, na.rm=TRUE)
if("years" == units[[1]] || max_x > 3 * year && "years" %in% units){
# > 3 year, use years
x <- x /year
x <- paste(round(x,2),"years")
} else if("months" == units[[1]] || max_x > 3 * month && "months" %in% units){
# > 3 months, use months
x <- x /month
x <- paste(round(x,2),"months")
} else if("weeks" == units[[1]] || max_x > 3 * week && "weeks" %in% units){
# > 3 weeks, use weeks
x <- x /week
x <- paste(round(x,2),"weeks")
} else if("days" == units[[1]] || max_x > 3 * day && "days" %in% units){
# > 3 days, use days
x <- x /day
x <- paste(round(x,2),"days")
} else if("hours" == units[[1]] || max_x > 3 * h && "hours" %in% units){
# > 3 h, use h
x <- x /h
x <- paste(round(x,2),"h")
} else if("minutes" == units[[1]] || max_x > 3 * min && "minutes" %in% units){
# > 3 min, use min
x <- x /min
x <- paste(round(x,2),"min")
} else if("seconds" == units[[1]] || max_x > 3 * min && "seconds" %in% units){
# > 3 min, use min
x <- paste(round(x,2),"s")
} else if("ms" %in% units){
# > 3 min, use min
x <- x /min
x <- paste(round(x,2),"min")
} else {
stop("no unit was found for provided value of x")
}
}
breaks <- function(x){
max_x <- max(x, na.rm=TRUE)
if("years" == units[[1]] || max_x > 3 * year && "years" %in% units){
# > 3 year, use years
scales:::extended_breaks()(x/year) * year
} else if("months" == units[[1]] || max_x > 3 * month && "months" %in% units){
# > 3 months, use months
scales:::extended_breaks()(x/month) * month
} else if("weeks" == units[[1]] || max_x > 3 * week && "weeks" %in% units){
# > 3 weeks, use weeks
scales:::extended_breaks()(x/week) * week
} else if("days" == units[[1]] || max_x > 3 * day && "days" %in% units){
# > 3 days, use days
scales:::extended_breaks()(x/day) * day
} else if("hours" == units[[1]] || max_x > 3 * h && "hours" %in% units){
# > 3 h, use h
scales:::extended_breaks()(x/h) * h
} else if("minutes" == units[[1]] || max_x > 3 * min && "minutes" %in% units){
# > 3 min, use min
scales:::extended_breaks()(x/min) * min
} else if("seconds" == units[[1]] || max_x > 3 && "seconds" %in% units){
# > 3 s, use s
scales:::extended_breaks()(x)
} else if("ms" %in% units){
scales:::extended_breaks()(x/ms) * ms
} else {
stop("no unit was found for provided value of x")
}
}
scale_y_continuous(..., labels = labels, breaks = breaks)
}
df <- data.frame(x=1:3, time = c(1,2,5))
ggplot(df, aes(x, time)) + geom_point() + scale_y_duration() + ggtitle("seconds")
df <- data.frame(x=1:3, time = c(1,2,5) * 1000)
ggplot(df, aes(x, time)) + geom_point() + scale_y_duration() + ggtitle("min")
df <- data.frame(x=1:3, time = c(1,2,5) * 10000)
ggplot(df, aes(x, time)) + geom_point() + scale_y_duration() + ggtitle("hours")
df <- data.frame(x=1:3, time = c(1,2,5) * 100000)
ggplot(df, aes(x, time)) + geom_point() + scale_y_duration() + ggtitle("days")
df <- data.frame(x=1:3, time = c(1,2,5) * 1000)
ggplot(df, aes(x, time)) + geom_point() + scale_y_duration(units = "h") + ggtitle("force hours")
df <- data.frame(x=1:3, time = c(1,2,5) * 1000000)
ggplot(df, aes(x, time)) + geom_point() + scale_y_duration() + ggtitle("not weeks, by default")
ggplot(df, aes(x, time)) + geom_point() + scale_y_duration(units = c("day","week","month")) + ggtitle("weeks")
df <- data.frame(x=1:3, time = c(1,2,5) * 10000000)
ggplot(df, aes(x, time)) + geom_point() + scale_y_duration(units = c("day","week","month")) + ggtitle("months")
ggplot(df, aes(x, time)) + geom_point() + scale_y_duration(units = c("year")) + ggtitle("force year")
@moodymudskipper
Copy link
Author

more flexible now, we can choose a set of units.
Even more flexible would be to set the thresholds through the unit parameter, now it's always 3, meaning, if "hours" is part of units (as is by default) and max(ime) is more than 3 hours, we'll use hours.
A flexible argument would allow something lile units = list("s","min", h = 10)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment