diff --git a/DESCRIPTION b/DESCRIPTION index 8427ea1..158b000 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -41,6 +41,7 @@ Imports: rsvg, jsonlite, rlang, + glue, grDevices, svglite Suggests: diff --git a/NAMESPACE b/NAMESPACE index 9c79e83..4e2ef59 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -9,6 +9,7 @@ import(rsvg) importFrom(ggplot2,ggsave) importFrom(ggplot2,set_last_plot) importFrom(gifski,gifski) +importFrom(glue,glue) importFrom(grDevices,dev.copy) importFrom(grDevices,dev.cur) importFrom(grDevices,dev.list) diff --git a/R/gg_record.R b/R/gg_record.R index 9daf285..ab61ce8 100644 --- a/R/gg_record.R +++ b/R/gg_record.R @@ -10,9 +10,13 @@ #' @param device Device to use. Can either be a device function (e.g. png()), or #' one of "png", "pdf", "jpeg", "bmp", "tiff", "emf", "svg", "eps", "ps". #' @param device_ext file extension to use for images created. Does not usually need to be populated manually. -#' @return Used initialize recording, nothing returned +#' @param filename_pattern Pattern to use when naming the interim files. Must use one of the +#' reserved camcorder iterators: {timestamp},{i} #' @inheritParams ggplot2::ggsave #' +#' +#' @return Used initialize recording, nothing returned +#' #' @importFrom ggplot2 ggsave #' #' @examples @@ -40,7 +44,8 @@ gg_record <- function(dir = NULL, dpi = 300, limitsize = TRUE, device_ext = NULL, - bg = NULL + bg = NULL, + filename_pattern = "{timestamp}" ){ if (is.null(dir)) { @@ -67,22 +72,35 @@ gg_record <- function(dir = NULL, device_ext <- derive_ext(device) } + filename_pattern <- verify_filename_pattern(filename_pattern) + units <- match.arg(units) if (!dir.exists(dir)) { dir.create(dir, recursive = TRUE) } else{ - if (length(list.files(dir, pattern = paste0("[.]", device_ext, "$"))) > 1) { + device_files <- + list.files(dir, + pattern = paste0( + "^", + cleanup_filename_pattern_to_regex(filename_pattern), + "[.]", + device_ext, + "$" + )) + if (length(device_files) > 1) { warning( "Writing to a folder that already exists. gg_playback may use more files than intended!" ) } } - GG_RECORDING_ENV$recording_dir <- dir - GG_RECORDING_ENV$device <- device - GG_RECORDING_ENV$device_ext <- device_ext - GG_RECORDING_ENV$is_temp_dir <- is_temp_dir + + GG_RECORDING_ENV$recording_dir <- dir + GG_RECORDING_ENV$device <- device + GG_RECORDING_ENV$device_ext <- device_ext + GG_RECORDING_ENV$is_temp_dir <- is_temp_dir + GG_RECORDING_ENV$filename_pattern <- filename_pattern GG_RECORDING_ENV$image_width <- width GG_RECORDING_ENV$image_height <- height diff --git a/R/preview.R b/R/preview.R index aeab5e3..be03fbd 100644 --- a/R/preview.R +++ b/R/preview.R @@ -13,6 +13,8 @@ preview_film <- function(){ wait = FALSE) } else{ + + image_viewer_html <- file.path(tempdir(), "preview.html") @@ -37,11 +39,12 @@ get_file_records <- function(full_path = FALSE){ file_preview_ext <- paste0("[.]", GG_RECORDING_ENV$device_ext, "$") - file_preview_format <- "\\d{4}_\\d{2}_\\d{2}_\\d{2}_\\d{2}_\\d{2}[.]\\d+" + filename_pattern <- GG_RECORDING_ENV$filename_pattern + filename_pattern <- cleanup_filename_pattern_to_regex(filename_pattern) list.files( path = GG_RECORDING_ENV$recording_dir, - pattern = paste0("^",file_preview_format,file_preview_ext), + pattern = paste0("^",filename_pattern,file_preview_ext), full.names = full_path ) diff --git a/R/recording.R b/R/recording.R index 0fec4b0..dacf130 100644 --- a/R/recording.R +++ b/R/recording.R @@ -7,17 +7,13 @@ #' @param ... allow for traditionally pass arguments to printing that are ignored #' #' @importFrom ggplot2 set_last_plot +#' @importFrom glue glue #' #' @noRd #' record_ggplot <- function(x, ...) { - plot_file <- - file.path(GG_RECORDING_ENV$recording_dir, paste0( - format(Sys.time(), "%Y_%m_%d_%H_%M_%OS6"), - ".", - GG_RECORDING_ENV$device_ext - )) + plot_file <- camcorder_plot_file_path() suppressMessages({ ggsave( @@ -44,12 +40,7 @@ record_ggplot <- function(x, ...) { #' @importFrom utils capture.output record_patchwork <- function(x,...) { - plot_file <- - file.path(GG_RECORDING_ENV$recording_dir, paste0( - format(Sys.time(), "%Y_%m_%d_%H_%M_%OS6"), - ".", - GG_RECORDING_ENV$device_ext - )) + plot_file <- camcorder_plot_file_path() registerS3method( genname = "print", @@ -118,12 +109,7 @@ record_patchwork <- function(x,...) { #' @export record_polaroid <- function(){ - plot_file <- - file.path(GG_RECORDING_ENV$recording_dir, paste0( - format(Sys.time(), "%Y_%m_%d_%H_%M_%OS6"), - ".", - GG_RECORDING_ENV$device_ext - )) + plot_file <- camcorder_plot_file_path() suppressMessages({ diff --git a/R/utils.R b/R/utils.R index 26999dd..cc5e5b2 100644 --- a/R/utils.R +++ b/R/utils.R @@ -56,3 +56,61 @@ derive_ext <- function(x){ } } } + +camcorder_plot_file_path <- function(){ + + timestamp <- format(Sys.time(), "%Y_%m_%d_%H_%M_%OS6") + i <- camcorder_plot_count() + + file.path( + GG_RECORDING_ENV$recording_dir, + paste0( + glue(GG_RECORDING_ENV$filename_pattern), + ".", + GG_RECORDING_ENV$device_ext + )) +} + + +camcorder_reserved_patterns <- list( + list(pattern = "{timestamp}", regex = "\\d{4}_\\d{2}_\\d{2}_\\d{2}_\\d{2}_\\d{2}[.]\\d+"), + list(pattern = "{i}", regex = "\\d+") +) + +verify_filename_pattern <- function(x){ + has_pattern <- FALSE + for(reserved_pattern in camcorder_reserved_patterns){ + has_pattern <- grepl(reserved_pattern$pattern, x, fixed = TRUE) + if(has_pattern){ + break + } + } + + if(!has_pattern){ + stop(paste0( + "filename_pattern must have one of the camcorder reserved filename", + " patterns to ensure uniqueness:\n", + paste0("\t`",sapply(camcorder_reserved_patterns, `[[`, "pattern"),"`", collapse = "\n") + ) + ) + } + + x +} + +camcorder_plot_count <- function(){ + i <- mget("plot_count", GG_RECORDING_ENV, ifnotfound = 0)[[1]] + 1 + set_plot_count(i) + i +} + +cleanup_filename_pattern_to_regex <- function(filename_pattern){ + for(reserved_pattern in camcorder_reserved_patterns){ + filename_pattern <- gsub(reserved_pattern$pattern,reserved_pattern$regex, filename_pattern, fixed=TRUE) + } + filename_pattern +} + +set_plot_count <- function(i){ + GG_RECORDING_ENV$plot_count <- i +} diff --git a/man/Recording.Rd b/man/Recording.Rd index 199b536..2cdda49 100644 --- a/man/Recording.Rd +++ b/man/Recording.Rd @@ -17,7 +17,8 @@ gg_record( dpi = 300, limitsize = TRUE, device_ext = NULL, - bg = NULL + bg = NULL, + filename_pattern = "{timestamp}" ) gg_playback( @@ -64,6 +65,9 @@ specifying dimensions in pixels.} \item{bg}{Background colour. If \code{NULL}, uses the \code{plot.background} fill value from the plot theme.} +\item{filename_pattern}{Pattern to use when naming the interim files. Must use one of the +reserved camcorder iterators: {timestamp},{i}} + \item{name}{name of gif.} \item{first_image_duration}{n units of frame_duration to show the first image for.}