diff --git a/R/epi_df.R b/R/epi_df.R index a1a5f3bb..abef52c0 100644 --- a/R/epi_df.R +++ b/R/epi_df.R @@ -105,8 +105,9 @@ NULL #' then the current day-time will be used. #' @param additional_metadata List of additional metadata to attach to the #' `epi_df` object. The metadata will have `geo_type`, `time_type`, and -#' `as_of` fields; named entries from the passed list or will be included as -#' well. +#' `as_of` fields; named entries from the passed list will be included as +#' well. If your tibble has additional keys, be sure to specify them as a +#' character vector in the `other_keys` component of `additional_metadata`. #' @param ... Additional arguments passed to methods. #' @return An `epi_df` object. #' @@ -117,7 +118,11 @@ new_epi_df = function(x = tibble::tibble(), geo_type, time_type, as_of, if (!is.data.frame(x)) { Abort("`x` must be a data frame.") } - + + if (!is.list(additional_metadata)) { + Abort("`additional_metadata` must be a list type.") + } + # If geo type is missing, then try to guess it if (missing(geo_type)) { geo_type = guess_geo_type(x$geo_value) @@ -184,8 +189,9 @@ new_epi_df = function(x = tibble::tibble(), geo_type, time_type, as_of, #' then the current day-time will be used. #' @param additional_metadata List of additional metadata to attach to the #' `epi_df` object. The metadata will have `geo_type`, `time_type`, and -#' `as_of` fields; named entries from the passed list or will be included as -#' well. +#' `as_of` fields; named entries from the passed list will be included as +#' well. If your tibble has additional keys, be sure to specify them as a +#' character vector in the `other_keys` component of `additional_metadata`. #' @param ... Additional arguments passed to methods. #' @return An `epi_df` object. #' @@ -230,7 +236,7 @@ new_epi_df = function(x = tibble::tibble(), geo_type, time_type, as_of, #' #' ex2 <- ex2_input %>% dplyr::rename(geo_value = state, time_value = reported_date) %>% #' as_epi_df(geo_type = "state", as_of = "2020-06-03", -#' additional_metadata = c(other_keys = "pol")) +#' additional_metadata = list(other_keys = "pol")) #' #' attr(ex2,"metadata") #' @@ -244,8 +250,13 @@ new_epi_df = function(x = tibble::tibble(), geo_type, time_type, as_of, #' #' ex3 <- ex3_input %>% #' tsibble::as_tsibble() %>% # needed to add the additional metadata -#' dplyr::mutate(state = rep("MA",6)) %>% -#' as_epi_df(additional_metadata = c(other_keys = "state")) +#' # add 2 extra keys +#' dplyr::mutate( +#' state = rep("MA",6), +#' pol = rep(c("blue", "swing", "swing"), each = 2)) %>% +#' # the 2 extra keys we added have to be specified in the other_keys +#' # component of additional_metadata. +#' as_epi_df(additional_metadata = list(other_keys = c("state", "pol"))) #' #' attr(ex3,"metadata") as_epi_df = function(x, ...) { diff --git a/man/as_epi_archive.Rd b/man/as_epi_archive.Rd index a98798cc..d13ba4d6 100644 --- a/man/as_epi_archive.Rd +++ b/man/as_epi_archive.Rd @@ -91,15 +91,11 @@ examples. } \details{ This simply a wrapper around the \code{new()} method of the \code{epi_archive} -class, so for example: - -\if{html}{\out{
}}\preformatted{x <- as_epi_archive(df, geo_type = "state", time_type = "day") -}\if{html}{\out{
}} - -would be equivalent to: +class, so for example:\preformatted{x <- as_epi_archive(df, geo_type = "state", time_type = "day") +} -\if{html}{\out{
}}\preformatted{x <- epi_archive$new(df, geo_type = "state", time_type = "day") -}\if{html}{\out{
}} +would be equivalent to:\preformatted{x <- epi_archive$new(df, geo_type = "state", time_type = "day") +} } \examples{ # Simple ex. with necessary keys diff --git a/man/as_epi_df.Rd b/man/as_epi_df.Rd index b5df1302..6d7592e4 100644 --- a/man/as_epi_df.Rd +++ b/man/as_epi_df.Rd @@ -39,8 +39,9 @@ then the current day-time will be used.} \item{additional_metadata}{List of additional metadata to attach to the \code{epi_df} object. The metadata will have \code{geo_type}, \code{time_type}, and -\code{as_of} fields; named entries from the passed list or will be included as -well.} +\code{as_of} fields; named entries from the passed list will be included as +well. If your tibble has additional keys, be sure to specify them as a +character vector in the \code{other_keys} component of \code{additional_metadata}.} } \value{ An \code{epi_df} object. @@ -51,9 +52,9 @@ examples. } \section{Methods (by class)}{ \itemize{ -\item \code{as_epi_df(epi_df)}: Simply returns the \code{epi_df} object unchanged. +\item \code{epi_df}: Simply returns the \code{epi_df} object unchanged. -\item \code{as_epi_df(tbl_df)}: The input tibble \code{x} must contain the columns +\item \code{tbl_df}: The input tibble \code{x} must contain the columns \code{geo_value} and \code{time_value}. All other columns will be preserved as is, and treated as measured variables. If \code{as_of} is missing, then the function will try to guess it from an \code{as_of}, \code{issue}, or \code{version} column of \code{x} @@ -61,14 +62,14 @@ will try to guess it from an \code{as_of}, \code{issue}, or \code{version} colum (stored in its attributes); if this fails, then the current day-time will be used. -\item \code{as_epi_df(data.frame)}: Works analogously to \code{as_epi_df.tbl_df()}. +\item \code{data.frame}: Works analogously to \code{as_epi_df.tbl_df()}. -\item \code{as_epi_df(tbl_ts)}: Works analogously to \code{as_epi_df.tbl_df()}, except that +\item \code{tbl_ts}: Works analogously to \code{as_epi_df.tbl_df()}, except that the \code{tbl_ts} class is dropped, and any key variables (other than "geo_value") are added to the metadata of the returned object, under the \code{other_keys} field. - }} + \examples{ # Convert a `tsibble` that has county code as an extra key # Notice that county code should be a character string to preserve any leading zeroes @@ -109,7 +110,7 @@ print(ex2_input) ex2 <- ex2_input \%>\% dplyr::rename(geo_value = state, time_value = reported_date) \%>\% as_epi_df(geo_type = "state", as_of = "2020-06-03", - additional_metadata = c(other_keys = "pol")) + additional_metadata = list(other_keys = "pol")) attr(ex2,"metadata") @@ -123,8 +124,13 @@ ex3_input <- jhu_csse_county_level_subset \%>\% ex3 <- ex3_input \%>\% tsibble::as_tsibble() \%>\% # needed to add the additional metadata - dplyr::mutate(state = rep("MA",6)) \%>\% - as_epi_df(additional_metadata = c(other_keys = "state")) + # add 2 extra keys + dplyr::mutate( + state = rep("MA",6), + pol = rep(c("blue", "swing", "swing"), each = 2)) \%>\% + # the 2 extra keys we added have to be specified in the other_keys + # component of additional_metadata. + as_epi_df(additional_metadata = list(other_keys = c("state", "pol"))) attr(ex3,"metadata") } diff --git a/man/epi_archive.Rd b/man/epi_archive.Rd index 026f27e1..0b198eab 100644 --- a/man/epi_archive.Rd +++ b/man/epi_archive.Rd @@ -114,18 +114,18 @@ toy_epi_archive \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-epi_archive-new}{\code{epi_archive$new()}} -\item \href{#method-epi_archive-print}{\code{epi_archive$print()}} -\item \href{#method-epi_archive-as_of}{\code{epi_archive$as_of()}} -\item \href{#method-epi_archive-fill_through_version}{\code{epi_archive$fill_through_version()}} -\item \href{#method-epi_archive-merge}{\code{epi_archive$merge()}} -\item \href{#method-epi_archive-slide}{\code{epi_archive$slide()}} -\item \href{#method-epi_archive-clone}{\code{epi_archive$clone()}} +\item \href{#method-new}{\code{epi_archive$new()}} +\item \href{#method-print}{\code{epi_archive$print()}} +\item \href{#method-as_of}{\code{epi_archive$as_of()}} +\item \href{#method-fill_through_version}{\code{epi_archive$fill_through_version()}} +\item \href{#method-merge}{\code{epi_archive$merge()}} +\item \href{#method-slide}{\code{epi_archive$slide()}} +\item \href{#method-clone}{\code{epi_archive$clone()}} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-epi_archive-new}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-new}{}}} \subsection{Method \code{new()}}{ Creates a new \code{epi_archive} object. \subsection{Usage}{ @@ -195,8 +195,8 @@ An \code{epi_archive} object. } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-epi_archive-print}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-print}{}}} \subsection{Method \code{print()}}{ \subsection{Usage}{ \if{html}{\out{
}}\preformatted{epi_archive$print()}\if{html}{\out{
}} @@ -204,8 +204,8 @@ An \code{epi_archive} object. } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-epi_archive-as_of}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-as_of}{}}} \subsection{Method \code{as_of()}}{ Generates a snapshot in \code{epi_df} format as of a given version. See the documentation for the wrapper function \code{\link[=epix_as_of]{epix_as_of()}} for details. @@ -215,8 +215,8 @@ See the documentation for the wrapper function \code{\link[=epix_as_of]{epix_as_ } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-epi_archive-fill_through_version}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-fill_through_version}{}}} \subsection{Method \code{fill_through_version()}}{ Fill in unobserved history using requested scheme by mutating \code{self} and potentially reseating its fields. See @@ -237,8 +237,8 @@ version, which doesn't mutate the input archive but might alias its fields. } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-epi_archive-merge}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-merge}{}}} \subsection{Method \code{merge()}}{ Merges another \code{epi_archive} with the current one, mutating the current one by reseating its \code{DT} and several other fields, but avoiding @@ -267,8 +267,8 @@ does not alias either archive's \code{DT}. } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-epi_archive-slide}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-slide}{}}} \subsection{Method \code{slide()}}{ Slides a given function over variables in an \code{epi_archive} object. See the documentation for the wrapper function \code{\link[=epix_slide]{epix_slide()}} for @@ -290,8 +290,8 @@ details. } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-epi_archive-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ diff --git a/man/epi_slide.Rd b/man/epi_slide.Rd index 1b620b69..c64bbce1 100644 --- a/man/epi_slide.Rd +++ b/man/epi_slide.Rd @@ -107,16 +107,12 @@ incomplete windows) is therefore left up to the user, either through the specified function or formula \code{f}, or through post-processing. If \code{f} is missing, then an expression for tidy evaluation can be specified, -for example, as in: - -\if{html}{\out{
}}\preformatted{epi_slide(x, cases_7dav = mean(cases), n = 7) -}\if{html}{\out{
}} - -which would be equivalent to: +for example, as in:\preformatted{epi_slide(x, cases_7dav = mean(cases), n = 7) +} -\if{html}{\out{
}}\preformatted{epi_slide(x, function(x, ...) mean(x$cases), n = 7, +which would be equivalent to:\preformatted{epi_slide(x, function(x, ...) mean(x$cases), n = 7, new_col_name = "cases_7dav") -}\if{html}{\out{
}} +} Thus, to be clear, when the computation is specified via an expression for tidy evaluation (first example, above), then the name for the new column is diff --git a/man/epix_as_of.Rd b/man/epix_as_of.Rd index 4053cd28..6dc72a44 100644 --- a/man/epix_as_of.Rd +++ b/man/epix_as_of.Rd @@ -29,15 +29,11 @@ examples. } \details{ This is simply a wrapper around the \code{as_of()} method of the -\code{epi_archive} class, so if \code{x} is an \code{epi_archive} object, then: - -\if{html}{\out{
}}\preformatted{epix_as_of(x, max_version = v) -}\if{html}{\out{
}} - -is equivalent to: +\code{epi_archive} class, so if \code{x} is an \code{epi_archive} object, then:\preformatted{epix_as_of(x, max_version = v) +} -\if{html}{\out{
}}\preformatted{x$as_of(max_version = v) -}\if{html}{\out{
}} +is equivalent to:\preformatted{x$as_of(max_version = v) +} } \examples{ # warning message of data latency shown diff --git a/man/epix_slide.Rd b/man/epix_slide.Rd index 79e9c1c3..2acae1a1 100644 --- a/man/epix_slide.Rd +++ b/man/epix_slide.Rd @@ -115,15 +115,11 @@ should never be used in place of \code{epi_slide()}, and only used when version-aware sliding is necessary (as it its purpose). Finally, this is simply a wrapper around the \code{slide()} method of the -\code{epi_archive} class, so if \code{x} is an \code{epi_archive} object, then: - -\if{html}{\out{
}}\preformatted{epix_slide(x, new_var = comp(old_var), n = 120) -}\if{html}{\out{
}} - -is equivalent to: +\code{epi_archive} class, so if \code{x} is an \code{epi_archive} object, then:\preformatted{epix_slide(x, new_var = comp(old_var), n = 120) +} -\if{html}{\out{
}}\preformatted{x$slide(x, new_var = comp(old_var), n = 120) -}\if{html}{\out{
}} +is equivalent to:\preformatted{x$slide(x, new_var = comp(old_var), n = 120) +} } \examples{ # these dates are reference time points for the 3 day average sliding window diff --git a/man/new_epi_df.Rd b/man/new_epi_df.Rd index 95f8dc9f..7182c222 100644 --- a/man/new_epi_df.Rd +++ b/man/new_epi_df.Rd @@ -32,8 +32,9 @@ then the current day-time will be used.} \item{additional_metadata}{List of additional metadata to attach to the \code{epi_df} object. The metadata will have \code{geo_type}, \code{time_type}, and -\code{as_of} fields; named entries from the passed list or will be included as -well.} +\code{as_of} fields; named entries from the passed list will be included as +well. If your tibble has additional keys, be sure to specify them as a +character vector in the \code{other_keys} component of \code{additional_metadata}.} \item{...}{Additional arguments passed to methods.} } diff --git a/tests/testthat/test-epi_df.R b/tests/testthat/test-epi_df.R index 9165ac4d..10b0015e 100644 --- a/tests/testthat/test-epi_df.R +++ b/tests/testthat/test-epi_df.R @@ -24,3 +24,18 @@ test_that("new_epi_df works as intended", { expect_identical(attributes(epi_tib)$metadata$time_type, "day") expect_true(lubridate::is.POSIXt(attributes(epi_tib)$metadata$as_of)) }) + +test_that("as_epi_df errors when additional_metadata is not a list", { + # This is the 3rd example from as_epi_df + ex_input <- jhu_csse_county_level_subset %>% + dplyr::filter(time_value > "2021-12-01", state_name == "Massachusetts") %>% + dplyr::slice_tail(n = 6) %>% + tsibble::as_tsibble() %>% + dplyr::mutate( + state = rep("MA",6), + pol = rep(c("blue", "swing", "swing"), each = 2)) + + expect_error( + as_epi_df(ex_input, additional_metadata = c(other_keys = "state", "pol")), + "`additional_metadata` must be a list type.") +}) \ No newline at end of file diff --git a/tests/testthat/test-methods-epi_df.R b/tests/testthat/test-methods-epi_df.R index cc6116d8..c03b49ec 100644 --- a/tests/testthat/test-methods-epi_df.R +++ b/tests/testthat/test-methods-epi_df.R @@ -8,7 +8,7 @@ toy_epi_df <- tibble::tibble( ), times = 2), geo_value = rep(c("ca", "hi"), each = 5), indicator_var = as.factor(rep(1:2, times = 5)), -) %>% as_epi_df(additional_metadata = c(other_keys = "indicator_var")) +) %>% as_epi_df(additional_metadata = list(other_keys = "indicator_var")) att_toy = attr(toy_epi_df, "metadata") diff --git a/vignettes/epiprocess.Rmd b/vignettes/epiprocess.Rmd index 379423b0..2dc2266b 100644 --- a/vignettes/epiprocess.Rmd +++ b/vignettes/epiprocess.Rmd @@ -180,7 +180,7 @@ head(ex2) ex2 <- ex2 %>% rename(geo_value = state, time_value = reported_date) %>% as_epi_df(geo_type = "state", as_of = "2020-06-03", - additional_metadata = c(other_keys = "pol")) + additional_metadata = list(other_keys = "pol")) attr(ex2,"metadata") ``` @@ -200,17 +200,21 @@ ex3 <- jhu_csse_county_level_subset %>% attr(ex3,"metadata") # geo_type is county currently ``` -Now we add state (MA) as a new column and a key to the metadata. Reminder that lower case state name abbreviations are what we would expect if this were a `geo_value` column. -```{r} +Now we add `state` (MA) and `pol` as new columns to the data and as new keys to the metadata. Reminder that lower case state name abbreviations are what we would expect if this were a `geo_value` column. +```{r} ex3 <- ex3 %>% as_tibble() %>% # needed to add the additional metadata - mutate(state = rep(tolower("MA"),6)) %>% - as_epi_df(additional_metadata = c(other_keys = "state")) + mutate( + state = rep(tolower("MA"),6), + pol = rep(c("blue", "swing", "swing"), each = 2)) %>% + as_epi_df(additional_metadata = list(other_keys = c("state", "pol"))) attr(ex3,"metadata") ``` +Note that the two additional keys we added, `state` and `pol`, are specified as a character vector in the `other_keys` component of the `additional_metadata` list. They must be specified in this manner so that downstream actions on the `epi_df`, like model fitting and prediction, can recognize and use these keys. + Currently `other_keys` metadata in `epi_df` doesn't impact `epi_slide()`, contrary to `other_keys` in `as_epi_archive` which affects how the update data is interpreted. ## Working with `epi_df` objects downstream