R/scale_x_time.R

Defines functions scale_x_time

Documented in scale_x_time

#' Automatically scale a ggplot graph x axis for time
#'
#' \code{scale_x_time} formats a ggplot graph x axis to have breaks that make
#' sense for the user-specified time units and adds a minor tick between the
#' labels. It optionally adds padding to the left and right sides of the x axis.
#'
#' @param time_range time range to show for the graph. Options: \describe{
#'
#'   \item{NA}{(default) entire time range of data}
#'
#'   \item{a start time and end time in hours}{only data in that range, e.g.
#'   \code{time_range = c(24, 48)}. Note that there are no quotes around numeric
#'   data.}}
#' @param impose_limits TRUE (default) or FALSE to actually \emph{set} the
#'   limits listed in \code{time_range}. Why on earth would you \emph{not}
#'   impose limits on the graph here? Behind the scenes, \code{scale_x_time}
#'   uses the ggplot2 function \code{\link{ggplot::scale_x_continuous}}, which
#'   filters out all data beyond the limits you specify. That means that you
#'   can, in some situations, get graphs where lines are cut off abruptly. This
#'   is set up with the idea that you can set the time range here to get
#'   reasonable x axis intervals, but then you can add a call to
#'   \code{\link{ggplot::coord_cartesian}} to limit the range without the abrupt
#'   cut off.
#' @param time_units the units of time in the graph. Options are "hours"
#'   (default), "minutes", "days", or "weeks". 
#' @param x_axis_interval optionally set the x-axis major tick-mark interval.
#'   Acceptable input: any number or leave as NA to accept default values, which
#'   are generally reasonable guesses as to aesthetically pleasing and
#'   time-relevant intervals.
#' @param pad_x_axis optionally add a smidge of padding to the the x axis
#'   (default is TRUE, which includes some generally reasonable padding). If
#'   changed to FALSE, the y axis will be placed right at the beginning of your
#'   time range and all data will end \emph{exactly} at the end of the time
#'   range specified. If you want a \emph{specific} amount of x-axis padding,
#'   set this to a number; the default is \code{c(0.02, 0.04)}, which adds 2\%
#'   more space to the left side and 4\% more to the right side of the x axis.
#'   If you only specify one number, we'll assume that's the percent you want
#'   added to the left side.
#'
#' @return a ggplot2 graph scale for the x axis (replaces scale_x_continuous in
#'   a graph)
#' @export
#'
#' @examples
#' MyData <- data.frame(Time = 0:168,
#'                      Conc = rnorm(n = 169, mean = 100))
#' ggplot(MyData, aes(x = Time, y = Conc)) +
#'     geom_point() + scale_x_time()
#'
#' ggplot(MyData, aes(x = Time, y = Conc)) +
#'     geom_point() + scale_x_time(time_range = c(24, 48))
#'
#' # You don't have to name the column with your x-axis data "Time".
#' MyAltData <- data.frame(Mango = 0:24,
#'                         Conc = rnorm(n = 25, mean = 100))
#'
#' ggplot(MyAltData, aes(x = Mango, y = Conc)) +
#'     geom_point() + scale_x_time()
#'
#' 
scale_x_time <- function(time_range = NA, 
                         impose_limits = TRUE,
                         time_units = "hours", 
                         x_axis_interval = NA, 
                         pad_x_axis = TRUE){
    
    # Error catching --------------------------------------------------------
    if(all(complete.cases(time_range)) && class(time_range) == "numeric" &
       time_range[1] >= time_range[2]){
        warning("The 1st value for 'time_range' must be less than the 2nd value. We'll use the full time range instead.",
                call. = FALSE)
        time_range <- NA
    }
    
    # Main body of function ------------------------------------------------
    
    Setup <- scale_x_time_setup(time_range = time_range, 
                                time_units = time_units, 
                                x_axis_interval = x_axis_interval, 
                                pad_x_axis = pad_x_axis)
    
    return(scale_x_continuous(breaks = Setup$xbreaks, 
                              labels = Setup$xlabels, 
                              limits = switch(as.character(impose_limits), 
                                              "TRUE" = Setup$limits,
                                              "FALSE" = NULL),
                              expand = Setup$expand))
    
}
shirewoman2/Consultancy documentation built on Feb. 18, 2025, 10 p.m.