From 9d9ee701c0964ae86ccf939738e144bd1b90e8cc Mon Sep 17 00:00:00 2001 From: "Daniel J. McDonald" Date: Mon, 11 Sep 2023 17:47:06 -0700 Subject: [PATCH 001/189] use delphi/CMU red, match `epipredict` --- _pkgdown.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/_pkgdown.yml b/_pkgdown.yml index 7b5c1c3b..26cf0d2b 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -1,3 +1,17 @@ +template: + bootstrap: 5 + bootswatch: cosmo + bslib: + font_scale: 1.0 + primary: '#C41230' + link-color: '#C41230' + navbar-bg: '#C41230' + navbar-fg: '#f8f8f8' + +navbar: + bg: '#C41230' + fg: '#f8f8f8' + home: links: - text: Get the Python client @@ -5,6 +19,18 @@ home: - text: View the Delphi Website href: https://delphi.cmu.edu/ + + - text: Introduction to Delphi's Tooling Work + href: https://cmu-delphi.github.io/delphi-tooling-book/ + + - text: The epiprocess R package + href: https://cmu-delphi.github.io/epiprocess/ + + - text: The epipredict R package + href: https://cmu-delphi.github.io/epipredict/ + + - text: The epidatasets R package + href: https://cmu-delphi.github.io/epidatasets/ reference: - title: Configuration and utilities From b28e56c4e993b52fa04ddf53dff4da195c65afb0 Mon Sep 17 00:00:00 2001 From: "Daniel J. McDonald" Date: Mon, 11 Sep 2023 17:48:36 -0700 Subject: [PATCH 002/189] Make the readme an Rmd * rebuild it with `devtools::render_readme()` * easier to track changes / multiple files * Note that the rebuilt figure looks a bit different. --- .Rbuildignore | 1 + README.Rmd | 100 ++++++++++++++++++++ README.md | 121 ++++++++++++++++--------- man/figures/README-fb-cli-signal-1.png | Bin 0 -> 33909 bytes 4 files changed, 177 insertions(+), 45 deletions(-) create mode 100644 README.Rmd create mode 100644 man/figures/README-fb-cli-signal-1.png diff --git a/.Rbuildignore b/.Rbuildignore index d8980c48..cc347d67 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -20,3 +20,4 @@ ^.venv$ ^env$ ^.env$ +^README\.Rmd$ diff --git a/README.Rmd b/README.Rmd new file mode 100644 index 00000000..47e44f43 --- /dev/null +++ b/README.Rmd @@ -0,0 +1,100 @@ +--- +output: github_document +--- + + + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + fig.path = "man/figures/README-", + out.width = "100%" +) +ggplot2::theme_set(ggplot2::theme_bw()) +``` + +# Delphi Epidata R client + + + +[![License: MIT][mit-image]][mit-url] [![Github Actions][github-actions-image]][github-actions-url] +[![codecov](https://codecov.io/gh/dsweber2/epidatr/branch/dev/graph/badge.svg?token=jVHL9eHZNZ)](https://app.codecov.io/gh/dsweber2/epidatr) + + + + +The [Delphi Epidata API](https://cmu-delphi.github.io/delphi-epidata/) provides real-time access to epidemiological surveillance data for influenza, COVID-19, and other diseases for the USA at various geographical resolutions, both from official government sources such as the [Center for Disease Control (CDC)](https://www.cdc.gov/datastatistics/index.html) and [Google Trends](https://cmu-delphi.github.io/delphi-epidata/api/covidcast-signals/google-symptoms.html) and private partners such as [Facebook](https://delphi.cmu.edu/blog/2020/08/26/covid-19-symptom-surveys-through-facebook/) and [Change Healthcare](https://www.changehealthcare.com/). It is built and maintained by the Carnegie Mellon University [Delphi research group](https://delphi.cmu.edu/). + +This package is designed to streamline the downloading and usage of data from the [Delphi Epidata +API](https://cmu-delphi.github.io/delphi-epidata/). It provides a simple R interface to the API, including functions for downloading data, parsing the results, and converting the data into a tidy format. The API stores a historical record of all data, including corrections and updates, which is particularly useful for accurately backtesting forecasting models. We also provide packages for downstream data processing ([epiprocess](https://github.com/cmu-delphi/epiprocess)) and modeling ([epipredict](https://github.com/cmu-delphi/epipredict)). + +## Usage + +```{r} +library(epidatr) +# Obtain the smoothed covid-like illness (CLI) signal from the +# Facebook survey as it was on April 10, 2021 for the US +epidata <- pub_covidcast( + source = "fb-survey", + signals = "smoothed_cli", + geo_type = "nation", + time_type = "day", + geo_values = "us", + time_values = epirange(20210101, 20210601), + as_of = "2021-06-01" +) +epidata +``` + +```{r fb-cli-signal} +# Plot this data +library(ggplot2) +ggplot(epidata, aes(x = time_value, y = value)) + + geom_line() + + labs(title = "Smoothed CLI from Facebook Survey", + subtitle = "US, 2021", + x = "Date", + y = "CLI") +``` + + +## Installation + +Install from GitHub: + +```R +# Install the dev version using `pak` or `remotes` +pak::pkg_install("cmu-delphi/epidatr") +remotes::install_github("cmu-delphi/epidatr") +``` + +CRAN version coming soon. + +### API Keys + +The Delphi API requires a (free) API key for full functionality. To generate +your key, register for a pseudo-anonymous account +[here](https://api.delphi.cmu.edu/epidata/admin/registration_form) and see more +discussion on the [general API +website](https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html). The +`epidatr` client will automatically look for this key in the R option +`delphi.epidata.key` or in the environment variable +`DELPHI_EPIDATA_KEY`. We recommend storing your key in `.Renviron` file, which R +will read by default. + +Note that for the time being, the private endpoints (i.e. those prefixed with +`pvt`) will require a separate key that needs to be passed as an argument. + +[mit-image]: https://img.shields.io/badge/License-MIT-yellow.svg +[mit-url]: https://opensource.org/license/mit/ +[github-actions-image]: https://github.com/cmu-delphi/epidatr/workflows/ci/badge.svg +[github-actions-url]: https://github.com/cmu-delphi/epidatr/actions + +## Get updates + +You should consider subscribing to the [API mailing list](https://lists.andrew.cmu.edu/mailman/listinfo/delphi-covidcast-api) to be notified of package updates, new data sources, corrections, and other updates. + +## For users of the `covidcast` R package + +The `epidatr` package is a complete rewrite of the [`covidcast` package](https://cmu-delphi.github.io/covidcast/covidcastR/), with a focus on speed, reliability, and ease of use. The `covidcast` package is deprecated and will no longer be updated. diff --git a/README.md b/README.md index 643ec3f0..224445ad 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,47 @@ -# Delphi Epidata R client -[![License: MIT][mit-image]][mit-url] [![Github Actions][github-actions-image]][github-actions-url] -[![codecov](https://codecov.io/gh/dsweber2/epidatr/branch/dev/graph/badge.svg?token=jVHL9eHZNZ)](https://app.codecov.io/gh/dsweber2/epidatr) + -The [Delphi Epidata API](https://cmu-delphi.github.io/delphi-epidata/) provides real-time access to epidemiological surveillance data for influenza, COVID-19, and other diseases for the USA at various geographical resolutions, both from official government sources such as the [Center for Disease Control (CDC)](https://www.cdc.gov/datastatistics/index.html) and [Google Trends](https://cmu-delphi.github.io/delphi-epidata/api/covidcast-signals/google-symptoms.html) and private partners such as [Facebook](https://delphi.cmu.edu/blog/2020/08/26/covid-19-symptom-surveys-through-facebook/) and [Change Healthcare](https://www.changehealthcare.com/). It is built and maintained by the Carnegie Mellon University [Delphi research group](https://delphi.cmu.edu/). +# Delphi Epidata R client -This package is designed to streamline the downloading and usage of data from the [Delphi Epidata -API](https://cmu-delphi.github.io/delphi-epidata/). It provides a simple R interface to the API, including functions for downloading data, parsing the results, and converting the data into a tidy format. The API stores a historical record of all data, including corrections and updates, which is particularly useful for accurately backtesting forecasting models. We also provide packages for downstream data processing ([epiprocess](https://github.com/cmu-delphi/epiprocess)) and modeling ([epipredict](https://github.com/cmu-delphi/epipredict)). + + +[![License: +MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/license/mit/) +[![Github +Actions](https://github.com/cmu-delphi/epidatr/workflows/ci/badge.svg)](https://github.com/cmu-delphi/epidatr/actions) +[![codecov](https://codecov.io/gh/dsweber2/epidatr/branch/dev/graph/badge.svg?token=jVHL9eHZNZ)](https://app.codecov.io/gh/dsweber2/epidatr) + + +The [Delphi Epidata API](https://cmu-delphi.github.io/delphi-epidata/) +provides real-time access to epidemiological surveillance data for +influenza, COVID-19, and other diseases for the USA at various +geographical resolutions, both from official government sources such as +the [Center for Disease Control +(CDC)](https://www.cdc.gov/datastatistics/index.html) and [Google +Trends](https://cmu-delphi.github.io/delphi-epidata/api/covidcast-signals/google-symptoms.html) +and private partners such as +[Facebook](https://delphi.cmu.edu/blog/2020/08/26/covid-19-symptom-surveys-through-facebook/) +and [Change Healthcare](https://www.changehealthcare.com/). It is built +and maintained by the Carnegie Mellon University [Delphi research +group](https://delphi.cmu.edu/). + +This package is designed to streamline the downloading and usage of data +from the [Delphi Epidata +API](https://cmu-delphi.github.io/delphi-epidata/). It provides a simple +R interface to the API, including functions for downloading data, +parsing the results, and converting the data into a tidy format. The API +stores a historical record of all data, including corrections and +updates, which is particularly useful for accurately backtesting +forecasting models. We also provide packages for downstream data +processing ([epiprocess](https://github.com/cmu-delphi/epiprocess)) and +modeling ([epipredict](https://github.com/cmu-delphi/epipredict)). ## Usage -```R +``` r library(epidatr) -# Obtain the smoothed covid-like illness (CLI) signal from the Facebook survey as it was on April 10, 2021 for the US +# Obtain the smoothed covid-like illness (CLI) signal from the +# Facebook survey as it was on April 10, 2021 for the US epidata <- pub_covidcast( source = "fb-survey", signals = "smoothed_cli", @@ -23,25 +52,25 @@ epidata <- pub_covidcast( as_of = "2021-06-01" ) epidata +#> # A tibble: 151 × 15 +#> geo_value signal source geo_type time_type time_value direction issue +#> +#> 1 us smoothed… fb-su… nation day 2021-01-01 NA 2021-01-06 +#> 2 us smoothed… fb-su… nation day 2021-01-02 NA 2021-01-07 +#> 3 us smoothed… fb-su… nation day 2021-01-03 NA 2021-01-08 +#> 4 us smoothed… fb-su… nation day 2021-01-04 NA 2021-01-09 +#> 5 us smoothed… fb-su… nation day 2021-01-05 NA 2021-01-10 +#> 6 us smoothed… fb-su… nation day 2021-01-06 NA 2021-01-29 +#> 7 us smoothed… fb-su… nation day 2021-01-07 NA 2021-01-29 +#> 8 us smoothed… fb-su… nation day 2021-01-08 NA 2021-01-29 +#> 9 us smoothed… fb-su… nation day 2021-01-09 NA 2021-01-29 +#> 10 us smoothed… fb-su… nation day 2021-01-10 NA 2021-01-29 +#> # ℹ 141 more rows +#> # ℹ 7 more variables: lag , missing_value , missing_stderr , +#> # missing_sample_size , value , stderr , sample_size ``` -``` -# A tibble: 6 × 15 - geo_value signal source geo_type time_type time_value - -1 us smoothed_cli fb-surv… nation day 2021-04-05 -2 us smoothed_cli fb-surv… nation day 2021-04-06 -3 us smoothed_cli fb-surv… nation day 2021-04-07 -4 us smoothed_cli fb-surv… nation day 2021-04-08 -5 us smoothed_cli fb-surv… nation day 2021-04-09 -6 us smoothed_cli fb-surv… nation day 2021-04-10 -# ℹ 9 more variables: direction , issue , -# lag , missing_value , missing_stderr , -# missing_sample_size , value , stderr , -# sample_size -``` - -```r +``` r # Plot this data library(ggplot2) ggplot(epidata, aes(x = time_value, y = value)) + @@ -52,13 +81,13 @@ ggplot(epidata, aes(x = time_value, y = value)) + y = "CLI") ``` -![Smoothed CLI from Facebook Survey](man/figures/fb-cli-signal.png) + ## Installation Install from GitHub: -```R +``` r # Install the dev version using `pak` or `remotes` pak::pkg_install("cmu-delphi/epidatr") remotes::install_github("cmu-delphi/epidatr") @@ -68,28 +97,30 @@ CRAN version coming soon. ### API Keys -The Delphi API requires a (free) API key for full functionality. To generate -your key, register for a pseudo-anonymous account -[here](https://api.delphi.cmu.edu/epidata/admin/registration_form) and see more -discussion on the [general API -website](https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html). The -`epidatr` client will automatically look for this key in the R option -`delphi.epidata.key` or in the environment variable -`DELPHI_EPIDATA_KEY`. We recommend storing your key in `.Renviron` file, which R -will read by default. - -Note that for the time being, the private endpoints (i.e. those prefixed with -`pvt`) will require a separate key that needs to be passed as an argument. +The Delphi API requires a (free) API key for full functionality. To +generate your key, register for a pseudo-anonymous account +[here](https://api.delphi.cmu.edu/epidata/admin/registration_form) and +see more discussion on the [general API +website](https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html). +The `epidatr` client will automatically look for this key in the R +option `delphi.epidata.key` or in the environment variable +`DELPHI_EPIDATA_KEY`. We recommend storing your key in `.Renviron` file, +which R will read by default. -[mit-image]: https://img.shields.io/badge/License-MIT-yellow.svg -[mit-url]: https://opensource.org/license/mit/ -[github-actions-image]: https://github.com/cmu-delphi/epidatr/workflows/ci/badge.svg -[github-actions-url]: https://github.com/cmu-delphi/epidatr/actions +Note that for the time being, the private endpoints (i.e. those prefixed +with `pvt`) will require a separate key that needs to be passed as an +argument. ## Get updates -You should consider subscribing to the [API mailing list](https://lists.andrew.cmu.edu/mailman/listinfo/delphi-covidcast-api) to be notified of package updates, new data sources, corrections, and other updates. +You should consider subscribing to the [API mailing +list](https://lists.andrew.cmu.edu/mailman/listinfo/delphi-covidcast-api) +to be notified of package updates, new data sources, corrections, and +other updates. ## For users of the `covidcast` R package -The `epidatr` package is a complete rewrite of the [`covidcast` package](https://cmu-delphi.github.io/covidcast/covidcastR/), with a focus on speed, reliability, and ease of use. The `covidcast` package is deprecated and will no longer be updated. +The `epidatr` package is a complete rewrite of the [`covidcast` +package](https://cmu-delphi.github.io/covidcast/covidcastR/), with a +focus on speed, reliability, and ease of use. The `covidcast` package is +deprecated and will no longer be updated. diff --git a/man/figures/README-fb-cli-signal-1.png b/man/figures/README-fb-cli-signal-1.png new file mode 100644 index 0000000000000000000000000000000000000000..5a76514d301c351006ccbe139a1b544cd1b6f40a GIT binary patch literal 33909 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 Date: Mon, 11 Sep 2023 18:01:38 -0700 Subject: [PATCH 003/189] run styler, then rebuild README --- README.Rmd | 12 +++++++----- README.md | 12 +++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/README.Rmd b/README.Rmd index 47e44f43..821c6690 100644 --- a/README.Rmd +++ b/README.Rmd @@ -33,7 +33,7 @@ API](https://cmu-delphi.github.io/delphi-epidata/). It provides a simple R inter ```{r} library(epidatr) -# Obtain the smoothed covid-like illness (CLI) signal from the +# Obtain the smoothed covid-like illness (CLI) signal from the # Facebook survey as it was on April 10, 2021 for the US epidata <- pub_covidcast( source = "fb-survey", @@ -52,10 +52,12 @@ epidata library(ggplot2) ggplot(epidata, aes(x = time_value, y = value)) + geom_line() + - labs(title = "Smoothed CLI from Facebook Survey", - subtitle = "US, 2021", - x = "Date", - y = "CLI") + labs( + title = "Smoothed CLI from Facebook Survey", + subtitle = "US, 2021", + x = "Date", + y = "CLI" + ) ``` diff --git a/README.md b/README.md index 224445ad..66b934b4 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ modeling ([epipredict](https://github.com/cmu-delphi/epipredict)). ``` r library(epidatr) -# Obtain the smoothed covid-like illness (CLI) signal from the +# Obtain the smoothed covid-like illness (CLI) signal from the # Facebook survey as it was on April 10, 2021 for the US epidata <- pub_covidcast( source = "fb-survey", @@ -75,10 +75,12 @@ epidata library(ggplot2) ggplot(epidata, aes(x = time_value, y = value)) + geom_line() + - labs(title = "Smoothed CLI from Facebook Survey", - subtitle = "US, 2021", - x = "Date", - y = "CLI") + labs( + title = "Smoothed CLI from Facebook Survey", + subtitle = "US, 2021", + x = "Date", + y = "CLI" + ) ``` From 96889540a74b2607d80a6f13695aec0529e6d5f6 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Tue, 12 Sep 2023 11:09:53 -0700 Subject: [PATCH 004/189] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 66b934b4..b3423f1f 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,8 @@ provides real-time access to epidemiological surveillance data for influenza, COVID-19, and other diseases for the USA at various geographical resolutions, both from official government sources such as the [Center for Disease Control -(CDC)](https://www.cdc.gov/datastatistics/index.html) and [Google -Trends](https://cmu-delphi.github.io/delphi-epidata/api/covidcast-signals/google-symptoms.html) +(CDC)](https://www.cdc.gov/datastatistics/index.html), public sources such as [Google +Trends](https://cmu-delphi.github.io/delphi-epidata/api/covidcast-signals/google-symptoms.html), and private partners such as [Facebook](https://delphi.cmu.edu/blog/2020/08/26/covid-19-symptom-surveys-through-facebook/) and [Change Healthcare](https://www.changehealthcare.com/). It is built From 016d2a746b78ae55136885054fb482c6671f7f9a Mon Sep 17 00:00:00 2001 From: Alex Reinhart Date: Fri, 15 Sep 2023 15:16:56 -0400 Subject: [PATCH 005/189] Rename get_auth_key, add set_api_key, document Moves the API key documentation to a central spot that is easy to point users to. Edits the warning message to point here, so we don't repeat the key advice in different places. Expand description of how to set options or environment variables. --- NAMESPACE | 3 +- R/auth.R | 67 ++++++++++++++++++++++------- R/epidatr-package.R | 5 +++ R/request.R | 4 +- _pkgdown.yml | 2 +- man/epidatr-package.Rd | 7 +++ man/get_api_key.Rd | 58 +++++++++++++++++++++++++ man/get_auth_key.Rd | 15 ------- tests/testthat/generate_test_data.R | 2 +- tests/testthat/test-auth.R | 9 ++-- vignettes/epidatr.Rmd | 10 +---- 11 files changed, 133 insertions(+), 49 deletions(-) create mode 100644 man/get_api_key.Rd delete mode 100644 man/get_auth_key.Rd diff --git a/NAMESPACE b/NAMESPACE index 5e0849a0..5a9f2939 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -15,7 +15,7 @@ export(disable_cache) export(epirange) export(fetch) export(fetch_args_list) -export(get_auth_key) +export(get_api_key) export(pub_covid_hosp_facility) export(pub_covid_hosp_facility_lookup) export(pub_covid_hosp_state_timeseries) @@ -44,6 +44,7 @@ export(pvt_norostat) export(pvt_quidel) export(pvt_sensors) export(pvt_twitter) +export(set_api_key) export(set_cache) import(cachem) import(glue) diff --git a/R/auth.R b/R/auth.R index 1dbaaf43..95fcfe70 100644 --- a/R/auth.R +++ b/R/auth.R @@ -1,36 +1,71 @@ -#' Getting the API key +#' Get and set API keys #' -#' @description -#' Get the API key from the environment variable `DELPHI_EPIDATA_KEY` or -#' `getOption("delphi.epidata.key")`. +#' Get and set the API key used to make requests to the Epidata API. Without a +#' key, requests may be subject to rate limits and other limitations. #' -#' @return The API key as a string or "". +#' We recommend you register for an API key. While most endpoints are available +#' without one, there are [limits on API usage for anonymous +#' users](https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html), +#' including a rate limit. If you regularly request large amounts of data, +#' please consider [registering for an API +#' key](https://api.delphi.cmu.edu/epidata/admin/registration_form). #' +#' API keys are strings and can be set in two ways. If the environment variable +#' `DELPHI_EPIDATA_KEY` is set, it will be used automatically. Environment +#' variables can be set either in the shell or by editing your `.Renviron` file, +#' which will ensure the setting applies to all R sessions. See `?Startup` for a +#' description of `Renviron` files and where they can be placed. +#' +#' Alternately, the API key can be set from within a session by using +#' `set_api_key()`, which sets the R option `delphi.epidata.key` using +#' `options()`. If this option is set, it is used in preference to the +#' environment variable, so you may change keys within an R session. R options +#' are not preserved between sessions, so `set_api_key()` must be run every time +#' you open R. Alternately, you can have R set the option at startup by adding +#' it to your `.Rprofile`; see `?Startup` for a description of `Rprofile` files +#' and where they can be placed. +#' +#' Once an API key is set, it is automatically used for all requests made by +#' functions in this package. +#' +#' @return For `get_api_key()`, returns the current API key as a string, or +#' `""` if none is set. +#' +#' @seealso [usethis::edit_r_environ()] to automatically edit the `.Renviron` +#' file; [usethis::edit_r_profile()] to automatically edit the `.Rprofile` +#' file +#' +#' @references Delphi Epidata API Keys documentation. +#' +#' +#' Delphi Epidata API Registration Form. +#' #' @export -get_auth_key <- function() { - key <- Sys.getenv("DELPHI_EPIDATA_KEY", unset = "") +get_api_key <- function() { + key <- getOption("delphi.epidata.key", default = "") if (key != "") { return(key) } - key <- getOption("delphi.epidata.key", default = "") + key <- Sys.getenv("DELPHI_EPIDATA_KEY", unset = "") if (key != "") { return(key) } cli::cli_warn( c( - "No API key found. You will be limited to non-complex queries and encounter rate limits if you proceed. - To avoid this, you can get your key by registering - at https://api.delphi.cmu.edu/epidata/admin/registration_form and then:", - "i" = "set the environment variable DELPHI_EPIDATA_KEY", - "i" = "set the option 'delphi.epidata.key'", - "", - "To save your key for later sessions (and hide it from your code), you can edit your .Renviron file with:", - "i" = "usethis::edit_r_environ()" + "No API key found. You will be limited to non-complex queries and encounter rate limits if you proceed.", + "i" = "See {.help set_api_key} for details on obtaining and setting API keys." ), .frequency = "regularly", .frequency_id = "delphi.epidata.key" ) return("") } + +#' @rdname get_api_key +#' @param key API key to use for future requests +#' @export +set_api_key <- function(key) { + options(delphi.epidata.key = key) +} diff --git a/R/epidatr-package.R b/R/epidatr-package.R index 8d272a30..ad1ed5da 100644 --- a/R/epidatr-package.R +++ b/R/epidatr-package.R @@ -1,3 +1,8 @@ +#' @section Package options: +#' +#' The `delphi.epidata.key` option specifies the API key to be used when making +#' requests to the Epidata API. +#' #' @keywords internal #' @include cache.R "_PACKAGE" diff --git a/R/request.R b/R/request.R index 276df8df..d6fd5ea3 100644 --- a/R/request.R +++ b/R/request.R @@ -29,7 +29,7 @@ do_request <- function(url, params, timeout_seconds = 30) { query = params, terminate_on = c(400, 401, 403, 405, 414, 500), http_headers, - httr::authenticate("epidata", get_auth_key()), + httr::authenticate("epidata", get_api_key()), httr::timeout(timeout_seconds) ) if (res$status_code == 414) { @@ -39,7 +39,7 @@ do_request <- function(url, params, timeout_seconds = 30) { encode = "form", terminate_on = c(400, 401, 403, 405, 414, 500), http_headers, - httr::authenticate("epidata", get_auth_key()) + httr::authenticate("epidata", get_api_key()) ) } res diff --git a/_pkgdown.yml b/_pkgdown.yml index 26cf0d2b..3dd28794 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -36,7 +36,7 @@ reference: - title: Configuration and utilities desc: Set API keys and handle API data types - contents: - - get_auth_key + - get_api_key - avail_endpoints - epirange - timeset diff --git a/man/epidatr-package.Rd b/man/epidatr-package.Rd index b2e49714..9521ea06 100644 --- a/man/epidatr-package.Rd +++ b/man/epidatr-package.Rd @@ -8,6 +8,13 @@ \description{ The Delphi 'Epidata' API provides real-time access to epidemiological surveillance data for influenza, 'COVID-19', and other diseases for the USA at various geographical resolutions, both from official government sources such as the Center for Disease Control (CDC) and Google Trends and private partners such as Facebook and Change 'Healthcare'. It is built and maintained by the Carnegie Mellon University Delphi research group. To cite this API: David C. Farrow, Logan C. Brooks, Aaron 'Rumack', Ryan J. 'Tibshirani', 'Roni' 'Rosenfeld' (2015). Delphi 'Epidata' API. \url{https://github.com/cmu-delphi/delphi-epidata}. } +\section{Package options}{ + + +The \code{delphi.epidata.key} option specifies the API key to be used when making +requests to the Epidata API. +} + \seealso{ Useful links: \itemize{ diff --git a/man/get_api_key.Rd b/man/get_api_key.Rd new file mode 100644 index 00000000..40774c66 --- /dev/null +++ b/man/get_api_key.Rd @@ -0,0 +1,58 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/auth.R +\name{get_api_key} +\alias{get_api_key} +\alias{set_api_key} +\title{Get and set API keys} +\usage{ +get_api_key() + +set_api_key(key) +} +\arguments{ +\item{key}{API key to use for future requests} +} +\value{ +For \code{get_api_key()}, returns the current API key as a string, or +\code{""} if none is set. +} +\description{ +Get and set the API key used to make requests to the Epidata API. Without a +key, requests may be subject to rate limits and other limitations. +} +\details{ +We recommend you register for an API key. While most endpoints are available +without one, there are \href{https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html}{limits on API usage for anonymous users}, +including a rate limit. If you regularly request large amounts of data, +please consider \href{https://api.delphi.cmu.edu/epidata/admin/registration_form}{registering for an API key}. + +API keys are strings and can be set in two ways. If the environment variable +\code{DELPHI_EPIDATA_KEY} is set, it will be used automatically. Environment +variables can be set either in the shell or by editing your \code{.Renviron} file, +which will ensure the setting applies to all R sessions. See \code{?Startup} for a +description of \code{Renviron} files and where they can be placed. + +Alternately, the API key can be set from within a session by using +\code{set_api_key()}, which sets the R option \code{delphi.epidata.key} using +\code{options()}. If this option is set, it is used in preference to the +environment variable, so you may change keys within an R session. R options +are not preserved between sessions, so \code{set_api_key()} must be run every time +you open R. Alternately, you can have R set the option at startup by adding +it to your \code{.Rprofile}; see \code{?Startup} for a description of \code{Rprofile} files +and where they can be placed. + +Once an API key is set, it is automatically used for all requests made by +functions in this package. +} +\references{ +Delphi Epidata API Keys documentation. +\url{https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html} + +Delphi Epidata API Registration Form. +\url{https://api.delphi.cmu.edu/epidata/admin/registration_form} +} +\seealso{ +\code{\link[usethis:edit]{usethis::edit_r_environ()}} to automatically edit the \code{.Renviron} +file; \code{\link[usethis:edit]{usethis::edit_r_profile()}} to automatically edit the \code{.Rprofile} +file +} diff --git a/man/get_auth_key.Rd b/man/get_auth_key.Rd deleted file mode 100644 index 65808781..00000000 --- a/man/get_auth_key.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/auth.R -\name{get_auth_key} -\alias{get_auth_key} -\title{Getting the API key} -\usage{ -get_auth_key() -} -\value{ -The API key as a string or "". -} -\description{ -Get the API key from the environment variable \code{DELPHI_EPIDATA_KEY} or -\code{getOption("delphi.epidata.key")}. -} diff --git a/tests/testthat/generate_test_data.R b/tests/testthat/generate_test_data.R index 95032fba..1aac8393 100644 --- a/tests/testthat/generate_test_data.R +++ b/tests/testthat/generate_test_data.R @@ -33,5 +33,5 @@ response <- httr::RETRY("GET", query = list(), terminate_on = c(400, 401, 403, 405, 414, 500), http_headers, - httr::authenticate("epidata", get_auth_key()) + httr::authenticate("epidata", get_api_key()) ) %>% readr::write_rds(testthat::test_path("data/test-do_request-httpbin.rds")) diff --git a/tests/testthat/test-auth.R b/tests/testthat/test-auth.R index 3aa07cd3..9d9ab391 100644 --- a/tests/testthat/test-auth.R +++ b/tests/testthat/test-auth.R @@ -1,15 +1,14 @@ -test_that("get_auth_key", { +test_that("get_api_key", { withr::with_envvar(c(DELPHI_EPIDATA_KEY = "epidata_key_from_envvar"), { withr::with_options(list(delphi.epidata.key = "epidata_key_from_options"), { - # envvar takes precedence over option (characterization test; we don't - # guarantee this in docs): - expect_identical(get_auth_key(), "epidata_key_from_envvar") + # option takes precedence over environment variable + expect_identical(get_api_key(), "epidata_key_from_options") }) }) withr::with_envvar(c(DELPHI_EPIDATA_KEY = NA_character_), { withr::with_options(list(delphi.epidata.key = "epidata_key_from_options"), { # option by itself works: - expect_identical(get_auth_key(), "epidata_key_from_options") + expect_identical(get_api_key(), "epidata_key_from_options") }) }) }) diff --git a/vignettes/epidatr.Rmd b/vignettes/epidatr.Rmd index a2913b38..f3120468 100644 --- a/vignettes/epidatr.Rmd +++ b/vignettes/epidatr.Rmd @@ -23,14 +23,8 @@ regions. We recommend you register for an API key. While most endpoints are available without one, there are [limits on API usage for anonymous users](https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html), including -a rate limit. If you regularly request large amounts of data, please consider -[registering for an API -key](https://api.delphi.cmu.edu/epidata/admin/registration_form). You can then -specify this key by either - -- setting the environment variable `DELPHI_EPIDATA_KEY`, such as by editing your - `.Renviron` file -- setting the option `delphi.epidata.key` using `options()` +a rate limit. See `set_api_key()` for details on how to obtain an API key and +set this package to use it. ## Basic Usage From 9e971e49e4f182b2bc712ec282c49633c0ab1f2c Mon Sep 17 00:00:00 2001 From: Alex Reinhart Date: Fri, 15 Sep 2023 15:50:32 -0400 Subject: [PATCH 006/189] Update README explanation of how to get keys --- README.Rmd | 14 ++++++-------- README.md | 18 ++++++++---------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/README.Rmd b/README.Rmd index 821c6690..0233fc8a 100644 --- a/README.Rmd +++ b/README.Rmd @@ -79,14 +79,12 @@ The Delphi API requires a (free) API key for full functionality. To generate your key, register for a pseudo-anonymous account [here](https://api.delphi.cmu.edu/epidata/admin/registration_form) and see more discussion on the [general API -website](https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html). The -`epidatr` client will automatically look for this key in the R option -`delphi.epidata.key` or in the environment variable -`DELPHI_EPIDATA_KEY`. We recommend storing your key in `.Renviron` file, which R -will read by default. - -Note that for the time being, the private endpoints (i.e. those prefixed with -`pvt`) will require a separate key that needs to be passed as an argument. +website](https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html). See the +`set_api_key()` function documentation for details on how to use your API key. + +Note that the private endpoints (i.e. those prefixed with `pvt_`) require a +separate key that needs to be passed as an argument. These endpoints require +specific data use agreements to access. [mit-image]: https://img.shields.io/badge/License-MIT-yellow.svg [mit-url]: https://opensource.org/license/mit/ diff --git a/README.md b/README.md index b3423f1f..f04b7be9 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,8 @@ provides real-time access to epidemiological surveillance data for influenza, COVID-19, and other diseases for the USA at various geographical resolutions, both from official government sources such as the [Center for Disease Control -(CDC)](https://www.cdc.gov/datastatistics/index.html), public sources such as [Google -Trends](https://cmu-delphi.github.io/delphi-epidata/api/covidcast-signals/google-symptoms.html), +(CDC)](https://www.cdc.gov/datastatistics/index.html) and [Google +Trends](https://cmu-delphi.github.io/delphi-epidata/api/covidcast-signals/google-symptoms.html) and private partners such as [Facebook](https://delphi.cmu.edu/blog/2020/08/26/covid-19-symptom-surveys-through-facebook/) and [Change Healthcare](https://www.changehealthcare.com/). It is built @@ -104,14 +104,12 @@ generate your key, register for a pseudo-anonymous account [here](https://api.delphi.cmu.edu/epidata/admin/registration_form) and see more discussion on the [general API website](https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html). -The `epidatr` client will automatically look for this key in the R -option `delphi.epidata.key` or in the environment variable -`DELPHI_EPIDATA_KEY`. We recommend storing your key in `.Renviron` file, -which R will read by default. - -Note that for the time being, the private endpoints (i.e. those prefixed -with `pvt`) will require a separate key that needs to be passed as an -argument. +See the `set_api_key()` function documentation for details on how to use +your API key. + +Note that the private endpoints (i.e. those prefixed with `pvt_`) +require a separate key that needs to be passed as an argument. These +endpoints require specific data use agreements to access. ## Get updates From 94024b11ede93c6185131ed8e63e23a9824827cf Mon Sep 17 00:00:00 2001 From: capnrefsmmat Date: Fri, 15 Sep 2023 19:52:37 +0000 Subject: [PATCH 007/189] docs: document (GHA) --- man/get_api_key.Rd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/man/get_api_key.Rd b/man/get_api_key.Rd index 40774c66..18f7ae65 100644 --- a/man/get_api_key.Rd +++ b/man/get_api_key.Rd @@ -52,7 +52,7 @@ Delphi Epidata API Registration Form. \url{https://api.delphi.cmu.edu/epidata/admin/registration_form} } \seealso{ -\code{\link[usethis:edit]{usethis::edit_r_environ()}} to automatically edit the \code{.Renviron} -file; \code{\link[usethis:edit]{usethis::edit_r_profile()}} to automatically edit the \code{.Rprofile} +\code{\link[usethis:edit_r_environ]{usethis::edit_r_environ()}} to automatically edit the \code{.Renviron} +file; \code{\link[usethis:edit_r_profile]{usethis::edit_r_profile()}} to automatically edit the \code{.Rprofile} file } From f7976e4fbdab130a25cb421297bb17ed87ec9c6a Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Fri, 15 Sep 2023 16:56:04 -0700 Subject: [PATCH 008/189] ci: remove release helper --- .github/workflows/create_release.yml | 43 ---------------- .github/workflows/release_helper.yml | 76 ---------------------------- 2 files changed, 119 deletions(-) delete mode 100644 .github/workflows/create_release.yml delete mode 100644 .github/workflows/release_helper.yml diff --git a/.github/workflows/create_release.yml b/.github/workflows/create_release.yml deleted file mode 100644 index 2d82e6fd..00000000 --- a/.github/workflows/create_release.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: Create Release -on: - workflow_dispatch: - inputs: - versionName: - description: "Semantic Version Number (i.e., 5.5.0 or patch, minor, major, prepatch, preminor, premajor, prerelease)" - required: true - default: patch -jobs: - create_release: - runs-on: ubuntu-latest - steps: - - name: Check out code - uses: actions/checkout@v2 - with: - ref: main - ssh-key: ${{ secrets.CMU_DELPHI_DEPLOY_MACHINE_SSH }} - - name: Reset main branch - run: | - git fetch origin dev:dev - git reset --hard dev - - name: Set up Python 3.8 - uses: actions/setup-python@v2 - with: - python-version: 3.8 - - name: Change version number - id: version - run: | - python -m pip install bump2version - echo -n "::set-output name=next_tag::" - bump2version --list ${{ github.event.inputs.versionName }} | grep new_version | sed -r s,"^.*=",, - - name: Create pull request into main - uses: peter-evans/create-pull-request@v3 - with: - branch: release/${{ steps.version.outputs.next_tag }} - commit-message: "chore: release ${{ steps.version.outputs.next_tag }}" - base: main - title: Release ${{ steps.version.outputs.next_tag }} - labels: chore - reviewers: krivard - assignees: krivard - body: | - Releasing ${{ steps.version.outputs.next_tag }}. diff --git a/.github/workflows/release_helper.yml b/.github/workflows/release_helper.yml deleted file mode 100644 index 90e288ec..00000000 --- a/.github/workflows/release_helper.yml +++ /dev/null @@ -1,76 +0,0 @@ -name: Release Helper -on: - push: - branches: - - main - -jobs: - correct_repository: - runs-on: ubuntu-latest - steps: - - name: fail on fork - if: github.repository_owner != 'cmu-delphi' - run: exit 1 - - create_release: - needs: correct_repository - runs-on: ubuntu-latest - steps: - - name: Check out code - uses: actions/checkout@v2 - - name: Set up Python 3.8 - uses: actions/setup-python@v2 - with: - python-version: 3.8 - - name: Extract version - id: extract_version - run: | - python -m pip install bump2version - echo -n "::set-output name=version::" - bump2version --dry-run --list patch | grep ^current_version | sed -r s,"^.*=",, - - name: Create Release - id: create_release - uses: release-drafter/release-drafter@v5 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - version: ${{ steps.extract_version.outputs.version }} - publish: true - outputs: - version: ${{ steps.extract_version.outputs.version }} - upload_url: ${{ steps.create_release.outputs.upload_url }} - tag_name: ${{ steps.create_release.outputs.tag_name }} - - release_package: - needs: create_release - runs-on: ubuntu-latest - steps: - - name: Check out code - uses: actions/checkout@v2 - # TODO - - sync_dev: - needs: correct_repository - runs-on: ubuntu-latest - steps: - - name: Check out code - uses: actions/checkout@v2 - with: - ref: dev - ssh-key: ${{ secrets.CMU_DELPHI_DEPLOY_MACHINE_SSH }} - - name: Reset dev branch - run: | - git fetch origin main:main - git reset --hard main - - name: Create pull request into dev - uses: peter-evans/create-pull-request@v3 - with: - branch: bot/sync-main-dev - commit-message: "chore: sync main-dev" - base: dev - title: "chore: sync main->dev" - labels: chore - reviewers: dshemetov - assignees: dshemetov - body: | - Syncing Main->Dev. From a4a6da0f627d5432bb6fdfa42c2cbe6bfce6dd06 Mon Sep 17 00:00:00 2001 From: dsweber2 Date: Fri, 15 Sep 2023 17:07:44 -0700 Subject: [PATCH 009/189] fix+chore: version bump, fix #177 --- .bumpversion.cfg | 2 +- DESCRIPTION | 2 +- NEWS.md | 6 ++++++ R/constants.R | 2 +- R/request.R | 47 +++++++++++++++++++++++++++++++++------------- man/get_api_key.Rd | 4 ++-- 6 files changed, 45 insertions(+), 18 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index c4459027..23851e7c 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 1.0.0 +current_version = 1.1.0 commit = False tag = False diff --git a/DESCRIPTION b/DESCRIPTION index 6f00eb30..7f94c34a 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: epidatr Type: Package Title: Client for Delphi's 'Epidata' API -Version: 1.0.0 +Version: 1.1.0 Date: 2023-09-11 Authors@R: c( diff --git a/NEWS.md b/NEWS.md index 9dd1990e..661b3340 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,9 @@ +# epidatr 1.1.0 +- renamed the mostly internal `get_auth_key` to `get_api_key` +- added `set_api_key` to more easily set the option +- various CRAN submission related doc-fixes +- fixed some errors from passing "" as a key + # epidatr 1.0.0 - Add `set_cache` and other caching functions. diff --git a/R/constants.R b/R/constants.R index b00768ca..1fbc4add 100644 --- a/R/constants.R +++ b/R/constants.R @@ -1,3 +1,3 @@ -version <- "1.0.0" +version <- "1.1.0" http_headers <- httr::add_headers("User-Agent" = paste0("epidatr/", version), "Accept-Encoding" = "gzip") global_base_url <- "https://api.delphi.cmu.edu/epidata/" diff --git a/R/request.R b/R/request.R index d6fd5ea3..1e3be1b4 100644 --- a/R/request.R +++ b/R/request.R @@ -24,23 +24,44 @@ join_url <- function(url, endpoint) { #' @keywords internal do_request <- function(url, params, timeout_seconds = 30) { # don't retry in case of certain status codes - res <- httr::RETRY("GET", - url = url, - query = params, - terminate_on = c(400, 401, 403, 405, 414, 500), - http_headers, - httr::authenticate("epidata", get_api_key()), - httr::timeout(timeout_seconds) - ) - if (res$status_code == 414) { - res <- httr::RETRY("POST", + key <- get_api_key() + if (key != "") { + res <- httr::RETRY("GET", url = url, - body = params, - encode = "form", + query = params, terminate_on = c(400, 401, 403, 405, 414, 500), http_headers, - httr::authenticate("epidata", get_api_key()) + httr::authenticate("epidata", get_api_key()), + httr::timeout(timeout_seconds) ) + } else { + res <- httr::RETRY("GET", + url = url, + query = params, + terminate_on = c(400, 401, 403, 405, 414, 500), + http_headers, + httr::timeout(timeout_seconds) + ) + } + if (res$status_code == 414) { + if (key != "") { + res <- httr::RETRY("POST", + url = url, + body = params, + encode = "form", + terminate_on = c(400, 401, 403, 405, 414, 500), + http_headers, + httr::authenticate("epidata", get_api_key()) + ) + } else { + res <- httr::RETRY("POST", + url = url, + body = params, + encode = "form", + terminate_on = c(400, 401, 403, 405, 414, 500), + http_headers + ) + } } res } diff --git a/man/get_api_key.Rd b/man/get_api_key.Rd index 18f7ae65..40774c66 100644 --- a/man/get_api_key.Rd +++ b/man/get_api_key.Rd @@ -52,7 +52,7 @@ Delphi Epidata API Registration Form. \url{https://api.delphi.cmu.edu/epidata/admin/registration_form} } \seealso{ -\code{\link[usethis:edit_r_environ]{usethis::edit_r_environ()}} to automatically edit the \code{.Renviron} -file; \code{\link[usethis:edit_r_profile]{usethis::edit_r_profile()}} to automatically edit the \code{.Rprofile} +\code{\link[usethis:edit]{usethis::edit_r_environ()}} to automatically edit the \code{.Renviron} +file; \code{\link[usethis:edit]{usethis::edit_r_profile()}} to automatically edit the \code{.Rprofile} file } From afd94adb64b2ee590973785e3f6ad190550efca6 Mon Sep 17 00:00:00 2001 From: dsweber2 Date: Sat, 16 Sep 2023 00:14:03 +0000 Subject: [PATCH 010/189] docs: document (GHA) --- man/get_api_key.Rd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/man/get_api_key.Rd b/man/get_api_key.Rd index 40774c66..18f7ae65 100644 --- a/man/get_api_key.Rd +++ b/man/get_api_key.Rd @@ -52,7 +52,7 @@ Delphi Epidata API Registration Form. \url{https://api.delphi.cmu.edu/epidata/admin/registration_form} } \seealso{ -\code{\link[usethis:edit]{usethis::edit_r_environ()}} to automatically edit the \code{.Renviron} -file; \code{\link[usethis:edit]{usethis::edit_r_profile()}} to automatically edit the \code{.Rprofile} +\code{\link[usethis:edit_r_environ]{usethis::edit_r_environ()}} to automatically edit the \code{.Renviron} +file; \code{\link[usethis:edit_r_profile]{usethis::edit_r_profile()}} to automatically edit the \code{.Rprofile} file } From fe34d29c68140dda36a00a94d72e26f56483866a Mon Sep 17 00:00:00 2001 From: David Weber Date: Thu, 21 Sep 2023 10:34:36 -0700 Subject: [PATCH 011/189] docs: readme link to package and CRAN --- README.md | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f04b7be9..d679afa8 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,9 @@ Actions](https://github.com/cmu-delphi/epidatr/workflows/ci/badge.svg)](https:// [![codecov](https://codecov.io/gh/dsweber2/epidatr/branch/dev/graph/badge.svg?token=jVHL9eHZNZ)](https://app.codecov.io/gh/dsweber2/epidatr) -The [Delphi Epidata API](https://cmu-delphi.github.io/delphi-epidata/) +The [Delphi Epidatr package](https://cmu-delphi.github.io/epidatr/) is +an R frontend for the +[Delphi Epidata API](https://cmu-delphi.github.io/delphi-epidata/), which provides real-time access to epidemiological surveillance data for influenza, COVID-19, and other diseases for the USA at various geographical resolutions, both from official government sources such as @@ -37,6 +39,8 @@ processing ([epiprocess](https://github.com/cmu-delphi/epiprocess)) and modeling ([epipredict](https://github.com/cmu-delphi/epipredict)). ## Usage +You can find detailed docs here: +[https://cmu-delphi.github.io/epidatr/](https://cmu-delphi.github.io/epidatr/) ``` r library(epidatr) @@ -86,17 +90,23 @@ ggplot(epidata, aes(x = time_value, y = value)) + ## Installation +You can install the stable version of this package from CRAN: -Install from GitHub: +``` r +install.packages("epidatr") +pak::pkg_install("epidatr") +renv::install("epidatr") +``` + +Or if you want the development version, install from GitHub: ``` r # Install the dev version using `pak` or `remotes` pak::pkg_install("cmu-delphi/epidatr") +renv::install("cmu-delphi/epidatr") remotes::install_github("cmu-delphi/epidatr") ``` -CRAN version coming soon. - ### API Keys The Delphi API requires a (free) API key for full functionality. To From 265fbe33d6cfb46342e7e0121227e785c0abf9ea Mon Sep 17 00:00:00 2001 From: dsweber2 Date: Thu, 21 Sep 2023 14:18:38 -0700 Subject: [PATCH 012/189] docs: render readme changes --- README.Rmd | 19 +++++++++---- README.md | 36 ++++++++++++++----------- man/figures/README-fb-cli-signal-1.png | Bin 33909 -> 13135 bytes man/get_api_key.Rd | 4 +-- 4 files changed, 36 insertions(+), 23 deletions(-) diff --git a/README.Rmd b/README.Rmd index 0233fc8a..ce620d26 100644 --- a/README.Rmd +++ b/README.Rmd @@ -23,13 +23,13 @@ ggplot2::theme_set(ggplot2::theme_bw()) - -The [Delphi Epidata API](https://cmu-delphi.github.io/delphi-epidata/) provides real-time access to epidemiological surveillance data for influenza, COVID-19, and other diseases for the USA at various geographical resolutions, both from official government sources such as the [Center for Disease Control (CDC)](https://www.cdc.gov/datastatistics/index.html) and [Google Trends](https://cmu-delphi.github.io/delphi-epidata/api/covidcast-signals/google-symptoms.html) and private partners such as [Facebook](https://delphi.cmu.edu/blog/2020/08/26/covid-19-symptom-surveys-through-facebook/) and [Change Healthcare](https://www.changehealthcare.com/). It is built and maintained by the Carnegie Mellon University [Delphi research group](https://delphi.cmu.edu/). +The [Delphi Epidatr package](https://cmu-delphi.github.io/epidatr/) is an R front-end for the [Delphi Epidata API](https://cmu-delphi.github.io/delphi-epidata/), which provides real-time access to epidemiological surveillance data for influenza, COVID-19, and other diseases for the USA at various geographical resolutions, both from official government sources such as the [Center for Disease Control (CDC)](https://www.cdc.gov/datastatistics/index.html) and [Google Trends](https://cmu-delphi.github.io/delphi-epidata/api/covidcast-signals/google-symptoms.html) and private partners such as [Facebook](https://delphi.cmu.edu/blog/2020/08/26/covid-19-symptom-surveys-through-facebook/) and [Change Healthcare](https://www.changehealthcare.com/). It is built and maintained by the Carnegie Mellon University [Delphi research group](https://delphi.cmu.edu/). This package is designed to streamline the downloading and usage of data from the [Delphi Epidata API](https://cmu-delphi.github.io/delphi-epidata/). It provides a simple R interface to the API, including functions for downloading data, parsing the results, and converting the data into a tidy format. The API stores a historical record of all data, including corrections and updates, which is particularly useful for accurately backtesting forecasting models. We also provide packages for downstream data processing ([epiprocess](https://github.com/cmu-delphi/epiprocess)) and modeling ([epipredict](https://github.com/cmu-delphi/epipredict)). ## Usage +You can find detailed docs here: ```{r} library(epidatr) @@ -62,16 +62,25 @@ ggplot(epidata, aes(x = time_value, y = value)) + ## Installation +You can install the stable version of this package from CRAN: + +``` r +```R +install.packages("epidatr") +pak::pkg_install("epidatr") +renv::install("epidatr") +``` +``` -Install from GitHub: +Or if you want the development version, install from GitHub: +```R ```R # Install the dev version using `pak` or `remotes` pak::pkg_install("cmu-delphi/epidatr") remotes::install_github("cmu-delphi/epidatr") ``` - -CRAN version coming soon. +``` ### API Keys diff --git a/README.md b/README.md index d679afa8..57483d13 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ Actions](https://github.com/cmu-delphi/epidatr/workflows/ci/badge.svg)](https:// [![codecov](https://codecov.io/gh/dsweber2/epidatr/branch/dev/graph/badge.svg?token=jVHL9eHZNZ)](https://app.codecov.io/gh/dsweber2/epidatr) -The [Delphi Epidatr package](https://cmu-delphi.github.io/epidatr/) is -an R frontend for the -[Delphi Epidata API](https://cmu-delphi.github.io/delphi-epidata/), which -provides real-time access to epidemiological surveillance data for -influenza, COVID-19, and other diseases for the USA at various -geographical resolutions, both from official government sources such as -the [Center for Disease Control +The [Delphi Epidatr package](https://cmu-delphi.github.io/epidatr/) is +an R front-end for the [Delphi Epidata +API](https://cmu-delphi.github.io/delphi-epidata/), which provides +real-time access to epidemiological surveillance data for influenza, +COVID-19, and other diseases for the USA at various geographical +resolutions, both from official government sources such as the [Center +for Disease Control (CDC)](https://www.cdc.gov/datastatistics/index.html) and [Google Trends](https://cmu-delphi.github.io/delphi-epidata/api/covidcast-signals/google-symptoms.html) and private partners such as @@ -39,8 +39,8 @@ processing ([epiprocess](https://github.com/cmu-delphi/epiprocess)) and modeling ([epipredict](https://github.com/cmu-delphi/epipredict)). ## Usage -You can find detailed docs here: -[https://cmu-delphi.github.io/epidatr/](https://cmu-delphi.github.io/epidatr/) + +You can find detailed docs here: ``` r library(epidatr) @@ -90,22 +90,26 @@ ggplot(epidata, aes(x = time_value, y = value)) + ## Installation + You can install the stable version of this package from CRAN: ``` r +```R install.packages("epidatr") pak::pkg_install("epidatr") renv::install("epidatr") ``` -Or if you want the development version, install from GitHub: -``` r -# Install the dev version using `pak` or `remotes` -pak::pkg_install("cmu-delphi/epidatr") -renv::install("cmu-delphi/epidatr") -remotes::install_github("cmu-delphi/epidatr") -``` + Or if you want the development version, install from GitHub: + + ```R + ```R + # Install the dev version using `pak` or `remotes` + pak::pkg_install("cmu-delphi/epidatr") + remotes::install_github("cmu-delphi/epidatr") + +\`\`\` ### API Keys diff --git a/man/figures/README-fb-cli-signal-1.png b/man/figures/README-fb-cli-signal-1.png index 5a76514d301c351006ccbe139a1b544cd1b6f40a..1c05ba7be3ea3eb0266bceefec4d3079a245395d 100644 GIT binary patch literal 13135 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 Date: Thu, 21 Sep 2023 18:25:55 -0700 Subject: [PATCH 013/189] fix: doubled code block tags in README --- README.Rmd | 9 +++------ README.md | 17 +++++++---------- man/figures/README-fb-cli-signal-1.png | Bin 13135 -> 13023 bytes 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/README.Rmd b/README.Rmd index ce620d26..f109948b 100644 --- a/README.Rmd +++ b/README.Rmd @@ -16,19 +16,18 @@ ggplot2::theme_set(ggplot2::theme_bw()) # Delphi Epidata R client - [![License: MIT][mit-image]][mit-url] [![Github Actions][github-actions-image]][github-actions-url] [![codecov](https://codecov.io/gh/dsweber2/epidatr/branch/dev/graph/badge.svg?token=jVHL9eHZNZ)](https://app.codecov.io/gh/dsweber2/epidatr) - The [Delphi Epidatr package](https://cmu-delphi.github.io/epidatr/) is an R front-end for the [Delphi Epidata API](https://cmu-delphi.github.io/delphi-epidata/), which provides real-time access to epidemiological surveillance data for influenza, COVID-19, and other diseases for the USA at various geographical resolutions, both from official government sources such as the [Center for Disease Control (CDC)](https://www.cdc.gov/datastatistics/index.html) and [Google Trends](https://cmu-delphi.github.io/delphi-epidata/api/covidcast-signals/google-symptoms.html) and private partners such as [Facebook](https://delphi.cmu.edu/blog/2020/08/26/covid-19-symptom-surveys-through-facebook/) and [Change Healthcare](https://www.changehealthcare.com/). It is built and maintained by the Carnegie Mellon University [Delphi research group](https://delphi.cmu.edu/). This package is designed to streamline the downloading and usage of data from the [Delphi Epidata API](https://cmu-delphi.github.io/delphi-epidata/). It provides a simple R interface to the API, including functions for downloading data, parsing the results, and converting the data into a tidy format. The API stores a historical record of all data, including corrections and updates, which is particularly useful for accurately backtesting forecasting models. We also provide packages for downstream data processing ([epiprocess](https://github.com/cmu-delphi/epiprocess)) and modeling ([epipredict](https://github.com/cmu-delphi/epipredict)). ## Usage + You can find detailed docs here: ```{r} @@ -62,24 +61,22 @@ ggplot(epidata, aes(x = time_value, y = value)) + ## Installation + You can install the stable version of this package from CRAN: -``` r ```R install.packages("epidatr") pak::pkg_install("epidatr") renv::install("epidatr") ``` -``` Or if you want the development version, install from GitHub: -```R ```R # Install the dev version using `pak` or `remotes` pak::pkg_install("cmu-delphi/epidatr") remotes::install_github("cmu-delphi/epidatr") -``` +renv::install("cmu-delphi/epidatr") ``` ### API Keys diff --git a/README.md b/README.md index 57483d13..96a846f5 100644 --- a/README.md +++ b/README.md @@ -94,22 +94,19 @@ ggplot(epidata, aes(x = time_value, y = value)) + You can install the stable version of this package from CRAN: ``` r -```R install.packages("epidatr") pak::pkg_install("epidatr") renv::install("epidatr") ``` +Or if you want the development version, install from GitHub: - Or if you want the development version, install from GitHub: - - ```R - ```R - # Install the dev version using `pak` or `remotes` - pak::pkg_install("cmu-delphi/epidatr") - remotes::install_github("cmu-delphi/epidatr") - -\`\`\` +``` r +# Install the dev version using `pak` or `remotes` +pak::pkg_install("cmu-delphi/epidatr") +remotes::install_github("cmu-delphi/epidatr") +renv::install("cmu-delphi/epidatr") +``` ### API Keys diff --git a/man/figures/README-fb-cli-signal-1.png b/man/figures/README-fb-cli-signal-1.png index 1c05ba7be3ea3eb0266bceefec4d3079a245395d..21c040f1096a63e995711e91757af88fc6f0a54d 100644 GIT binary patch literal 13023 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 Date: Fri, 29 Sep 2023 15:59:25 -0700 Subject: [PATCH 014/189] fix: cache size integer overflow --- R/cache.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/cache.R b/R/cache.R index dda3d15f..9ff12c3d 100644 --- a/R/cache.R +++ b/R/cache.R @@ -163,7 +163,7 @@ set_cache <- function(cache_dir = NULL, } else if (cache_exists) { cache_environ$epidatr_cache <- cachem::cache_disk( dir = cache_dir, - max_size = as.integer(max_size * 1024^2), + max_size = max_size * 1024^2, max_age = days * 24 * 60 * 60, logfile = file.path(cache_dir, logfile) ) From a7d9007eba4e6169ce940e275002ed65427e36da Mon Sep 17 00:00:00 2001 From: dshemetov Date: Fri, 29 Sep 2023 23:01:28 +0000 Subject: [PATCH 015/189] docs: document (GHA) --- man/get_api_key.Rd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/man/get_api_key.Rd b/man/get_api_key.Rd index 40774c66..18f7ae65 100644 --- a/man/get_api_key.Rd +++ b/man/get_api_key.Rd @@ -52,7 +52,7 @@ Delphi Epidata API Registration Form. \url{https://api.delphi.cmu.edu/epidata/admin/registration_form} } \seealso{ -\code{\link[usethis:edit]{usethis::edit_r_environ()}} to automatically edit the \code{.Renviron} -file; \code{\link[usethis:edit]{usethis::edit_r_profile()}} to automatically edit the \code{.Rprofile} +\code{\link[usethis:edit_r_environ]{usethis::edit_r_environ()}} to automatically edit the \code{.Renviron} +file; \code{\link[usethis:edit_r_profile]{usethis::edit_r_profile()}} to automatically edit the \code{.Rprofile} file } From f2c1dcbdbdf38e0e9e8dc8e91c9cdd51cde9c5f5 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Fri, 29 Sep 2023 18:18:42 -0700 Subject: [PATCH 016/189] lint: update lintr --- .lintr | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.lintr b/.lintr index c0bfc243..c7c90554 100644 --- a/.lintr +++ b/.lintr @@ -3,3 +3,7 @@ linters: linters_with_defaults( cyclocomp_linter = NULL, object_length_linter(length = 40L) ) +exclusions: list( + "renv", + "venv" + ) From 19ac3bfdc91b3092871f5881aefe9046af5fbd85 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Fri, 29 Sep 2023 19:05:20 -0700 Subject: [PATCH 017/189] style: use glue for line-wrapping in cache warnings --- R/cache.R | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/R/cache.R b/R/cache.R index 9ff12c3d..de28b868 100644 --- a/R/cache.R +++ b/R/cache.R @@ -252,23 +252,20 @@ cache_epidata_call <- function(epidata_call, fetch_args = fetch_args_list()) { if (as_of_recent || issues_recent) { cli::cli_warn( c( - "using cached results with `as_of` within the past week (or the future!).", - "This will likely result in an invalid cache. Consider\n", - "1. disabling the cache for this session with `disable_cache` or permanently with environmental ", - "variable `EPIDATR_USE_CACHE=FALSE`\n", - "2. setting `EPIDATR_CACHE_MAX_AGE_DAYS={Sys.getenv('EPIDATR_CACHE_MAX_AGE_DAYS', unset = 1)}`", - " to e.g. `3/24` (3 hours)." - ), - .frequency = "regularly", - .frequency_id = "cache timing issues", - class = "cache_recent_data" + "Using cached results with `as_of` within the past week (or the future!). + This will likely result in an invalid cache. Consider", + "i" = "disabling the cache for this session with `disable_cache` or + permanently with environmental variable `EPIDATR_USE_CACHE=FALSE`", + "i" = "setting `EPIDATR_CACHE_MAX_AGE_DAYS={Sys.getenv('EPIDATR_CACHE_MAX_AGE_DAYS + ', unset = 1)}` to e.g. `3/24` (3 hours)." + ) ) } if (!is.key_missing(cached)) { cli::cli_warn( c( - "loading from the cache at {cache_environ$epidatr_cache$info()$dir}; ", - "see {cache_environ$epidatr_cache$info()$logfile} for more details." + "Loading from the cache at {cache_environ$epidatr_cache$info()$dir}; + see {cache_environ$epidatr_cache$info()$logfile} for more details." ), .frequency = "regularly", .frequency_id = "using the cache", @@ -277,7 +274,6 @@ cache_epidata_call <- function(epidata_call, fetch_args = fetch_args_list()) { return(cached[[1]]) } } - 'which was saved on {format(cached[[2]],"%A %B %d, %Y")}, which took {round(cached[[3]][[3]], digits=5)} seconds.' # need to actually get the data, since its either not in the cache or we're not caching runtime <- system.time(if (epidata_call$only_supports_classic) { fetched <- fetch_classic(epidata_call, fetch_args) From c839ee0b9226bfa10cdae093b81a98e1950feb80 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Fri, 29 Sep 2023 19:06:42 -0700 Subject: [PATCH 018/189] fix: bring back warning metadata --- R/cache.R | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/R/cache.R b/R/cache.R index de28b868..cddd3919 100644 --- a/R/cache.R +++ b/R/cache.R @@ -258,7 +258,10 @@ cache_epidata_call <- function(epidata_call, fetch_args = fetch_args_list()) { permanently with environmental variable `EPIDATR_USE_CACHE=FALSE`", "i" = "setting `EPIDATR_CACHE_MAX_AGE_DAYS={Sys.getenv('EPIDATR_CACHE_MAX_AGE_DAYS ', unset = 1)}` to e.g. `3/24` (3 hours)." - ) + ), + .frequency = "regularly", + .frequency_id = "cache timing issues", + class = "cache_recent_data" ) } if (!is.key_missing(cached)) { From 9aad3d4a76128aadcee56fc3d69f22c80e829847 Mon Sep 17 00:00:00 2001 From: dsweber2 Date: Fri, 6 Oct 2023 15:07:43 -0700 Subject: [PATCH 019/189] fix: actual license details --- .Rbuildignore | 1 + LICENSE | 2 +- LICENSE.md | 21 +++++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 LICENSE.md diff --git a/.Rbuildignore b/.Rbuildignore index 5da1eff9..9815dfff 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -22,3 +22,4 @@ ^.env$ ^README\.Rmd$ ^CRAN-SUBMISSION$ +^LICENSE\.md$ diff --git a/LICENSE b/LICENSE index c90c919a..94c71f45 100644 --- a/LICENSE +++ b/LICENSE @@ -1,2 +1,2 @@ YEAR: 2023 -COPYRIGHT HOLDER: Logan Brooks, Ryan Tibshirani +COPYRIGHT HOLDER: epidatr authors diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 00000000..90c4cc71 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2023 epidatr authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 3fb33808efe08889130bdd19c7d0a6e5ad2fd88b Mon Sep 17 00:00:00 2001 From: dsweber2 Date: Fri, 13 Oct 2023 14:27:27 -0700 Subject: [PATCH 020/189] fix: order of args in `clear_cache` positional bugs --- R/cache.R | 2 +- man/clear_cache.Rd | 8 ++++---- man/get_api_key.Rd | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/R/cache.R b/R/cache.R index cddd3919..d544d760 100644 --- a/R/cache.R +++ b/R/cache.R @@ -185,7 +185,7 @@ set_cache <- function(cache_dir = NULL, #' [`disable_cache`] to only disable without deleting, and [`cache_info`] #' @export #' @import cachem -clear_cache <- function(disable = FALSE, ...) { +clear_cache <- function(..., disable = FALSE) { if (any(!is.na(cache_environ$epidatr_cache))) { cache_environ$epidatr_cache$destroy() } diff --git a/man/clear_cache.Rd b/man/clear_cache.Rd index c377c612..f53148ad 100644 --- a/man/clear_cache.Rd +++ b/man/clear_cache.Rd @@ -4,12 +4,9 @@ \alias{clear_cache} \title{Manually reset the cache, deleting all currently saved data and starting afresh} \usage{ -clear_cache(disable = FALSE, ...) +clear_cache(..., disable = FALSE) } \arguments{ -\item{disable}{instead of setting a new cache, disable caching entirely; -defaults to \code{FALSE}} - \item{...}{ Arguments passed on to \code{\link[=set_cache]{set_cache}} \describe{ @@ -29,6 +26,9 @@ variable is \code{EPIDATR_CACHE_LOGFILE}.} \item{\code{confirm}}{whether to confirm directory creation. default is \code{TRUE}; should only be set in non-interactive scripts} }} + +\item{disable}{instead of setting a new cache, disable caching entirely; +defaults to \code{FALSE}} } \value{ \code{\link{NULL}} no return value, all effects are stored in the package diff --git a/man/get_api_key.Rd b/man/get_api_key.Rd index 18f7ae65..40774c66 100644 --- a/man/get_api_key.Rd +++ b/man/get_api_key.Rd @@ -52,7 +52,7 @@ Delphi Epidata API Registration Form. \url{https://api.delphi.cmu.edu/epidata/admin/registration_form} } \seealso{ -\code{\link[usethis:edit_r_environ]{usethis::edit_r_environ()}} to automatically edit the \code{.Renviron} -file; \code{\link[usethis:edit_r_profile]{usethis::edit_r_profile()}} to automatically edit the \code{.Rprofile} +\code{\link[usethis:edit]{usethis::edit_r_environ()}} to automatically edit the \code{.Renviron} +file; \code{\link[usethis:edit]{usethis::edit_r_profile()}} to automatically edit the \code{.Rprofile} file } From d77505c629af1609697899b1b7c740c3b278f664 Mon Sep 17 00:00:00 2001 From: dsweber2 Date: Fri, 13 Oct 2023 21:31:41 +0000 Subject: [PATCH 021/189] docs: document (GHA) --- man/get_api_key.Rd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/man/get_api_key.Rd b/man/get_api_key.Rd index 40774c66..18f7ae65 100644 --- a/man/get_api_key.Rd +++ b/man/get_api_key.Rd @@ -52,7 +52,7 @@ Delphi Epidata API Registration Form. \url{https://api.delphi.cmu.edu/epidata/admin/registration_form} } \seealso{ -\code{\link[usethis:edit]{usethis::edit_r_environ()}} to automatically edit the \code{.Renviron} -file; \code{\link[usethis:edit]{usethis::edit_r_profile()}} to automatically edit the \code{.Rprofile} +\code{\link[usethis:edit_r_environ]{usethis::edit_r_environ()}} to automatically edit the \code{.Renviron} +file; \code{\link[usethis:edit_r_profile]{usethis::edit_r_profile()}} to automatically edit the \code{.Rprofile} file } From fb395a29c42e5971828bba4875522c75c01bb3c9 Mon Sep 17 00:00:00 2001 From: Alex Reinhart Date: Sat, 4 Nov 2023 17:41:01 -0400 Subject: [PATCH 022/189] Improve avail_endpoints() documentation --- R/avail_endpoints.R | 13 +++++++------ man/avail_endpoints.Rd | 12 +++++++----- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/R/avail_endpoints.R b/R/avail_endpoints.R index 7677076d..34555446 100644 --- a/R/avail_endpoints.R +++ b/R/avail_endpoints.R @@ -1,11 +1,12 @@ -#' List all available endpoints. +#' List all available Epidata API endpoints #' -#' @description -#' A function that prints a tibble with two columns: `Endpoint` contains the -#' function for accessing the Delphi Epidata API endpoint along with a -#' `Description`. +#' Fetches a data frame of all Epidata API endpoints that can be accessed using +#' this package, with a brief description. #' -#' @return A [`tibble::tibble`]. +#' @return A [`tibble::tibble`] of endpoints, with two columns: +#' \item{Endpoint}{Name of the function for accessing this API endpoint.} +#' \item{Description}{One-sentence description of the data available at the +#' endpoint.} #' @export #' @importFrom utils help.search #' diff --git a/man/avail_endpoints.Rd b/man/avail_endpoints.Rd index f669cd22..9a6cb0ce 100644 --- a/man/avail_endpoints.Rd +++ b/man/avail_endpoints.Rd @@ -2,17 +2,19 @@ % Please edit documentation in R/avail_endpoints.R \name{avail_endpoints} \alias{avail_endpoints} -\title{List all available endpoints.} +\title{List all available Epidata API endpoints} \usage{ avail_endpoints() } \value{ -A \code{\link[tibble:tibble]{tibble::tibble}}. +A \code{\link[tibble:tibble]{tibble::tibble}} of endpoints, with two columns: +\item{Endpoint}{Name of the function for accessing this API endpoint.} +\item{Description}{One-sentence description of the data available at the +endpoint.} } \description{ -A function that prints a tibble with two columns: \code{Endpoint} contains the -function for accessing the Delphi Epidata API endpoint along with a -\code{Description}. +Fetches a data frame of all Epidata API endpoints that can be accessed using +this package, with a brief description. } \examples{ avail_endpoints() From 380d971ec6cbf500c26de1002afa02d3cda7ca16 Mon Sep 17 00:00:00 2001 From: Alex Reinhart Date: Sat, 4 Nov 2023 18:03:59 -0400 Subject: [PATCH 023/189] Improve epirange and timeset documentation --- R/model.R | 38 ++++++++++++++++++-------------------- man/epirange.Rd | 11 ++++++----- man/timeset.Rd | 28 ++++++++++++++-------------- 3 files changed, 38 insertions(+), 39 deletions(-) diff --git a/R/model.R b/R/model.R index 34865e91..249124e8 100644 --- a/R/model.R +++ b/R/model.R @@ -1,12 +1,12 @@ -#' EpiRange +#' Specify a range of days or weeks for API requests #' -#' @description #' Specify a date range (in days or epiweeks) for an API request. #' -#' @param from A `Date`, integer-like value, or integer-like string that takes the -#' form YYYYMMDD for dates or YYYYWW for epiweeks. -#' @param to A `Date`, integer-like value, or integer-like string that takes the -#' form YYYYMMDD for dates or YYYYWW for epiweeks. +#' @param from The first date to request. Can be specified as a `Date` or as an +#' integer or integer-like string in the format YYYYMMDD for dates or YYYYWW +#' for epiweeks. +#' @param to The final date to request (inclusive), specified the same way as +#' `from`. #' @return An `EpiRange` object. #' @importFrom checkmate check_integerish check_character check_date assert #' @@ -62,28 +62,26 @@ epirange <- function(from, to) { } -#' Timeset +#' Timeset formats for specifying dates #' -#' @description #' Many API calls accept timesets to specify the time ranges of data being #' requested. Timesets can be specified with `epirange()`, as `Date` objects, or #' with wildcards. #' -#' Timesets are not special R types; the term simply describes any value that -#' would be accepted by epidatr to specify the time value of an epidata query. -#' The allowed values are: +#' Timesets are not special R types; the term simply describes any value that is +#' accepted by epidatr to specify the time value of an epidata query: #' -#' - Dates: `Date` instances, integer-like values, or integer-like strings that -#' take the form YYYYMMDD. -#' - Epiweeks: Integer-like values or integer-like strings that take the form -#' YYYYWW. +#' - Dates: `Date` instances. +#' - Date strings or integers: Strings or integers in the format YYYYMMDD. +#' - Epiweeks: Strings or integers in the format YYYYWW, where WW is the epiweek +#' number. #' - EpiRanges: A range returned by `epirange()`, or a list of multiple ranges. -#' - Wildcard: The string `"*"`, which request all available time values. +#' - Wildcard: The string `"*"`, which requests all available time values. #' -#' Please refer to the specific endpoint documentation for guidance on using -#' dates vs weeks. Most endpoints support only one or the other. Some (less -#' commonly used) endpoints may not accept the `"*"` wildcard, but this can be -#' simulated with a large `epirange()`. +#' Refer to the specific endpoint documentation for guidance on using dates vs +#' weeks. Most endpoints support only one or the other. Some (less commonly +#' used) endpoints may not accept the `"*"` wildcard, but this can be simulated +#' with a large `epirange()`. #' #' @name timeset NULL diff --git a/man/epirange.Rd b/man/epirange.Rd index 1f4605e6..0fba2433 100644 --- a/man/epirange.Rd +++ b/man/epirange.Rd @@ -2,16 +2,17 @@ % Please edit documentation in R/model.R \name{epirange} \alias{epirange} -\title{EpiRange} +\title{Specify a range of days or weeks for API requests} \usage{ epirange(from, to) } \arguments{ -\item{from}{A \code{Date}, integer-like value, or integer-like string that takes the -form YYYYMMDD for dates or YYYYWW for epiweeks.} +\item{from}{The first date to request. Can be specified as a \code{Date} or as an +integer or integer-like string in the format YYYYMMDD for dates or YYYYWW +for epiweeks.} -\item{to}{A \code{Date}, integer-like value, or integer-like string that takes the -form YYYYMMDD for dates or YYYYWW for epiweeks.} +\item{to}{The final date to request (inclusive), specified the same way as +\code{from}.} } \value{ An \code{EpiRange} object. diff --git a/man/timeset.Rd b/man/timeset.Rd index 5d49151d..6dcdc2b8 100644 --- a/man/timeset.Rd +++ b/man/timeset.Rd @@ -2,26 +2,26 @@ % Please edit documentation in R/model.R \name{timeset} \alias{timeset} -\title{Timeset} +\title{Timeset formats for specifying dates} \description{ Many API calls accept timesets to specify the time ranges of data being requested. Timesets can be specified with \code{epirange()}, as \code{Date} objects, or with wildcards. - -Timesets are not special R types; the term simply describes any value that -would be accepted by epidatr to specify the time value of an epidata query. -The allowed values are: +} +\details{ +Timesets are not special R types; the term simply describes any value that is +accepted by epidatr to specify the time value of an epidata query: \itemize{ -\item Dates: \code{Date} instances, integer-like values, or integer-like strings that -take the form YYYYMMDD. -\item Epiweeks: Integer-like values or integer-like strings that take the form -YYYYWW. +\item Dates: \code{Date} instances. +\item Date strings or integers: Strings or integers in the format YYYYMMDD. +\item Epiweeks: Strings or integers in the format YYYYWW, where WW is the epiweek +number. \item EpiRanges: A range returned by \code{epirange()}, or a list of multiple ranges. -\item Wildcard: The string \code{"*"}, which request all available time values. +\item Wildcard: The string \code{"*"}, which requests all available time values. } -Please refer to the specific endpoint documentation for guidance on using -dates vs weeks. Most endpoints support only one or the other. Some (less -commonly used) endpoints may not accept the \code{"*"} wildcard, but this can be -simulated with a large \code{epirange()}. +Refer to the specific endpoint documentation for guidance on using dates vs +weeks. Most endpoints support only one or the other. Some (less commonly +used) endpoints may not accept the \code{"*"} wildcard, but this can be simulated +with a large \code{epirange()}. } From 06f835954265870230a13d464c963adc172fe641 Mon Sep 17 00:00:00 2001 From: Alex Reinhart Date: Sat, 4 Nov 2023 18:05:53 -0400 Subject: [PATCH 024/189] Fix endpoint documentation capitalization --- R/endpoints.R | 2 +- man/pub_covid_hosp_state_timeseries.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/endpoints.R b/R/endpoints.R index da14c2bb..c8ba2497 100644 --- a/R/endpoints.R +++ b/R/endpoints.R @@ -433,7 +433,7 @@ pub_covid_hosp_facility <- function( ) %>% fetch(fetch_args = fetch_args) } -#' COVID Hospitalization Data by State +#' COVID hospitalization data by state #' #' @description #' API docs: . diff --git a/man/pub_covid_hosp_state_timeseries.Rd b/man/pub_covid_hosp_state_timeseries.Rd index e032314f..ed959c28 100644 --- a/man/pub_covid_hosp_state_timeseries.Rd +++ b/man/pub_covid_hosp_state_timeseries.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pub_covid_hosp_state_timeseries} \alias{pub_covid_hosp_state_timeseries} -\title{COVID Hospitalization Data by State} +\title{COVID hospitalization data by state} \usage{ pub_covid_hosp_state_timeseries( states, From 6d1bd312697e3dd19501418867f2840d91a1b703 Mon Sep 17 00:00:00 2001 From: Alex Reinhart Date: Sat, 4 Nov 2023 18:15:46 -0400 Subject: [PATCH 025/189] Improve and correct fetch_args_list() documentation --- R/epidatacall.R | 58 ++++++++++++++++++++---------------------- man/fetch_args_list.Rd | 50 ++++++++++++++++++------------------ 2 files changed, 52 insertions(+), 56 deletions(-) diff --git a/R/epidatacall.R b/R/epidatacall.R index 3e2ad5ba..b33d7653 100644 --- a/R/epidatacall.R +++ b/R/epidatacall.R @@ -103,42 +103,38 @@ print.epidata_call <- function(x, ...) { )) } -#' Customize fetch settings +#' Set custom API request parameters #' -#' @rdname fetch_args_list -#' @aliases fetch_args -#' -#' @description -#' A constructor for `fetch_args` objects, which are used to pass arguments to -#' the `fetch` function. +#' Used to specify custom options when making API requests, such as to set +#' timeouts or change data formats. These options are used by `fetch()` when it +#' makes calls to the Epidata API. #' #' @param ... not used for values, forces later arguments to bind by name -#' @param fields a list of epidata fields to return, or NULL to return all -#' fields (default) e.g. c("time_value", "value") to return only the -#' time_value and value fields or c("-direction") to return everything except -#' the direction field -#' @param disable_date_parsing disable automatic date parsing; by default `FALSE` -#' @param disable_data_frame_parsing disable automatic conversion to data frame; this -#' is only supported by endpoints that only support the 'classic' format (non-tabular). -#' by default `FALSE` -#' @param return_empty boolean that allows returning an empty tibble if there is no data; -#' by default `FALSE` -#' @param timeout_seconds the maximum amount of time to wait for a response; by default -#' `FALSE` -#' @param base_url base URL to use; by default `NULL`, which means the global base url -#' `"https://api.delphi.cmu.edu/epidata/"` -#' @param dry_run boolean that allows skipping the call to the API and instead -#' returns the `epidata_call` object (useful for debugging); by default `TRUE` -#' @param debug boolean that allows returning the raw response from the API; by default -#' `FALSE` -#' @param format_type the format to request from the API, one of classic, json, csv; this -#' is only used by `fetch_debug`, and by default is `"json"` -#' @return -#' - For `fetch_args_list`: a `fetch_args` object +#' @param fields a list of epidata fields to return, or `NULL` to return all +#' fields (default). e.g. `c("time_value", "value")` to return only the +#' `time_value` and `value` fields or `c("-direction")` to return everything +#' except the direction field +#' @param disable_date_parsing disable automatic date parsing; by default +#' `FALSE` +#' @param disable_data_frame_parsing disable automatic conversion to data frame; +#' this is only supported by endpoints that only support the 'classic' format +#' (non-tabular). by default `FALSE` +#' @param return_empty boolean that allows returning an empty tibble if there is +#' no data; by default `FALSE` +#' @param timeout_seconds the maximum amount of time (in seconds) to wait for a +#' response from the API server; by default 30 +#' @param base_url base URL to use; by default `NULL`, which means the global +#' base URL `"https://api.delphi.cmu.edu/epidata/"` +#' @param dry_run if `TRUE`, skip the call to the API and instead return the +#' `epidata_call` object (useful for debugging); by default `FALSE` +#' @param debug if `TRUE`, return the raw response from the API; by default +#' `FALSE` +#' @param format_type the format to request from the API, one of classic, json, +#' csv; this is only used by `fetch_debug`, and by default is `"json"` +#' @return A `fetch_args` object containing all the specified options #' @export -#' +#' @aliases fetch_args #' @importFrom checkmate assert_character assert_logical assert_numeric -#' fetch_args_list <- function( ..., fields = NULL, diff --git a/man/fetch_args_list.Rd b/man/fetch_args_list.Rd index e33de228..ac0db01b 100644 --- a/man/fetch_args_list.Rd +++ b/man/fetch_args_list.Rd @@ -3,7 +3,7 @@ \name{fetch_args_list} \alias{fetch_args_list} \alias{fetch_args} -\title{Customize fetch settings} +\title{Set custom API request parameters} \usage{ fetch_args_list( ..., @@ -21,41 +21,41 @@ fetch_args_list( \arguments{ \item{...}{not used for values, forces later arguments to bind by name} -\item{fields}{a list of epidata fields to return, or NULL to return all -fields (default) e.g. c("time_value", "value") to return only the -time_value and value fields or c("-direction") to return everything except -the direction field} +\item{fields}{a list of epidata fields to return, or \code{NULL} to return all +fields (default). e.g. \code{c("time_value", "value")} to return only the +\code{time_value} and \code{value} fields or \code{c("-direction")} to return everything +except the direction field} -\item{disable_date_parsing}{disable automatic date parsing; by default \code{FALSE}} +\item{disable_date_parsing}{disable automatic date parsing; by default +\code{FALSE}} -\item{disable_data_frame_parsing}{disable automatic conversion to data frame; this -is only supported by endpoints that only support the 'classic' format (non-tabular). -by default \code{FALSE}} +\item{disable_data_frame_parsing}{disable automatic conversion to data frame; +this is only supported by endpoints that only support the 'classic' format +(non-tabular). by default \code{FALSE}} -\item{return_empty}{boolean that allows returning an empty tibble if there is no data; -by default \code{FALSE}} +\item{return_empty}{boolean that allows returning an empty tibble if there is +no data; by default \code{FALSE}} -\item{timeout_seconds}{the maximum amount of time to wait for a response; by default -\code{FALSE}} +\item{timeout_seconds}{the maximum amount of time (in seconds) to wait for a +response from the API server; by default 30} -\item{base_url}{base URL to use; by default \code{NULL}, which means the global base url -\code{"https://api.delphi.cmu.edu/epidata/"}} +\item{base_url}{base URL to use; by default \code{NULL}, which means the global +base URL \code{"https://api.delphi.cmu.edu/epidata/"}} -\item{dry_run}{boolean that allows skipping the call to the API and instead -returns the \code{epidata_call} object (useful for debugging); by default \code{TRUE}} +\item{dry_run}{if \code{TRUE}, skip the call to the API and instead return the +\code{epidata_call} object (useful for debugging); by default \code{FALSE}} -\item{debug}{boolean that allows returning the raw response from the API; by default +\item{debug}{if \code{TRUE}, return the raw response from the API; by default \code{FALSE}} -\item{format_type}{the format to request from the API, one of classic, json, csv; this -is only used by \code{fetch_debug}, and by default is \code{"json"}} +\item{format_type}{the format to request from the API, one of classic, json, +csv; this is only used by \code{fetch_debug}, and by default is \code{"json"}} } \value{ -\itemize{ -\item For \code{fetch_args_list}: a \code{fetch_args} object -} +A \code{fetch_args} object containing all the specified options } \description{ -A constructor for \code{fetch_args} objects, which are used to pass arguments to -the \code{fetch} function. +Used to specify custom options when making API requests, such as to set +timeouts or change data formats. These options are used by \code{fetch()} when it +makes calls to the Epidata API. } From 4aee8f5916da0528aa3f54648b4ee32a0b14c603 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Wed, 8 Nov 2023 12:57:49 -0500 Subject: [PATCH 026/189] add jeremy and nat as codeowners --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 16f04afb..bc50b4e0 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @dshemetov @brookslogan @dsweber2 +* @dshemetov @brookslogan @dsweber2 @jeremy-goldwasser @nmdefries From 4c7f3531f37d1aa3a27c96b1e589407d6bb653f4 Mon Sep 17 00:00:00 2001 From: Alex Reinhart Date: Wed, 8 Nov 2023 14:11:14 -0500 Subject: [PATCH 027/189] Use standard match.arg() for argument with 3 options This makes the available format_type options show up in the argument list, and matches how most base R functions taking enumerated options work. --- R/epidatacall.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/epidatacall.R b/R/epidatacall.R index b33d7653..ae41b0f0 100644 --- a/R/epidatacall.R +++ b/R/epidatacall.R @@ -145,7 +145,7 @@ fetch_args_list <- function( base_url = NULL, dry_run = FALSE, debug = FALSE, - format_type = "json") { + format_type = c("json", "classic", "csv")) { assert_character(fields, null.ok = TRUE, any.missing = FALSE) assert_logical(disable_date_parsing, null.ok = FALSE, len = 1L, any.missing = FALSE) assert_logical(disable_data_frame_parsing, null.ok = FALSE, len = 1L, any.missing = FALSE) @@ -155,7 +155,7 @@ fetch_args_list <- function( assert_logical(dry_run, null.ok = FALSE, len = 1L, any.missing = TRUE) assert_logical(debug, null.ok = FALSE, len = 1L, any.missing = FALSE) assert_character(format_type, null.ok = FALSE, len = 1L, any.missing = FALSE) - assert(format_type %in% c("json", "csv", "classic"), "format_type must be one of json, csv, classic") + format_type <- match.arg(format_type) structure( list( From cb6a55e7a969366719a475d6e9f03622e003fe5f Mon Sep 17 00:00:00 2001 From: Alex Reinhart Date: Wed, 8 Nov 2023 14:12:04 -0500 Subject: [PATCH 028/189] Don't repeat default arguments in the @param documentation --- R/epidatacall.R | 14 ++++++-------- man/fetch_args_list.Rd | 16 +++++++--------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/R/epidatacall.R b/R/epidatacall.R index ae41b0f0..b27b70a2 100644 --- a/R/epidatacall.R +++ b/R/epidatacall.R @@ -114,21 +114,19 @@ print.epidata_call <- function(x, ...) { #' fields (default). e.g. `c("time_value", "value")` to return only the #' `time_value` and `value` fields or `c("-direction")` to return everything #' except the direction field -#' @param disable_date_parsing disable automatic date parsing; by default -#' `FALSE` +#' @param disable_date_parsing disable automatic date parsing #' @param disable_data_frame_parsing disable automatic conversion to data frame; #' this is only supported by endpoints that only support the 'classic' format -#' (non-tabular). by default `FALSE` +#' (non-tabular) #' @param return_empty boolean that allows returning an empty tibble if there is -#' no data; by default `FALSE` +#' no data #' @param timeout_seconds the maximum amount of time (in seconds) to wait for a -#' response from the API server; by default 30 +#' response from the API server #' @param base_url base URL to use; by default `NULL`, which means the global #' base URL `"https://api.delphi.cmu.edu/epidata/"` #' @param dry_run if `TRUE`, skip the call to the API and instead return the -#' `epidata_call` object (useful for debugging); by default `FALSE` -#' @param debug if `TRUE`, return the raw response from the API; by default -#' `FALSE` +#' `epidata_call` object (useful for debugging) +#' @param debug if `TRUE`, return the raw response from the API #' @param format_type the format to request from the API, one of classic, json, #' csv; this is only used by `fetch_debug`, and by default is `"json"` #' @return A `fetch_args` object containing all the specified options diff --git a/man/fetch_args_list.Rd b/man/fetch_args_list.Rd index ac0db01b..9f7a2be4 100644 --- a/man/fetch_args_list.Rd +++ b/man/fetch_args_list.Rd @@ -15,7 +15,7 @@ fetch_args_list( base_url = NULL, dry_run = FALSE, debug = FALSE, - format_type = "json" + format_type = c("json", "classic", "csv") ) } \arguments{ @@ -26,27 +26,25 @@ fields (default). e.g. \code{c("time_value", "value")} to return only the \code{time_value} and \code{value} fields or \code{c("-direction")} to return everything except the direction field} -\item{disable_date_parsing}{disable automatic date parsing; by default -\code{FALSE}} +\item{disable_date_parsing}{disable automatic date parsing} \item{disable_data_frame_parsing}{disable automatic conversion to data frame; this is only supported by endpoints that only support the 'classic' format -(non-tabular). by default \code{FALSE}} +(non-tabular)} \item{return_empty}{boolean that allows returning an empty tibble if there is -no data; by default \code{FALSE}} +no data} \item{timeout_seconds}{the maximum amount of time (in seconds) to wait for a -response from the API server; by default 30} +response from the API server} \item{base_url}{base URL to use; by default \code{NULL}, which means the global base URL \code{"https://api.delphi.cmu.edu/epidata/"}} \item{dry_run}{if \code{TRUE}, skip the call to the API and instead return the -\code{epidata_call} object (useful for debugging); by default \code{FALSE}} +\code{epidata_call} object (useful for debugging)} -\item{debug}{if \code{TRUE}, return the raw response from the API; by default -\code{FALSE}} +\item{debug}{if \code{TRUE}, return the raw response from the API} \item{format_type}{the format to request from the API, one of classic, json, csv; this is only used by \code{fetch_debug}, and by default is \code{"json"}} From 1750e356fdc2f4ff1fb5b6fdebda1a9d48dbd27a Mon Sep 17 00:00:00 2001 From: Alex Reinhart Date: Wed, 8 Nov 2023 14:13:43 -0500 Subject: [PATCH 029/189] Add back an explicit @description --- R/avail_endpoints.R | 1 + 1 file changed, 1 insertion(+) diff --git a/R/avail_endpoints.R b/R/avail_endpoints.R index 34555446..e8c23b79 100644 --- a/R/avail_endpoints.R +++ b/R/avail_endpoints.R @@ -1,5 +1,6 @@ #' List all available Epidata API endpoints #' +#' @description #' Fetches a data frame of all Epidata API endpoints that can be accessed using #' this package, with a brief description. #' From 2bc580b103911d4ac66b2ad7ce1a892cb0e3b9b4 Mon Sep 17 00:00:00 2001 From: capnrefsmmat Date: Wed, 8 Nov 2023 19:16:16 +0000 Subject: [PATCH 030/189] docs: document (GHA) --- man/covidcast_epidata.Rd | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/man/covidcast_epidata.Rd b/man/covidcast_epidata.Rd index 2ab9fd75..3e62c550 100644 --- a/man/covidcast_epidata.Rd +++ b/man/covidcast_epidata.Rd @@ -25,22 +25,8 @@ leaving R. The \code{covidcast_epidata()} function fetches a list of all signals, and returns an object containing fields for every signal: -\if{html}{\out{
}}\preformatted{epidata <- covidcast_epidata() +\if{html}{\out{
}}\preformatted{epidata <- covidcast_epidata() epidata$signals -#> # A tibble: 443 x 3 -#> source signal short_description -#> -#> 1 chng smoothed_outpatient_cli Estimated percentage of outpatie~ -#> 2 chng smoothed_adj_outpatient_cli Estimated percentage of outpatie~ -#> 3 chng smoothed_outpatient_covid COVID-Confirmed Doctor Visits -#> 4 chng smoothed_adj_outpatient_covid COVID-Confirmed Doctor Visits -#> 5 chng smoothed_outpatient_flu Estimated percentage of outpatie~ -#> 6 chng smoothed_adj_outpatient_flu Estimated percentage of outpatie~ -#> 7 covid-act-now pcr_specimen_positivity_rate Proportion of PCR specimens test~ -#> 8 covid-act-now pcr_specimen_total_tests Total number of PCR specimens te~ -#> 9 doctor-visits smoothed_cli Percentage of daily doctor visit~ -#> 10 doctor-visits smoothed_adj_cli Percentage of daily doctor visit~ -#> # i 433 more rows }\if{html}{\out{
}} If you use an editor that supports tab completion, such as RStudio, type @@ -49,27 +35,13 @@ to type the name of signals and have the autocomplete feature select them from the list for you. Note that some signal names have dashes in them, so to access them we rely on the backtick operator: -\if{html}{\out{
}}\preformatted{epidata$signals$`fb-survey:smoothed_cli` -#> [1] "COVID-Like Symptoms (Unweighted 7-day average)" -#> [1] "fb-survey:smoothed_cli" -#> [1] "Estimated percentage of people with COVID-like illness " +\if{html}{\out{
}}\preformatted{epidata$signals$`fb-survey:smoothed_cli` }\if{html}{\out{
}} These objects can be used directly to fetch data, without requiring us to use the \code{covidcast()} function. Simply use the \verb{$call} attribute of the object: -\if{html}{\out{
}}\preformatted{epidata$signals$`fb-survey:smoothed_cli`$call("state", "pa", +\if{html}{\out{
}}\preformatted{epidata$signals$`fb-survey:smoothed_cli`$call("state", "pa", epirange(20210405, 20210410)) -#> # A tibble: 6 x 15 -#> geo_value signal source geo_type time_type time_value direction issue -#> -#> 1 pa smoothed_~ fb-su~ state day 2021-04-05 NA 2021-04-10 -#> 2 pa smoothed_~ fb-su~ state day 2021-04-06 NA 2021-04-11 -#> 3 pa smoothed_~ fb-su~ state day 2021-04-07 NA 2021-04-12 -#> 4 pa smoothed_~ fb-su~ state day 2021-04-08 NA 2021-04-13 -#> 5 pa smoothed_~ fb-su~ state day 2021-04-09 NA 2021-04-14 -#> 6 pa smoothed_~ fb-su~ state day 2021-04-10 NA 2021-04-15 -#> # i 7 more variables: lag , missing_value , missing_stderr , -#> # missing_sample_size , value , stderr , sample_size }\if{html}{\out{
}} } From 26e330389b1b2661e94cc60dcb70e94d2b8cf58c Mon Sep 17 00:00:00 2001 From: Alex Reinhart Date: Wed, 8 Nov 2023 14:55:32 -0500 Subject: [PATCH 031/189] Fix assertion on format_type, subsumed by match.arg() --- R/epidatacall.R | 1 - 1 file changed, 1 deletion(-) diff --git a/R/epidatacall.R b/R/epidatacall.R index b27b70a2..c67de901 100644 --- a/R/epidatacall.R +++ b/R/epidatacall.R @@ -152,7 +152,6 @@ fetch_args_list <- function( assert_character(base_url, null.ok = TRUE, len = 1L, any.missing = FALSE) assert_logical(dry_run, null.ok = FALSE, len = 1L, any.missing = TRUE) assert_logical(debug, null.ok = FALSE, len = 1L, any.missing = FALSE) - assert_character(format_type, null.ok = FALSE, len = 1L, any.missing = FALSE) format_type <- match.arg(format_type) structure( From 1805a06eb19e434b56b376a51a10d07313e56921 Mon Sep 17 00:00:00 2001 From: capnrefsmmat Date: Wed, 8 Nov 2023 20:02:28 +0000 Subject: [PATCH 032/189] docs: document (GHA) --- man/covidcast_epidata.Rd | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/man/covidcast_epidata.Rd b/man/covidcast_epidata.Rd index 3e62c550..2ab9fd75 100644 --- a/man/covidcast_epidata.Rd +++ b/man/covidcast_epidata.Rd @@ -25,8 +25,22 @@ leaving R. The \code{covidcast_epidata()} function fetches a list of all signals, and returns an object containing fields for every signal: -\if{html}{\out{
}}\preformatted{epidata <- covidcast_epidata() +\if{html}{\out{
}}\preformatted{epidata <- covidcast_epidata() epidata$signals +#> # A tibble: 443 x 3 +#> source signal short_description +#> +#> 1 chng smoothed_outpatient_cli Estimated percentage of outpatie~ +#> 2 chng smoothed_adj_outpatient_cli Estimated percentage of outpatie~ +#> 3 chng smoothed_outpatient_covid COVID-Confirmed Doctor Visits +#> 4 chng smoothed_adj_outpatient_covid COVID-Confirmed Doctor Visits +#> 5 chng smoothed_outpatient_flu Estimated percentage of outpatie~ +#> 6 chng smoothed_adj_outpatient_flu Estimated percentage of outpatie~ +#> 7 covid-act-now pcr_specimen_positivity_rate Proportion of PCR specimens test~ +#> 8 covid-act-now pcr_specimen_total_tests Total number of PCR specimens te~ +#> 9 doctor-visits smoothed_cli Percentage of daily doctor visit~ +#> 10 doctor-visits smoothed_adj_cli Percentage of daily doctor visit~ +#> # i 433 more rows }\if{html}{\out{
}} If you use an editor that supports tab completion, such as RStudio, type @@ -35,13 +49,27 @@ to type the name of signals and have the autocomplete feature select them from the list for you. Note that some signal names have dashes in them, so to access them we rely on the backtick operator: -\if{html}{\out{
}}\preformatted{epidata$signals$`fb-survey:smoothed_cli` +\if{html}{\out{
}}\preformatted{epidata$signals$`fb-survey:smoothed_cli` +#> [1] "COVID-Like Symptoms (Unweighted 7-day average)" +#> [1] "fb-survey:smoothed_cli" +#> [1] "Estimated percentage of people with COVID-like illness " }\if{html}{\out{
}} These objects can be used directly to fetch data, without requiring us to use the \code{covidcast()} function. Simply use the \verb{$call} attribute of the object: -\if{html}{\out{
}}\preformatted{epidata$signals$`fb-survey:smoothed_cli`$call("state", "pa", +\if{html}{\out{
}}\preformatted{epidata$signals$`fb-survey:smoothed_cli`$call("state", "pa", epirange(20210405, 20210410)) +#> # A tibble: 6 x 15 +#> geo_value signal source geo_type time_type time_value direction issue +#> +#> 1 pa smoothed_~ fb-su~ state day 2021-04-05 NA 2021-04-10 +#> 2 pa smoothed_~ fb-su~ state day 2021-04-06 NA 2021-04-11 +#> 3 pa smoothed_~ fb-su~ state day 2021-04-07 NA 2021-04-12 +#> 4 pa smoothed_~ fb-su~ state day 2021-04-08 NA 2021-04-13 +#> 5 pa smoothed_~ fb-su~ state day 2021-04-09 NA 2021-04-14 +#> 6 pa smoothed_~ fb-su~ state day 2021-04-10 NA 2021-04-15 +#> # i 7 more variables: lag , missing_value , missing_stderr , +#> # missing_sample_size , value , stderr , sample_size }\if{html}{\out{
}} } From a05a196672f2a5874902d8f45ff457f430474937 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Wed, 8 Nov 2023 14:05:46 -0800 Subject: [PATCH 033/189] Update .github/CODEOWNERS --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index bc50b4e0..b8a5df51 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @dshemetov @brookslogan @dsweber2 @jeremy-goldwasser @nmdefries +* @dshemetov @brookslogan @dsweber2 @nmdefries From 11b77fd2a22b1e85de4e8c5d6ae7859706e9ad89 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 10 Nov 2023 11:39:32 -0500 Subject: [PATCH 034/189] redocument --- man/get_api_key.Rd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/man/get_api_key.Rd b/man/get_api_key.Rd index 18f7ae65..40774c66 100644 --- a/man/get_api_key.Rd +++ b/man/get_api_key.Rd @@ -52,7 +52,7 @@ Delphi Epidata API Registration Form. \url{https://api.delphi.cmu.edu/epidata/admin/registration_form} } \seealso{ -\code{\link[usethis:edit_r_environ]{usethis::edit_r_environ()}} to automatically edit the \code{.Renviron} -file; \code{\link[usethis:edit_r_profile]{usethis::edit_r_profile()}} to automatically edit the \code{.Rprofile} +\code{\link[usethis:edit]{usethis::edit_r_environ()}} to automatically edit the \code{.Renviron} +file; \code{\link[usethis:edit]{usethis::edit_r_profile()}} to automatically edit the \code{.Rprofile} file } From 7e2642122d36094642980ee1bf0ba556d42f8194 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 10 Nov 2023 11:43:30 -0500 Subject: [PATCH 035/189] fetch description typo --- R/epidatacall.R | 4 ++-- man/epidata_call.Rd | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/R/epidatacall.R b/R/epidatacall.R index c67de901..34b6c39f 100644 --- a/R/epidatacall.R +++ b/R/epidatacall.R @@ -6,8 +6,8 @@ #' `epidata_call` objects are generated internally by endpoint functions like #' [`pub_covidcast`]; by default, they are piped directly into the `fetch` #' function to fetch and format the data. For most endpoints this will return -#' a tibble, but a few non-COVIDCAST endpoints only support will return a -#' JSON-like list instead. +#' a tibble, but a few non-COVIDCAST endpoints will return a JSON-like list +#' instead. #' #' @details #' `create_epidata_call` is the constructor for `epidata_call` objects, but you diff --git a/man/epidata_call.Rd b/man/epidata_call.Rd index dab13c9c..d0b62e73 100644 --- a/man/epidata_call.Rd +++ b/man/epidata_call.Rd @@ -41,8 +41,8 @@ fetch(epidata_call, fetch_args = fetch_args_list()) \code{epidata_call} objects are generated internally by endpoint functions like \code{\link{pub_covidcast}}; by default, they are piped directly into the \code{fetch} function to fetch and format the data. For most endpoints this will return -a tibble, but a few non-COVIDCAST endpoints only support will return a -JSON-like list instead. +a tibble, but a few non-COVIDCAST endpoints will return a JSON-like list +instead. } \details{ \code{create_epidata_call} is the constructor for \code{epidata_call} objects, but you From 910702f7c9ed73df49ffba3c49e82cd88b7fa247 Mon Sep 17 00:00:00 2001 From: nmdefries Date: Fri, 10 Nov 2023 16:45:46 +0000 Subject: [PATCH 036/189] docs: document (GHA) --- man/get_api_key.Rd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/man/get_api_key.Rd b/man/get_api_key.Rd index 40774c66..18f7ae65 100644 --- a/man/get_api_key.Rd +++ b/man/get_api_key.Rd @@ -52,7 +52,7 @@ Delphi Epidata API Registration Form. \url{https://api.delphi.cmu.edu/epidata/admin/registration_form} } \seealso{ -\code{\link[usethis:edit]{usethis::edit_r_environ()}} to automatically edit the \code{.Renviron} -file; \code{\link[usethis:edit]{usethis::edit_r_profile()}} to automatically edit the \code{.Rprofile} +\code{\link[usethis:edit_r_environ]{usethis::edit_r_environ()}} to automatically edit the \code{.Renviron} +file; \code{\link[usethis:edit_r_profile]{usethis::edit_r_profile()}} to automatically edit the \code{.Rprofile} file } From 6afbb25a5db1c4adbe06ae108f1a55e1d55c04fe Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 10 Nov 2023 11:46:12 -0500 Subject: [PATCH 037/189] make geo_values plural in arg error message --- R/endpoints.R | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/R/endpoints.R b/R/endpoints.R index c8ba2497..cb58ebcb 100644 --- a/R/endpoints.R +++ b/R/endpoints.R @@ -717,10 +717,11 @@ pub_covidcast <- function( missing(signals) || missing(time_type) || missing(geo_type) || - missing(time_values) || missing(geo_values) + missing(time_values) || + missing(geo_values) ) { stop( - "`source`, `signals`, `time_type`, `geo_type`, `time_values`, and `geo_value` are all required" + "`source`, `signals`, `time_type`, `geo_type`, `time_values`, and `geo_values` are all required" ) } From 6a2cc52a7124dd4ed2b35396de0bfd85c36230ae Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 10 Nov 2023 11:48:56 -0500 Subject: [PATCH 038/189] update reference to old covidcast() fn --- R/covidcast.R | 2 +- man/covidcast_epidata.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/covidcast.R b/R/covidcast.R index 66263be1..32868499 100644 --- a/R/covidcast.R +++ b/R/covidcast.R @@ -127,7 +127,7 @@ print.covidcast_data_source <- function(x, ...) { #' ``` #' #' These objects can be used directly to fetch data, without requiring us to use -#' the `covidcast()` function. Simply use the `$call` attribute of the object: +#' the `pub_covidcast()` function. Simply use the `$call` attribute of the object: #' #' ```{r} #' epidata$signals$`fb-survey:smoothed_cli`$call("state", "pa", diff --git a/man/covidcast_epidata.Rd b/man/covidcast_epidata.Rd index 2ab9fd75..2ca1d0cf 100644 --- a/man/covidcast_epidata.Rd +++ b/man/covidcast_epidata.Rd @@ -56,7 +56,7 @@ to access them we rely on the backtick operator: }\if{html}{\out{
}} These objects can be used directly to fetch data, without requiring us to use -the \code{covidcast()} function. Simply use the \verb{$call} attribute of the object: +the \code{pub_covidcast()} function. Simply use the \verb{$call} attribute of the object: \if{html}{\out{
}}\preformatted{epidata$signals$`fb-survey:smoothed_cli`$call("state", "pa", epirange(20210405, 20210410)) From 8346bc922cb6726a5c68d444b6fdafd2b062e5c3 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 10 Nov 2023 17:48:47 -0500 Subject: [PATCH 039/189] deploy docs website on push/pull to dev --- .github/workflows/pkgdown.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index d25a7086..2a5e77cb 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -5,9 +5,9 @@ # update the documentation web site on pushes to `dev` branch. on: push: - branches: [main] + branches: [dev] pull_request: - branches: [main] + branches: [dev] release: types: [published] workflow_dispatch: From ab97ca4d7ab388e3fc9e5271d4de5cab2e11e9ce Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 10 Nov 2023 18:21:26 -0500 Subject: [PATCH 040/189] make new signal discover fn ref section --- _pkgdown.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/_pkgdown.yml b/_pkgdown.yml index 3dd28794..0dc0e230 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -37,10 +37,14 @@ reference: desc: Set API keys and handle API data types - contents: - get_api_key - - avail_endpoints - epirange - timeset - - title: Control Caching behavior + - title: Data source and signal discovery + desc: Quickly explore endpoints, and API signal and source names + - contents: + - avail_endpoints + - covidcast_epidata + - title: Control caching behavior desc: Configure an optional persistent cache - contents: - set_cache @@ -58,7 +62,3 @@ reference: desc: These endpoints require additional authorization to use - contents: - starts_with("pvt_") - - title: Autocomplete helpers - desc: Objects that can autocomplete API signals names for faster exploration - - contents: - - covidcast_epidata From cbb69e7afb01db09ad2bcc06ba14628eb021bc4d Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Mon, 13 Nov 2023 15:17:58 -0500 Subject: [PATCH 041/189] build doc website on push to both dev and main --- .github/workflows/pkgdown.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index 2a5e77cb..e67a789c 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -5,9 +5,9 @@ # update the documentation web site on pushes to `dev` branch. on: push: - branches: [dev] + branches: [main, dev] pull_request: - branches: [dev] + branches: [main, dev] release: types: [published] workflow_dispatch: From 5799fe6cd094cfca643a192266acbde98f8fc8b2 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Mon, 13 Nov 2023 15:18:25 -0500 Subject: [PATCH 042/189] dev version needs a 4-part version number to trigger dev doc site --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 7f94c34a..c23d688c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: epidatr Type: Package Title: Client for Delphi's 'Epidata' API -Version: 1.1.0 +Version: 1.1.0.9000 Date: 2023-09-11 Authors@R: c( From 5db0821dd3905b1b5653905b5800227cc1112163 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Mon, 13 Nov 2023 15:19:37 -0500 Subject: [PATCH 043/189] build separate public and dev doc sites --- _pkgdown.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/_pkgdown.yml b/_pkgdown.yml index 3dd28794..3355c584 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -8,6 +8,9 @@ template: navbar-bg: '#C41230' navbar-fg: '#f8f8f8' +development: + mode: auto + navbar: bg: '#C41230' fg: '#f8f8f8' From 39927e79c3b738d2aee309b4c24c346f99a08d9f Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Tue, 14 Nov 2023 11:34:49 -0500 Subject: [PATCH 044/189] add info about public and local doc site --- DEVELOPMENT.md | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 95a93c25..cbd10961 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -1,19 +1,52 @@ -## Development Environment - -Relevant R commands +## Setting up the development environment ```r install.packages(c('devtools', 'pkgdown', 'styler', 'lintr')) # install dev dependencies devtools::install_deps(dependencies = TRUE) # install package dependencies devtools::document() # generate package meta data and man files devtools::build() # build package + +``` + +## Validating the package + +```r styler::style_pkg() # format code -lintr::lint_package() # lint package +lintr::lint_package() # lint code + devtools::test() # test package devtools::check() # check package for errors ``` -## Release Process +## Developing the documentation site + +The [documentation site](https://cmu-delphi.github.io/epidatr/) is built off of the `main` branch. The `dev` version of the site is available at https://cmu-delphi.github.io/epidatr/dev. + +The documentation site can be previewed locally by running in R + +```r +pkgdown::build_site(preview=TRUE) +``` + +The `main` version is available at `file:////epidatr/docs/index.html` and `dev` at `file:////epidatr/docs/dev/index.html`. + +You can also build the docs manually and launch the site with python. From the terminal, this looks like +```bash +R -e 'devtools::document()' +python -m http.server -d docs +``` + +## Release process + +### Manual + +TBD + +For `pkgdown` to correctly generate both public (`main`) and `dev` documentation sites, the package version in `DESCRIPTION` on `dev` must have four components, and be of the format `x.x.x.9000`. The package version on `main` must be in the format `x.x.x`. + +The documentation website is updated on push or pull request to the `main` and `dev` branches. + +### Automated (currently unavailable) The release consists of multiple steps which can be all done via the GitHub website: From bc4e22fd59c452ce90cbfaa47ef50ce000d77057 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Tue, 14 Nov 2023 11:35:09 -0500 Subject: [PATCH 045/189] remove unused url refs from dev.md --- DEVELOPMENT.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index cbd10961..3d74a0ff 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -58,8 +58,3 @@ The release consists of multiple steps which can be all done via the GitHub webs 2. create another [Pull Request](https://github.com/cmu-delphi/epidatr/pulls) to merge the changes back to the `dev` branch 3. create a [GitHub release](https://github.com/cmu-delphi/epidatr/releases) with automatically derived release notes 5. Release to CRAN - -[mit-image]: https://img.shields.io/badge/License-MIT-yellow.svg -[mit-url]: https://opensource.org/license/MIT -[github-actions-image]: https://github.com/cmu-delphi/epidatr/workflows/ci/badge.svg -[github-actions-url]: https://github.com/cmu-delphi/epidatr/actions From 2faf053a727de4290a2850251f6102f641770540 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Tue, 14 Nov 2023 11:37:27 -0500 Subject: [PATCH 046/189] move doc version info to doc development section --- DEVELOPMENT.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 3d74a0ff..095c25d7 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -36,16 +36,16 @@ R -e 'devtools::document()' python -m http.server -d docs ``` +For `pkgdown` to correctly generate both public (`main`) and `dev` documentation sites, the package version in `DESCRIPTION` on `dev` must have four components, and be of the format `x.x.x.9000`. The package version on `main` must be in the format `x.x.x`. + +The documentation website is updated on push or pull request to the `main` and `dev` branches. + ## Release process ### Manual TBD -For `pkgdown` to correctly generate both public (`main`) and `dev` documentation sites, the package version in `DESCRIPTION` on `dev` must have four components, and be of the format `x.x.x.9000`. The package version on `main` must be in the format `x.x.x`. - -The documentation website is updated on push or pull request to the `main` and `dev` branches. - ### Automated (currently unavailable) The release consists of multiple steps which can be all done via the GitHub website: From 233824ff1401b4911ba370e5a1545dfbc0aeb8f5 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Tue, 14 Nov 2023 12:08:04 -0500 Subject: [PATCH 047/189] check dots empty in endpoints --- R/endpoints.R | 26 ++++++++++++++++++++++++++ R/epidatacall.R | 2 ++ 2 files changed, 28 insertions(+) diff --git a/R/endpoints.R b/R/endpoints.R index c8ba2497..4c49eae9 100644 --- a/R/endpoints.R +++ b/R/endpoints.R @@ -89,6 +89,8 @@ pub_covid_hosp_facility_lookup <- function( zip = NULL, fips_code = NULL, fetch_args = fetch_args_list()) { + rlang::check_dots_empty() + assert_character_param("state", state, len = 1, required = FALSE) assert_character_param("ccn", ccn, len = 1, required = FALSE) assert_character_param("city", city, len = 1, required = FALSE) @@ -171,6 +173,8 @@ pub_covid_hosp_facility <- function( ..., publication_dates = NULL, fetch_args = fetch_args_list()) { + rlang::check_dots_empty() + assert_character_param("hospital_pks", hospital_pks) assert_timeset_param("collection_weeks", collection_weeks) assert_timeset_param("publication_dates", publication_dates, required = FALSE) @@ -465,6 +469,8 @@ pub_covid_hosp_facility <- function( #' @export # pub_covid_hosp_state_timeseries <- function(states, dates, ..., issues = NULL, fetch_args = fetch_args_list()) { + rlang::check_dots_empty() + assert_character_param("states", states) assert_timeset_param("dates", dates) assert_timeset_param("issues", issues, required = FALSE) @@ -711,6 +717,8 @@ pub_covidcast <- function( issues = NULL, lag = NULL, fetch_args = fetch_args_list()) { + rlang::check_dots_empty() + # Check parameters if ( missing(source) || @@ -918,6 +926,8 @@ pvt_dengue_sensors <- function(auth, names, locations, epiweeks, fetch_args = fe #' @keywords endpoint #' @export pub_ecdc_ili <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, fetch_args = fetch_args_list()) { + rlang::check_dots_empty() + assert_character_param("regions", regions) assert_timeset_param("epiweeks", epiweeks) assert_timeset_param("issues", issues, required = FALSE) @@ -975,6 +985,8 @@ pub_ecdc_ili <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, fetc #' @keywords endpoint #' @export pub_flusurv <- function(locations, epiweeks, ..., issues = NULL, lag = NULL, fetch_args = fetch_args_list()) { + rlang::check_dots_empty() + assert_character_param("locations", locations) assert_timeset_param("epiweeks", epiweeks) assert_timeset_param("issues", issues, required = FALSE) @@ -1031,6 +1043,8 @@ pub_flusurv <- function(locations, epiweeks, ..., issues = NULL, lag = NULL, fet #' @keywords endpoint #' @export pub_fluview_clinical <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, fetch_args = fetch_args_list()) { + rlang::check_dots_empty() + assert_character_param("regions", regions) assert_timeset_param("epiweeks", epiweeks) assert_timeset_param("issues", issues, required = FALSE) @@ -1134,6 +1148,8 @@ pub_fluview <- function( lag = NULL, auth = NULL, fetch_args = fetch_args_list()) { + rlang::check_dots_empty() + assert_character_param("regions", regions) assert_timeset_param("epiweeks", epiweeks) assert_timeset_param("issues", issues, required = FALSE) @@ -1284,6 +1300,8 @@ pvt_ght <- function(auth, locations, epiweeks, query, fetch_args = fetch_args_li #' @keywords endpoint #' @export pub_kcdc_ili <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, fetch_args = fetch_args_list()) { + rlang::check_dots_empty() + assert_character_param("regions", regions) assert_timeset_param("epiweeks", epiweeks) assert_timeset_param("issues", issues, required = FALSE) @@ -1413,6 +1431,8 @@ pub_nidss_dengue <- function(locations, epiweeks, fetch_args = fetch_args_list() #' @keywords endpoint #' @export pub_nidss_flu <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, fetch_args = fetch_args_list()) { + rlang::check_dots_empty() + assert_character_param("regions", regions) assert_timeset_param("epiweeks", epiweeks) assert_timeset_param("issues", issues, required = FALSE) @@ -1544,6 +1564,8 @@ pub_nowcast <- function(locations, epiweeks, fetch_args = fetch_args_list()) { #' @keywords endpoint #' @export pub_paho_dengue <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, fetch_args = fetch_args_list()) { + rlang::check_dots_empty() + assert_character_param("regions", regions) assert_timeset_param("epiweeks", epiweeks) assert_timeset_param("issues", issues, required = FALSE) @@ -1699,6 +1721,8 @@ pvt_sensors <- function(auth, names, locations, epiweeks, fetch_args = fetch_arg #' @keywords endpoint #' @export pvt_twitter <- function(auth, locations, ..., dates = NULL, epiweeks = NULL, fetch_args = fetch_args_list()) { + rlang::check_dots_empty() + assert_character_param("auth", auth, len = 1) assert_character_param("locations", locations) assert_timeset_param("dates", dates, required = FALSE) @@ -1767,6 +1791,8 @@ pub_wiki <- function( hours = NULL, language = "en", fetch_args = fetch_args_list()) { + rlang::check_dots_empty() + assert_character_param("articles", articles) assert_timeset_param("dates", dates, required = FALSE) assert_timeset_param("epiweeks", epiweeks, required = FALSE) diff --git a/R/epidatacall.R b/R/epidatacall.R index c67de901..165c058f 100644 --- a/R/epidatacall.R +++ b/R/epidatacall.R @@ -144,6 +144,8 @@ fetch_args_list <- function( dry_run = FALSE, debug = FALSE, format_type = c("json", "classic", "csv")) { + rlang::check_dots_empty() + assert_character(fields, null.ok = TRUE, any.missing = FALSE) assert_logical(disable_date_parsing, null.ok = FALSE, len = 1L, any.missing = FALSE) assert_logical(disable_data_frame_parsing, null.ok = FALSE, len = 1L, any.missing = FALSE) From 6820111b6d327982dd6dc8c9037e2dc29e7e1d94 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Tue, 14 Nov 2023 13:11:43 -0500 Subject: [PATCH 048/189] move endpoints and data discovery higher in fn ref list --- _pkgdown.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/_pkgdown.yml b/_pkgdown.yml index 0dc0e230..e7307e8d 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -33,17 +33,24 @@ home: href: https://cmu-delphi.github.io/epidatasets/ reference: + - title: Data source and signal discovery + desc: Quickly explore endpoints, and API signal and source names + - contents: + - avail_endpoints + - covidcast_epidata + - title: Make API requests + desc: Query Delphi Epidata endpoints + - contents: + - epidata_call + - fetch_args_list + - has_keyword("endpoint") + - -starts_with("pvt_") - title: Configuration and utilities desc: Set API keys and handle API data types - contents: - get_api_key - epirange - timeset - - title: Data source and signal discovery - desc: Quickly explore endpoints, and API signal and source names - - contents: - - avail_endpoints - - covidcast_epidata - title: Control caching behavior desc: Configure an optional persistent cache - contents: @@ -51,13 +58,6 @@ reference: - clear_cache - disable_cache - cache_info - - title: Make API requests - desc: Query Delphi Epidata endpoints - - contents: - - epidata_call - - fetch_args_list - - has_keyword("endpoint") - - -starts_with("pvt_") - title: Make requests to private API endpoints desc: These endpoints require additional authorization to use - contents: From b07e3e34fdb5b3765068b7eb762cf80780806093 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Tue, 14 Nov 2023 12:39:34 -0500 Subject: [PATCH 049/189] test that empty dots check errors for endpoints --- tests/testthat/test-endpoints.R | 102 ++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/tests/testthat/test-endpoints.R b/tests/testthat/test-endpoints.R index 3c81dea1..7fa42e21 100644 --- a/tests/testthat/test-endpoints.R +++ b/tests/testthat/test-endpoints.R @@ -146,3 +146,105 @@ test_that("basic_epidata_call", { fetch_args = fetch_args_list(dry_run = TRUE) ) %>% request_url()) }) + +test_that("endpoints fail when given args via dots", { + dots_error <- "`...` must be empty" + + # time value/epiweek arg is passed erroneously as `date_range` + expect_error( + pub_covid_hosp_facility_lookup( + state = "fl", + date_range = 20200101 + ), + regexp = dots_error + ) + expect_error( + pub_covid_hosp_facility( + hospital_pks = "100075", + date_range = epirange(20200101, 20200501) + ), + regexp = dots_error + ) + expect_error( + pub_covid_hosp_state_timeseries( + states = "fl", + date_range = epirange(20200101, 20200501) + ), + regexp = dots_error + ) + expect_error( + pub_covidcast( + source = "jhu-csse", + signals = "confirmed_7dav_incidence_prop", + time_type = "day", + geo_type = "state", + date_range = epirange(20200601, 20200801), + geo_values = "ca,fl" + ), + regexp = dots_error + ) + expect_error( + pub_ecdc_ili( + regions = "austria", + date_range = epirange(201201, 202001) + ), + regexp = dots_error + ) + expect_error( + pub_flusurv( + locations = "CA", + date_range = epirange(201201, 202001) + ), + regexp = dots_error + ) + expect_error( + pub_fluview_clinical( + regions = "nat", + date_range = epirange(201601, 201701) + ), + regexp = dots_error + ) + expect_error( + pub_fluview( + regions = "nat", + date_range = epirange(201601, 201701) + ), + regexp = dots_error + ) + expect_error( + pub_kcdc_ili( + regions = "?", + date_range = epirange(201201, 202001) + ), + regexp = dots_error + ) + expect_error( + pub_nidss_flu( + regions = "taipei", + date_range = epirange(201201, 202001) + ), + regexp = dots_error + ) + expect_error( + pub_paho_dengue( + regions = "ca", + date_range = epirange(201201, 202001) + ), + regexp = dots_error + ) + expect_error( + pvt_twitter( + auth = "yourkey", + locations = "CA", + date_range = epirange(201501, 202001) + ), + regexp = dots_error + ) + expect_error( + pub_wiki( + articles = "avian_influenza", + date_range = epirange(201501, 202001) + ), + regexp = dots_error + ) +}) From 31343e3484c71528f3c6a1e7385cac5f905007ba Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Thu, 16 Nov 2023 12:58:40 -0800 Subject: [PATCH 050/189] refactor+docs: set_api_key --- DESCRIPTION | 5 ++-- R/auth.R | 57 ++++++++++++++++++++++------------------------ man/get_api_key.Rd | 37 ++++++++---------------------- 3 files changed, 40 insertions(+), 59 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index c23d688c..bfe2839c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -3,7 +3,7 @@ Type: Package Title: Client for Delphi's 'Epidata' API Version: 1.1.0.9000 Date: 2023-09-11 -Authors@R: +Authors@R: c( person("Logan", "Brooks", email = "lcbrooks@andrew.cmu.edu", role = c("aut")), person("Dmitry", "Shemetov", email = "dshemeto@andrew.cmu.edu", role = c("aut")), @@ -37,6 +37,7 @@ Imports: openssl, readr, tibble, + usethis, xml2 RoxygenNote: 7.2.3 Suggests: @@ -50,7 +51,7 @@ Suggests: VignetteBuilder: knitr Language: en-US Config/testthat/edition: 3 -Collate: +Collate: 'auth.R' 'avail_endpoints.R' 'cache.R' diff --git a/R/auth.R b/R/auth.R index 95fcfe70..b72e60bb 100644 --- a/R/auth.R +++ b/R/auth.R @@ -10,20 +10,12 @@ #' please consider [registering for an API #' key](https://api.delphi.cmu.edu/epidata/admin/registration_form). #' -#' API keys are strings and can be set in two ways. If the environment variable -#' `DELPHI_EPIDATA_KEY` is set, it will be used automatically. Environment -#' variables can be set either in the shell or by editing your `.Renviron` file, -#' which will ensure the setting applies to all R sessions. See `?Startup` for a -#' description of `Renviron` files and where they can be placed. -#' -#' Alternately, the API key can be set from within a session by using -#' `set_api_key()`, which sets the R option `delphi.epidata.key` using -#' `options()`. If this option is set, it is used in preference to the -#' environment variable, so you may change keys within an R session. R options -#' are not preserved between sessions, so `set_api_key()` must be run every time -#' you open R. Alternately, you can have R set the option at startup by adding -#' it to your `.Rprofile`; see `?Startup` for a description of `Rprofile` files -#' and where they can be placed. +#' API keys are strings read from the environment variable `DELPHI_EPIDATA_KEY`. +#' We recommend setting your key with `set_api_key()`, which will modify your +#' `.Renviron` file and will persist your key across R sessions (see `?Startup` +#' for a description of `.Renviron` files). Alternatively, you can modify the +#' environment variable in the shell or with `Sys.setenv()`, but these will not +#' persist across sessions. #' #' Once an API key is set, it is automatically used for all requests made by #' functions in this package. @@ -31,22 +23,14 @@ #' @return For `get_api_key()`, returns the current API key as a string, or #' `""` if none is set. #' -#' @seealso [usethis::edit_r_environ()] to automatically edit the `.Renviron` -#' file; [usethis::edit_r_profile()] to automatically edit the `.Rprofile` -#' file -#' -#' @references Delphi Epidata API Keys documentation. -#' +#' @references +#' - [Delphi Epidata API Keys +#' documentation](https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html). +#' - [Delphi Epidata API Registration +#' Form](https://api.delphi.cmu.edu/epidata/admin/registration_form). #' -#' Delphi Epidata API Registration Form. -#' #' @export get_api_key <- function() { - key <- getOption("delphi.epidata.key", default = "") - if (key != "") { - return(key) - } - key <- Sys.getenv("DELPHI_EPIDATA_KEY", unset = "") if (key != "") { return(key) @@ -64,8 +48,21 @@ get_api_key <- function() { } #' @rdname get_api_key -#' @param key API key to use for future requests #' @export -set_api_key <- function(key) { - options(delphi.epidata.key = key) +set_api_key <- function() { + cli::cli_inform( + c( + "i" = "This function will open your .Renviron file in a text editor. You will need to + write DELPHI_EPIDATA_KEY=yourkeyhere in the file and save it. If the editor + does not open, you will need to edit the file manually.", + "i" = "Press any key to continue." + ), + ) + readline() + + if (file.exists(usethis::proj_path(".Renviron"))) { + usethis::edit_r_environ(scope = "project") + } else { + usethis::edit_r_environ(scope = "user") + } } diff --git a/man/get_api_key.Rd b/man/get_api_key.Rd index 18f7ae65..a3f3b5ec 100644 --- a/man/get_api_key.Rd +++ b/man/get_api_key.Rd @@ -7,10 +7,7 @@ \usage{ get_api_key() -set_api_key(key) -} -\arguments{ -\item{key}{API key to use for future requests} +set_api_key() } \value{ For \code{get_api_key()}, returns the current API key as a string, or @@ -26,33 +23,19 @@ without one, there are \href{https://cmu-delphi.github.io/delphi-epidata/api/api including a rate limit. If you regularly request large amounts of data, please consider \href{https://api.delphi.cmu.edu/epidata/admin/registration_form}{registering for an API key}. -API keys are strings and can be set in two ways. If the environment variable -\code{DELPHI_EPIDATA_KEY} is set, it will be used automatically. Environment -variables can be set either in the shell or by editing your \code{.Renviron} file, -which will ensure the setting applies to all R sessions. See \code{?Startup} for a -description of \code{Renviron} files and where they can be placed. - -Alternately, the API key can be set from within a session by using -\code{set_api_key()}, which sets the R option \code{delphi.epidata.key} using -\code{options()}. If this option is set, it is used in preference to the -environment variable, so you may change keys within an R session. R options -are not preserved between sessions, so \code{set_api_key()} must be run every time -you open R. Alternately, you can have R set the option at startup by adding -it to your \code{.Rprofile}; see \code{?Startup} for a description of \code{Rprofile} files -and where they can be placed. +API keys are strings read from the environment variable \code{DELPHI_EPIDATA_KEY}. +We recommend setting your key with \code{set_api_key()}, which will modify your +\code{.Renviron} file and will persist your key across R sessions (see \code{?Startup} +for a description of \code{.Renviron} files). Alternatively, you can modify the +environment variable in the shell or with \code{Sys.setenv()}, but these will not +persist across sessions. Once an API key is set, it is automatically used for all requests made by functions in this package. } \references{ -Delphi Epidata API Keys documentation. -\url{https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html} - -Delphi Epidata API Registration Form. -\url{https://api.delphi.cmu.edu/epidata/admin/registration_form} +\itemize{ +\item \href{https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html}{Delphi Epidata API Keys documentation}. +\item \href{https://api.delphi.cmu.edu/epidata/admin/registration_form}{Delphi Epidata API Registration Form}. } -\seealso{ -\code{\link[usethis:edit_r_environ]{usethis::edit_r_environ()}} to automatically edit the \code{.Renviron} -file; \code{\link[usethis:edit_r_profile]{usethis::edit_r_profile()}} to automatically edit the \code{.Rprofile} -file } From 127de77dedf16d69b253e14af8460eb6e6d03fe2 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Thu, 16 Nov 2023 13:05:13 -0800 Subject: [PATCH 051/189] test: fix auth test --- tests/testthat/test-auth.R | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/tests/testthat/test-auth.R b/tests/testthat/test-auth.R index 9d9ab391..660b18e7 100644 --- a/tests/testthat/test-auth.R +++ b/tests/testthat/test-auth.R @@ -1,14 +1,5 @@ test_that("get_api_key", { withr::with_envvar(c(DELPHI_EPIDATA_KEY = "epidata_key_from_envvar"), { - withr::with_options(list(delphi.epidata.key = "epidata_key_from_options"), { - # option takes precedence over environment variable - expect_identical(get_api_key(), "epidata_key_from_options") - }) - }) - withr::with_envvar(c(DELPHI_EPIDATA_KEY = NA_character_), { - withr::with_options(list(delphi.epidata.key = "epidata_key_from_options"), { - # option by itself works: - expect_identical(get_api_key(), "epidata_key_from_options") - }) + expect_identical(get_api_key(), "epidata_key_from_envvar") }) }) From 0ef3cfe5076ec8325626c088a96d4cb5603c2ee2 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Thu, 16 Nov 2023 15:11:12 -0800 Subject: [PATCH 052/189] refactor(auth): rename to save_api_key --- R/auth.R | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/R/auth.R b/R/auth.R index b72e60bb..c6b48079 100644 --- a/R/auth.R +++ b/R/auth.R @@ -11,7 +11,7 @@ #' key](https://api.delphi.cmu.edu/epidata/admin/registration_form). #' #' API keys are strings read from the environment variable `DELPHI_EPIDATA_KEY`. -#' We recommend setting your key with `set_api_key()`, which will modify your +#' We recommend setting your key with `save_api_key()`, which will modify your #' `.Renviron` file and will persist your key across R sessions (see `?Startup` #' for a description of `.Renviron` files). Alternatively, you can modify the #' environment variable in the shell or with `Sys.setenv()`, but these will not @@ -39,7 +39,7 @@ get_api_key <- function() { cli::cli_warn( c( "No API key found. You will be limited to non-complex queries and encounter rate limits if you proceed.", - "i" = "See {.help set_api_key} for details on obtaining and setting API keys." + "i" = "See {.help save_api_key} for details on obtaining and setting API keys." ), .frequency = "regularly", .frequency_id = "delphi.epidata.key" @@ -49,7 +49,7 @@ get_api_key <- function() { #' @rdname get_api_key #' @export -set_api_key <- function() { +save_api_key <- function() { cli::cli_inform( c( "i" = "This function will open your .Renviron file in a text editor. You will need to From d45bf6fd0447f3bd5969cf602eb468c1a4515703 Mon Sep 17 00:00:00 2001 From: dshemetov Date: Thu, 16 Nov 2023 23:13:46 +0000 Subject: [PATCH 053/189] docs: document (GHA) --- NAMESPACE | 2 +- man/get_api_key.Rd | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 5a9f2939..9b5b245c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -44,7 +44,7 @@ export(pvt_norostat) export(pvt_quidel) export(pvt_sensors) export(pvt_twitter) -export(set_api_key) +export(save_api_key) export(set_cache) import(cachem) import(glue) diff --git a/man/get_api_key.Rd b/man/get_api_key.Rd index a3f3b5ec..0a77debb 100644 --- a/man/get_api_key.Rd +++ b/man/get_api_key.Rd @@ -2,12 +2,12 @@ % Please edit documentation in R/auth.R \name{get_api_key} \alias{get_api_key} -\alias{set_api_key} +\alias{save_api_key} \title{Get and set API keys} \usage{ get_api_key() -set_api_key() +save_api_key() } \value{ For \code{get_api_key()}, returns the current API key as a string, or @@ -24,7 +24,7 @@ including a rate limit. If you regularly request large amounts of data, please consider \href{https://api.delphi.cmu.edu/epidata/admin/registration_form}{registering for an API key}. API keys are strings read from the environment variable \code{DELPHI_EPIDATA_KEY}. -We recommend setting your key with \code{set_api_key()}, which will modify your +We recommend setting your key with \code{save_api_key()}, which will modify your \code{.Renviron} file and will persist your key across R sessions (see \code{?Startup} for a description of \code{.Renviron} files). Alternatively, you can modify the environment variable in the shell or with \code{Sys.setenv()}, but these will not From 3018188d48d41d69c2a05519951d1cd95e139819 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Fri, 17 Nov 2023 11:03:59 -0800 Subject: [PATCH 054/189] Update R/auth.R Co-authored-by: Alex Reinhart --- R/auth.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/auth.R b/R/auth.R index c6b48079..3010d97b 100644 --- a/R/auth.R +++ b/R/auth.R @@ -52,8 +52,8 @@ get_api_key <- function() { save_api_key <- function() { cli::cli_inform( c( - "i" = "This function will open your .Renviron file in a text editor. You will need to - write DELPHI_EPIDATA_KEY=yourkeyhere in the file and save it. If the editor + "i" = "This function will open your {.code .Renviron} file in a text editor. You will need to + write {.code DELPHI_EPIDATA_KEY=yourkeyhere} in the file and save it. If the editor does not open, you will need to edit the file manually.", "i" = "Press any key to continue." ), From 08f391ae35623dfe16d1ab205d8a7483ae667961 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Fri, 17 Nov 2023 12:04:06 -0800 Subject: [PATCH 055/189] docs: rename to save_api_key --- NEWS.md | 3 ++- README.Rmd | 4 ++-- README.md | 4 ++-- vignettes/epidatr.Rmd | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/NEWS.md b/NEWS.md index 661b3340..644898d3 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,7 @@ # epidatr 1.1.0 + - renamed the mostly internal `get_auth_key` to `get_api_key` -- added `set_api_key` to more easily set the option +- added `save_api_key` to more easily set the option - various CRAN submission related doc-fixes - fixed some errors from passing "" as a key diff --git a/README.Rmd b/README.Rmd index f109948b..cd43d3c9 100644 --- a/README.Rmd +++ b/README.Rmd @@ -28,7 +28,7 @@ API](https://cmu-delphi.github.io/delphi-epidata/). It provides a simple R inter ## Usage -You can find detailed docs here: +You can find detailed docs here: ```{r} library(epidatr) @@ -86,7 +86,7 @@ your key, register for a pseudo-anonymous account [here](https://api.delphi.cmu.edu/epidata/admin/registration_form) and see more discussion on the [general API website](https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html). See the -`set_api_key()` function documentation for details on how to use your API key. +`save_api_key()` function documentation for details on how to use your API key. Note that the private endpoints (i.e. those prefixed with `pvt_`) require a separate key that needs to be passed as an argument. These endpoints require diff --git a/README.md b/README.md index 96a846f5..ea27a6fd 100644 --- a/README.md +++ b/README.md @@ -115,8 +115,8 @@ generate your key, register for a pseudo-anonymous account [here](https://api.delphi.cmu.edu/epidata/admin/registration_form) and see more discussion on the [general API website](https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html). -See the `set_api_key()` function documentation for details on how to use -your API key. +See the `save_api_key()` function documentation for details on how to +use your API key. Note that the private endpoints (i.e. those prefixed with `pvt_`) require a separate key that needs to be passed as an argument. These diff --git a/vignettes/epidatr.Rmd b/vignettes/epidatr.Rmd index f3120468..6a512bd2 100644 --- a/vignettes/epidatr.Rmd +++ b/vignettes/epidatr.Rmd @@ -23,7 +23,7 @@ regions. We recommend you register for an API key. While most endpoints are available without one, there are [limits on API usage for anonymous users](https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html), including -a rate limit. See `set_api_key()` for details on how to obtain an API key and +a rate limit. See `save_api_key()` for details on how to obtain an API key and set this package to use it. ## Basic Usage From 3ee71a5a623a58fcd47b4828ca575630c7faf151 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Fri, 17 Nov 2023 12:18:21 -0800 Subject: [PATCH 056/189] docs: add suggestion to .gitignore .Renviron --- R/auth.R | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/R/auth.R b/R/auth.R index 3010d97b..5d8e46e9 100644 --- a/R/auth.R +++ b/R/auth.R @@ -56,12 +56,20 @@ save_api_key <- function() { write {.code DELPHI_EPIDATA_KEY=yourkeyhere} in the file and save it. If the editor does not open, you will need to edit the file manually.", "i" = "Press any key to continue." - ), + ) ) readline() if (file.exists(usethis::proj_path(".Renviron"))) { usethis::edit_r_environ(scope = "project") + + cat("\n\n") + cli::cli_inform( + c( + "i" = "Your project {.code .Renviron} file has been updated. Make sure not to share this + file (add it to .gitignore or equivalents)." + ) + ) } else { usethis::edit_r_environ(scope = "user") } From be0b32d5095307d5d503c40ece7f243d1bbfff1b Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 17 Nov 2023 18:36:26 -0500 Subject: [PATCH 057/189] fluview_meta missing a fetch --- R/endpoints.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/endpoints.R b/R/endpoints.R index 270a0476..e27fafaa 100644 --- a/R/endpoints.R +++ b/R/endpoints.R @@ -1103,7 +1103,7 @@ pub_fluview_meta <- function(fetch_args = fetch_args_list()) { create_epidata_field_info("latest_issue", "date"), create_epidata_field_info("table_rows", "int") ) - ) + ) %>% fetch(fetch_args = fetch_args) } From 31a14184ad938e724ded26963c65a723e54384d8 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 17 Nov 2023 19:13:24 -0500 Subject: [PATCH 058/189] add detail to endpoint short descriptions --- R/endpoints.R | 58 ++++++++++++++------------ man/pub_covid_hosp_facility.Rd | 2 +- man/pub_covid_hosp_facility_lookup.Rd | 2 +- man/pub_covid_hosp_state_timeseries.Rd | 2 +- man/pub_covidcast.Rd | 2 +- man/pub_delphi.Rd | 2 +- man/pub_dengue_nowcast.Rd | 2 +- man/pub_ecdc_ili.Rd | 2 +- man/pub_flusurv.Rd | 4 +- man/pub_fluview.Rd | 2 +- man/pub_fluview_clinical.Rd | 2 +- man/pub_fluview_meta.Rd | 5 ++- man/pub_gft.Rd | 2 +- man/pub_kcdc_ili.Rd | 2 +- man/pub_meta.Rd | 2 +- man/pub_nidss_dengue.Rd | 2 +- man/pub_nidss_flu.Rd | 2 +- man/pub_nowcast.Rd | 2 +- man/pub_paho_dengue.Rd | 2 +- man/pub_wiki.Rd | 2 +- man/pvt_cdc.Rd | 2 +- man/pvt_dengue_sensors.Rd | 2 +- man/pvt_ght.Rd | 2 +- man/pvt_meta_norostat.Rd | 5 ++- man/pvt_norostat.Rd | 4 +- man/pvt_sensors.Rd | 2 +- man/pvt_twitter.Rd | 2 +- 27 files changed, 66 insertions(+), 54 deletions(-) diff --git a/R/endpoints.R b/R/endpoints.R index e27fafaa..5beda43a 100644 --- a/R/endpoints.R +++ b/R/endpoints.R @@ -1,4 +1,4 @@ -#' CDC page hits +#' CDC total and by topic webpage visits #' #' @description #' API docs: @@ -51,7 +51,7 @@ pvt_cdc <- function(auth, locations, epiweeks, fetch_args = fetch_args_list()) { ) %>% fetch(fetch_args = fetch_args) } -#' COVID hospitalization facility identifiers +#' Helper for finding COVID hospitalization facilities #' #' @description #' API docs: @@ -135,7 +135,7 @@ pub_covid_hosp_facility_lookup <- function( ) %>% fetch(fetch_args = fetch_args) } -#' COVID hospitalization data for specific facilities +#' COVID hospitalizations by facility #' #' @description #' API docs: @@ -437,7 +437,7 @@ pub_covid_hosp_facility <- function( ) %>% fetch(fetch_args = fetch_args) } -#' COVID hospitalization data by state +#' COVID hospitalizations by state #' #' @description #' API docs: . @@ -647,7 +647,7 @@ pub_covidcast_meta <- function(fetch_args = fetch_args_list()) { ) %>% fetch(fetch_args = fetch_args) } -#' COVID data via the covidcast endpoint +#' Various COVID and flu signals via the COVIDcast endpoint #' #' @description #' API docs: @@ -790,7 +790,7 @@ pub_covidcast <- function( ) %>% fetch(fetch_args = fetch_args) } -#' Delphi's ILINet forecasts +#' Delphi's ILINet outpatient doctor visits forecasts #' @description #' API docs: #' @@ -821,7 +821,7 @@ pub_delphi <- function(system, epiweek, fetch_args = fetch_args_list()) { ) %>% fetch(fetch_args = fetch_args) } -#' Delphi's PAHO Dengue nowcast +#' Delphi's PAHO dengue nowcasts (North and South America) #' @description #' API docs: #' @@ -855,7 +855,7 @@ pub_dengue_nowcast <- function(locations, epiweeks, fetch_args = fetch_args_list ) %>% fetch(fetch_args = fetch_args) } -#' Dengue digital surveillance sensors in PAHO member countries +#' PAHO dengue digital surveillance sensors (North and South America) #' @description #' API docs: #' @@ -900,7 +900,7 @@ pvt_dengue_sensors <- function(auth, names, locations, epiweeks, fetch_args = fe ) %>% fetch(fetch_args = fetch_args) } -#' ECDC ILI data +#' ECDC ILI incidence (Europe) #' @description #' API docs: . #' @@ -958,11 +958,11 @@ pub_ecdc_ili <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, fetc ) %>% fetch(fetch_args = fetch_args) } -#' FluSurv hospitalization data +#' CDC FluSurv flu hospitalizations #' @description #' API docs: . #' -#' Obtain information on flu hospitalization rates from the Center of Disease +#' Obtain information on influenza hospitalization rates from the Center of Disease #' Control. #' #' See also . @@ -1022,7 +1022,7 @@ pub_flusurv <- function(locations, epiweeks, ..., issues = NULL, lag = NULL, fet ) %>% fetch(fetch_args = fetch_args) } -#' FluView virological data from clinical labs +#' CDC FluView flu tests from clinical labs #' @description #' API docs: #' @@ -1080,7 +1080,7 @@ pub_fluview_clinical <- function(regions, epiweeks, ..., issues = NULL, lag = NU ) %>% fetch(fetch_args = fetch_args) } -#' FluView metadata +#' Metadata for the FluView endpoint #' @description #' API docs: #' Returns information about the fluview endpoint. @@ -1092,6 +1092,7 @@ pub_fluview_clinical <- function(regions, epiweeks, ..., issues = NULL, lag = NU #' @param fetch_args [`fetch_args`]. Additional arguments to pass to `fetch()`. #' #' @return [`tibble::tibble`] +#' @seealso [`pub_fluview()`] #' @keywords endpoint #' @export pub_fluview_meta <- function(fetch_args = fetch_args_list()) { @@ -1107,7 +1108,7 @@ pub_fluview_meta <- function(fetch_args = fetch_args_list()) { } -#' FluView ILINet data +#' CDC FluView ILINet outpatient doctor visits #' @description #' API docs: . For #' @@ -1192,7 +1193,7 @@ pub_fluview <- function( ) %>% fetch(fetch_args = fetch_args) } -#' Google Flu Trends data +#' Google Flu Trends flu search volume #' @description #' API docs: #' @@ -1234,7 +1235,7 @@ pub_gft <- function(locations, epiweeks, fetch_args = fetch_args_list()) { ) %>% fetch(fetch_args = fetch_args) } -#' Google Health Trends data +#' Google Health Trends health topics search volume #' #' @description #' API docs: @@ -1281,7 +1282,7 @@ pvt_ght <- function(auth, locations, epiweeks, query, fetch_args = fetch_args_li ) %>% fetch(fetch_args = fetch_args) } -#' KCDC ILI data +#' KCDC ILI incidence (Korea) #' @description #' API docs: #' @@ -1332,7 +1333,7 @@ pub_kcdc_ili <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, fetc ) %>% fetch(fetch_args = fetch_args) } -#' NoroSTAT metadata +#' Metadata for the NoroSTAT endpoint #' @description #' API docs: #' @@ -1343,6 +1344,7 @@ pub_kcdc_ili <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, fetc #' @param auth string. Restricted access key (not the same as API key). #' @param fetch_args [`fetch_args`]. Additional arguments to pass to `fetch()`. #' @return [`list`] +#' @seealso [`pvt_norostat()`] #' @keywords endpoint #' @export pvt_meta_norostat <- function(auth, fetch_args = fetch_args_list()) { @@ -1355,7 +1357,7 @@ pvt_meta_norostat <- function(auth, fetch_args = fetch_args_list()) { ) %>% fetch(fetch_args = fetch_args) } -#' API metadata +#' Metadata for the Delphi Epidata API #' @description #' API docs: #' @@ -1368,7 +1370,7 @@ pub_meta <- function(fetch_args = fetch_args_list()) { create_epidata_call("meta/", list(), only_supports_classic = TRUE) %>% fetch(fetch_args = fetch_args) } -#' NIDSS dengue data +#' NIDSS dengue cases (Taiwan) #' @description #' API docs: #' @@ -1408,7 +1410,7 @@ pub_nidss_dengue <- function(locations, epiweeks, fetch_args = fetch_args_list() ) %>% fetch(fetch_args = fetch_args) } -#' NIDSS flu data +#' NIDSS flu doctor visits (Taiwan) #' @description #' API docs: #' @@ -1466,8 +1468,10 @@ pub_nidss_flu <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, fet } -#' NoroSTAT data (point data, no min/max) +#' CDC NoroSTAT norovirus outbreaks #' @description +#' This is point data only, and does not include minima or maxima. +#' #' API docs: #' #' This is the documentation of the API for accessing the NoroSTAT (norostat) @@ -1509,7 +1513,7 @@ pvt_norostat <- function(auth, locations, epiweeks, fetch_args = fetch_args_list ) %>% fetch(fetch_args = fetch_args) } -#' Delphi's ILI nowcast +#' Delphi's ILI Nearby nowcasts #' @description #' API docs: . #' @@ -1545,7 +1549,7 @@ pub_nowcast <- function(locations, epiweeks, fetch_args = fetch_args_list()) { ) %>% fetch(fetch_args = fetch_args) } -#' PAHO Dengue data +#' PAHO dengue data (North and South America) #' @description #' API docs: #' @@ -1640,7 +1644,7 @@ pvt_quidel <- function(auth, locations, epiweeks, fetch_args = fetch_args_list() ) %>% fetch(fetch_args = fetch_args) } -#' Digital surveillance sensors +#' Influenza and dengue digital surveillance sensors #' @description #' API docs: #' @@ -1696,7 +1700,7 @@ pvt_sensors <- function(auth, names, locations, epiweeks, fetch_args = fetch_arg ) %>% fetch(fetch_args = fetch_args) } -#' HealthTweets data +#' HealthTweets total and influenza-related tweets #' @description #' API docs: #' @@ -1757,7 +1761,7 @@ pvt_twitter <- function(auth, locations, ..., dates = NULL, epiweeks = NULL, fet ) %>% fetch(fetch_args = fetch_args) } -#' Wikipedia access data +#' Wikipedia webpage counts by article #' @description #' API docs: # diff --git a/man/pub_covid_hosp_facility.Rd b/man/pub_covid_hosp_facility.Rd index df7d4d9a..46d6f51e 100644 --- a/man/pub_covid_hosp_facility.Rd +++ b/man/pub_covid_hosp_facility.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pub_covid_hosp_facility} \alias{pub_covid_hosp_facility} -\title{COVID hospitalization data for specific facilities} +\title{COVID hospitalizations by facility} \usage{ pub_covid_hosp_facility( hospital_pks, diff --git a/man/pub_covid_hosp_facility_lookup.Rd b/man/pub_covid_hosp_facility_lookup.Rd index 88b5d93d..718d153b 100644 --- a/man/pub_covid_hosp_facility_lookup.Rd +++ b/man/pub_covid_hosp_facility_lookup.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pub_covid_hosp_facility_lookup} \alias{pub_covid_hosp_facility_lookup} -\title{COVID hospitalization facility identifiers} +\title{Helper for finding COVID hospitalization facilities} \usage{ pub_covid_hosp_facility_lookup( ..., diff --git a/man/pub_covid_hosp_state_timeseries.Rd b/man/pub_covid_hosp_state_timeseries.Rd index ed959c28..b30113c1 100644 --- a/man/pub_covid_hosp_state_timeseries.Rd +++ b/man/pub_covid_hosp_state_timeseries.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pub_covid_hosp_state_timeseries} \alias{pub_covid_hosp_state_timeseries} -\title{COVID hospitalization data by state} +\title{COVID hospitalizations by state} \usage{ pub_covid_hosp_state_timeseries( states, diff --git a/man/pub_covidcast.Rd b/man/pub_covidcast.Rd index c530bc03..0d87bcd6 100644 --- a/man/pub_covidcast.Rd +++ b/man/pub_covidcast.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pub_covidcast} \alias{pub_covidcast} -\title{COVID data via the covidcast endpoint} +\title{Various COVID and flu signals via the COVIDcast endpoint} \usage{ pub_covidcast( source, diff --git a/man/pub_delphi.Rd b/man/pub_delphi.Rd index 83658abf..4613ad6c 100644 --- a/man/pub_delphi.Rd +++ b/man/pub_delphi.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pub_delphi} \alias{pub_delphi} -\title{Delphi's ILINet forecasts} +\title{Delphi's ILINet outpatient doctor visits forecasts} \usage{ pub_delphi(system, epiweek, fetch_args = fetch_args_list()) } diff --git a/man/pub_dengue_nowcast.Rd b/man/pub_dengue_nowcast.Rd index 8bfa5c37..f3709faf 100644 --- a/man/pub_dengue_nowcast.Rd +++ b/man/pub_dengue_nowcast.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pub_dengue_nowcast} \alias{pub_dengue_nowcast} -\title{Delphi's PAHO Dengue nowcast} +\title{Delphi's PAHO dengue nowcasts (North and South America)} \usage{ pub_dengue_nowcast(locations, epiweeks, fetch_args = fetch_args_list()) } diff --git a/man/pub_ecdc_ili.Rd b/man/pub_ecdc_ili.Rd index 85e5f789..7546d28f 100644 --- a/man/pub_ecdc_ili.Rd +++ b/man/pub_ecdc_ili.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pub_ecdc_ili} \alias{pub_ecdc_ili} -\title{ECDC ILI data} +\title{ECDC ILI incidence (Europe)} \usage{ pub_ecdc_ili( regions, diff --git a/man/pub_flusurv.Rd b/man/pub_flusurv.Rd index 4936499f..8d15ccfb 100644 --- a/man/pub_flusurv.Rd +++ b/man/pub_flusurv.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pub_flusurv} \alias{pub_flusurv} -\title{FluSurv hospitalization data} +\title{CDC FluSurv flu hospitalizations} \usage{ pub_flusurv( locations, @@ -34,7 +34,7 @@ the most recent issue is returned. Mutually exclusive with \code{issues}.} \description{ API docs: \url{https://cmu-delphi.github.io/delphi-epidata/api/flusurv.html}. -Obtain information on flu hospitalization rates from the Center of Disease +Obtain information on influenza hospitalization rates from the Center of Disease Control. See also \url{https://gis.cdc.gov/GRASP/Fluview/FluHospRates.html}. diff --git a/man/pub_fluview.Rd b/man/pub_fluview.Rd index 6dd15c31..30c47449 100644 --- a/man/pub_fluview.Rd +++ b/man/pub_fluview.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pub_fluview} \alias{pub_fluview} -\title{FluView ILINet data} +\title{CDC FluView ILINet outpatient doctor visits} \usage{ pub_fluview( regions, diff --git a/man/pub_fluview_clinical.Rd b/man/pub_fluview_clinical.Rd index 460179ac..db2eccbf 100644 --- a/man/pub_fluview_clinical.Rd +++ b/man/pub_fluview_clinical.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pub_fluview_clinical} \alias{pub_fluview_clinical} -\title{FluView virological data from clinical labs} +\title{CDC FluView flu tests from clinical labs} \usage{ pub_fluview_clinical( regions, diff --git a/man/pub_fluview_meta.Rd b/man/pub_fluview_meta.Rd index 37816b84..51e962b3 100644 --- a/man/pub_fluview_meta.Rd +++ b/man/pub_fluview_meta.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pub_fluview_meta} \alias{pub_fluview_meta} -\title{FluView metadata} +\title{Metadata for the FluView endpoint} \usage{ pub_fluview_meta(fetch_args = fetch_args_list()) } @@ -21,5 +21,8 @@ Returns information about the fluview endpoint. pub_fluview_meta() } +} +\seealso{ +\code{\link[=pub_fluview]{pub_fluview()}} } \keyword{endpoint} diff --git a/man/pub_gft.Rd b/man/pub_gft.Rd index 95d57239..ed736232 100644 --- a/man/pub_gft.Rd +++ b/man/pub_gft.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pub_gft} \alias{pub_gft} -\title{Google Flu Trends data} +\title{Google Flu Trends flu search volume} \usage{ pub_gft(locations, epiweeks, fetch_args = fetch_args_list()) } diff --git a/man/pub_kcdc_ili.Rd b/man/pub_kcdc_ili.Rd index f6107603..c6f4ab8e 100644 --- a/man/pub_kcdc_ili.Rd +++ b/man/pub_kcdc_ili.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pub_kcdc_ili} \alias{pub_kcdc_ili} -\title{KCDC ILI data} +\title{KCDC ILI incidence (Korea)} \usage{ pub_kcdc_ili( regions, diff --git a/man/pub_meta.Rd b/man/pub_meta.Rd index 438c17fb..202d3cfa 100644 --- a/man/pub_meta.Rd +++ b/man/pub_meta.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pub_meta} \alias{pub_meta} -\title{API metadata} +\title{Metadata for the Delphi Epidata API} \usage{ pub_meta(fetch_args = fetch_args_list()) } diff --git a/man/pub_nidss_dengue.Rd b/man/pub_nidss_dengue.Rd index b5e2aa90..2f390ac8 100644 --- a/man/pub_nidss_dengue.Rd +++ b/man/pub_nidss_dengue.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pub_nidss_dengue} \alias{pub_nidss_dengue} -\title{NIDSS dengue data} +\title{NIDSS dengue cases (Taiwan)} \usage{ pub_nidss_dengue(locations, epiweeks, fetch_args = fetch_args_list()) } diff --git a/man/pub_nidss_flu.Rd b/man/pub_nidss_flu.Rd index 480b288c..fc0e7d6d 100644 --- a/man/pub_nidss_flu.Rd +++ b/man/pub_nidss_flu.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pub_nidss_flu} \alias{pub_nidss_flu} -\title{NIDSS flu data} +\title{NIDSS flu doctor visits (Taiwan)} \usage{ pub_nidss_flu( regions, diff --git a/man/pub_nowcast.Rd b/man/pub_nowcast.Rd index 508d4fc1..13aa1a22 100644 --- a/man/pub_nowcast.Rd +++ b/man/pub_nowcast.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pub_nowcast} \alias{pub_nowcast} -\title{Delphi's ILI nowcast} +\title{Delphi's ILI Nearby nowcasts} \usage{ pub_nowcast(locations, epiweeks, fetch_args = fetch_args_list()) } diff --git a/man/pub_paho_dengue.Rd b/man/pub_paho_dengue.Rd index e99fbc5f..773927b7 100644 --- a/man/pub_paho_dengue.Rd +++ b/man/pub_paho_dengue.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pub_paho_dengue} \alias{pub_paho_dengue} -\title{PAHO Dengue data} +\title{PAHO dengue data (North and South America)} \usage{ pub_paho_dengue( regions, diff --git a/man/pub_wiki.Rd b/man/pub_wiki.Rd index cde73d95..2669ff1a 100644 --- a/man/pub_wiki.Rd +++ b/man/pub_wiki.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pub_wiki} \alias{pub_wiki} -\title{Wikipedia access data} +\title{Wikipedia webpage counts by article} \usage{ pub_wiki( articles, diff --git a/man/pvt_cdc.Rd b/man/pvt_cdc.Rd index 744ee76e..74497b29 100644 --- a/man/pvt_cdc.Rd +++ b/man/pvt_cdc.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pvt_cdc} \alias{pvt_cdc} -\title{CDC page hits} +\title{CDC total and by topic webpage visits} \usage{ pvt_cdc(auth, locations, epiweeks, fetch_args = fetch_args_list()) } diff --git a/man/pvt_dengue_sensors.Rd b/man/pvt_dengue_sensors.Rd index 47f50eaa..560e9e4b 100644 --- a/man/pvt_dengue_sensors.Rd +++ b/man/pvt_dengue_sensors.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pvt_dengue_sensors} \alias{pvt_dengue_sensors} -\title{Dengue digital surveillance sensors in PAHO member countries} +\title{PAHO dengue digital surveillance sensors (North and South America)} \usage{ pvt_dengue_sensors( auth, diff --git a/man/pvt_ght.Rd b/man/pvt_ght.Rd index 3366416f..cfa1038c 100644 --- a/man/pvt_ght.Rd +++ b/man/pvt_ght.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pvt_ght} \alias{pvt_ght} -\title{Google Health Trends data} +\title{Google Health Trends health topics search volume} \usage{ pvt_ght(auth, locations, epiweeks, query, fetch_args = fetch_args_list()) } diff --git a/man/pvt_meta_norostat.Rd b/man/pvt_meta_norostat.Rd index e967e316..491c7218 100644 --- a/man/pvt_meta_norostat.Rd +++ b/man/pvt_meta_norostat.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pvt_meta_norostat} \alias{pvt_meta_norostat} -\title{NoroSTAT metadata} +\title{Metadata for the NoroSTAT endpoint} \usage{ pvt_meta_norostat(auth, fetch_args = fetch_args_list()) } @@ -22,4 +22,7 @@ API docs: \url{https://cmu-delphi.github.io/delphi-epidata/api/meta_norostat.htm pvt_meta_norostat(auth = Sys.getenv("SECRET_API_AUTH_NOROSTAT")) } } +\seealso{ +\code{\link[=pvt_norostat]{pvt_norostat()}} +} \keyword{endpoint} diff --git a/man/pvt_norostat.Rd b/man/pvt_norostat.Rd index 60808134..8cf4ed10 100644 --- a/man/pvt_norostat.Rd +++ b/man/pvt_norostat.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pvt_norostat} \alias{pvt_norostat} -\title{NoroSTAT data (point data, no min/max)} +\title{CDC NoroSTAT norovirus outbreaks} \usage{ pvt_norostat(auth, locations, epiweeks, fetch_args = fetch_args_list()) } @@ -19,6 +19,8 @@ pvt_norostat(auth, locations, epiweeks, fetch_args = fetch_args_list()) \code{\link[tibble:tibble]{tibble::tibble}} } \description{ +This is point data only, and does not include minima or maxima. + API docs: \url{https://cmu-delphi.github.io/delphi-epidata/api/norostat.html} This is the documentation of the API for accessing the NoroSTAT (norostat) diff --git a/man/pvt_sensors.Rd b/man/pvt_sensors.Rd index 0d88e2dd..ec536fdf 100644 --- a/man/pvt_sensors.Rd +++ b/man/pvt_sensors.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pvt_sensors} \alias{pvt_sensors} -\title{Digital surveillance sensors} +\title{Influenza and dengue digital surveillance sensors} \usage{ pvt_sensors(auth, names, locations, epiweeks, fetch_args = fetch_args_list()) } diff --git a/man/pvt_twitter.Rd b/man/pvt_twitter.Rd index 92ee2c39..30763a74 100644 --- a/man/pvt_twitter.Rd +++ b/man/pvt_twitter.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/endpoints.R \name{pvt_twitter} \alias{pvt_twitter} -\title{HealthTweets data} +\title{HealthTweets total and influenza-related tweets} \usage{ pvt_twitter( auth, From 3f7897efbdbe30c04f015abe576f1e95c8bb19f8 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 17 Nov 2023 19:16:29 -0500 Subject: [PATCH 059/189] inform about regional coverage --- R/avail_endpoints.R | 1 + 1 file changed, 1 insertion(+) diff --git a/R/avail_endpoints.R b/R/avail_endpoints.R index e8c23b79..991dff78 100644 --- a/R/avail_endpoints.R +++ b/R/avail_endpoints.R @@ -22,5 +22,6 @@ avail_endpoints <- function() { Endpoint = paste0(h$Name, "()"), Description = h$Title ) + cli::cli_inform(c("i" = "Data is available for the US only, unless otherwise specified")) tib %>% print(n = 50) } From 63e2a72d1e041ed33159107aad53dfd0894c1d71 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Fri, 17 Nov 2023 16:24:51 -0800 Subject: [PATCH 060/189] Update R/auth.R Co-authored-by: brookslogan --- R/auth.R | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/R/auth.R b/R/auth.R index 5d8e46e9..6da1df70 100644 --- a/R/auth.R +++ b/R/auth.R @@ -11,11 +11,12 @@ #' key](https://api.delphi.cmu.edu/epidata/admin/registration_form). #' #' API keys are strings read from the environment variable `DELPHI_EPIDATA_KEY`. -#' We recommend setting your key with `save_api_key()`, which will modify your -#' `.Renviron` file and will persist your key across R sessions (see `?Startup` -#' for a description of `.Renviron` files). Alternatively, you can modify the -#' environment variable in the shell or with `Sys.setenv()`, but these will not -#' persist across sessions. +#' We recommend setting your key with `save_api_key()`, which will modify an +#' applicable `.Renviron` file, which will be read in automatically when you +#' start future R sessions (see [`?Startup`][base::Startup] for details on +#' `.Renviron` files). Alternatively, you can modify the environment variable at +#' the command line before/while launching R, or inside an R session with +#' [`Sys.setenv()`], but these will not persist across sessions. #' #' Once an API key is set, it is automatically used for all requests made by #' functions in this package. From 7a18d4a5167d32fbe4bc1711f43b669214a1384a Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Fri, 17 Nov 2023 16:25:17 -0800 Subject: [PATCH 061/189] Update R/auth.R Co-authored-by: brookslogan --- R/auth.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/auth.R b/R/auth.R index 6da1df70..ca7b48ff 100644 --- a/R/auth.R +++ b/R/auth.R @@ -54,7 +54,7 @@ save_api_key <- function() { cli::cli_inform( c( "i" = "This function will open your {.code .Renviron} file in a text editor. You will need to - write {.code DELPHI_EPIDATA_KEY=yourkeyhere} in the file and save it. If the editor + write {.code DELPHI_EPIDATA_KEY=yourkeyhere} (without quotes) in the file and save it. If the editor does not open, you will need to edit the file manually.", "i" = "Press any key to continue." ) From b33a5f5bf570d44107e8ea00499b9565dc399b75 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Fri, 17 Nov 2023 16:25:26 -0800 Subject: [PATCH 062/189] Update R/auth.R Co-authored-by: brookslogan --- R/auth.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/auth.R b/R/auth.R index ca7b48ff..53ff13b5 100644 --- a/R/auth.R +++ b/R/auth.R @@ -56,7 +56,7 @@ save_api_key <- function() { "i" = "This function will open your {.code .Renviron} file in a text editor. You will need to write {.code DELPHI_EPIDATA_KEY=yourkeyhere} (without quotes) in the file and save it. If the editor does not open, you will need to edit the file manually.", - "i" = "Press any key to continue." + "i" = "Press enter to continue." ) ) readline() From 6fabeca4795acee326cfaa1268312dab3313c3f9 Mon Sep 17 00:00:00 2001 From: dshemetov Date: Sat, 18 Nov 2023 00:27:21 +0000 Subject: [PATCH 063/189] docs: document (GHA) --- man/get_api_key.Rd | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/man/get_api_key.Rd b/man/get_api_key.Rd index 0a77debb..2fd9b1b7 100644 --- a/man/get_api_key.Rd +++ b/man/get_api_key.Rd @@ -24,11 +24,12 @@ including a rate limit. If you regularly request large amounts of data, please consider \href{https://api.delphi.cmu.edu/epidata/admin/registration_form}{registering for an API key}. API keys are strings read from the environment variable \code{DELPHI_EPIDATA_KEY}. -We recommend setting your key with \code{save_api_key()}, which will modify your -\code{.Renviron} file and will persist your key across R sessions (see \code{?Startup} -for a description of \code{.Renviron} files). Alternatively, you can modify the -environment variable in the shell or with \code{Sys.setenv()}, but these will not -persist across sessions. +We recommend setting your key with \code{save_api_key()}, which will modify an +applicable \code{.Renviron} file, which will be read in automatically when you +start future R sessions (see \code{\link[base:Startup]{?Startup}} for details on +\code{.Renviron} files). Alternatively, you can modify the environment variable at +the command line before/while launching R, or inside an R session with +\code{\link[=Sys.setenv]{Sys.setenv()}}, but these will not persist across sessions. Once an API key is set, it is automatically used for all requests made by functions in this package. From dc3e6ec5b9387f76bd24af7475370f48a247acbb Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 17 Nov 2023 15:44:00 -0500 Subject: [PATCH 064/189] add as_of arg to hosp state timeseries --- R/endpoints.R | 33 ++++++++++++++++++++++---- man/pub_covid_hosp_state_timeseries.Rd | 10 ++++++-- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/R/endpoints.R b/R/endpoints.R index c8ba2497..ac12877c 100644 --- a/R/endpoints.R +++ b/R/endpoints.R @@ -455,28 +455,53 @@ pub_covid_hosp_facility <- function( #' #' @param states character. Two letter state abbreviations. #' @param dates [`timeset`]. Dates to fetch. -#' @param issues [`timeset`]. Optionally, the issues to fetch. If not set, the -#' most recent issue is returned. #' @param ... not used for values, forces later arguments to bind by name +#' @param as_of Date. Optionally, the as of date for the issues to fetch. If not +#' specified, the most recent data is returned. Mutually exclusive with +#' `issues` or `lag`. +#' @param issues [`timeset`]. Optionally, the issue of the data to fetch. If not +#' specified, the most recent issue is returned. Mutually exclusive with +#' `as_of` or `lag`. #' @param fetch_args [`fetch_args`]. Additional arguments to pass to `fetch()`. #' @return [`tibble::tibble`] #' #' @keywords endpoint #' @export # -pub_covid_hosp_state_timeseries <- function(states, dates, ..., issues = NULL, fetch_args = fetch_args_list()) { +pub_covid_hosp_state_timeseries <- function( + states, + dates, + ..., + as_of = NULL, + issues = NULL, + fetch_args = fetch_args_list()) { + # Check parameters + if (missing(states) || missing(dates)) { + stop( + "`states` and `dates` are both required" + ) + } + + if (sum(!is.null(issues), !is.null(as_of)) > 1) { + stop("`issues`and `as_of` are mutually exclusive") + } + assert_character_param("states", states) assert_timeset_param("dates", dates) + assert_date_param("as_of", as_of, len = 1, required = FALSE) assert_timeset_param("issues", issues, required = FALSE) + dates <- parse_timeset_input(dates) issues <- parse_timeset_input(issues) + as_of <- parse_timeset_input(as_of) create_epidata_call( "covid_hosp_state_timeseries/", list( states = states, dates = dates, - issues = issues + issues = issues, + as_of = as_of ), list( create_epidata_field_info("state", "text"), diff --git a/man/pub_covid_hosp_state_timeseries.Rd b/man/pub_covid_hosp_state_timeseries.Rd index ed959c28..4cde92c1 100644 --- a/man/pub_covid_hosp_state_timeseries.Rd +++ b/man/pub_covid_hosp_state_timeseries.Rd @@ -8,6 +8,7 @@ pub_covid_hosp_state_timeseries( states, dates, ..., + as_of = NULL, issues = NULL, fetch_args = fetch_args_list() ) @@ -19,8 +20,13 @@ pub_covid_hosp_state_timeseries( \item{...}{not used for values, forces later arguments to bind by name} -\item{issues}{\code{\link{timeset}}. Optionally, the issues to fetch. If not set, the -most recent issue is returned.} +\item{as_of}{Date. Optionally, the as of date for the issues to fetch. If not +specified, the most recent data is returned. Mutually exclusive with +\code{issues} or \code{lag}.} + +\item{issues}{\code{\link{timeset}}. Optionally, the issue of the data to fetch. If not +specified, the most recent issue is returned. Mutually exclusive with +\code{as_of} or \code{lag}.} \item{fetch_args}{\code{\link{fetch_args}}. Additional arguments to pass to \code{fetch()}.} } From 1b932263b5a879fff7e3c15692e122eebb6b43bb Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Mon, 27 Nov 2023 13:14:44 -0500 Subject: [PATCH 065/189] test versioned queries --- tests/testthat/test-endpoints.R | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/testthat/test-endpoints.R b/tests/testthat/test-endpoints.R index 3c81dea1..1f2a3bc7 100644 --- a/tests/testthat/test-endpoints.R +++ b/tests/testthat/test-endpoints.R @@ -146,3 +146,32 @@ test_that("basic_epidata_call", { fetch_args = fetch_args_list(dry_run = TRUE) ) %>% request_url()) }) + +test_that("pub_covid_hosp_state_timeseries supports versioned queries", { + epidata_call <- pub_covid_hosp_state_timeseries( + "ut", epirange(12340101, 34560101), + issues = 20220101, + fetch_args = fetch_args_list( + fields = c("state","geocoded_state","date","issue","previous_day_admission_influenza_confirmed","previous_day_admission_influenza_confirmed_coverage"), + disable_date_parsing = TRUE, + dry_run = TRUE + ) + ) + expect_identical(epidata_call$params$issues, 20220101) + expect_identical(epidata_call$params$as_of, NULL) + # COVID hosp state timeseries server code doesn't support `lag` + expect_identical(epidata_call$params$lag, NULL) + + epidata_call <- pub_covid_hosp_state_timeseries( + "ut", epirange(12340101, 34560101), + as_of = 20220101, + fetch_args = fetch_args_list( + fields = c("state","geocoded_state","date","issue","previous_day_admission_influenza_confirmed","previous_day_admission_influenza_confirmed_coverage"), + disable_date_parsing = TRUE, + dry_run = TRUE + ) + ) + expect_identical(epidata_call$params$issues, NULL) + expect_identical(epidata_call$params$as_of, 20220101) + expect_identical(epidata_call$params$lag, NULL) +}) From a7091c2cfb6f2e9201811b0c7aa0887314dbc61a Mon Sep 17 00:00:00 2001 From: nmdefries Date: Mon, 27 Nov 2023 18:17:32 +0000 Subject: [PATCH 066/189] style: styler (GHA) --- tests/testthat/test-endpoints.R | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/testthat/test-endpoints.R b/tests/testthat/test-endpoints.R index 1f2a3bc7..0b6e83c7 100644 --- a/tests/testthat/test-endpoints.R +++ b/tests/testthat/test-endpoints.R @@ -149,13 +149,13 @@ test_that("basic_epidata_call", { test_that("pub_covid_hosp_state_timeseries supports versioned queries", { epidata_call <- pub_covid_hosp_state_timeseries( - "ut", epirange(12340101, 34560101), - issues = 20220101, - fetch_args = fetch_args_list( - fields = c("state","geocoded_state","date","issue","previous_day_admission_influenza_confirmed","previous_day_admission_influenza_confirmed_coverage"), - disable_date_parsing = TRUE, - dry_run = TRUE - ) + "ut", epirange(12340101, 34560101), + issues = 20220101, + fetch_args = fetch_args_list( + fields = c("state", "geocoded_state", "date", "issue", "previous_day_admission_influenza_confirmed", "previous_day_admission_influenza_confirmed_coverage"), + disable_date_parsing = TRUE, + dry_run = TRUE + ) ) expect_identical(epidata_call$params$issues, 20220101) expect_identical(epidata_call$params$as_of, NULL) @@ -163,13 +163,13 @@ test_that("pub_covid_hosp_state_timeseries supports versioned queries", { expect_identical(epidata_call$params$lag, NULL) epidata_call <- pub_covid_hosp_state_timeseries( - "ut", epirange(12340101, 34560101), - as_of = 20220101, - fetch_args = fetch_args_list( - fields = c("state","geocoded_state","date","issue","previous_day_admission_influenza_confirmed","previous_day_admission_influenza_confirmed_coverage"), - disable_date_parsing = TRUE, - dry_run = TRUE - ) + "ut", epirange(12340101, 34560101), + as_of = 20220101, + fetch_args = fetch_args_list( + fields = c("state", "geocoded_state", "date", "issue", "previous_day_admission_influenza_confirmed", "previous_day_admission_influenza_confirmed_coverage"), + disable_date_parsing = TRUE, + dry_run = TRUE + ) ) expect_identical(epidata_call$params$issues, NULL) expect_identical(epidata_call$params$as_of, 20220101) From 97beab315b9e84ba3c74466bc5e756983bdbdfce Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Mon, 27 Nov 2023 15:33:16 -0500 Subject: [PATCH 067/189] linting --- tests/testthat/test-endpoints.R | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/testthat/test-endpoints.R b/tests/testthat/test-endpoints.R index cb267612..8560b1a6 100644 --- a/tests/testthat/test-endpoints.R +++ b/tests/testthat/test-endpoints.R @@ -254,7 +254,9 @@ test_that("pub_covid_hosp_state_timeseries supports versioned queries", { "ut", epirange(12340101, 34560101), issues = 20220101, fetch_args = fetch_args_list( - fields = c("state", "geocoded_state", "date", "issue", "previous_day_admission_influenza_confirmed", "previous_day_admission_influenza_confirmed_coverage"), + fields = c("state", "geocoded_state", "date", "issue", + "previous_day_admission_influenza_confirmed", + "previous_day_admission_influenza_confirmed_coverage"), disable_date_parsing = TRUE, dry_run = TRUE ) @@ -268,7 +270,9 @@ test_that("pub_covid_hosp_state_timeseries supports versioned queries", { "ut", epirange(12340101, 34560101), as_of = 20220101, fetch_args = fetch_args_list( - fields = c("state", "geocoded_state", "date", "issue", "previous_day_admission_influenza_confirmed", "previous_day_admission_influenza_confirmed_coverage"), + fields = c("state", "geocoded_state", "date", "issue", + "previous_day_admission_influenza_confirmed", + "previous_day_admission_influenza_confirmed_coverage"), disable_date_parsing = TRUE, dry_run = TRUE ) From 0ce96942b17ab37fb97b836812c04742a62d1b09 Mon Sep 17 00:00:00 2001 From: nmdefries Date: Mon, 27 Nov 2023 20:34:37 +0000 Subject: [PATCH 068/189] style: styler (GHA) --- tests/testthat/test-endpoints.R | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/testthat/test-endpoints.R b/tests/testthat/test-endpoints.R index 8560b1a6..7bdf0fa4 100644 --- a/tests/testthat/test-endpoints.R +++ b/tests/testthat/test-endpoints.R @@ -254,9 +254,11 @@ test_that("pub_covid_hosp_state_timeseries supports versioned queries", { "ut", epirange(12340101, 34560101), issues = 20220101, fetch_args = fetch_args_list( - fields = c("state", "geocoded_state", "date", "issue", + fields = c( + "state", "geocoded_state", "date", "issue", "previous_day_admission_influenza_confirmed", - "previous_day_admission_influenza_confirmed_coverage"), + "previous_day_admission_influenza_confirmed_coverage" + ), disable_date_parsing = TRUE, dry_run = TRUE ) @@ -270,9 +272,11 @@ test_that("pub_covid_hosp_state_timeseries supports versioned queries", { "ut", epirange(12340101, 34560101), as_of = 20220101, fetch_args = fetch_args_list( - fields = c("state", "geocoded_state", "date", "issue", + fields = c( + "state", "geocoded_state", "date", "issue", "previous_day_admission_influenza_confirmed", - "previous_day_admission_influenza_confirmed_coverage"), + "previous_day_admission_influenza_confirmed_coverage" + ), disable_date_parsing = TRUE, dry_run = TRUE ) From 737e2cb0e7cd204192033cb5e8221a76e44e0154 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Mon, 27 Nov 2023 16:48:08 -0500 Subject: [PATCH 069/189] remove duplicate spec for issue field in hosp state timeseries --- R/endpoints.R | 1 - 1 file changed, 1 deletion(-) diff --git a/R/endpoints.R b/R/endpoints.R index a1cba8f6..2acebe76 100644 --- a/R/endpoints.R +++ b/R/endpoints.R @@ -513,7 +513,6 @@ pub_covid_hosp_state_timeseries <- function( create_epidata_field_info("state", "text"), create_epidata_field_info("issue", "date"), create_epidata_field_info("date", "date"), - create_epidata_field_info("issue", "date"), create_epidata_field_info("critical_staffing_shortage_today_yes", "bool"), create_epidata_field_info("critical_staffing_shortage_today_no", "bool"), create_epidata_field_info("critical_staffing_shortage_today_not_reported", "bool"), From a43ea6f47cc8d5032b9056bb10dd0a2040c3e2cf Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Mon, 27 Nov 2023 16:49:46 -0500 Subject: [PATCH 070/189] error if epidata meta has duplicates --- R/epidatacall.R | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/R/epidatacall.R b/R/epidatacall.R index c858d25f..47f7eb58 100644 --- a/R/epidatacall.R +++ b/R/epidatacall.R @@ -41,12 +41,31 @@ #' @return #' - For `create_epidata_call`: an `epidata_call` object #' +#' @importFrom purrr map_chr create_epidata_call <- function(endpoint, params, meta = NULL, only_supports_classic = FALSE) { stopifnot(is.character(endpoint), length(endpoint) == 1) stopifnot(is.list(params)) stopifnot(is.null(meta) || is.list(meta)) stopifnot(is.logical(only_supports_classic), length(only_supports_classic) == 1) + + if (length(unique(meta)) != length(meta)) { + cli::cli_abort(c( + "List of expected epidata fields contains duplicate entries", + "i" = "duplicates in meta can cause problems parsing fetched data", + "Please fix in `endpoints.R`" + )) + } + + meta_field_names <- map_chr(meta, ~ .x$name) + if (length(meta_field_names) != length(unique(meta_field_names))) { + cli::cli_abort(c( + "List of expected epidata fields contains duplicate names", + "i" = "duplicates in meta can cause problems parsing fetched data", + "Please fix in `endpoints.R`" + )) + } + if (is.null(meta)) { meta <- list() } From 83d781337afff487ad4149c906a90acc683838d5 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Mon, 27 Nov 2023 16:50:36 -0500 Subject: [PATCH 071/189] don't try to convert date fields to date again; warn if meta and return values have diff number of fields --- R/model.R | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/R/model.R b/R/model.R index 249124e8..85fd5516 100644 --- a/R/model.R +++ b/R/model.R @@ -122,9 +122,9 @@ parse_value <- function(info, value, disable_date_parsing = FALSE) { if (is.null(value)) { return(value) - } else if (info$type == "date" && !disable_date_parsing) { + } else if (info$type == "date" && !disable_date_parsing && !inherits(value, "Date")) { return(parse_api_date(value)) - } else if (info$type == "epiweek" && !disable_date_parsing) { + } else if (info$type == "epiweek" && !disable_date_parsing && !inherits(value, "Date")) { return(parse_api_week(value)) } else if (info$type == "bool") { return(as.logical(value)) @@ -142,6 +142,11 @@ parse_data_frame <- function(epidata_call, df, disable_date_parsing = FALSE) { stopifnot(inherits(epidata_call, "epidata_call")) meta <- epidata_call$meta df <- as.data.frame(df) + + if (length(meta) != 0 && ncol(df) != length(meta)) { + cli::cli_warn("Not all return columns are specified as expected epidata fields") + } + if (length(meta) == 0) { return(df) } From 8f21658ab8028c77db5858370a3dfb1d5de35e0d Mon Sep 17 00:00:00 2001 From: nmdefries <42820733+nmdefries@users.noreply.github.com> Date: Tue, 28 Nov 2023 09:28:23 -0500 Subject: [PATCH 072/189] remove mention of `lag` in doc Co-authored-by: Dmitry Shemetov --- R/endpoints.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/endpoints.R b/R/endpoints.R index a1cba8f6..7c70840b 100644 --- a/R/endpoints.R +++ b/R/endpoints.R @@ -462,7 +462,7 @@ pub_covid_hosp_facility <- function( #' @param ... not used for values, forces later arguments to bind by name #' @param as_of Date. Optionally, the as of date for the issues to fetch. If not #' specified, the most recent data is returned. Mutually exclusive with -#' `issues` or `lag`. +#' `issues`. #' @param issues [`timeset`]. Optionally, the issue of the data to fetch. If not #' specified, the most recent issue is returned. Mutually exclusive with #' `as_of` or `lag`. From a4ca176a2900ac14c141295f328d8c3acf6324d0 Mon Sep 17 00:00:00 2001 From: nmdefries Date: Tue, 28 Nov 2023 14:29:47 +0000 Subject: [PATCH 073/189] docs: document (GHA) --- man/pub_covid_hosp_state_timeseries.Rd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/pub_covid_hosp_state_timeseries.Rd b/man/pub_covid_hosp_state_timeseries.Rd index d8dd3b6c..2823f6da 100644 --- a/man/pub_covid_hosp_state_timeseries.Rd +++ b/man/pub_covid_hosp_state_timeseries.Rd @@ -22,7 +22,7 @@ pub_covid_hosp_state_timeseries( \item{as_of}{Date. Optionally, the as of date for the issues to fetch. If not specified, the most recent data is returned. Mutually exclusive with -\code{issues} or \code{lag}.} +\code{issues}.} \item{issues}{\code{\link{timeset}}. Optionally, the issue of the data to fetch. If not specified, the most recent issue is returned. Mutually exclusive with From 2d4f1d4b616d0da6481e938f9e2bd2d0c712c24f Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Tue, 28 Nov 2023 10:32:33 -0500 Subject: [PATCH 074/189] check diff of expected and actual field names, since user can request subset --- R/model.R | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/R/model.R b/R/model.R index 85fd5516..9438350f 100644 --- a/R/model.R +++ b/R/model.R @@ -138,18 +138,23 @@ parse_value <- function(info, value, disable_date_parsing = FALSE) { value } +#' @importFrom purrr map_chr parse_data_frame <- function(epidata_call, df, disable_date_parsing = FALSE) { stopifnot(inherits(epidata_call, "epidata_call")) meta <- epidata_call$meta df <- as.data.frame(df) - if (length(meta) != 0 && ncol(df) != length(meta)) { - cli::cli_warn("Not all return columns are specified as expected epidata fields") - } - if (length(meta) == 0) { return(df) } + + meta_field_names <- map_chr(meta, ~ .x$name) + if ( + length(setdiff(names(df), meta_field_names)) != 0 + ) { + cli::cli_warn("Not all return columns are specified as expected epidata fields") + } + columns <- colnames(df) for (i in seq_len(length(meta))) { info <- meta[[i]] From 0f6b003aeefaa6523435aed63585e410f1edc332 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Tue, 28 Nov 2023 11:04:48 -0500 Subject: [PATCH 075/189] provide error and warning class names --- R/epidatacall.R | 26 ++++++++++++++++---------- R/model.R | 5 ++++- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/R/epidatacall.R b/R/epidatacall.R index 47f7eb58..92c431df 100644 --- a/R/epidatacall.R +++ b/R/epidatacall.R @@ -50,20 +50,26 @@ create_epidata_call <- function(endpoint, params, meta = NULL, stopifnot(is.logical(only_supports_classic), length(only_supports_classic) == 1) if (length(unique(meta)) != length(meta)) { - cli::cli_abort(c( - "List of expected epidata fields contains duplicate entries", - "i" = "duplicates in meta can cause problems parsing fetched data", - "Please fix in `endpoints.R`" - )) + cli::cli_abort( + c( + "List of expected epidata fields contains duplicate entries", + "i" = "duplicates in meta can cause problems parsing fetched data", + "Please fix in `endpoints.R`" + ), + class = "epidatr__duplicate_meta_entries" + ) } meta_field_names <- map_chr(meta, ~ .x$name) if (length(meta_field_names) != length(unique(meta_field_names))) { - cli::cli_abort(c( - "List of expected epidata fields contains duplicate names", - "i" = "duplicates in meta can cause problems parsing fetched data", - "Please fix in `endpoints.R`" - )) + cli::cli_abort( + c( + "List of expected epidata fields contains duplicate names", + "i" = "duplicates in meta can cause problems parsing fetched data", + "Please fix in `endpoints.R`" + ), + class = "epidatr__duplicate_meta_names" + ) } if (is.null(meta)) { diff --git a/R/model.R b/R/model.R index 9438350f..051a3d33 100644 --- a/R/model.R +++ b/R/model.R @@ -152,7 +152,10 @@ parse_data_frame <- function(epidata_call, df, disable_date_parsing = FALSE) { if ( length(setdiff(names(df), meta_field_names)) != 0 ) { - cli::cli_warn("Not all return columns are specified as expected epidata fields") + cli::cli_warn( + "Not all return columns are specified as expected epidata fields", + class = "epidatr__missing_meta_fields" + ) } columns <- colnames(df) From c093c11452b08952118183ccb5363bf4e5a7a150 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Tue, 28 Nov 2023 11:05:03 -0500 Subject: [PATCH 076/189] test create_epidata_call success and failures --- tests/testthat/test-epidatacall.R | 36 +++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/testthat/test-epidatacall.R b/tests/testthat/test-epidatacall.R index b0d171d8..83a1c71f 100644 --- a/tests/testthat/test-epidatacall.R +++ b/tests/testthat/test-epidatacall.R @@ -160,3 +160,39 @@ test_that("classic only fetch", { # making sure that fetch_tbl and throws the expected error on classic only expect_error(epidata_call %>% fetch_tbl(), class = "only_supports_classic_format") }) + +test_that("create_epidata_call basic behavior", { + endpoint <- "endpoint" + params <- list() + + # Success + meta <- list(list(name = "time_value", class = "date"), list(name = "value", class = "double")) + expected <- list( + endpoint = endpoint, + params = params, + base_url = "https://api.delphi.cmu.edu/epidata/", + meta = meta, + only_supports_classic = FALSE + ) + class(expected) = "epidata_call" + + expect_identical(create_epidata_call(endpoint, params, meta = meta), expected) + + expected$meta <- list() + expect_identical(create_epidata_call(endpoint, params, meta = NULL), expected) + expect_identical(create_epidata_call(endpoint, params, meta = list()), expected) +}) + + +test_that("create_epidata_call fails when meta arg contains duplicates", { + endpoint <- "endpoint" + params <- list() + + # Duplicate names + meta <- list(list(name = "time_value", class = "date"), list(name = "time_value", class = "int")) + expect_error(create_epidata_call(endpoint, params, meta = meta), class = "epidatr__duplicate_meta_names") + + # Duplicate entries + meta <- list(list(name = "time_value", class = "date"), list(name = "time_value", class = "date")) + expect_error(create_epidata_call(endpoint, params, meta = meta), class = "epidatr__duplicate_meta_entries") +}) From a716b27816ef4632d62af00211b24b7c0ae0217b Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Tue, 28 Nov 2023 11:30:22 -0500 Subject: [PATCH 077/189] test parse_data_frame --- tests/testthat/test-model.R | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/tests/testthat/test-model.R b/tests/testthat/test-model.R index 7a05aa0e..d5acf51d 100644 --- a/tests/testthat/test-model.R +++ b/tests/testthat/test-model.R @@ -69,7 +69,32 @@ test_that("null parsing", { }) test_that("parse invalid time", { - vale <- list(3) - vale$class <- "my nonexistant class" - expect_error(parse_timeset_input(vale)) + value <- list(3) + value$class <- "my nonexistant class" + expect_error(parse_timeset_input(value)) +}) + +test_that("parse_data_frame warns when df contains fields not listed in meta", { + epidata_call <- pub_flusurv( + locations = "ca", + epiweeks = 202001, + fetch_args = fetch_args_list(dry_run = TRUE) + ) + # see generate_test_data.R + mock_df <- as.data.frame(readr::read_rds(testthat::test_path("data/flusurv-epiweeks.rds"))) + + # Success when meta and df fields match exactly + expect_no_warning(parse_data_frame(epidata_call, mock_df)) + + # Warning when df contains extra fields + mock_df$extra <- 5 + expect_warning( + parse_data_frame(epidata_call, mock_df), + class = "epidatr__missing_meta_fields" + ) + mock_df$extra <- NULL + + # Success when meta contains extra fields + mock_df$rate_age_0 <- NULL + expect_no_warning(parse_data_frame(epidata_call, mock_df)) }) From 073ac5b7e2f2f25aac303a7d0e588d8d48f538f5 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Tue, 28 Nov 2023 11:50:59 -0500 Subject: [PATCH 078/189] linting --- tests/testthat/test-epidatacall.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testthat/test-epidatacall.R b/tests/testthat/test-epidatacall.R index 83a1c71f..bc198fbc 100644 --- a/tests/testthat/test-epidatacall.R +++ b/tests/testthat/test-epidatacall.R @@ -174,7 +174,7 @@ test_that("create_epidata_call basic behavior", { meta = meta, only_supports_classic = FALSE ) - class(expected) = "epidata_call" + class(expected) <- "epidata_call" expect_identical(create_epidata_call(endpoint, params, meta = meta), expected) From 4228e79c3e2e60c30b704e0405248de1b95c4a38 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Tue, 28 Nov 2023 12:12:51 -0500 Subject: [PATCH 079/189] list unspecified fields in warning message --- R/model.R | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/R/model.R b/R/model.R index 051a3d33..93d79807 100644 --- a/R/model.R +++ b/R/model.R @@ -149,11 +149,15 @@ parse_data_frame <- function(epidata_call, df, disable_date_parsing = FALSE) { } meta_field_names <- map_chr(meta, ~ .x$name) + missing_fields <- setdiff(names(df), meta_field_names) if ( - length(setdiff(names(df), meta_field_names)) != 0 + length(missing_fields) != 0 ) { cli::cli_warn( - "Not all return columns are specified as expected epidata fields", + c( + "Not all return columns are specified as expected epidata fields", + "i" = "Unspecified fields {missing_fields} may need to be manually converted to more appropriate classes" + ), class = "epidatr__missing_meta_fields" ) } From 30655c7930c9b315cdbcef931b63be27f156a673 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Tue, 28 Nov 2023 12:22:39 -0500 Subject: [PATCH 080/189] fill in ? for public endpoints --- tests/testthat/test-endpoints.R | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/testthat/test-endpoints.R b/tests/testthat/test-endpoints.R index 7bdf0fa4..ca5f3d24 100644 --- a/tests/testthat/test-endpoints.R +++ b/tests/testthat/test-endpoints.R @@ -37,7 +37,7 @@ test_that("basic_epidata_call", { fetch_args = fetch_args_list(dry_run = TRUE) ) %>% request_url()) expect_no_error(pub_dengue_nowcast( - locations = "?", + locations = "ca", epiweeks = epirange(201501, 202001), fetch_args = fetch_args_list(dry_run = TRUE) ) %>% request_url()) @@ -84,7 +84,7 @@ test_that("basic_epidata_call", { fetch_args = fetch_args_list(dry_run = TRUE) ) %>% request_url()) expect_no_error(pub_kcdc_ili( - regions = "?", + regions = "ROK", epiweeks = epirange(201201, 202001), fetch_args = fetch_args_list(dry_run = TRUE) ) %>% request_url()) @@ -213,7 +213,7 @@ test_that("endpoints fail when given args via dots", { ) expect_error( pub_kcdc_ili( - regions = "?", + regions = "ROK", date_range = epirange(201201, 202001) ), regexp = dots_error From 89556fd736ab7d7e09665910420093fec039e316 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Tue, 28 Nov 2023 17:50:03 -0500 Subject: [PATCH 081/189] add missing field info entries --- R/endpoints.R | 216 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 214 insertions(+), 2 deletions(-) diff --git a/R/endpoints.R b/R/endpoints.R index 2acebe76..724e1555 100644 --- a/R/endpoints.R +++ b/R/endpoints.R @@ -432,7 +432,63 @@ pub_covid_hosp_facility <- function( create_epidata_field_info( "total_patients_hosp_confirmed_influenza_and_covid_7d_avg", "float" - ) + ), + create_epidata_field_info("geocoded_hospital_address", "text"), + create_epidata_field_info("hhs_ids", "text"), + create_epidata_field_info("is_corrected", "bool"), + create_epidata_field_info( + "previous_day_admission_adult_covid_confirmed_7_day_coverage", + "int" + ), + create_epidata_field_info( + "previous_day_admission_adult_covid_suspected_7_day_coverage", + "int" + ), + create_epidata_field_info( + "previous_day_admission_pediatric_covid_confirmed_7_day_coverage", + "int" + ), + create_epidata_field_info( + "previous_day_admission_pediatric_covid_suspected_7_day_coverage", + "int" + ), + create_epidata_field_info( + "previous_week_patients_covid_vaccinated_doses_all_7_day", + "int" + ), + create_epidata_field_info( + "previous_week_patients_covid_vaccinated_doses_all_7_day_sum", + "int" + ), + create_epidata_field_info( + "previous_week_patients_covid_vaccinated_doses_one_7_day", + "int" + ), + create_epidata_field_info( + "previous_week_patients_covid_vaccinated_doses_one_7_day_sum", + "int" + ), + create_epidata_field_info( + "previous_week_personnel_covid_vaccd_doses_administered_7_day", + "int" + ), + create_epidata_field_info( + "previous_week_personnel_covid_vaccd_doses_administered_7_day_sum", + "int" + ), + create_epidata_field_info("total_personnel_covid_vaccinated_doses_all_7_day", "int"), + create_epidata_field_info( + "total_personnel_covid_vaccinated_doses_all_7_day_sum", + "int" + ), + create_epidata_field_info("total_personnel_covid_vaccinated_doses_none_7_day", "int"), + create_epidata_field_info( + "total_personnel_covid_vaccinated_doses_none_7_day_sum", + "int" + ), + create_epidata_field_info("total_personnel_covid_vaccinated_doses_one_7_day", "int"), + create_epidata_field_info("total_personnel_covid_vaccinated_doses_one_7_day_sum", + "int") ) ) %>% fetch(fetch_args = fetch_args) } @@ -618,7 +674,157 @@ pub_covid_hosp_state_timeseries <- function( create_epidata_field_info("percent_of_inpatients_with_covid", "float"), create_epidata_field_info("inpatient_bed_covid_utilization", "float"), create_epidata_field_info("adult_icu_bed_covid_utilization", "float"), - create_epidata_field_info("adult_icu_bed_utilization", "float") + create_epidata_field_info("adult_icu_bed_utilization", "float"), + create_epidata_field_info("geocoded_state", "text"), + create_epidata_field_info("deaths_covid", "int"), + create_epidata_field_info("deaths_covid_coverage", "int"), + create_epidata_field_info("icu_patients_confirmed_influenza", "int"), + create_epidata_field_info("icu_patients_confirmed_influenza_coverage", "int"), + create_epidata_field_info( + "on_hand_supply_therapeutic_a_casirivimab_imdevimab_courses", + "int" + ), + create_epidata_field_info("on_hand_supply_therapeutic_b_bamlanivimab_courses", "int"), + create_epidata_field_info( + "on_hand_supply_therapeutic_c_bamlanivimab_etesevimab_courses", + "int" + ), + create_epidata_field_info("previous_day_admission_adult_covid_confirmed_18_19", "int"), + create_epidata_field_info( + "previous_day_admission_adult_covid_confirmed_18_19_coverage", + "int" + ), + create_epidata_field_info("previous_day_admission_adult_covid_confirmed_20_29", "int"), + create_epidata_field_info( + "previous_day_admission_adult_covid_confirmed_20_29_coverage", + "int" + ), + create_epidata_field_info("previous_day_admission_adult_covid_confirmed_30_39", "int"), + create_epidata_field_info( + "previous_day_admission_adult_covid_confirmed_30_39_coverage", + "int" + ), + create_epidata_field_info("previous_day_admission_adult_covid_confirmed_40_49", "int"), + create_epidata_field_info( + "previous_day_admission_adult_covid_confirmed_40_49_coverage", + "int" + ), + create_epidata_field_info("previous_day_admission_adult_covid_confirmed_50_59", "int"), + create_epidata_field_info( + "previous_day_admission_adult_covid_confirmed_50_59_coverage", + "int" + ), + create_epidata_field_info("previous_day_admission_adult_covid_confirmed_60_69", "int"), + create_epidata_field_info( + "previous_day_admission_adult_covid_confirmed_60_69_coverage", + "int" + ), + create_epidata_field_info("previous_day_admission_adult_covid_confirmed_70_79", "int"), + create_epidata_field_info( + "previous_day_admission_adult_covid_confirmed_70_79_coverage", + "int" + ), + create_epidata_field_info( + "previous_day_admission_adult_covid_confirmed_80plus", + "int" + ), + create_epidata_field_info( + "previous_day_admission_adult_covid_confirmed_80plus_coverage", + "int" + ), + create_epidata_field_info( + "previous_day_admission_adult_covid_confirmed_unknown", + "int" + ), + create_epidata_field_info( + "previous_day_admission_adult_covid_confirmed_unknown_coverage", + "int" + ), + create_epidata_field_info("previous_day_admission_adult_covid_suspected_18_19", "int"), + create_epidata_field_info( + "previous_day_admission_adult_covid_suspected_18_19_coverage", + "int" + ), + create_epidata_field_info("previous_day_admission_adult_covid_suspected_20_29", "int"), + create_epidata_field_info( + "previous_day_admission_adult_covid_suspected_20_29_coverage", + "int" + ), + create_epidata_field_info("previous_day_admission_adult_covid_suspected_30_39", "int"), + create_epidata_field_info( + "previous_day_admission_adult_covid_suspected_30_39_coverage", + "int" + ), + create_epidata_field_info("previous_day_admission_adult_covid_suspected_40_49", "int"), + create_epidata_field_info( + "previous_day_admission_adult_covid_suspected_40_49_coverage", + "int" + ), + create_epidata_field_info("previous_day_admission_adult_covid_suspected_50_59", "int"), + create_epidata_field_info( + "previous_day_admission_adult_covid_suspected_50_59_coverage", + "int" + ), + create_epidata_field_info("previous_day_admission_adult_covid_suspected_60_69", "int"), + create_epidata_field_info( + "previous_day_admission_adult_covid_suspected_60_69_coverage", + "int" + ), + create_epidata_field_info("previous_day_admission_adult_covid_suspected_70_79", "int"), + create_epidata_field_info( + "previous_day_admission_adult_covid_suspected_70_79_coverage", + "int" + ), + create_epidata_field_info( + "previous_day_admission_adult_covid_suspected_80plus", + "int" + ), + create_epidata_field_info( + "previous_day_admission_adult_covid_suspected_80plus_coverage", + "int" + ), + create_epidata_field_info( + "previous_day_admission_adult_covid_suspected_unknown", + "int" + ), + create_epidata_field_info( + "previous_day_admission_adult_covid_suspected_unknown_coverage", + "int" + ), + create_epidata_field_info("previous_day_admission_influenza_confirmed", "int"), + create_epidata_field_info( + "previous_day_admission_influenza_confirmed_coverage", + "int" + ), + create_epidata_field_info("previous_day_deaths_covid_and_influenza", "int"), + create_epidata_field_info("previous_day_deaths_covid_and_influenza_coverage", "int"), + create_epidata_field_info("previous_day_deaths_influenza", "int"), + create_epidata_field_info("previous_day_deaths_influenza_coverage", "int"), + create_epidata_field_info( + "previous_week_therapeutic_a_casirivimab_imdevimab_courses_used", + "int" + ), + create_epidata_field_info( + "previous_week_therapeutic_b_bamlanivimab_courses_used", + "int" + ), + create_epidata_field_info( + "previous_week_therapeutic_c_bamlanivimab_etesevimab_courses_used", + "int" + ), + create_epidata_field_info( + "total_patients_hospitalized_confirmed_influenza_covid", + "int" + ), + create_epidata_field_info( + "total_patients_hospitalized_confirmed_influenza_covid_coverage", + "int" + ), + create_epidata_field_info("total_patients_hospitalized_confirmed_influenza", "int"), + create_epidata_field_info( + "total_patients_hospitalized_confirmed_influenza_coverage", + "int" + ) ) ) %>% fetch(fetch_args = fetch_args) } @@ -656,6 +862,11 @@ pub_covidcast_meta <- function(fetch_args = fetch_args_list()) { categories = c("week", "day") ), + create_epidata_field_info( + "geo_type", + "categorical", + categories = c("nation", "msa", "hrr", "hhs", "state", "county", "dma") + ), create_epidata_field_info("min_time", "date"), create_epidata_field_info("max_time", "date"), create_epidata_field_info("num_locations", "int"), @@ -1205,6 +1416,7 @@ pub_fluview <- function( create_epidata_field_info("lag", "int"), create_epidata_field_info("num_ili", "int"), create_epidata_field_info("num_patients", "int"), + create_epidata_field_info("num_providers", "int"), create_epidata_field_info("num_age_0", "int"), create_epidata_field_info("num_age_1", "int"), create_epidata_field_info("num_age_2", "int"), From 2fce66d1e7880da7b69223fbc4648744185f3d93 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Wed, 29 Nov 2023 10:17:02 -0500 Subject: [PATCH 082/189] parse `release_date`s as date --- R/endpoints.R | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/R/endpoints.R b/R/endpoints.R index 724e1555..0c73fbd0 100644 --- a/R/endpoints.R +++ b/R/endpoints.R @@ -1242,7 +1242,7 @@ pub_flusurv <- function(locations, epiweeks, ..., issues = NULL, lag = NULL, fet lag = lag ), list( - create_epidata_field_info("release_date", "text"), + create_epidata_field_info("release_date", "date"), create_epidata_field_info("location", "text"), create_epidata_field_info("issue", "epiweek"), create_epidata_field_info("epiweek", "epiweek"), @@ -1300,7 +1300,7 @@ pub_fluview_clinical <- function(regions, epiweeks, ..., issues = NULL, lag = NU lag = lag ), list( - create_epidata_field_info("release_date", "text"), + create_epidata_field_info("release_date", "date"), create_epidata_field_info("region", "text"), create_epidata_field_info("issue", "epiweek"), create_epidata_field_info("epiweek", "epiweek"), @@ -1335,7 +1335,7 @@ pub_fluview_meta <- function(fetch_args = fetch_args_list()) { "fluview_meta/", list(), list( - create_epidata_field_info("latest_update", "text"), + create_epidata_field_info("latest_update", "date"), create_epidata_field_info("latest_issue", "date"), create_epidata_field_info("table_rows", "int") ) @@ -1409,7 +1409,7 @@ pub_fluview <- function( auth = auth ), list( - create_epidata_field_info("release_date", "text"), + create_epidata_field_info("release_date", "date"), create_epidata_field_info("region", "text"), create_epidata_field_info("issue", "epiweek"), create_epidata_field_info("epiweek", "epiweek"), @@ -1559,7 +1559,7 @@ pub_kcdc_ili <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, fetc lag = lag ), list( - create_epidata_field_info("release_date", "text"), + create_epidata_field_info("release_date", "date"), create_epidata_field_info("region", "text"), create_epidata_field_info("issue", "epiweek"), create_epidata_field_info("epiweek", "epiweek"), @@ -1692,7 +1692,7 @@ pub_nidss_flu <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, fet lag = lag ), list( - create_epidata_field_info("release_date", "text"), + create_epidata_field_info("release_date", "date"), create_epidata_field_info("region", "text"), create_epidata_field_info("epiweek", "epiweek"), create_epidata_field_info("issue", "epiweek"), @@ -1742,7 +1742,7 @@ pvt_norostat <- function(auth, locations, epiweeks, fetch_args = fetch_args_list epiweeks = epiweeks ), list( - create_epidata_field_info("release_date", "text"), + create_epidata_field_info("release_date", "date"), create_epidata_field_info("epiweek", "epiweek"), create_epidata_field_info("value", "int") ) @@ -1823,7 +1823,7 @@ pub_paho_dengue <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, f lag = lag ), list( - create_epidata_field_info("release_date", "text"), + create_epidata_field_info("release_date", "date"), create_epidata_field_info("region", "text"), create_epidata_field_info("serotype", "text"), create_epidata_field_info("epiweek", "epiweek"), From fa038fa347d430e56ddbf3550338024935719657 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Wed, 29 Nov 2023 10:40:37 -0500 Subject: [PATCH 083/189] allow dash-separate dates to be parsed --- R/model.R | 2 +- tests/testthat/test-model.R | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/R/model.R b/R/model.R index 93d79807..7cc6e638 100644 --- a/R/model.R +++ b/R/model.R @@ -174,7 +174,7 @@ parse_data_frame <- function(epidata_call, df, disable_date_parsing = FALSE) { #' @keywords internal parse_api_date <- function(value) { - as.Date(as.character(value), format = "%Y%m%d") + as.Date(as.character(value), tryFormats = c("%Y%m%d", "%Y-%m-%d")) } #' parse_api_week converts an integer to a date diff --git a/tests/testthat/test-model.R b/tests/testthat/test-model.R index d5acf51d..36a5d1d5 100644 --- a/tests/testthat/test-model.R +++ b/tests/testthat/test-model.R @@ -98,3 +98,13 @@ test_that("parse_data_frame warns when df contains fields not listed in meta", { mock_df$rate_age_0 <- NULL expect_no_warning(parse_data_frame(epidata_call, mock_df)) }) + +test_that("parse_api_date accepts str and int input", { + expect_identical(parse_api_date("20200101"), as.Date("2020-01-01")) + expect_identical(parse_api_date(20200101), as.Date("2020-01-01")) +}) + +test_that("parse_api_date accepts YYYYMMDD and YYYY-MM-DD", { + expect_identical(parse_api_date(20200101), as.Date("2020-01-01")) + expect_identical(parse_api_date("2020-01-01"), as.Date("2020-01-01")) +}) From 5e7a0f655363d0afa39bccb236857a0cd4da07af Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Wed, 29 Nov 2023 11:36:23 -0500 Subject: [PATCH 084/189] test missing date parsing behavior --- tests/testthat/test-model.R | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/testthat/test-model.R b/tests/testthat/test-model.R index 36a5d1d5..9f9b739c 100644 --- a/tests/testthat/test-model.R +++ b/tests/testthat/test-model.R @@ -57,11 +57,12 @@ test_that("null parsing", { # see generate_test_data.R mock_df <- as.data.frame(readr::read_rds(testthat::test_path("data/flusurv-epiweeks.rds"))) metadata <- epidata_call$meta - mock_df[[metadata[[1]]$name]][1] <- list(NULL) + mock_df[[metadata[[1]]$name]][1] <- NA mock_df[[metadata[[2]]$name]] <- c(TRUE) epidata_call$meta[[2]]$type <- "bool" - res <- parse_data_frame(epidata_call, mock_df) %>% as_tibble() + expect_no_error(res <- parse_data_frame(epidata_call, mock_df) %>% as_tibble()) expect_true(res$location) + expect_identical(res$release_date, as.Date(NA)) # if the call has no metadata, return the whole frame as is epidata_call$meta <- NULL @@ -108,3 +109,7 @@ test_that("parse_api_date accepts YYYYMMDD and YYYY-MM-DD", { expect_identical(parse_api_date(20200101), as.Date("2020-01-01")) expect_identical(parse_api_date("2020-01-01"), as.Date("2020-01-01")) }) + +test_that("parse_api_date handles missing values appropriately", { + expect_identical(parse_api_date(NA), as.Date(NA)) +}) From d534e3e7069a6c3ae5db722907a1985887cf51b6 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Wed, 29 Nov 2023 11:41:23 -0500 Subject: [PATCH 085/189] linting --- R/endpoints.R | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/R/endpoints.R b/R/endpoints.R index 0c73fbd0..1e1521b3 100644 --- a/R/endpoints.R +++ b/R/endpoints.R @@ -487,8 +487,10 @@ pub_covid_hosp_facility <- function( "int" ), create_epidata_field_info("total_personnel_covid_vaccinated_doses_one_7_day", "int"), - create_epidata_field_info("total_personnel_covid_vaccinated_doses_one_7_day_sum", - "int") + create_epidata_field_info( + "total_personnel_covid_vaccinated_doses_one_7_day_sum", + "int" + ) ) ) %>% fetch(fetch_args = fetch_args) } @@ -823,8 +825,8 @@ pub_covid_hosp_state_timeseries <- function( create_epidata_field_info("total_patients_hospitalized_confirmed_influenza", "int"), create_epidata_field_info( "total_patients_hospitalized_confirmed_influenza_coverage", - "int" - ) + "int" + ) ) ) %>% fetch(fetch_args = fetch_args) } From 38a5c1bf962e13c1ca6ea61fc73a37881fdf9d72 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Wed, 29 Nov 2023 11:46:25 -0500 Subject: [PATCH 086/189] fill in ? for private endpoints --- tests/testthat/test-endpoints.R | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/testthat/test-endpoints.R b/tests/testthat/test-endpoints.R index ca5f3d24..53aca4cf 100644 --- a/tests/testthat/test-endpoints.R +++ b/tests/testthat/test-endpoints.R @@ -43,8 +43,8 @@ test_that("basic_epidata_call", { ) %>% request_url()) expect_no_error(pvt_dengue_sensors( auth = "yourkey", - names = "?", - locations = "?", + names = "ght", + locations = "ag", epiweeks = epirange(201501, 202001), fetch_args = fetch_args_list(dry_run = TRUE) ) %>% request_url()) @@ -80,7 +80,7 @@ test_that("basic_epidata_call", { auth = "yourkey", locations = "ca", epiweeks = epirange(201201, 202001), - query = "?", + query = "how to get over the flu", fetch_args = fetch_args_list(dry_run = TRUE) ) %>% request_url()) expect_no_error(pub_kcdc_ili( From 8e4fb6c018956142dc3e7fd518783ad253e87deb Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Wed, 29 Nov 2023 12:17:49 -0500 Subject: [PATCH 087/189] verify that field specs are all EpidataFieldInfo objs --- R/epidatacall.R | 5 +++-- R/model.R | 2 +- tests/testthat/test-epidatacall.R | 26 ++++++++++++++++++++------ 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/R/epidatacall.R b/R/epidatacall.R index 92c431df..dbf3fc23 100644 --- a/R/epidatacall.R +++ b/R/epidatacall.R @@ -41,12 +41,13 @@ #' @return #' - For `create_epidata_call`: an `epidata_call` object #' -#' @importFrom purrr map_chr +#' @importFrom purrr map_chr map_lgl create_epidata_call <- function(endpoint, params, meta = NULL, only_supports_classic = FALSE) { stopifnot(is.character(endpoint), length(endpoint) == 1) stopifnot(is.list(params)) stopifnot(is.null(meta) || is.list(meta)) + stopifnot(all(map_lgl(meta, ~ inherits(.x, "EpidataFieldInfo")))) stopifnot(is.logical(only_supports_classic), length(only_supports_classic) == 1) if (length(unique(meta)) != length(meta)) { @@ -60,7 +61,7 @@ create_epidata_call <- function(endpoint, params, meta = NULL, ) } - meta_field_names <- map_chr(meta, ~ .x$name) + meta_field_names <- map_chr(meta, "name") if (length(meta_field_names) != length(unique(meta_field_names))) { cli::cli_abort( c( diff --git a/R/model.R b/R/model.R index 93d79807..0bad9a84 100644 --- a/R/model.R +++ b/R/model.R @@ -148,7 +148,7 @@ parse_data_frame <- function(epidata_call, df, disable_date_parsing = FALSE) { return(df) } - meta_field_names <- map_chr(meta, ~ .x$name) + meta_field_names <- map_chr(meta, "name") missing_fields <- setdiff(names(df), meta_field_names) if ( length(missing_fields) != 0 diff --git a/tests/testthat/test-epidatacall.R b/tests/testthat/test-epidatacall.R index bc198fbc..642c609d 100644 --- a/tests/testthat/test-epidatacall.R +++ b/tests/testthat/test-epidatacall.R @@ -166,7 +166,10 @@ test_that("create_epidata_call basic behavior", { params <- list() # Success - meta <- list(list(name = "time_value", class = "date"), list(name = "value", class = "double")) + meta <- list( + create_epidata_field_info("time_value", "date"), + create_epidata_field_info("value", "float") + ) expected <- list( endpoint = endpoint, params = params, @@ -175,7 +178,6 @@ test_that("create_epidata_call basic behavior", { only_supports_classic = FALSE ) class(expected) <- "epidata_call" - expect_identical(create_epidata_call(endpoint, params, meta = meta), expected) expected$meta <- list() @@ -189,10 +191,22 @@ test_that("create_epidata_call fails when meta arg contains duplicates", { params <- list() # Duplicate names - meta <- list(list(name = "time_value", class = "date"), list(name = "time_value", class = "int")) - expect_error(create_epidata_call(endpoint, params, meta = meta), class = "epidatr__duplicate_meta_names") + meta <- list( + create_epidata_field_info("time_value", "date"), + create_epidata_field_info("time_value", "int") + ) + expect_error( + create_epidata_call(endpoint, params, meta = meta), + class = "epidatr__duplicate_meta_names" + ) # Duplicate entries - meta <- list(list(name = "time_value", class = "date"), list(name = "time_value", class = "date")) - expect_error(create_epidata_call(endpoint, params, meta = meta), class = "epidatr__duplicate_meta_entries") + meta <- list( + create_epidata_field_info("time_value", "date"), + create_epidata_field_info("time_value", "date") + ) + expect_error( + create_epidata_call(endpoint, params, meta = meta), + class = "epidatr__duplicate_meta_entries" + ) }) From ff87a71dd0e8ea5494251da0162a39d0c1ca8e00 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Wed, 29 Nov 2023 14:38:42 -0500 Subject: [PATCH 088/189] use identical to compare as_of and issues to `*` --- R/utils.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/utils.R b/R/utils.R index 3695c501..eed7c88f 100644 --- a/R/utils.R +++ b/R/utils.R @@ -29,8 +29,8 @@ check_is_recent <- function(dates, max_age) { #' #' @keywords internal check_is_cachable <- function(epidata_call, fetch_args) { - as_of_cachable <- (!is.null(epidata_call$params$as_of) && epidata_call$params$as_of != "*") - issues_cachable <- (!is.null(epidata_call$params$issues) && all(epidata_call$params$issues != "*")) + as_of_cachable <- (!is.null(epidata_call$params$as_of) && !identical(epidata_call$params$as_of, "*")) + issues_cachable <- (!is.null(epidata_call$params$issues) && all(!identical(epidata_call$params$issues, "*"))) is_cachable <- ( !is.null(cache_environ$epidatr_cache) && (as_of_cachable || issues_cachable) && From 0fa2491d443abcb9b9abe9a10a639f321b3b398e Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Wed, 29 Nov 2023 14:58:47 -0500 Subject: [PATCH 089/189] test date/str handling --- tests/testthat/test-utils.R | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index ad0e6c8f..f840f9fb 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -20,3 +20,42 @@ test_that("format_list", { expect_identical(format_list(list("5", "6")), "5,6") expect_identical(format_list(list("*", "*")), "*,*") }) + +test_that("check_is_cachable can handle both str and date inputs of various lengths", { + epidata_call <- list( + params = list(as_of = NULL, issues = NULL) + ) + fetch_args <- fetch_args_list() + + expect_no_error(check_is_cachable(epidata_call, fetch_args)) + + # as_of string + epidata_call$params$as_of <- "2022-01-01" + epidata_call$params$issues <- NULL + expect_no_error(check_is_cachable(epidata_call, fetch_args)) + + # as_of date + epidata_call$params$as_of <- as.Date("2022-01-01") + epidata_call$params$issues <- NULL + expect_no_error(check_is_cachable(epidata_call, fetch_args)) + + # issues single string + epidata_call$params$as_of <- NULL + epidata_call$params$issues <- "2022-01-01" + expect_no_error(check_is_cachable(epidata_call, fetch_args)) + + # issues string vector + epidata_call$params$as_of <- NULL + epidata_call$params$issues <- c("2022-01-01", "2022-02-01") + expect_no_error(check_is_cachable(epidata_call, fetch_args)) + + # issues single date + epidata_call$params$as_of <- NULL + epidata_call$params$issues <- as.Date("2022-01-01") + expect_no_error(check_is_cachable(epidata_call, fetch_args)) + + # issues date vector + epidata_call$params$as_of <- NULL + epidata_call$params$issues <- c(as.Date("2022-01-01"), as.Date("2022-02-01")) + expect_no_error(check_is_cachable(epidata_call, fetch_args)) +}) From 77048b3074253a259cdc105019d432d3c7e808bf Mon Sep 17 00:00:00 2001 From: nmdefries <42820733+nmdefries@users.noreply.github.com> Date: Thu, 30 Nov 2023 09:28:29 -0500 Subject: [PATCH 090/189] check when issues is an epirange Co-authored-by: Dmitry Shemetov --- tests/testthat/test-utils.R | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index f840f9fb..2d3cda94 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -58,4 +58,9 @@ test_that("check_is_cachable can handle both str and date inputs of various leng epidata_call$params$as_of <- NULL epidata_call$params$issues <- c(as.Date("2022-01-01"), as.Date("2022-02-01")) expect_no_error(check_is_cachable(epidata_call, fetch_args)) + + # issues epirange + epidata_call$params$as_of <- NULL + epidata_call$params$issues <- epirange(as.Date("2022-01-01"), as.Date("2022-02-01")) + expect_no_error(check_is_cachable(epidata_call, fetch_args)) }) From fb02033f851d38281c727fc0135927d721357a9a Mon Sep 17 00:00:00 2001 From: nmdefries Date: Thu, 30 Nov 2023 14:30:06 +0000 Subject: [PATCH 091/189] style: styler (GHA) --- tests/testthat/test-utils.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index 2d3cda94..fb5cfbe5 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -58,7 +58,7 @@ test_that("check_is_cachable can handle both str and date inputs of various leng epidata_call$params$as_of <- NULL epidata_call$params$issues <- c(as.Date("2022-01-01"), as.Date("2022-02-01")) expect_no_error(check_is_cachable(epidata_call, fetch_args)) - + # issues epirange epidata_call$params$as_of <- NULL epidata_call$params$issues <- epirange(as.Date("2022-01-01"), as.Date("2022-02-01")) From abd8f4d298bb849056678622bd138cb3527cb403 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Thu, 30 Nov 2023 10:28:58 -0500 Subject: [PATCH 092/189] lastest_issue is an epiweek, not a date --- R/endpoints.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/endpoints.R b/R/endpoints.R index d8bb34d6..25f3ed2e 100644 --- a/R/endpoints.R +++ b/R/endpoints.R @@ -1338,7 +1338,7 @@ pub_fluview_meta <- function(fetch_args = fetch_args_list()) { list(), list( create_epidata_field_info("latest_update", "date"), - create_epidata_field_info("latest_issue", "date"), + create_epidata_field_info("latest_issue", "epiweek"), create_epidata_field_info("table_rows", "int") ) ) %>% fetch(fetch_args = fetch_args) From 33c83664771c25f70de261323c921ac0221466c7 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Thu, 7 Dec 2023 12:20:02 -0500 Subject: [PATCH 093/189] describe recent bug fix changes. change some formatting --- NEWS.md | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index 644898d3..eaf61d10 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,9 +1,25 @@ +# epidatr 1.1.0.9000 + +- Function reference now displays commonly-used functions first (#205). +- Endpoints now fail when passed misspelled arguments (#187, #201). +- `pub_fluview_meta` fixed to `fetch` the response automatically. +- `pub_covid_hosp_state_timeseries` now supports use of the `as_of` parameter + (#209). +- `pub_covid_hosp_state_timeseries` now correctly parses the `issue` field, + instead of returning a missing value (#202). +- `release_date` and `latest_update` fields are now parsed as `Date`, rather + than as text. This change impacts several endpoints.. +- In `pub_fluview_meta`, `latest_issue` field is now parsed as epiweek, rather + than being parsed as `Date` and returning a missing value. +- Support `Date` objects passed to version arguments `as_of` and `issues` in + endpoints (#192, #194). + # epidatr 1.1.0 -- renamed the mostly internal `get_auth_key` to `get_api_key` -- added `save_api_key` to more easily set the option -- various CRAN submission related doc-fixes -- fixed some errors from passing "" as a key +- Rename the mostly internal `get_auth_key` to `get_api_key` (#181). +- Add `save_api_key` to more easily set the option (#181). +- Fix documentation related to CRAN submission. +- Fix some errors from passing "" as a key. # epidatr 1.0.0 From e43fec6cfd943964c720313fddfc0fd9726ea931 Mon Sep 17 00:00:00 2001 From: nmdefries <42820733+nmdefries@users.noreply.github.com> Date: Thu, 7 Dec 2023 14:57:09 -0500 Subject: [PATCH 094/189] add cache, api key, and line-wrapping updates Co-authored-by: Dmitry Shemetov --- NEWS.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/NEWS.md b/NEWS.md index eaf61d10..63560201 100644 --- a/NEWS.md +++ b/NEWS.md @@ -13,6 +13,11 @@ than being parsed as `Date` and returning a missing value. - Support `Date` objects passed to version arguments `as_of` and `issues` in endpoints (#192, #194). +- `set_cache` cache size no longer runs into integer overflow (#189) +- `clear_cache` now handles positional arguments just like `set_cache` (#197) +- Improve line-wrapping of warning messages (#191) +- `set_api_key` now available to help persist API key environment variables (#181, #217) +- `get_api_key` no longer reads from R options and only uses environment variables (#217) # epidatr 1.1.0 From 6f4dff541329381f604b9d35de7dff8548955340 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Thu, 7 Dec 2023 14:58:49 -0500 Subject: [PATCH 095/189] periods --- NEWS.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/NEWS.md b/NEWS.md index 63560201..31096d72 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,8 +3,7 @@ - Function reference now displays commonly-used functions first (#205). - Endpoints now fail when passed misspelled arguments (#187, #201). - `pub_fluview_meta` fixed to `fetch` the response automatically. -- `pub_covid_hosp_state_timeseries` now supports use of the `as_of` parameter - (#209). +- `pub_covid_hosp_state_timeseries` now supports use of the `as_of` parameter (#209). - `pub_covid_hosp_state_timeseries` now correctly parses the `issue` field, instead of returning a missing value (#202). - `release_date` and `latest_update` fields are now parsed as `Date`, rather @@ -13,11 +12,11 @@ than being parsed as `Date` and returning a missing value. - Support `Date` objects passed to version arguments `as_of` and `issues` in endpoints (#192, #194). -- `set_cache` cache size no longer runs into integer overflow (#189) -- `clear_cache` now handles positional arguments just like `set_cache` (#197) -- Improve line-wrapping of warning messages (#191) -- `set_api_key` now available to help persist API key environment variables (#181, #217) -- `get_api_key` no longer reads from R options and only uses environment variables (#217) +- `set_cache` cache size no longer runs into integer overflow (#189). +- `clear_cache` now handles positional arguments just like `set_cache` (#197). +- Improve line-wrapping of warning messages (#191). +- `set_api_key` now available to help persist API key environment variables (#181, #217). +- `get_api_key` no longer reads from R options and only uses environment variables (#217). # epidatr 1.1.0 From 6938fcd0b12640c1609d887ac3df229b22308c95 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Thu, 7 Dec 2023 15:05:50 -0500 Subject: [PATCH 096/189] combine changelog 1.1.0 and 1.1.0.9000, and change version to 1.0.0.9000 --- .bumpversion.cfg | 2 +- DESCRIPTION | 4 ++-- NEWS.md | 5 +---- R/constants.R | 2 +- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 23851e7c..c4459027 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 1.1.0 +current_version = 1.0.0 commit = False tag = False diff --git a/DESCRIPTION b/DESCRIPTION index bfe2839c..3e02fafe 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,8 +1,8 @@ Package: epidatr Type: Package Title: Client for Delphi's 'Epidata' API -Version: 1.1.0.9000 -Date: 2023-09-11 +Version: 1.0.0.9000 +Date: 2023-12-07 Authors@R: c( person("Logan", "Brooks", email = "lcbrooks@andrew.cmu.edu", role = c("aut")), diff --git a/NEWS.md b/NEWS.md index 31096d72..06bd7ed3 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -# epidatr 1.1.0.9000 +# epidatr 1.0.0.9000 - Function reference now displays commonly-used functions first (#205). - Endpoints now fail when passed misspelled arguments (#187, #201). @@ -17,9 +17,6 @@ - Improve line-wrapping of warning messages (#191). - `set_api_key` now available to help persist API key environment variables (#181, #217). - `get_api_key` no longer reads from R options and only uses environment variables (#217). - -# epidatr 1.1.0 - - Rename the mostly internal `get_auth_key` to `get_api_key` (#181). - Add `save_api_key` to more easily set the option (#181). - Fix documentation related to CRAN submission. diff --git a/R/constants.R b/R/constants.R index 1fbc4add..b00768ca 100644 --- a/R/constants.R +++ b/R/constants.R @@ -1,3 +1,3 @@ -version <- "1.1.0" +version <- "1.0.0" http_headers <- httr::add_headers("User-Agent" = paste0("epidatr/", version), "Accept-Encoding" = "gzip") global_base_url <- "https://api.delphi.cmu.edu/epidata/" From 8cc7d5b6677a8720311ff76df76c410da255b820 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Thu, 7 Dec 2023 17:11:54 -0500 Subject: [PATCH 097/189] add .9000 everywhere --- .bumpversion.cfg | 2 +- R/constants.R | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index c4459027..f6301400 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 1.0.0 +current_version = 1.0.0.9000 commit = False tag = False diff --git a/R/constants.R b/R/constants.R index b00768ca..2a4aa3d7 100644 --- a/R/constants.R +++ b/R/constants.R @@ -1,3 +1,3 @@ -version <- "1.0.0" +version <- "1.0.0.9000" http_headers <- httr::add_headers("User-Agent" = paste0("epidatr/", version), "Accept-Encoding" = "gzip") global_base_url <- "https://api.delphi.cmu.edu/epidata/" From 4ea1453f9fa98801cae2516f2fe7dc0eb5e68256 Mon Sep 17 00:00:00 2001 From: nmdefries <42820733+nmdefries@users.noreply.github.com> Date: Thu, 7 Dec 2023 21:29:37 -0500 Subject: [PATCH 098/189] api key changes deduped Co-authored-by: Dmitry Shemetov --- NEWS.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 06bd7ed3..e41e8fc6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -16,9 +16,8 @@ - `clear_cache` now handles positional arguments just like `set_cache` (#197). - Improve line-wrapping of warning messages (#191). - `set_api_key` now available to help persist API key environment variables (#181, #217). +- `get_auth_key` renamed to `get_api_key` (#181). - `get_api_key` no longer reads from R options and only uses environment variables (#217). -- Rename the mostly internal `get_auth_key` to `get_api_key` (#181). -- Add `save_api_key` to more easily set the option (#181). - Fix documentation related to CRAN submission. - Fix some errors from passing "" as a key. From e6bcee6b4d9e4c9f254d47fe741a9406169b89cb Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 8 Dec 2023 10:28:04 -0500 Subject: [PATCH 099/189] remove usage from landing page; add licensing info and more description --- README.Rmd | 84 ++++++--------------------- README.md | 164 +++++++++++++++++++---------------------------------- 2 files changed, 75 insertions(+), 173 deletions(-) diff --git a/README.Rmd b/README.Rmd index cd43d3c9..f1801944 100644 --- a/README.Rmd +++ b/README.Rmd @@ -21,86 +21,34 @@ ggplot2::theme_set(ggplot2::theme_bw()) [![codecov](https://codecov.io/gh/dsweber2/epidatr/branch/dev/graph/badge.svg?token=jVHL9eHZNZ)](https://app.codecov.io/gh/dsweber2/epidatr) -The [Delphi Epidatr package](https://cmu-delphi.github.io/epidatr/) is an R front-end for the [Delphi Epidata API](https://cmu-delphi.github.io/delphi-epidata/), which provides real-time access to epidemiological surveillance data for influenza, COVID-19, and other diseases for the USA at various geographical resolutions, both from official government sources such as the [Center for Disease Control (CDC)](https://www.cdc.gov/datastatistics/index.html) and [Google Trends](https://cmu-delphi.github.io/delphi-epidata/api/covidcast-signals/google-symptoms.html) and private partners such as [Facebook](https://delphi.cmu.edu/blog/2020/08/26/covid-19-symptom-surveys-through-facebook/) and [Change Healthcare](https://www.changehealthcare.com/). It is built and maintained by the Carnegie Mellon University [Delphi research group](https://delphi.cmu.edu/). - -This package is designed to streamline the downloading and usage of data from the [Delphi Epidata -API](https://cmu-delphi.github.io/delphi-epidata/). It provides a simple R interface to the API, including functions for downloading data, parsing the results, and converting the data into a tidy format. The API stores a historical record of all data, including corrections and updates, which is particularly useful for accurately backtesting forecasting models. We also provide packages for downstream data processing ([epiprocess](https://github.com/cmu-delphi/epiprocess)) and modeling ([epipredict](https://github.com/cmu-delphi/epipredict)). - -## Usage - -You can find detailed docs here: - -```{r} -library(epidatr) -# Obtain the smoothed covid-like illness (CLI) signal from the -# Facebook survey as it was on April 10, 2021 for the US -epidata <- pub_covidcast( - source = "fb-survey", - signals = "smoothed_cli", - geo_type = "nation", - time_type = "day", - geo_values = "us", - time_values = epirange(20210101, 20210601), - as_of = "2021-06-01" -) -epidata -``` +The [Delphi `epidatr` package](https://cmu-delphi.github.io/epidatr/) is an R front-end for the [Delphi Epidata API](https://cmu-delphi.github.io/delphi-epidata/), which provides real-time access to epidemiological surveillance data for influenza, COVID-19, and other diseases. `epidatr` is built and maintained by the Carnegie Mellon University [Delphi research group](https://delphi.cmu.edu/). -```{r fb-cli-signal} -# Plot this data -library(ggplot2) -ggplot(epidata, aes(x = time_value, y = value)) + - geom_line() + - labs( - title = "Smoothed CLI from Facebook Survey", - subtitle = "US, 2021", - x = "Date", - y = "CLI" - ) -``` +Data is available for the United States and a handful of other countries at various geographical resolutions, both from official government sources such as the [US Center for Disease Control (CDC)](https://www.cdc.gov/datastatistics/index.html), and private partners such as [Facebook](https://delphi.cmu.edu/blog/2020/08/26/covid-19-symptom-surveys-through-facebook/) and [Change Healthcare](https://www.changehealthcare.com/). The API stores a historical record of all data, including corrections and updates, which is particularly useful for accurately backtesting forecasting models. +`epidatr` is designed to streamline the downloading and usage of data from the Epidata API. The package provides a simple R interface to the API, including functions for downloading data, parsing the results, and converting the data into a tidy format. We also provide the [epiprocess](https://github.com/cmu-delphi/epiprocess) package for downstream data processing and [epipredict](https://github.com/cmu-delphi/epipredict) for modeling. -## Installation +Consult the [Epidata API documentation](https://cmu-delphi.github.io/delphi-epidata/) for details on the data included in the API, API key registration, licensing, and how to cite this data in your work. The documentation lists all the data sources and signals available through this API for [COVID-19](https://cmu-delphi.github.io/delphi-epidata/api/covidcast_signals.html) and for [other diseases](https://cmu-delphi.github.io/delphi-epidata/api/README.html#source-specific-parameters). -You can install the stable version of this package from CRAN: +**To get started** using this package, view the Getting Started guide at `vignette("epidatr")`. -```R -install.packages("epidatr") -pak::pkg_install("epidatr") -renv::install("epidatr") -``` +## Get updates -Or if you want the development version, install from GitHub: +**You should consider subscribing to the [API mailing list](https://lists.andrew.cmu.edu/mailman/listinfo/delphi-covidcast-api)** to be notified of package updates, new data sources, corrections, and other updates. -```R -# Install the dev version using `pak` or `remotes` -pak::pkg_install("cmu-delphi/epidatr") -remotes::install_github("cmu-delphi/epidatr") -renv::install("cmu-delphi/epidatr") -``` +## For users of the `covidcast` R package + +`epidatr` is a complete rewrite of the [`covidcast` package](https://cmu-delphi.github.io/covidcast/covidcastR/), with a focus on speed, reliability, and ease of use. The `covidcast` package is deprecated and will no longer be updated. -### API Keys +## Usage terms and citation -The Delphi API requires a (free) API key for full functionality. To generate -your key, register for a pseudo-anonymous account -[here](https://api.delphi.cmu.edu/epidata/admin/registration_form) and see more -discussion on the [general API -website](https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html). See the -`save_api_key()` function documentation for details on how to use your API key. +We request that if you use the `epidatr` package in your work, or use any of the data provided by the Delphi Epidata API through non-`covidcast` endpoints, that you cite us using the citation given by [`citation("epidatr")`](https://cmu-delphi.github.io/epidatr/dev/authors.html#citation). If you use any of the data from the `covidcast` endpoint, please use the [COVIDcast citation](https://cmu-delphi.github.io/covidcast/covidcastR/authors.html#citation) as well. See the [COVIDcast licensing documentation](https://cmu-delphi.github.io/delphi-epidata/api/covidcast_licensing.html) and the [licensing documentation for other endpoints](https://cmu-delphi.github.io/delphi-epidata/api/README.html#data-licensing) for information about citing the datasets provided by the API. + +**Warning:** If you use data from the Epidata API to power a product, dashboard, app, or other service, please download the data you need and store it centrally rather than making API requests for every user. Our server resources are limited and cannot support high-volume interactive use. + +See also the [Terms of Use](https://delphi.cmu.edu/covidcast/terms-of-use/), noting that the data is a research product and not warranted for a particular purpose. -Note that the private endpoints (i.e. those prefixed with `pvt_`) require a -separate key that needs to be passed as an argument. These endpoints require -specific data use agreements to access. [mit-image]: https://img.shields.io/badge/License-MIT-yellow.svg [mit-url]: https://opensource.org/license/mit/ [github-actions-image]: https://github.com/cmu-delphi/epidatr/workflows/ci/badge.svg [github-actions-url]: https://github.com/cmu-delphi/epidatr/actions - -## Get updates - -You should consider subscribing to the [API mailing list](https://lists.andrew.cmu.edu/mailman/listinfo/delphi-covidcast-api) to be notified of package updates, new data sources, corrections, and other updates. - -## For users of the `covidcast` R package - -The `epidatr` package is a complete rewrite of the [`covidcast` package](https://cmu-delphi.github.io/covidcast/covidcastR/), with a focus on speed, reliability, and ease of use. The `covidcast` package is deprecated and will no longer be updated. diff --git a/README.md b/README.md index ea27a6fd..dabaf5a9 100644 --- a/README.md +++ b/README.md @@ -12,126 +12,80 @@ Actions](https://github.com/cmu-delphi/epidatr/workflows/ci/badge.svg)](https:// [![codecov](https://codecov.io/gh/dsweber2/epidatr/branch/dev/graph/badge.svg?token=jVHL9eHZNZ)](https://app.codecov.io/gh/dsweber2/epidatr) -The [Delphi Epidatr package](https://cmu-delphi.github.io/epidatr/) is +The [Delphi `epidatr` package](https://cmu-delphi.github.io/epidatr/) is an R front-end for the [Delphi Epidata API](https://cmu-delphi.github.io/delphi-epidata/), which provides real-time access to epidemiological surveillance data for influenza, -COVID-19, and other diseases for the USA at various geographical -resolutions, both from official government sources such as the [Center -for Disease Control -(CDC)](https://www.cdc.gov/datastatistics/index.html) and [Google -Trends](https://cmu-delphi.github.io/delphi-epidata/api/covidcast-signals/google-symptoms.html) -and private partners such as -[Facebook](https://delphi.cmu.edu/blog/2020/08/26/covid-19-symptom-surveys-through-facebook/) -and [Change Healthcare](https://www.changehealthcare.com/). It is built -and maintained by the Carnegie Mellon University [Delphi research +COVID-19, and other diseases. `epidatr` is built and maintained by the +Carnegie Mellon University [Delphi research group](https://delphi.cmu.edu/). -This package is designed to streamline the downloading and usage of data -from the [Delphi Epidata -API](https://cmu-delphi.github.io/delphi-epidata/). It provides a simple -R interface to the API, including functions for downloading data, -parsing the results, and converting the data into a tidy format. The API +Data is available for the United States and a handful of other countries +at various geographical resolutions, both from official government +sources such as the [US Center for Disease Control +(CDC)](https://www.cdc.gov/datastatistics/index.html), and private +partners such as +[Facebook](https://delphi.cmu.edu/blog/2020/08/26/covid-19-symptom-surveys-through-facebook/) +and [Change Healthcare](https://www.changehealthcare.com/). The API stores a historical record of all data, including corrections and updates, which is particularly useful for accurately backtesting -forecasting models. We also provide packages for downstream data -processing ([epiprocess](https://github.com/cmu-delphi/epiprocess)) and -modeling ([epipredict](https://github.com/cmu-delphi/epipredict)). - -## Usage - -You can find detailed docs here: - -``` r -library(epidatr) -# Obtain the smoothed covid-like illness (CLI) signal from the -# Facebook survey as it was on April 10, 2021 for the US -epidata <- pub_covidcast( - source = "fb-survey", - signals = "smoothed_cli", - geo_type = "nation", - time_type = "day", - geo_values = "us", - time_values = epirange(20210101, 20210601), - as_of = "2021-06-01" -) -epidata -#> # A tibble: 151 × 15 -#> geo_value signal source geo_type time_type time_value direction issue -#> -#> 1 us smoothed… fb-su… nation day 2021-01-01 NA 2021-01-06 -#> 2 us smoothed… fb-su… nation day 2021-01-02 NA 2021-01-07 -#> 3 us smoothed… fb-su… nation day 2021-01-03 NA 2021-01-08 -#> 4 us smoothed… fb-su… nation day 2021-01-04 NA 2021-01-09 -#> 5 us smoothed… fb-su… nation day 2021-01-05 NA 2021-01-10 -#> 6 us smoothed… fb-su… nation day 2021-01-06 NA 2021-01-29 -#> 7 us smoothed… fb-su… nation day 2021-01-07 NA 2021-01-29 -#> 8 us smoothed… fb-su… nation day 2021-01-08 NA 2021-01-29 -#> 9 us smoothed… fb-su… nation day 2021-01-09 NA 2021-01-29 -#> 10 us smoothed… fb-su… nation day 2021-01-10 NA 2021-01-29 -#> # ℹ 141 more rows -#> # ℹ 7 more variables: lag , missing_value , missing_stderr , -#> # missing_sample_size , value , stderr , sample_size -``` - -``` r -# Plot this data -library(ggplot2) -ggplot(epidata, aes(x = time_value, y = value)) + - geom_line() + - labs( - title = "Smoothed CLI from Facebook Survey", - subtitle = "US, 2021", - x = "Date", - y = "CLI" - ) -``` - - - -## Installation - -You can install the stable version of this package from CRAN: - -``` r -install.packages("epidatr") -pak::pkg_install("epidatr") -renv::install("epidatr") -``` - -Or if you want the development version, install from GitHub: - -``` r -# Install the dev version using `pak` or `remotes` -pak::pkg_install("cmu-delphi/epidatr") -remotes::install_github("cmu-delphi/epidatr") -renv::install("cmu-delphi/epidatr") -``` - -### API Keys - -The Delphi API requires a (free) API key for full functionality. To -generate your key, register for a pseudo-anonymous account -[here](https://api.delphi.cmu.edu/epidata/admin/registration_form) and -see more discussion on the [general API -website](https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html). -See the `save_api_key()` function documentation for details on how to -use your API key. - -Note that the private endpoints (i.e. those prefixed with `pvt_`) -require a separate key that needs to be passed as an argument. These -endpoints require specific data use agreements to access. +forecasting models. + +`epidatr` is designed to streamline the downloading and usage of data +from the Epidata API. The package provides a simple R interface to the +API, including functions for downloading data, parsing the results, and +converting the data into a tidy format. We also provide the +[epiprocess](https://github.com/cmu-delphi/epiprocess) package for +downstream data processing and +[epipredict](https://github.com/cmu-delphi/epipredict) for modeling. + +Consult the [Epidata API +documentation](https://cmu-delphi.github.io/delphi-epidata/) for details +on the data included in the API, API key registration, licensing, and +how to cite this data in your work. The documentation lists all the data +sources and signals available through this API for +[COVID-19](https://cmu-delphi.github.io/delphi-epidata/api/covidcast_signals.html) +and for [other +diseases](https://cmu-delphi.github.io/delphi-epidata/api/README.html#source-specific-parameters). + +**To get started** using this package, view the Getting Started guide at +`vignette("epidatr")`. ## Get updates -You should consider subscribing to the [API mailing -list](https://lists.andrew.cmu.edu/mailman/listinfo/delphi-covidcast-api) +**You should consider subscribing to the [API mailing +list](https://lists.andrew.cmu.edu/mailman/listinfo/delphi-covidcast-api)** to be notified of package updates, new data sources, corrections, and other updates. ## For users of the `covidcast` R package -The `epidatr` package is a complete rewrite of the [`covidcast` +`epidatr` is a complete rewrite of the [`covidcast` package](https://cmu-delphi.github.io/covidcast/covidcastR/), with a focus on speed, reliability, and ease of use. The `covidcast` package is deprecated and will no longer be updated. + +## Usage terms and citation + +We request that if you use the `epidatr` package in your work, or use +any of the data provided by the Delphi Epidata API through +non-`covidcast` endpoints, that you cite us using the citation given by +[`citation("epidatr")`](https://cmu-delphi.github.io/epidatr/dev/authors.html#citation). +If you use any of the data from the `covidcast` endpoint, please use the +[COVIDcast +citation](https://cmu-delphi.github.io/covidcast/covidcastR/authors.html#citation) +as well. See the [COVIDcast licensing +documentation](https://cmu-delphi.github.io/delphi-epidata/api/covidcast_licensing.html) +and the [licensing documentation for other +endpoints](https://cmu-delphi.github.io/delphi-epidata/api/README.html#data-licensing) +for information about citing the datasets provided by the API. + +**Warning:** If you use data from the Epidata API to power a product, +dashboard, app, or other service, please download the data you need and +store it centrally rather than making API requests for every user. Our +server resources are limited and cannot support high-volume interactive +use. + +See also the [Terms of +Use](https://delphi.cmu.edu/covidcast/terms-of-use/), noting that the +data is a research product and not warranted for a particular purpose. From 637f6f4d4115f6af91e5a242c4ecc8096fb7f813 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 8 Dec 2023 10:56:32 -0500 Subject: [PATCH 100/189] move mailing list ad down --- README.Rmd | 8 ++++---- README.md | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.Rmd b/README.Rmd index f1801944..792ed89f 100644 --- a/README.Rmd +++ b/README.Rmd @@ -31,14 +31,14 @@ Consult the [Epidata API documentation](https://cmu-delphi.github.io/delphi-epid **To get started** using this package, view the Getting Started guide at `vignette("epidatr")`. -## Get updates - -**You should consider subscribing to the [API mailing list](https://lists.andrew.cmu.edu/mailman/listinfo/delphi-covidcast-api)** to be notified of package updates, new data sources, corrections, and other updates. - ## For users of the `covidcast` R package `epidatr` is a complete rewrite of the [`covidcast` package](https://cmu-delphi.github.io/covidcast/covidcastR/), with a focus on speed, reliability, and ease of use. The `covidcast` package is deprecated and will no longer be updated. +## Get updates + +**You should consider subscribing to the [API mailing list](https://lists.andrew.cmu.edu/mailman/listinfo/delphi-covidcast-api)** to be notified of package updates, new data sources, corrections, and other updates. + ## Usage terms and citation We request that if you use the `epidatr` package in your work, or use any of the data provided by the Delphi Epidata API through non-`covidcast` endpoints, that you cite us using the citation given by [`citation("epidatr")`](https://cmu-delphi.github.io/epidatr/dev/authors.html#citation). If you use any of the data from the `covidcast` endpoint, please use the [COVIDcast citation](https://cmu-delphi.github.io/covidcast/covidcastR/authors.html#citation) as well. See the [COVIDcast licensing documentation](https://cmu-delphi.github.io/delphi-epidata/api/covidcast_licensing.html) and the [licensing documentation for other endpoints](https://cmu-delphi.github.io/delphi-epidata/api/README.html#data-licensing) for information about citing the datasets provided by the API. diff --git a/README.md b/README.md index dabaf5a9..c44270a8 100644 --- a/README.md +++ b/README.md @@ -51,13 +51,6 @@ diseases](https://cmu-delphi.github.io/delphi-epidata/api/README.html#source-spe **To get started** using this package, view the Getting Started guide at `vignette("epidatr")`. -## Get updates - -**You should consider subscribing to the [API mailing -list](https://lists.andrew.cmu.edu/mailman/listinfo/delphi-covidcast-api)** -to be notified of package updates, new data sources, corrections, and -other updates. - ## For users of the `covidcast` R package `epidatr` is a complete rewrite of the [`covidcast` @@ -65,6 +58,13 @@ package](https://cmu-delphi.github.io/covidcast/covidcastR/), with a focus on speed, reliability, and ease of use. The `covidcast` package is deprecated and will no longer be updated. +## Get updates + +**You should consider subscribing to the [API mailing +list](https://lists.andrew.cmu.edu/mailman/listinfo/delphi-covidcast-api)** +to be notified of package updates, new data sources, corrections, and +other updates. + ## Usage terms and citation We request that if you use the `epidatr` package in your work, or use From 3ba38367a7be0e7c960e7c3612b606dfee29672b Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 8 Dec 2023 12:16:06 -0500 Subject: [PATCH 101/189] move install, api keys to intro vignette; add more examples, take out giant endpt list --- vignettes/epidatr.Rmd | 426 +++++++++++------------------------------- 1 file changed, 105 insertions(+), 321 deletions(-) diff --git a/vignettes/epidatr.Rmd b/vignettes/epidatr.Rmd index 6a512bd2..1b10fa55 100644 --- a/vignettes/epidatr.Rmd +++ b/vignettes/epidatr.Rmd @@ -11,379 +11,163 @@ vignette: > ```{r, echo = FALSE, message = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") options(tibble.print_min = 4L, tibble.print_max = 4L, max.print = 4L) -library(epidatr) -library(dplyr) ``` The epidatr package provides access to all the endpoints of the [Delphi Epidata API](https://cmu-delphi.github.io/delphi-epidata/), and can be used to make -requests for specific signals on specific dates and in selected geographic +requests for specific signals on specific dates and in select geographic regions. -We recommend you register for an API key. While most endpoints are available -without one, there are [limits on API usage for anonymous -users](https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html), including -a rate limit. See `save_api_key()` for details on how to obtain an API key and -set this package to use it. -## Basic Usage +## Setup -Fetching some data from the Delphi Epidata API is simple. Suppose we are -interested in the [`covidcast` -endpoint](https://cmu-delphi.github.io/delphi-epidata/api/covidcast.html), which -provides access to a range of data on COVID-19. Reviewing the endpoint -documentation, we see that we need to specify a data source name, a signal name, -a geographic level, a time resolution, and the location and times of interest. +### Installation -In this case, the `pub_covidcast()` function lets us specify these parameters for -the endpoint and returns a tibble with the results: +You can install the stable version of this package from CRAN: -```{r} -epidata <- pub_covidcast( - "fb-survey", "smoothed_cli", "state", "day", "pa", - epirange(20210105, 20210410) -) -epidata -``` - -We can then easily plot the data using ggplot2: - -```{r, out.height="65%"} -library(ggplot2) -ggplot(epidata, aes(x = time_value, y = value)) + - geom_line() + - labs( - title = "Smoothed CLI from Facebook Survey", - subtitle = "PA, 2021", - x = "Date", - y = "CLI" - ) +```R +install.packages("epidatr") +pak::pkg_install("epidatr") +renv::install("epidatr") ``` -The [Delphi Epidata API documentation](https://cmu-delphi.github.io/delphi-epidata/) has more information on the available endpoints and arguments. You can also use the `avail_endpoints()` function to get a table of endpoint functions: +Or if you want the development version, install from GitHub: -```{r} -avail_endpoints() +```R +# Install the dev version using `pak` or `remotes` +pak::pkg_install("cmu-delphi/epidatr@dev") +remotes::install_github("cmu-delphi/epidatr", ref = "dev") +renv::install("cmu-delphi/epidatr@dev") ``` -Example queries with all the endpoint functions available in this package are given [below](#example-queries). +### API Keys -## Advanced Usage (Experimental) +The Delphi API requires a (free) API key for full functionality. While most +endpoints are available without one, there are +[limits on API usage for anonymous users](https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html), +including a rate limit. -The [COVIDcast -endpoint](https://cmu-delphi.github.io/delphi-epidata/api/covidcast.html) of the -Epidata API contains many separate data sources and signals. It can be difficult -to find the name of the signal you're looking for, so you can use -`covidcast_epidata()` to get help with finding sources and functions without -leaving R. +To generate your key, +[register for a pseudo-anonymous account](https://api.delphi.cmu.edu/epidata/admin/registration_form). +See the `save_api_key()` function documentation for details on how to set up +`epidatr` to use your API key. -The `covidcast_epidata()` function fetches a list of all signals, and returns an -object containing fields for every signal: +_Note_ that private endpoints (i.e. those prefixed with `pvt_`) require a +separate key that needs to be passed as an argument. These endpoints require +specific data use agreements to access. -```{r} -epidata <- covidcast_epidata() -epidata$signals -``` -If you use an editor that supports tab completion, such as RStudio, type -`epidata$signals$` and wait for the tab completion popup. You will be able to -type the name of signals and have the autocomplete feature select them from the -list for you. Note that some signal names have dashes in them, so to access them -we rely on the backtick operator: +## Basic Usage -```{r} -epidata$signals$`fb-survey:smoothed_cli` -``` +Fetching data from the Delphi Epidata API is simple. Suppose we are +interested in the +[`covidcast` endpoint](https://cmu-delphi.github.io/delphi-epidata/api/covidcast.html), +which provides access to a +[wide range of data](https://cmu-delphi.github.io/delphi-epidata/api/covidcast_signals.html) +on COVID-19. Reviewing the endpoint documentation, we see that we +[need to specify](https://cmu-delphi.github.io/delphi-epidata/api/covidcast.html#constructing-api-queries) +a data source name, a signal name, a geographic level, a time resolution, and +the location and times of interest. -These objects can be used directly to fetch data, without requiring us to use -the `pub_covidcast()` function. Simply use the `$call` attribute of the object: +The `pub_covidcast()` function lets us access the `covidcast` endpoint: ```{r} -epidata$signals$`fb-survey:smoothed_cli`$call("state", "pa", epirange(20210405, 20210410)) -``` - -## Advanced Usage (Debugging) - -We can obtain the [`epidata_call`] object underlying a request by setting the -`dry_run` argument to `TRUE` in `fetch_args_list()`: +library(epidatr) +library(dplyr) -```{r} -pub_covidcast( - "fb-survey", "smoothed_cli", "state", "day", "pa", - epirange(20210405, 20210410), - fetch_args = fetch_args_list(dry_run = TRUE) +# Obtain the most up-to-date version of the smoothed covid-like illness (CLI) +# signal from the COVID-19 Trends and Impact survey for the US +epidata <- pub_covidcast( + source = "fb-survey", + signals = "smoothed_cli", + geo_type = "nation", + time_type = "day", + geo_values = "us", + time_values = epirange(20210105, 20210410) ) +knitr::kable(head(epidata)) ``` -## Example Queries - -(Some endpoints allow for the use of `*` to access data at all locations. Check the help for a given endpoint to see if it supports `*`.) - -### COVIDcast Main Endpoint - -API docs: +`pub_covidcast()` returns a `tibble`. (Here we’re using `knitr::kable()` to make +it more readable.) Each row represents one observation in Pennsylvania on one +day. The state abbreviation is given in the `geo_value` column, the date in +the `time_value` column. Here `value` is the requested signal -- in this +case, the smoothed estimate of the percentage of people with COVID-like +illness, based on the symptom surveys, and `stderr` is its standard error. -County geo_values are [FIPS codes](https://en.wikipedia.org/wiki/List_of_United_States_FIPS_codes_by_county) and are discussed in the API docs [here](https://cmu-delphi.github.io/delphi-epidata/api/covidcast_geography.html). The example below is for Orange County, California. +The Epidata API makes signals available at different geographic levels, +depending on the endpoint. To request signals for all states instead of the +entire US, we use the `geo_type` argument paired with `*` for the +`geo_values` argument. (Only some endpoints allow for the use of `*` to +access data at all locations. Check the help for a given endpoint to see if +it supports `*`.) -```{r} +```{r, eval = FALSE} +# Obtain the most up-to-date version of the smoothed covid-like illness (CLI) +# signal from the COVID-19 Trends and Impact survey for all states pub_covidcast( source = "fb-survey", - signals = "smoothed_accept_covid_vaccine", - geo_type = "county", + signals = "smoothed_cli", + geo_type = "state", time_type = "day", - time_values = epirange(20201221, 20201225), - geo_values = "06059" + geo_values = "*", + time_values = epirange(20210105, 20210410) ) ``` -The `covidcast` endpoint supports `*` in its time and geo fields: +We can fetch a subset of states by listing out the desired locations: -```{r} +```{r, eval = FALSE} +# Obtain the most up-to-date version of the smoothed covid-like illness (CLI) +# signal from the COVID-19 Trends and Impact survey for Pennsylvania pub_covidcast( source = "fb-survey", - signals = "smoothed_accept_covid_vaccine", - geo_type = "county", + signals = "smoothed_cli", + geo_type = "state", time_type = "day", - time_values = epirange(20201221, 20201225), - geo_values = "*" + geo_values = c("pa", "ca", "fl"), + time_values = epirange(20210105, 20210410) ) ``` -### Other Covid Endpoints - -#### COVID-19 Hospitalization: Facility Lookup - -API docs: - -```{r, eval = FALSE} -pub_covid_hosp_facility_lookup(city = "southlake") -pub_covid_hosp_facility_lookup(state = "WY") -# A non-example (there is no city called New York in Wyoming) -pub_covid_hosp_facility_lookup(state = "WY", city = "New York") -``` - -#### COVID-19 Hospitalization by Facility - -API docs: - -```{r, eval = FALSE} -pub_covid_hosp_facility( - hospital_pks = "100075", - collection_weeks = epirange(20200101, 20200501) -) -``` - -#### COVID-19 Hospitalization by State - -API docs: - -```{r, eval = FALSE} -pub_covid_hosp_state_timeseries(states = "MA", dates = "20200510") -``` - -### Flu Endpoints - -#### Delphi's ILINet forecasts - -API docs: - -```{r, eval = FALSE} -del <- pub_delphi(system = "ec", epiweek = 201501) -names(del[[1L]]$forecast) -``` - -#### FluSurv hospitalization data - -API docs: - -```{r, eval = FALSE} -pub_flusurv(locations = "ca", epiweeks = 202001) -``` - -#### Fluview data - -API docs: - -```{r, eval = FALSE} -pub_fluview(regions = "nat", epiweeks = epirange(201201, 202001)) -``` - -#### Fluview virological data from clinical labs - -API docs: - -```{r, eval = FALSE} -pub_fluview_clinical(regions = "nat", epiweeks = epirange(201601, 201701)) -``` - -#### Fluview metadata - -API docs: - -```{r, eval = FALSE} -pub_fluview_meta() -``` - -#### Google Flu Trends data - -API docs: +We can also request data for a single location at a time, via the `geo_values` argument. -```{r, eval = FALSE} -pub_gft(locations = "hhs1", epiweeks = epirange(201201, 202001)) -``` - -#### ECDC ILI - -API docs: - -```{r, eval = FALSE} -pub_ecdc_ili(regions = "Armenia", epiweeks = 201840) -``` - -#### KCDC ILI - -API docs: - -```{r, eval = FALSE} -pub_kcdc_ili(regions = "ROK", epiweeks = 200436) -``` - -#### NIDSS Flu - -API docs: - -```{r, eval = FALSE} -pub_nidss_flu(regions = "taipei", epiweeks = epirange(200901, 201301)) -``` - -#### ILI Nearby Nowcast - -API docs: - -```{r, eval = FALSE} -pub_nowcast(locations = "ca", epiweeks = epirange(202201, 202319)) -``` - -### Dengue Endpoints - -#### Delphi's Dengue Nowcast - -API docs: - -```{r, eval = FALSE} -pub_dengue_nowcast(locations = "pr", epiweeks = epirange(201401, 202301)) -``` - -#### NIDSS dengue - -API docs: - -```{r, eval = FALSE} -pub_nidss_dengue(locations = "taipei", epiweeks = epirange(200301, 201301)) -``` - -### PAHO Dengue - -API docs: - -```{r, eval=FALSE} -pub_paho_dengue(regions = "ca", epiweeks = epirange(200201, 202319)) -``` - -### Other Endpoints - -#### Wikipedia Access - -API docs: - -```{r, eval = FALSE} -pub_wiki(language = "en", articles = "influenza", epiweeks = epirange(202001, 202319)) -``` - -### Private methods - -These require private access keys to use (separate from the Delphi Epidata API key). -To actually run these locally, you will need to store these secrets in your `.Reviron` file, or set them as environmental variables. - -#### CDC - -API docs: - -```{r, eval=FALSE} -pvt_cdc(auth = Sys.getenv("SECRET_API_AUTH_CDC"), epiweeks = epirange(202003, 202304), locations = "ma") -``` - -#### Dengue Digital Surveillance Sensors - -API docs: - -```{r, eval=FALSE} -pvt_dengue_sensors( - auth = Sys.getenv("SECRET_API_AUTH_SENSORS"), - names = "ght", - locations = "ag", - epiweeks = epirange(201404, 202004) -) -``` - -#### Google Health Trends - -API docs: - -```{r, eval=FALSE} -pvt_ght( - auth = Sys.getenv("SECRET_API_AUTH_GHT"), - epiweeks = epirange(199301, 202304), - locations = "ma", - query = "how to get over the flu" +```{r} +# Obtain the most up-to-date version of the smoothed covid-like illness (CLI) +# signal from the COVID-19 Trends and Impact survey for Pennsylvania +epidata <- pub_covidcast( + source = "fb-survey", + signals = "smoothed_cli", + geo_type = "state", + time_type = "day", + geo_values = "pa", + time_values = epirange(20210105, 20210410) ) +knitr::kable(head(epidata)) ``` -#### NoroSTAT metadata - -API docs: - -```{r, eval=FALSE} -pvt_meta_norostat(auth = Sys.getenv("SECRET_API_AUTH_NOROSTAT")) -``` - -#### NoroSTAT data +## Plotting -API docs: +Because the output data is in a standard `tibble` format, we can easily plot +it using `ggplot2`: -```{r, eval=FALSE} -pvt_norostat(auth = Sys.getenv("SECRET_API_AUTH_NOROSTAT"), locations = "1", epiweeks = 201233) -``` - -#### Quidel Influenza testing - -API docs: - -```{r, eval=FALSE} -pvt_quidel(auth = Sys.getenv("SECRET_API_AUTH_QUIDEL"), locations = "hhs1", epiweeks = epirange(200301, 202105)) +```{r, out.height="65%"} +library(ggplot2) +ggplot(epidata, aes(x = time_value, y = value)) + + geom_line() + + labs( + title = "Smoothed CLI from Facebook Survey", + subtitle = "PA, 2021", + x = "Date", + y = "CLI" + ) ``` -#### Sensors +## Signal discovery -API docs: +The [Delphi Epidata API documentation](https://cmu-delphi.github.io/delphi-epidata/) has more information on available endpoints. You can also use the `avail_endpoints()` function to get a table of endpoint functions: -```{r, eval=FALSE} -pvt_sensors( - auth = Sys.getenv("SECRET_API_AUTH_SENSORS"), - names = "sar3", - locations = "nat", - epiweeks = epirange(200301, 202105) -) +```{r} +avail_endpoints() ``` -#### Twitter - -API docs: - -```{r, eval=FALSE} -pvt_twitter( - auth = Sys.getenv("SECRET_API_AUTH_TWITTER"), - locations = "nat", - epiweeks = epirange(200301, 202105) -) -``` From 6a8a224d9e9601ac0def5a56b82721ce364c33b0 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 8 Dec 2023 12:19:48 -0500 Subject: [PATCH 102/189] signal discovery blurb and vignette stub --- vignettes/epidatr.Rmd | 7 ++++++- vignettes/signal-discovery.Rmd | 0 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 vignettes/signal-discovery.Rmd diff --git a/vignettes/epidatr.Rmd b/vignettes/epidatr.Rmd index 1b10fa55..ceddab59 100644 --- a/vignettes/epidatr.Rmd +++ b/vignettes/epidatr.Rmd @@ -165,9 +165,14 @@ ggplot(epidata, aes(x = time_value, y = value)) + ## Signal discovery -The [Delphi Epidata API documentation](https://cmu-delphi.github.io/delphi-epidata/) has more information on available endpoints. You can also use the `avail_endpoints()` function to get a table of endpoint functions: +Above we used data from [Delphi’s symptom surveys](https://delphi.cmu.edu/covid19/ctis/), but the Epidata API includes numerous data streams: medical claims data, cases and deaths, mobility, and many others. This can make it a challenge to find the data stream that you are most interested in. + +The Epidata documentation lists all the data sources and signals available through the API for [COVID-19](https://cmu-delphi.github.io/delphi-epidata/api/covidcast_signals.html) and for [other diseases](https://cmu-delphi.github.io/delphi-epidata/api/README.html#source-specific-parameters). + +You can also use the `avail_endpoints()` function to get a table of endpoint functions: ```{r} avail_endpoints() ``` +See `vignette("signal-discovery")` for more information. diff --git a/vignettes/signal-discovery.Rmd b/vignettes/signal-discovery.Rmd new file mode 100644 index 00000000..e69de29b From a8b81bb3c72e500a13fb8c15b7aa217722745e8d Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 8 Dec 2023 12:26:29 -0500 Subject: [PATCH 103/189] versioned data blurb and vignette stub --- vignettes/epidatr.Rmd | 23 +++++++++++++++++++++++ vignettes/versioned-data.Rmd | 0 2 files changed, 23 insertions(+) create mode 100644 vignettes/versioned-data.Rmd diff --git a/vignettes/epidatr.Rmd b/vignettes/epidatr.Rmd index ceddab59..79cc2e0d 100644 --- a/vignettes/epidatr.Rmd +++ b/vignettes/epidatr.Rmd @@ -146,6 +146,29 @@ epidata <- pub_covidcast( knitr::kable(head(epidata)) ``` +## Getting versioned data + +The Epidata API stores a historical record of all data, including corrections and updates, which is particularly useful for accurately backtesting forecasting models. To fetch versioned data + +We can also request data for a single location at a time, via the `geo_values` argument. + +```{r, eval = FALSE} +# Obtain the smoothed covid-like illness (CLI) signal from the COVID-19 +# Trends and Impact survey for Pennsylvania as it was on 2021-06-01 +pub_covidcast( + source = "fb-survey", + signals = "smoothed_cli", + geo_type = "state", + time_type = "day", + geo_values = "pa", + time_values = epirange(20210105, 20210410), + as_of = "2021-06-01" +) +``` + +See `vignette("versioned-data")` for more information and more ways to specify versioned data. + + ## Plotting Because the output data is in a standard `tibble` format, we can easily plot diff --git a/vignettes/versioned-data.Rmd b/vignettes/versioned-data.Rmd new file mode 100644 index 00000000..e69de29b From f857d67f756b02e3d30bd54f82d74006ad281d6b Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 8 Dec 2023 12:45:26 -0500 Subject: [PATCH 104/189] add geo info and format avail_endpoint --- vignettes/epidatr.Rmd | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/vignettes/epidatr.Rmd b/vignettes/epidatr.Rmd index 79cc2e0d..94314143 100644 --- a/vignettes/epidatr.Rmd +++ b/vignettes/epidatr.Rmd @@ -186,7 +186,16 @@ ggplot(epidata, aes(x = time_value, y = value)) + ) ``` -## Signal discovery +## Finding locations of interest + +Most data is only available for the US. Select endpoints report other countries at the national and/or regional levels. Endpoint descriptions explicitly state when they cover non-US locations. + +For endpoints that report US data, see the +[geographic coding documentation](https://cmu-delphi.github.io/delphi-epidata/api/covidcast_geography.html) +for available geographic levels. + + +## Finding data sources and signals of interest Above we used data from [Delphi’s symptom surveys](https://delphi.cmu.edu/covid19/ctis/), but the Epidata API includes numerous data streams: medical claims data, cases and deaths, mobility, and many others. This can make it a challenge to find the data stream that you are most interested in. @@ -194,8 +203,13 @@ The Epidata documentation lists all the data sources and signals available throu You can also use the `avail_endpoints()` function to get a table of endpoint functions: -```{r} +```{r, eval = FALSE} avail_endpoints() ``` +```{r, echo = FALSE} +invisible(capture.output(endpts <- avail_endpoints())) +knitr::kable(endpts) +``` + See `vignette("signal-discovery")` for more information. From cf2ed737089f49960eb8d2d154b9ffe1796fcd9b Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 8 Dec 2023 12:51:19 -0500 Subject: [PATCH 105/189] list international endpoints --- vignettes/epidatr.Rmd | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/vignettes/epidatr.Rmd b/vignettes/epidatr.Rmd index 94314143..6fa7815b 100644 --- a/vignettes/epidatr.Rmd +++ b/vignettes/epidatr.Rmd @@ -195,6 +195,19 @@ For endpoints that report US data, see the for available geographic levels. +### International data + +International data is available via + +- `pub_dengue_nowcast` (North and South America) +- `pub_ecdc_ili` (Europe) +- `pub_kcdc_ili` (Korea) +- `pub_nidss_dengue` (Taiwan) +- `pub_nidss_flu` (Taiwan) +- `pub_paho_dengue` (North and South America) +- `pvt_dengue_sensors` (North and South America) + + ## Finding data sources and signals of interest Above we used data from [Delphi’s symptom surveys](https://delphi.cmu.edu/covid19/ctis/), but the Epidata API includes numerous data streams: medical claims data, cases and deaths, mobility, and many others. This can make it a challenge to find the data stream that you are most interested in. From 86502a37d58460466dcbea20116605b101e610bc Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 8 Dec 2023 13:23:04 -0500 Subject: [PATCH 106/189] rename and reflow text --- vignettes/epidatr.Rmd | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/vignettes/epidatr.Rmd b/vignettes/epidatr.Rmd index 6fa7815b..c17caa15 100644 --- a/vignettes/epidatr.Rmd +++ b/vignettes/epidatr.Rmd @@ -1,8 +1,8 @@ --- -title: "Delphi Epidata R API Client" +title: "Get started with `epidatr`" output: rmarkdown::html_vignette vignette: > - %\VignetteIndexEntry{Delphi Epidata R API Client} + %\VignetteIndexEntry{Get started with `epidatr`} %\VignetteEngine{knitr::rmarkdown} %\VignetteDepends{ggplot2} \usepackage[utf8]{inputenc} @@ -210,9 +210,14 @@ International data is available via ## Finding data sources and signals of interest -Above we used data from [Delphi’s symptom surveys](https://delphi.cmu.edu/covid19/ctis/), but the Epidata API includes numerous data streams: medical claims data, cases and deaths, mobility, and many others. This can make it a challenge to find the data stream that you are most interested in. +Above we used data from [Delphi’s symptom surveys](https://delphi.cmu.edu/covid19/ctis/), +but the Epidata API includes numerous data streams: medical claims data, cases +and deaths, mobility, and many others. This can make it a challenge to find +the data stream that you are most interested in. -The Epidata documentation lists all the data sources and signals available through the API for [COVID-19](https://cmu-delphi.github.io/delphi-epidata/api/covidcast_signals.html) and for [other diseases](https://cmu-delphi.github.io/delphi-epidata/api/README.html#source-specific-parameters). +The Epidata documentation lists all the data sources and signals available +through the API for [COVID-19](https://cmu-delphi.github.io/delphi-epidata/api/covidcast_signals.html) +and for [other diseases](https://cmu-delphi.github.io/delphi-epidata/api/README.html#source-specific-parameters). You can also use the `avail_endpoints()` function to get a table of endpoint functions: From ade3ea249af722484714be2bfa69cde6c255e006 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 8 Dec 2023 13:50:08 -0500 Subject: [PATCH 107/189] flesh out signal discovery vignette --- vignettes/signal-discovery.Rmd | 360 +++++++++++++++++++++++++++++++++ 1 file changed, 360 insertions(+) diff --git a/vignettes/signal-discovery.Rmd b/vignettes/signal-discovery.Rmd index e69de29b..6a3bd628 100644 --- a/vignettes/signal-discovery.Rmd +++ b/vignettes/signal-discovery.Rmd @@ -0,0 +1,360 @@ +--- +title: "Finding data sources and signals of interest" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Finding data sources and signals of interest} + %\VignetteEngine{knitr::rmarkdown} + \usepackage[utf8]{inputenc} +--- + +```{r, echo = FALSE, message = FALSE} +knitr::opts_chunk$set(collapse = TRUE, comment = "#>") +options(tibble.print_min = 4L, tibble.print_max = 4L, max.print = 4L) +library(epidatr) +library(dplyr) +``` + +The Epidata API includes numerous data streams -- medical claims data, cases and deaths, mobility, and many others -- covering different geographic regions. This can make it a challenge to find the data stream that you are most interested in. + +Example queries with all the endpoint functions available in this package are +given [below](#example-queries). + + +## Using the documentation + +The Epidata documentation lists all the data sources and signals available +through the API for +[COVID-19](https://cmu-delphi.github.io/delphi-epidata/api/covidcast_signals.html) and +for [other diseases](https://cmu-delphi.github.io/delphi-epidata/api/README.html#source-specific-parameters). +The site also includes a search tool if you have a keyword (e.g. "Taiwan") in mind. + + +## Interactive tooling + +We provide a couple `epidatr` functions to help find data sources and signals. + +The `avail_endpoints()` function lists endpoints, each of which, except for +COVIDcast, corresponds to a single data source. `avail_endpoints()` outputs a +`tibble` of endpoints and brief descriptions, which explicitly state when they +cover non-US locations: + +```{r, eval = FALSE} +avail_endpoints() +``` + +```{r, echo = FALSE} +invisible(capture.output(endpts <- avail_endpoints())) +knitr::kable(endpts) +``` + +The `covidcast_epidata()` function lets you look more in-depth at the data +sources available through the COVIDcast endpoint. The function describes +all available data sources and signals: + +```{r} +covid_sources <- covidcast_epidata() +head(covid_sources$sources, n = 2) +``` + +Each source is included as an entry in the `covid_sources$sources` list, associated +with a `tibble` describing included signals. + +If you use an editor that supports tab completion, such as RStudio, type +`covid_sources$source$` and wait for the tab completion popup. You will be able to +browse the list of data sources. + +```{r} +covid_sources$signals +``` + +If you use an editor that supports tab completion, type +`covid_sources$signals$` and wait for the tab completion popup. You will be +able to type the name of signals and have the autocomplete feature select +them from the list for you. In the tab-completion popup, signal names are +prefixed with the name of the data source for filtering convenience. + +_Note_ that some signal names have dashes in them, so to access them +we rely on the backtick operator: + +```{r} +covid_sources$signals$`fb-survey:smoothed_cli` +``` + +These signal objects can be used directly to fetch data, without requiring us to use +the `pub_covidcast()` function. Simply use the `$call` attribute of the object: + +```{r} +covid_sources$signals$`fb-survey:smoothed_cli`$call("state", "pa", epirange(20210405, 20210410)) +``` + + +## Example Queries + +### COVIDcast Main Endpoint + +API docs: + +County geo_values are [FIPS codes](https://en.wikipedia.org/wiki/List_of_United_States_FIPS_codes_by_county) and are discussed in the API docs [here](https://cmu-delphi.github.io/delphi-epidata/api/covidcast_geography.html). The example below is for Orange County, California. + +```{r} +pub_covidcast( + source = "fb-survey", + signals = "smoothed_accept_covid_vaccine", + geo_type = "county", + time_type = "day", + time_values = epirange(20201221, 20201225), + geo_values = "06059" +) +``` + +The `covidcast` endpoint supports `*` in its time and geo fields: + +```{r} +pub_covidcast( + source = "fb-survey", + signals = "smoothed_accept_covid_vaccine", + geo_type = "county", + time_type = "day", + time_values = epirange(20201221, 20201225), + geo_values = "*" +) +``` + +### Other Covid Endpoints + +#### COVID-19 Hospitalization: Facility Lookup + +API docs: + +```{r, eval = FALSE} +pub_covid_hosp_facility_lookup(city = "southlake") +pub_covid_hosp_facility_lookup(state = "WY") +# A non-example (there is no city called New York in Wyoming) +pub_covid_hosp_facility_lookup(state = "WY", city = "New York") +``` + +#### COVID-19 Hospitalization by Facility + +API docs: + +```{r, eval = FALSE} +pub_covid_hosp_facility( + hospital_pks = "100075", + collection_weeks = epirange(20200101, 20200501) +) +``` + +#### COVID-19 Hospitalization by State + +API docs: + +```{r, eval = FALSE} +pub_covid_hosp_state_timeseries(states = "MA", dates = "20200510") +``` + +### Flu Endpoints + +#### Delphi's ILINet forecasts + +API docs: + +```{r, eval = FALSE} +del <- pub_delphi(system = "ec", epiweek = 201501) +names(del[[1L]]$forecast) +``` + +#### FluSurv hospitalization data + +API docs: + +```{r, eval = FALSE} +pub_flusurv(locations = "ca", epiweeks = 202001) +``` + +#### Fluview data + +API docs: + +```{r, eval = FALSE} +pub_fluview(regions = "nat", epiweeks = epirange(201201, 202001)) +``` + +#### Fluview virological data from clinical labs + +API docs: + +```{r, eval = FALSE} +pub_fluview_clinical(regions = "nat", epiweeks = epirange(201601, 201701)) +``` + +#### Fluview metadata + +API docs: + +```{r, eval = FALSE} +pub_fluview_meta() +``` + +#### Google Flu Trends data + +API docs: + +```{r, eval = FALSE} +pub_gft(locations = "hhs1", epiweeks = epirange(201201, 202001)) +``` + +#### ECDC ILI + +API docs: + +```{r, eval = FALSE} +pub_ecdc_ili(regions = "Armenia", epiweeks = 201840) +``` + +#### KCDC ILI + +API docs: + +```{r, eval = FALSE} +pub_kcdc_ili(regions = "ROK", epiweeks = 200436) +``` + +#### NIDSS Flu + +API docs: + +```{r, eval = FALSE} +pub_nidss_flu(regions = "taipei", epiweeks = epirange(200901, 201301)) +``` + +#### ILI Nearby Nowcast + +API docs: + +```{r, eval = FALSE} +pub_nowcast(locations = "ca", epiweeks = epirange(202201, 202319)) +``` + +### Dengue Endpoints + +#### Delphi's Dengue Nowcast + +API docs: + +```{r, eval = FALSE} +pub_dengue_nowcast(locations = "pr", epiweeks = epirange(201401, 202301)) +``` + +#### NIDSS dengue + +API docs: + +```{r, eval = FALSE} +pub_nidss_dengue(locations = "taipei", epiweeks = epirange(200301, 201301)) +``` + +### PAHO Dengue + +API docs: + +```{r, eval=FALSE} +pub_paho_dengue(regions = "ca", epiweeks = epirange(200201, 202319)) +``` + +### Other Endpoints + +#### Wikipedia Access + +API docs: + +```{r, eval = FALSE} +pub_wiki(language = "en", articles = "influenza", epiweeks = epirange(202001, 202319)) +``` + +### Private methods + +These require private access keys to use (separate from the Delphi Epidata API key). +To actually run these locally, you will need to store these secrets in your `.Reviron` file, or set them as environmental variables. + +#### CDC + +API docs: + +```{r, eval=FALSE} +pvt_cdc(auth = Sys.getenv("SECRET_API_AUTH_CDC"), epiweeks = epirange(202003, 202304), locations = "ma") +``` + +#### Dengue Digital Surveillance Sensors + +API docs: + +```{r, eval=FALSE} +pvt_dengue_sensors( + auth = Sys.getenv("SECRET_API_AUTH_SENSORS"), + names = "ght", + locations = "ag", + epiweeks = epirange(201404, 202004) +) +``` + +#### Google Health Trends + +API docs: + +```{r, eval=FALSE} +pvt_ght( + auth = Sys.getenv("SECRET_API_AUTH_GHT"), + epiweeks = epirange(199301, 202304), + locations = "ma", + query = "how to get over the flu" +) +``` + +#### NoroSTAT metadata + +API docs: + +```{r, eval=FALSE} +pvt_meta_norostat(auth = Sys.getenv("SECRET_API_AUTH_NOROSTAT")) +``` + +#### NoroSTAT data + +API docs: + +```{r, eval=FALSE} +pvt_norostat(auth = Sys.getenv("SECRET_API_AUTH_NOROSTAT"), locations = "1", epiweeks = 201233) +``` + +#### Quidel Influenza testing + +API docs: + +```{r, eval=FALSE} +pvt_quidel(auth = Sys.getenv("SECRET_API_AUTH_QUIDEL"), locations = "hhs1", epiweeks = epirange(200301, 202105)) +``` + +#### Sensors + +API docs: + +```{r, eval=FALSE} +pvt_sensors( + auth = Sys.getenv("SECRET_API_AUTH_SENSORS"), + names = "sar3", + locations = "nat", + epiweeks = epirange(200301, 202105) +) +``` + +#### Twitter + +API docs: + +```{r, eval=FALSE} +pvt_twitter( + auth = Sys.getenv("SECRET_API_AUTH_TWITTER"), + locations = "nat", + epiweeks = epirange(200301, 202105) +) +``` From 06adbcd71835fc85cb059e8f57e1e88174906a5a Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 8 Dec 2023 13:54:05 -0500 Subject: [PATCH 108/189] clean up versioned data wording --- vignettes/epidatr.Rmd | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/vignettes/epidatr.Rmd b/vignettes/epidatr.Rmd index c17caa15..ae7f1c07 100644 --- a/vignettes/epidatr.Rmd +++ b/vignettes/epidatr.Rmd @@ -148,9 +148,10 @@ knitr::kable(head(epidata)) ## Getting versioned data -The Epidata API stores a historical record of all data, including corrections and updates, which is particularly useful for accurately backtesting forecasting models. To fetch versioned data - -We can also request data for a single location at a time, via the `geo_values` argument. +The Epidata API stores a historical record of all data, including corrections +and updates, which is particularly useful for accurately backtesting +forecasting models. To fetch versioned data, we can use the `as_of` +argument. ```{r, eval = FALSE} # Obtain the smoothed covid-like illness (CLI) signal from the COVID-19 @@ -166,7 +167,7 @@ pub_covidcast( ) ``` -See `vignette("versioned-data")` for more information and more ways to specify versioned data. +See `vignette("versioned-data")` for details and more ways to specify versioned data. ## Plotting From 3872109a3445e05bddd37856982d972fb08bd497 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 8 Dec 2023 13:59:59 -0500 Subject: [PATCH 109/189] pretty print tibbles in signal discovery vignette --- vignettes/signal-discovery.Rmd | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/vignettes/signal-discovery.Rmd b/vignettes/signal-discovery.Rmd index 6a3bd628..4df94ddc 100644 --- a/vignettes/signal-discovery.Rmd +++ b/vignettes/signal-discovery.Rmd @@ -29,6 +29,11 @@ for [other diseases](https://cmu-delphi.github.io/delphi-epidata/api/README.html The site also includes a search tool if you have a keyword (e.g. "Taiwan") in mind. +## Signal metadata + +...? + + ## Interactive tooling We provide a couple `epidatr` functions to help find data sources and signals. @@ -84,7 +89,10 @@ These signal objects can be used directly to fetch data, without requiring us to the `pub_covidcast()` function. Simply use the `$call` attribute of the object: ```{r} -covid_sources$signals$`fb-survey:smoothed_cli`$call("state", "pa", epirange(20210405, 20210410)) +epidata <- covid_sources$signals$`fb-survey:smoothed_cli`$call( + "state", "pa", epirange(20210405, 20210410) +) +knitr::kable(epidata) ``` From 06aed90cf7f0087ccd4f805e33fc5290f032c537 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 8 Dec 2023 14:17:07 -0500 Subject: [PATCH 110/189] metadata blurb for signal discovery --- vignettes/signal-discovery.Rmd | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/vignettes/signal-discovery.Rmd b/vignettes/signal-discovery.Rmd index 4df94ddc..8dbe2d35 100644 --- a/vignettes/signal-discovery.Rmd +++ b/vignettes/signal-discovery.Rmd @@ -31,8 +31,14 @@ The site also includes a search tool if you have a keyword (e.g. "Taiwan") in mi ## Signal metadata -...? +Some endpoints have partner metadata available that, depending on +the endpoint, provides information about the signals that are available, what +time ranges they are available for, and when they have been updated. +```{r, echo = FALSE} +invisible(capture.output(endpts <- avail_endpoints())) +filter(endpts, endsWith(Endpoint, "_meta()")) %>% knitr::kable() +``` ## Interactive tooling From 12a6e637f931ed0d1c4eb89972c956df3dc7df53 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 8 Dec 2023 14:20:43 -0500 Subject: [PATCH 111/189] silence us-only message --- vignettes/signal-discovery.Rmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vignettes/signal-discovery.Rmd b/vignettes/signal-discovery.Rmd index 8dbe2d35..8cd7799c 100644 --- a/vignettes/signal-discovery.Rmd +++ b/vignettes/signal-discovery.Rmd @@ -36,7 +36,7 @@ the endpoint, provides information about the signals that are available, what time ranges they are available for, and when they have been updated. ```{r, echo = FALSE} -invisible(capture.output(endpts <- avail_endpoints())) +suppressMessages(invisible(capture.output(endpts <- avail_endpoints()))) filter(endpts, endsWith(Endpoint, "_meta()")) %>% knitr::kable() ``` @@ -54,7 +54,7 @@ avail_endpoints() ``` ```{r, echo = FALSE} -invisible(capture.output(endpts <- avail_endpoints())) +suppressMessages(invisible(capture.output(endpts <- avail_endpoints()))) knitr::kable(endpts) ``` From cab8caeb67043b77d2180e5e71ae338bcc28c0a9 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 8 Dec 2023 14:31:50 -0500 Subject: [PATCH 112/189] versioned data header --- vignettes/versioned-data.Rmd | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/vignettes/versioned-data.Rmd b/vignettes/versioned-data.Rmd index e69de29b..048ba858 100644 --- a/vignettes/versioned-data.Rmd +++ b/vignettes/versioned-data.Rmd @@ -0,0 +1,15 @@ +--- +title: "Understanding and accessing versioned data" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Understanding and accessing versioned data} + %\VignetteEngine{knitr::rmarkdown} + \usepackage[utf8]{inputenc} +--- + +```{r, echo = FALSE, message = FALSE} +knitr::opts_chunk$set(collapse = TRUE, comment = "#>") +options(tibble.print_min = 4L, tibble.print_max = 4L, max.print = 4L) +library(epidatr) +library(dplyr) +``` From b6b0a6fb4a3d7b9e87b48f380470294f297357a1 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Mon, 11 Dec 2023 13:06:21 -0500 Subject: [PATCH 113/189] choropleth link and example --- vignettes/epidatr.Rmd | 53 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/vignettes/epidatr.Rmd b/vignettes/epidatr.Rmd index ae7f1c07..ca9c6c16 100644 --- a/vignettes/epidatr.Rmd +++ b/vignettes/epidatr.Rmd @@ -1,8 +1,10 @@ --- -title: "Get started with `epidatr`" -output: rmarkdown::html_vignette +title: "Get started with epidatr" +output: + rmarkdown::html_vignette: + code_folding: show vignette: > - %\VignetteIndexEntry{Get started with `epidatr`} + %\VignetteIndexEntry{Get started with epidatr} %\VignetteEngine{knitr::rmarkdown} %\VignetteDepends{ggplot2} \usepackage[utf8]{inputenc} @@ -187,6 +189,51 @@ ggplot(epidata, aes(x = time_value, y = value)) + ) ``` +`ggplot2` can also be used to [create choropleths](https://r-graphics.org/recipe-miscgraph-choropleth). + + +```{r class.source = "fold-hide", out.height="65%"} +library(maps) + +# Obtain the most up-to-date version of the smoothed covid-like illness (CLI) +# signal from the COVID-19 Trends and Impact survey for all states on a single day +cli_states <- pub_covidcast( + source = "fb-survey", + signals = "smoothed_cli", + geo_type = "state", + time_type = "day", + geo_values = "*", + time_values = 20210410 +) + +# Get a mapping of states to longitude/latitude coordinates +states_map <- map_data("state") + +# Convert state abbreviations into state names +cli_states <- mutate( + cli_states, state = ifelse( + geo_value == "dc", + "district of columbia", + state.name[match(geo_value, tolower(state.abb))] %>% tolower() + ) +) + +# Add coordinates for each state +cli_states <- left_join(states_map, cli_states, by = c("region" = "state")) + +# Plot +ggplot(cli_states, aes(x = long, y = lat, group = group, fill = value)) + + geom_polygon(colour = "black", linewidth = 0.2) + + coord_map("polyconic") + + labs( + title = "Smoothed CLI from Facebook Survey", + subtitle = "All states, 2021-04-10", + x = "Longitude", + y = "Latitude" + ) +``` + + ## Finding locations of interest Most data is only available for the US. Select endpoints report other countries at the national and/or regional levels. Endpoint descriptions explicitly state when they cover non-US locations. From 53d820112fa6af8c10408504d7093c2d6ad3ab2b Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Mon, 11 Dec 2023 13:56:13 -0500 Subject: [PATCH 114/189] add content to versioned data vignette --- vignettes/versioned-data.Rmd | 134 +++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) diff --git a/vignettes/versioned-data.Rmd b/vignettes/versioned-data.Rmd index 048ba858..70523e6f 100644 --- a/vignettes/versioned-data.Rmd +++ b/vignettes/versioned-data.Rmd @@ -13,3 +13,137 @@ options(tibble.print_min = 4L, tibble.print_max = 4L, max.print = 4L) library(epidatr) library(dplyr) ``` + + +The Epidata API records not just each signal's estimate for a given location +on a given day, but also *when* that estimate was made, and all updates to that +estimate. + +For example, let's look at the [doctor visits +signal](https://cmu-delphi.github.io/delphi-epidata/api/covidcast-signals/doctor-visits.html) +from the [`covidcast` endpoint](https://cmu-delphi.github.io/delphi-epidata/api/covidcast.html), +which estimates the percentage of outpatient doctor visits that are +COVID-related. Consider a result row with `time_value` 2020-05-01 for +`geo_values = "pa"`. This is an estimate for Pennsylvania on +May 1, 2020. That estimate was *issued* on May 5, 2020, the delay being due to +the aggregation of data by our source and the time taken by the Epidata API to +ingest the data provided. Later, the estimate for May 1st could be updated, +perhaps because additional visit data from May 1st arrived at our source and was +reported to us. This constitutes a new *issue* of the data. + + +### Data known "as of" a specific date + +By default, endpoint functions fetch the most recent issue available. This +is the best option for users who simply want to graph the latest data or +construct dashboards. But if we are interested in knowing *when* data was +reported, we can request specific data versions using the `as_of`, `issues`, or +`lag` arguments. + +_Note_ that these are mutually exclusive; only one can be specified +at a time. Also, not all endpoints support all three parameters, so please +check the documentation for that specific endpoint. + +First, we can request the data that was available *as of* a specific date, using +the `as_of` argument: + + +```{r} +epidata <- pub_covidcast( + source = "doctor-visits", + signals = "smoothed_adj_cli", + time_type = "day", + time_values = epirange("2020-05-01", "2020-05-01"), + geo_type = "state", + geo_values = "pa", + as_of = "2020-05-07" +) +knitr::kable(epidata) +``` + +This shows that an estimate of about 2.3% was issued on May 7. If we don't +specify `as_of`, we get the most recent estimate available: + + +```{r} +epidata <- pub_covidcast( + source = "doctor-visits", + signals = "smoothed_adj_cli", + time_type = "day", + time_values = epirange("2020-05-01", "2020-05-01"), + geo_type = "state", + geo_values = "pa" +) +knitr::kable(epidata) +``` + +Note the substantial change in the estimate, from less than 3% to almost 6%, +reflecting new data that became available after May 7 about visits *occurring on* +May 1. This illustrates the importance of issue date tracking, particularly +for forecasting tasks. To backtest a forecasting model on past data, it is +important to use the data that would have been available *at the time* the model +was or would have been fit, not data that arrived much later. + + +### Multiple issues of observations + +By using the `issues` argument, we can request all issues in a certain time +period: + +```{r} +epidata <- pub_covidcast( + source = "doctor-visits", + signals = "smoothed_adj_cli", + time_type = "day", + time_values = epirange("2020-05-01", "2020-05-01"), + geo_type = "state", + geo_values = "pa", + issues = epirange("2020-05-01", "2020-05-15") +) +knitr::kable(epidata) +``` + +This estimate was clearly updated many times as new data for May 1st arrived. + +Note that these results include only data issued or updated between +(inclusive) 2020-05-01 and 2020-05-15. If a value was first reported on +2020-04-15, and never updated, a query for issues between 2020-05-01 and +2020-05-15 will not include that value among its results. + + +### Observations issued with a specific lag + +Finally, we can use the `lag` argument to request only data reported with a +certain lag. For example, requesting a lag of 7 days fetches only data issued +exactly 7 days after the corresponding `time_value`: + +```{r} +epidata <- pub_covidcast( + source = "doctor-visits", + signals = "smoothed_adj_cli", + time_type = "day", + time_values = epirange("2020-05-01", "2020-05-07"), + geo_type = "state", + geo_values = "pa", + lag = 7 +) +knitr::kable(epidata) +``` + +Note that though this query requested all values between 2020-05-01 and +2020-05-07, May 3rd and May 4th were *not* included in the results set. This is +because the query will only include a result for May 3rd if a value were issued +on May 10th (a 7-day lag), but in fact the value was not updated on that day: + +```{r} +epidata <- pub_covidcast( + source = "doctor-visits", + signals = "smoothed_adj_cli", + time_type = "day", + time_values = epirange("2020-05-03", "2020-05-03"), + geo_type = "state", + geo_values = "pa", + issues = epirange("2020-05-09", "2020-05-15") +) +knitr::kable(epidata) +``` From 7b6b9bd14deaf68eb33dad7a1502ea2f1a35a219 Mon Sep 17 00:00:00 2001 From: nmdefries Date: Mon, 11 Dec 2023 18:57:44 +0000 Subject: [PATCH 115/189] style: styler (GHA) --- vignettes/epidatr.Rmd | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vignettes/epidatr.Rmd b/vignettes/epidatr.Rmd index ca9c6c16..33c560cf 100644 --- a/vignettes/epidatr.Rmd +++ b/vignettes/epidatr.Rmd @@ -211,7 +211,8 @@ states_map <- map_data("state") # Convert state abbreviations into state names cli_states <- mutate( - cli_states, state = ifelse( + cli_states, + state = ifelse( geo_value == "dc", "district of columbia", state.name[match(geo_value, tolower(state.abb))] %>% tolower() From 433b748f488a9e1d757e064fc0c26e86945162d9 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Mon, 11 Dec 2023 16:44:00 -0500 Subject: [PATCH 116/189] suggest `maps` for vignettes --- DESCRIPTION | 1 + 1 file changed, 1 insertion(+) diff --git a/DESCRIPTION b/DESCRIPTION index 3e02fafe..d05d4186 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -44,6 +44,7 @@ Suggests: dplyr, ggplot2, knitr, + maps, rmarkdown, rlang, testthat (>= 3.1.5), From 04c57b72875df70bc9594e1f952aa871e08eb21a Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Mon, 11 Dec 2023 16:53:27 -0500 Subject: [PATCH 117/189] add example showing use of list of dates with `issues` --- DESCRIPTION | 1 + vignettes/epidatr.Rmd | 2 +- vignettes/versioned-data.Rmd | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index d05d4186..3e1fc47e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -45,6 +45,7 @@ Suggests: ggplot2, knitr, maps, + mapproj, rmarkdown, rlang, testthat (>= 3.1.5), diff --git a/vignettes/epidatr.Rmd b/vignettes/epidatr.Rmd index 33c560cf..d96a2fdf 100644 --- a/vignettes/epidatr.Rmd +++ b/vignettes/epidatr.Rmd @@ -192,7 +192,7 @@ ggplot(epidata, aes(x = time_value, y = value)) + `ggplot2` can also be used to [create choropleths](https://r-graphics.org/recipe-miscgraph-choropleth). -```{r class.source = "fold-hide", out.height="65%"} +```{r, class.source = "fold-hide", out.height="65%"} library(maps) # Obtain the most up-to-date version of the smoothed covid-like illness (CLI) diff --git a/vignettes/versioned-data.Rmd b/vignettes/versioned-data.Rmd index 70523e6f..27271c6c 100644 --- a/vignettes/versioned-data.Rmd +++ b/vignettes/versioned-data.Rmd @@ -110,6 +110,20 @@ Note that these results include only data issued or updated between 2020-04-15, and never updated, a query for issues between 2020-05-01 and 2020-05-15 will not include that value among its results. +The `issues` parameter also accepts a list of dates. + +```{r, eval = FALSE} +pub_covidcast( + source = "doctor-visits", + signals = "smoothed_adj_cli", + time_type = "day", + time_values = epirange("2020-05-01", "2020-05-01"), + geo_type = "state", + geo_values = "pa", + issues = c("2020-05-07", "2020-05-09", "2020-05-15") +) +``` + ### Observations issued with a specific lag From b1917e9b1458f8f0d139c07362ede8efe25c3d93 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Tue, 12 Dec 2023 17:45:42 -0500 Subject: [PATCH 118/189] fix endpt refs missing pub_, pvt_ prefixes --- R/cache.R | 4 ++-- R/endpoints.R | 13 +++++++------ R/epidatacall.R | 7 ++++--- man/covidcast_epidata.Rd | 3 +++ man/epidata_call.Rd | 7 ++++--- man/pub_fluview_meta.Rd | 1 - man/pvt_norostat.Rd | 4 ++-- man/pvt_sensors.Rd | 2 +- man/pvt_twitter.Rd | 5 +++-- man/set_cache.Rd | 4 ++-- 10 files changed, 28 insertions(+), 22 deletions(-) diff --git a/R/cache.R b/R/cache.R index d544d760..cd94c92b 100644 --- a/R/cache.R +++ b/R/cache.R @@ -34,7 +34,7 @@ cache_environ$epidatr_cache <- NULL #' specify either `issues` before a certain date, or `as_of` before a certain #' date will actually cache. For example the call #' ``` -#' covidcast( +#' pub_covidcast( #' source = "jhu-csse", #' signals = "confirmed_7dav_incidence_prop", #' geo_type = "state", @@ -46,7 +46,7 @@ cache_environ$epidatr_cache <- NULL #' *won't* cache, since it is possible for the cache to be invalidated by new #' releases with no warning. On the other hand, the call #' ``` -#' covidcast( +#' pub_covidcast( #' source = "jhu-csse", #' signals = "confirmed_7dav_incidence_prop", #' geo_type = "state", diff --git a/R/endpoints.R b/R/endpoints.R index 25f3ed2e..9043243d 100644 --- a/R/endpoints.R +++ b/R/endpoints.R @@ -1320,7 +1320,7 @@ pub_fluview_clinical <- function(regions, epiweeks, ..., issues = NULL, lag = NU #' Metadata for the FluView endpoint #' @description #' API docs: -#' Returns information about the fluview endpoint. +#' #' @examples #' \dontrun{ #' pub_fluview_meta() @@ -1712,8 +1712,8 @@ pub_nidss_flu <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, fet #' #' API docs: #' -#' This is the documentation of the API for accessing the NoroSTAT (norostat) -#' endpoint of the Delphi’s epidemiological data. +#' This is the documentation of the API for accessing the NoroSTAT endpoint of +#' the Delphi’s epidemiological data. #' #' @examples #' \dontrun{ @@ -1887,7 +1887,7 @@ pvt_quidel <- function(auth, locations, epiweeks, fetch_args = fetch_args_list() #' API docs: #' #' This is the documentation of the API for accessing the Digital Surveillance -#' Sensors (sensors) endpoint of the Delphi’s epidemiological Note: this +#' Sensors endpoint of the Delphi’s epidemiological Note: this #' repository was built to support modeling and forecasting efforts #' surrounding seasonal influenza (and dengue). In the current COVID-19 #' pandemic, syndromic surveillance data, like ILI data (influenza-like @@ -1942,8 +1942,9 @@ pvt_sensors <- function(auth, names, locations, epiweeks, fetch_args = fetch_arg #' @description #' API docs: #' -#' This is the API documentation for accessing the Twitter Stream (twitter) endpoint of Delphi’s epidemiological data. -#' Sourced from [Healthtweets](http://www.healthtweets.org/) +#' This is the API documentation for accessing the Twitter Stream endpoint of +#' Delphi’s epidemiological data. Sourced from +#' [Healthtweets](http://www.healthtweets.org/) #' #' @examples #' \dontrun{ diff --git a/R/epidatacall.R b/R/epidatacall.R index dbf3fc23..625a377e 100644 --- a/R/epidatacall.R +++ b/R/epidatacall.R @@ -201,9 +201,10 @@ fetch_args_list <- function( #' Fetches the data #' #' @details -#' `fetch` usually returns the data in tibble format, but a few of the endpoints -#' only support the JSON classic format (delphi, pvt_meta_norostat, and meta). -#' In that case a JSON-like nested list structure is returned instead. +#' `fetch` usually returns the data in tibble format, but a few of the +#' endpoints only support the JSON classic format (`pub_delphi`, +#' `pvt_meta_norostat`, and `pub_meta`). In that case a +#' JSON-like nested list structure is returned instead. #' #' @rdname epidata_call #' @param epidata_call an instance of `epidata_call` diff --git a/man/covidcast_epidata.Rd b/man/covidcast_epidata.Rd index 2ca1d0cf..630904b8 100644 --- a/man/covidcast_epidata.Rd +++ b/man/covidcast_epidata.Rd @@ -26,6 +26,9 @@ The \code{covidcast_epidata()} function fetches a list of all signals, and retur an object containing fields for every signal: \if{html}{\out{
}}\preformatted{epidata <- covidcast_epidata() +#> Warning: No API key found. You will be limited to non-complex queries and encounter rate limits if you proceed. +#> i See `?save_api_key()` for details on obtaining and setting API keys. +#> This warning is displayed once every 8 hours. epidata$signals #> # A tibble: 443 x 3 #> source signal short_description diff --git a/man/epidata_call.Rd b/man/epidata_call.Rd index d0b62e73..c2ef4b6b 100644 --- a/man/epidata_call.Rd +++ b/man/epidata_call.Rd @@ -54,9 +54,10 @@ There are some other functions available for debugging and advanced usage: - \code{request_url} (for debugging): outputs the request URL from which data would be fetched (note additional parameters below) -\code{fetch} usually returns the data in tibble format, but a few of the endpoints -only support the JSON classic format (delphi, pvt_meta_norostat, and meta). -In that case a JSON-like nested list structure is returned instead. +\code{fetch} usually returns the data in tibble format, but a few of the +endpoints only support the JSON classic format (\code{pub_delphi}, +\code{pvt_meta_norostat}, and \code{pub_meta}). In that case a +JSON-like nested list structure is returned instead. } \examples{ \dontrun{ diff --git a/man/pub_fluview_meta.Rd b/man/pub_fluview_meta.Rd index 51e962b3..ab0c0b1a 100644 --- a/man/pub_fluview_meta.Rd +++ b/man/pub_fluview_meta.Rd @@ -14,7 +14,6 @@ pub_fluview_meta(fetch_args = fetch_args_list()) } \description{ API docs: \url{https://cmu-delphi.github.io/delphi-epidata/api/fluview_meta.html} -Returns information about the fluview endpoint. } \examples{ \dontrun{ diff --git a/man/pvt_norostat.Rd b/man/pvt_norostat.Rd index 8cf4ed10..837e16d8 100644 --- a/man/pvt_norostat.Rd +++ b/man/pvt_norostat.Rd @@ -23,8 +23,8 @@ This is point data only, and does not include minima or maxima. API docs: \url{https://cmu-delphi.github.io/delphi-epidata/api/norostat.html} -This is the documentation of the API for accessing the NoroSTAT (norostat) -endpoint of the Delphi’s epidemiological data. +This is the documentation of the API for accessing the NoroSTAT endpoint of +the Delphi’s epidemiological data. } \examples{ \dontrun{ diff --git a/man/pvt_sensors.Rd b/man/pvt_sensors.Rd index ec536fdf..f757b408 100644 --- a/man/pvt_sensors.Rd +++ b/man/pvt_sensors.Rd @@ -24,7 +24,7 @@ pvt_sensors(auth, names, locations, epiweeks, fetch_args = fetch_args_list()) API docs: \url{https://cmu-delphi.github.io/delphi-epidata/api/sensors.html} This is the documentation of the API for accessing the Digital Surveillance -Sensors (sensors) endpoint of the Delphi’s epidemiological Note: this +Sensors endpoint of the Delphi’s epidemiological Note: this repository was built to support modeling and forecasting efforts surrounding seasonal influenza (and dengue). In the current COVID-19 pandemic, syndromic surveillance data, like ILI data (influenza-like diff --git a/man/pvt_twitter.Rd b/man/pvt_twitter.Rd index 30763a74..ffee87b2 100644 --- a/man/pvt_twitter.Rd +++ b/man/pvt_twitter.Rd @@ -33,8 +33,9 @@ pvt_twitter( \description{ API docs: \url{https://cmu-delphi.github.io/delphi-epidata/api/twitter.html} -This is the API documentation for accessing the Twitter Stream (twitter) endpoint of Delphi’s epidemiological data. -Sourced from \href{http://www.healthtweets.org/}{Healthtweets} +This is the API documentation for accessing the Twitter Stream endpoint of +Delphi’s epidemiological data. Sourced from +\href{http://www.healthtweets.org/}{Healthtweets} } \examples{ \dontrun{ diff --git a/man/set_cache.Rd b/man/set_cache.Rd index 87c147f0..a3b42a1e 100644 --- a/man/set_cache.Rd +++ b/man/set_cache.Rd @@ -64,7 +64,7 @@ An important feature of the caching in this package is that only calls which specify either \code{issues} before a certain date, or \code{as_of} before a certain date will actually cache. For example the call -\if{html}{\out{
}}\preformatted{covidcast( +\if{html}{\out{
}}\preformatted{pub_covidcast( source = "jhu-csse", signals = "confirmed_7dav_incidence_prop", geo_type = "state", @@ -77,7 +77,7 @@ date will actually cache. For example the call \emph{won't} cache, since it is possible for the cache to be invalidated by new releases with no warning. On the other hand, the call -\if{html}{\out{
}}\preformatted{covidcast( +\if{html}{\out{
}}\preformatted{pub_covidcast( source = "jhu-csse", signals = "confirmed_7dav_incidence_prop", geo_type = "state", From 117bb84647883c1bf07d6ac6734c7c1a07fa5077 Mon Sep 17 00:00:00 2001 From: nmdefries Date: Tue, 12 Dec 2023 22:48:20 +0000 Subject: [PATCH 119/189] docs: document (GHA) --- man/covidcast_epidata.Rd | 3 --- 1 file changed, 3 deletions(-) diff --git a/man/covidcast_epidata.Rd b/man/covidcast_epidata.Rd index 630904b8..2ca1d0cf 100644 --- a/man/covidcast_epidata.Rd +++ b/man/covidcast_epidata.Rd @@ -26,9 +26,6 @@ The \code{covidcast_epidata()} function fetches a list of all signals, and retur an object containing fields for every signal: \if{html}{\out{
}}\preformatted{epidata <- covidcast_epidata() -#> Warning: No API key found. You will be limited to non-complex queries and encounter rate limits if you proceed. -#> i See `?save_api_key()` for details on obtaining and setting API keys. -#> This warning is displayed once every 8 hours. epidata$signals #> # A tibble: 443 x 3 #> source signal short_description From 439d18f398bc4106e562b49f2b090e99df648bfd Mon Sep 17 00:00:00 2001 From: nmdefries <42820733+nmdefries@users.noreply.github.com> Date: Tue, 12 Dec 2023 18:46:45 -0500 Subject: [PATCH 120/189] missing period Co-authored-by: Dmitry Shemetov --- R/endpoints.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/endpoints.R b/R/endpoints.R index 9043243d..ebc74fce 100644 --- a/R/endpoints.R +++ b/R/endpoints.R @@ -1887,7 +1887,7 @@ pvt_quidel <- function(auth, locations, epiweeks, fetch_args = fetch_args_list() #' API docs: #' #' This is the documentation of the API for accessing the Digital Surveillance -#' Sensors endpoint of the Delphi’s epidemiological Note: this +#' Sensors endpoint of the Delphi’s epidemiological. Note: this #' repository was built to support modeling and forecasting efforts #' surrounding seasonal influenza (and dengue). In the current COVID-19 #' pandemic, syndromic surveillance data, like ILI data (influenza-like From c7e95f67d0050301a03b31f9db2c8f225f5d4257 Mon Sep 17 00:00:00 2001 From: nmdefries Date: Tue, 12 Dec 2023 23:48:26 +0000 Subject: [PATCH 121/189] docs: document (GHA) --- man/pvt_sensors.Rd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/pvt_sensors.Rd b/man/pvt_sensors.Rd index f757b408..24073803 100644 --- a/man/pvt_sensors.Rd +++ b/man/pvt_sensors.Rd @@ -24,7 +24,7 @@ pvt_sensors(auth, names, locations, epiweeks, fetch_args = fetch_args_list()) API docs: \url{https://cmu-delphi.github.io/delphi-epidata/api/sensors.html} This is the documentation of the API for accessing the Digital Surveillance -Sensors endpoint of the Delphi’s epidemiological Note: this +Sensors endpoint of the Delphi’s epidemiological. Note: this repository was built to support modeling and forecasting efforts surrounding seasonal influenza (and dengue). In the current COVID-19 pandemic, syndromic surveillance data, like ILI data (influenza-like From 4c5d4d690731ad4725b2e8e3db74d8aec950b64b Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Thu, 4 Jan 2024 12:31:03 -0500 Subject: [PATCH 122/189] print method for epirange --- R/model.R | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/R/model.R b/R/model.R index 8ba7a2b6..785c7584 100644 --- a/R/model.R +++ b/R/model.R @@ -61,6 +61,31 @@ epirange <- function(from, to) { structure(list(from = from, to = to), class = "EpiRange") } +#' @export +print.EpiRange <- function(x, ...) { + stopifnot(inherits(x, "EpiRange")) + + if (nchar(x$from) == 8) { + date_type <- "Days" + x$from <- as.Date(as.character(x$from), "%Y%m%d") + x$to <- as.Date(as.character(x$to), "%Y%m%d") + } else if (nchar(x$from) == 6) { + date_type <- "Epiweeks" + x$from <- format( + as.Date(as.character(x$from), "%Y%U"), + "%Yw%U" + ) + x$to <- format( + as.Date(as.character(x$to), "%Y%U"), + "%Yw%U" + ) + } + + cli::cli_h1(" object:") + cli::cli_bullets( + "{date_type} from {x$from} to {x$to}" + ) +} #' Timeset formats for specifying dates #' @@ -86,7 +111,6 @@ epirange <- function(from, to) { #' @name timeset NULL - create_epidata_field_info <- function(name, type, description = "", From 1ec140e8af76063d08d8490c8988c0b770c21cef Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Thu, 4 Jan 2024 12:56:14 -0500 Subject: [PATCH 123/189] print simple list classes --- R/epidatacall.R | 8 ++++++++ R/model.R | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/R/epidatacall.R b/R/epidatacall.R index 625a377e..a7a17072 100644 --- a/R/epidatacall.R +++ b/R/epidatacall.R @@ -198,6 +198,14 @@ fetch_args_list <- function( ) } +#' @export +print.fetch_args <- function(x, ...) { + stopifnot(inherits(x, "fetch_args")) + cli::cli_h1(" object:") + # Print all non-class fields. + print(x[attr(x, "names")]) +} + #' Fetches the data #' #' @details diff --git a/R/model.R b/R/model.R index 785c7584..4169ded4 100644 --- a/R/model.R +++ b/R/model.R @@ -141,6 +141,14 @@ create_epidata_field_info <- function(name, ) } +#' @export +print.EpidataFieldInfo <- function(x, ...) { + stopifnot(inherits(x, "EpidataFieldInfo")) + cli::cli_h1(" object:") + # Print all non-class fields. + print(x[attr(x, "names")]) +} + parse_value <- function(info, value, disable_date_parsing = FALSE) { stopifnot(inherits(info, "EpidataFieldInfo")) From 42bda42858217748a52600fd622a4d5e2d6e5124 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Thu, 4 Jan 2024 13:14:45 -0500 Subject: [PATCH 124/189] document --- NAMESPACE | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NAMESPACE b/NAMESPACE index 9b5b245c..d9630348 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -2,11 +2,14 @@ S3method(as_tibble,covidcast_data_signal_list) S3method(as_tibble,covidcast_data_source_list) +S3method(print,EpiRange) +S3method(print,EpidataFieldInfo) S3method(print,covidcast_data_signal) S3method(print,covidcast_data_signal_list) S3method(print,covidcast_data_source) S3method(print,covidcast_epidata) S3method(print,epidata_call) +S3method(print,fetch_args) export(avail_endpoints) export(cache_info) export(clear_cache) From 093fac05bdf7bbad33681cd6bf3db19f389599ea Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Thu, 4 Jan 2024 13:33:51 -0500 Subject: [PATCH 125/189] linting; var used in glue syntax not recognized --- R/model.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/model.R b/R/model.R index 4169ded4..d4885f00 100644 --- a/R/model.R +++ b/R/model.R @@ -66,11 +66,11 @@ print.EpiRange <- function(x, ...) { stopifnot(inherits(x, "EpiRange")) if (nchar(x$from) == 8) { - date_type <- "Days" + date_type <- "Days" # nolint: object_usage_linter x$from <- as.Date(as.character(x$from), "%Y%m%d") x$to <- as.Date(as.character(x$to), "%Y%m%d") } else if (nchar(x$from) == 6) { - date_type <- "Epiweeks" + date_type <- "Epiweeks" # nolint: object_usage_linter x$from <- format( as.Date(as.character(x$from), "%Y%U"), "%Yw%U" From 3255ac4ed37d214c9554acb73f9db2d29efeb082 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Thu, 4 Jan 2024 16:26:55 -0500 Subject: [PATCH 126/189] don't check class in class-specific prints --- R/epidatacall.R | 2 -- R/model.R | 3 --- 2 files changed, 5 deletions(-) diff --git a/R/epidatacall.R b/R/epidatacall.R index a7a17072..b9f7d153 100644 --- a/R/epidatacall.R +++ b/R/epidatacall.R @@ -121,7 +121,6 @@ request_arguments <- function(epidata_call, format_type, fields = NULL) { #' @export print.epidata_call <- function(x, ...) { - stopifnot(inherits(x, "epidata_call")) cli::cli_h1(" object:") cli::cli_bullets(c( "*" = "Pipe this object into `fetch()` to actually fetch the data", @@ -200,7 +199,6 @@ fetch_args_list <- function( #' @export print.fetch_args <- function(x, ...) { - stopifnot(inherits(x, "fetch_args")) cli::cli_h1(" object:") # Print all non-class fields. print(x[attr(x, "names")]) diff --git a/R/model.R b/R/model.R index d4885f00..38923145 100644 --- a/R/model.R +++ b/R/model.R @@ -63,8 +63,6 @@ epirange <- function(from, to) { #' @export print.EpiRange <- function(x, ...) { - stopifnot(inherits(x, "EpiRange")) - if (nchar(x$from) == 8) { date_type <- "Days" # nolint: object_usage_linter x$from <- as.Date(as.character(x$from), "%Y%m%d") @@ -143,7 +141,6 @@ create_epidata_field_info <- function(name, #' @export print.EpidataFieldInfo <- function(x, ...) { - stopifnot(inherits(x, "EpidataFieldInfo")) cli::cli_h1(" object:") # Print all non-class fields. print(x[attr(x, "names")]) From c2dd04b1ec02fbec7704438ce02aef24ed504af6 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Thu, 4 Jan 2024 16:35:27 -0500 Subject: [PATCH 127/189] avoid date conversion for epiweek epiranges --- R/model.R | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/R/model.R b/R/model.R index 38923145..d3a18b41 100644 --- a/R/model.R +++ b/R/model.R @@ -69,13 +69,11 @@ print.EpiRange <- function(x, ...) { x$to <- as.Date(as.character(x$to), "%Y%m%d") } else if (nchar(x$from) == 6) { date_type <- "Epiweeks" # nolint: object_usage_linter - x$from <- format( - as.Date(as.character(x$from), "%Y%U"), - "%Yw%U" + x$from <- paste0( + substr(x$from, 1, 4), "w", substr(x$from, 5, 6) ) - x$to <- format( - as.Date(as.character(x$to), "%Y%U"), - "%Yw%U" + x$to <- paste0( + substr(x$to, 1, 4), "w", substr(x$to, 5, 6) ) } From 1b2f1bb6a92ea672cf9955b00f228b72b5bd0a7f Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Thu, 4 Jan 2024 16:49:02 -0500 Subject: [PATCH 128/189] use cli_dl to avoid mixing cli and `print` in class-print fns --- R/epidatacall.R | 2 +- R/model.R | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/epidatacall.R b/R/epidatacall.R index b9f7d153..cde20c9b 100644 --- a/R/epidatacall.R +++ b/R/epidatacall.R @@ -201,7 +201,7 @@ fetch_args_list <- function( print.fetch_args <- function(x, ...) { cli::cli_h1(" object:") # Print all non-class fields. - print(x[attr(x, "names")]) + cli::cli_dl(x[attr(x, "names")]) } #' Fetches the data diff --git a/R/model.R b/R/model.R index d3a18b41..a14f8960 100644 --- a/R/model.R +++ b/R/model.R @@ -141,7 +141,7 @@ create_epidata_field_info <- function(name, print.EpidataFieldInfo <- function(x, ...) { cli::cli_h1(" object:") # Print all non-class fields. - print(x[attr(x, "names")]) + cli::cli_dl(x[attr(x, "names")]) } parse_value <- function(info, value, disable_date_parsing = FALSE) { From c55c9dcf565a07d7220b3b0d6e546071283795e2 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 5 Jan 2024 11:09:01 -0500 Subject: [PATCH 129/189] fold private endpoint examples --- vignettes/signal-discovery.Rmd | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/vignettes/signal-discovery.Rmd b/vignettes/signal-discovery.Rmd index 8cd7799c..8ed0aac9 100644 --- a/vignettes/signal-discovery.Rmd +++ b/vignettes/signal-discovery.Rmd @@ -31,9 +31,9 @@ The site also includes a search tool if you have a keyword (e.g. "Taiwan") in mi ## Signal metadata -Some endpoints have partner metadata available that, depending on -the endpoint, provides information about the signals that are available, what -time ranges they are available for, and when they have been updated. +Some endpoints have partner metadata available that provides information about +the signals that are available, for example, what time ranges they are +available for, and when they have been updated. ```{r, echo = FALSE} suppressMessages(invisible(capture.output(endpts <- avail_endpoints()))) @@ -290,6 +290,10 @@ pub_wiki(language = "en", articles = "influenza", epiweeks = epirange(202001, 20 These require private access keys to use (separate from the Delphi Epidata API key). To actually run these locally, you will need to store these secrets in your `.Reviron` file, or set them as environmental variables. +
+ +Usage of private endpoints + #### CDC API docs: @@ -372,3 +376,5 @@ pvt_twitter( epiweeks = epirange(200301, 202105) ) ``` + +
From eb685cfd61f7839183c84b091ff9df224291d949 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 5 Jan 2024 12:38:35 -0500 Subject: [PATCH 130/189] endpoints fetch all dates by default; wildcard to date fn rename wildcard conversion type to "week" --- R/endpoints.R | 210 +++++++++++++++++++------ R/utils.R | 17 ++ man/get_wildcard_equivalent_dates.Rd | 12 ++ man/pub_covid_hosp_facility.Rd | 4 +- man/pub_covid_hosp_state_timeseries.Rd | 4 +- man/pub_covidcast.Rd | 6 +- man/pub_delphi.Rd | 2 +- man/pub_dengue_nowcast.Rd | 4 +- man/pub_ecdc_ili.Rd | 4 +- man/pub_flusurv.Rd | 4 +- man/pub_fluview.Rd | 4 +- man/pub_fluview_clinical.Rd | 4 +- man/pub_gft.Rd | 4 +- man/pub_kcdc_ili.Rd | 4 +- man/pub_nidss_dengue.Rd | 4 +- man/pub_nidss_flu.Rd | 4 +- man/pub_nowcast.Rd | 4 +- man/pub_paho_dengue.Rd | 4 +- man/pvt_cdc.Rd | 4 +- man/pvt_dengue_sensors.Rd | 4 +- man/pvt_ght.Rd | 4 +- man/pvt_norostat.Rd | 4 +- man/pvt_quidel.Rd | 4 +- man/pvt_sensors.Rd | 10 +- 24 files changed, 243 insertions(+), 86 deletions(-) create mode 100644 man/get_wildcard_equivalent_dates.Rd diff --git a/R/endpoints.R b/R/endpoints.R index 25f3ed2e..9d9bf162 100644 --- a/R/endpoints.R +++ b/R/endpoints.R @@ -14,14 +14,20 @@ #' #' @param auth string. Restricted access key (not the same as API key). #' @param locations character. Locations to fetch. -#' @param epiweeks [`timeset`]. Epiweeks to fetch. +#' @param epiweeks [`timeset`]. Epiweeks to fetch. Defaults to all ("*") dates. #' @param fetch_args [`fetch_args`]. Additional arguments to pass to `fetch()`. #' See `fetch_args_list()` for details. #' @return [`tibble::tibble`] #' #' @keywords endpoint #' @export -pvt_cdc <- function(auth, locations, epiweeks, fetch_args = fetch_args_list()) { +pvt_cdc <- function( + auth, + locations, + epiweeks = "*", + fetch_args = fetch_args_list()) { + epiweeks <- get_wildcard_equivalent_dates(epiweeks, "week") + assert_character_param("auth", auth, len = 1) assert_character_param("locations", locations) assert_timeset_param("epiweeks", epiweeks) @@ -157,7 +163,7 @@ pub_covid_hosp_facility_lookup <- function( #' ) #' } #' @param hospital_pks character. Facility identifiers. -#' @param collection_weeks [`timeset`]. Epiweeks to fetch. +#' @param collection_weeks [`timeset`]. Epiweeks to fetch. Defaults to all ("*") dates. #' @param ... not used for values, forces later arguments to bind by name #' @param publication_dates [`timeset`]. Publication dates to fetch. #' @param fetch_args [`fetch_args`]. Additional arguments to pass to `fetch()`. @@ -169,12 +175,14 @@ pub_covid_hosp_facility_lookup <- function( # pub_covid_hosp_facility <- function( hospital_pks, - collection_weeks, + collection_weeks = "*", ..., publication_dates = NULL, fetch_args = fetch_args_list()) { rlang::check_dots_empty() + collection_weeks <- get_wildcard_equivalent_dates(collection_weeks, "week") + assert_character_param("hospital_pks", hospital_pks) assert_timeset_param("collection_weeks", collection_weeks) assert_timeset_param("publication_dates", publication_dates, required = FALSE) @@ -516,7 +524,7 @@ pub_covid_hosp_facility <- function( #' } #' #' @param states character. Two letter state abbreviations. -#' @param dates [`timeset`]. Dates to fetch. +#' @param dates [`timeset`]. Dates to fetch. Defaults to all ("*") dates. #' @param ... not used for values, forces later arguments to bind by name #' @param as_of Date. Optionally, the as of date for the issues to fetch. If not #' specified, the most recent data is returned. Mutually exclusive with @@ -532,7 +540,7 @@ pub_covid_hosp_facility <- function( # pub_covid_hosp_state_timeseries <- function( states, - dates, + dates = "*", ..., as_of = NULL, issues = NULL, @@ -550,6 +558,8 @@ pub_covid_hosp_state_timeseries <- function( stop("`issues`and `as_of` are mutually exclusive") } + dates <- get_wildcard_equivalent_dates(dates, "day") + assert_character_param("states", states) assert_timeset_param("dates", dates) assert_date_param("as_of", as_of, len = 1, required = FALSE) @@ -925,7 +935,7 @@ pub_covidcast_meta <- function(fetch_args = fetch_args_list()) { #' @param geo_values character. The geographies to return. "*" fetches #' all. (See: #' .) -#' @param time_values [`timeset`]. Dates to fetch. +#' @param time_values [`timeset`]. Dates to fetch. Defaults to all ("*") dates. #' @param ... not used for values, forces later arguments to bind by name #' @param as_of Date. Optionally, the as of date for the issues to fetch. If not #' specified, the most recent data is returned. Mutually exclusive with @@ -947,8 +957,8 @@ pub_covidcast <- function( signals, geo_type, time_type, - geo_values, - time_values, + geo_values = "*", + time_values = "*", ..., as_of = NULL, issues = NULL, @@ -1036,12 +1046,15 @@ pub_covidcast <- function( #' pub_delphi(system = "ec", epiweek = 201501) #' } #' @param system character. System name to fetch. -#' @param epiweek [`timeset`]. Epiweeks to fetch. +#' @param epiweek [`timeset`]. Epiweek to fetch. Does not support multiple dates. #' @param fetch_args [`fetch_args`]. Additional arguments to pass to `fetch()`. #' @return [`list`] #' @keywords endpoint #' @export -pub_delphi <- function(system, epiweek, fetch_args = fetch_args_list()) { +pub_delphi <- function( + system, + epiweek, + fetch_args = fetch_args_list()) { assert_character_param("system", system) assert_timeset_param("epiweek", epiweek, len = 1) epiweek <- parse_timeset_input(epiweek) @@ -1070,12 +1083,17 @@ pub_delphi <- function(system, epiweek, fetch_args = fetch_args_list()) { #' ) #' } #' @param locations character. Locations to fetch. -#' @param epiweeks [`timeset`]. Epiweeks to fetch. +#' @param epiweeks [`timeset`]. Epiweeks to fetch. Defaults to all ("*") dates. #' @param fetch_args [`fetch_args`]. Additional arguments to pass to `fetch()`. #' @return [`tibble::tibble`] #' @keywords endpoint #' @export -pub_dengue_nowcast <- function(locations, epiweeks, fetch_args = fetch_args_list()) { +pub_dengue_nowcast <- function( + locations, + epiweeks = "*", + fetch_args = fetch_args_list()) { + epiweeks <- get_wildcard_equivalent_dates(epiweeks, "week") + assert_character_param("locations", locations) assert_timeset_param("epiweeks", epiweeks) epiweeks <- parse_timeset_input(epiweeks) @@ -1108,12 +1126,19 @@ pub_dengue_nowcast <- function(locations, epiweeks, fetch_args = fetch_args_list #' @param auth string. Restricted access key (not the same as API key). #' @param names character. Names to fetch. #' @param locations character. Locations to fetch. -#' @param epiweeks [`timeset`]. Epiweeks to fetch. +#' @param epiweeks [`timeset`]. Epiweeks to fetch. Defaults to all ("*") dates. #' @param fetch_args [`fetch_args`]. Additional arguments to pass to `fetch()`. #' @return [`tibble::tibble`] #' @keywords endpoint #' @export -pvt_dengue_sensors <- function(auth, names, locations, epiweeks, fetch_args = fetch_args_list()) { +pvt_dengue_sensors <- function( + auth, + names, + locations, + epiweeks = "*", + fetch_args = fetch_args_list()) { + epiweeks <- get_wildcard_equivalent_dates(epiweeks, "week") + assert_character_param("auth", auth, len = 1) assert_character_param("names", names) assert_character_param("locations", locations) @@ -1153,7 +1178,7 @@ pvt_dengue_sensors <- function(auth, names, locations, epiweeks, fetch_args = fe #' pub_ecdc_ili(regions = "austria", epiweeks = epirange(201901, 202001)) #' } #' @param regions character. Regions to fetch. -#' @param epiweeks [`timeset`]. Epiweeks to fetch. +#' @param epiweeks [`timeset`]. Epiweeks to fetch. Defaults to all ("*") dates. #' @param ... not used for values, forces later arguments to bind by name #' @param issues [`timeset`]. Optionally, the issues to fetch. If not set, the #' most recent issue is returned. Mutually exclusive with `lag`. @@ -1163,9 +1188,17 @@ pvt_dengue_sensors <- function(auth, names, locations, epiweeks, fetch_args = fe #' @return [`tibble::tibble`] #' @keywords endpoint #' @export -pub_ecdc_ili <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, fetch_args = fetch_args_list()) { +pub_ecdc_ili <- function( + regions, + epiweeks = "*", + ..., + issues = NULL, + lag = NULL, + fetch_args = fetch_args_list()) { rlang::check_dots_empty() + epiweeks <- get_wildcard_equivalent_dates(epiweeks, "week") + assert_character_param("regions", regions) assert_timeset_param("epiweeks", epiweeks) assert_timeset_param("issues", issues, required = FALSE) @@ -1212,7 +1245,7 @@ pub_ecdc_ili <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, fetc #' pub_flusurv(locations = "CA", epiweeks = epirange(201701, 201801)) #' } #' @param locations character. Character vector indicating location. -#' @param epiweeks [`timeset`]. Epiweeks to fetch. +#' @param epiweeks [`timeset`]. Epiweeks to fetch. Defaults to all ("*") dates. #' @param ... not used for values, forces later arguments to bind by name #' @param issues [`timeset`]. Optionally, the issues to fetch. If not set, the #' most recent issue is returned. Mutually exclusive with `lag`. @@ -1222,9 +1255,17 @@ pub_ecdc_ili <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, fetc #' @return [`tibble::tibble`] #' @keywords endpoint #' @export -pub_flusurv <- function(locations, epiweeks, ..., issues = NULL, lag = NULL, fetch_args = fetch_args_list()) { +pub_flusurv <- function( + locations, + epiweeks = "*", + ..., + issues = NULL, + lag = NULL, + fetch_args = fetch_args_list()) { rlang::check_dots_empty() + epiweeks <- get_wildcard_equivalent_dates(epiweeks, "week") + assert_character_param("locations", locations) assert_timeset_param("epiweeks", epiweeks) assert_timeset_param("issues", issues, required = FALSE) @@ -1270,7 +1311,7 @@ pub_flusurv <- function(locations, epiweeks, ..., issues = NULL, lag = NULL, fet #' @param regions character. Regions to fetch. #' @param epiweeks [`timeset`]. Epiweeks to fetch in the form #' epirange(startweek,endweek), where startweek and endweek are of the form -#' YYYYWW (string or numeric). +#' YYYYWW (string or numeric). Defaults to all ("*") dates. #' @param ... not used for values, forces later arguments to bind by name #' @param issues [`timeset`]. Optionally, the issues to fetch. If not set, the #' most recent issue is returned. Mutually exclusive with `lag`. @@ -1280,9 +1321,17 @@ pub_flusurv <- function(locations, epiweeks, ..., issues = NULL, lag = NULL, fet #' @return [`tibble::tibble`] #' @keywords endpoint #' @export -pub_fluview_clinical <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, fetch_args = fetch_args_list()) { +pub_fluview_clinical <- function( + regions, + epiweeks = "*", + ..., + issues = NULL, + lag = NULL, + fetch_args = fetch_args_list()) { rlang::check_dots_empty() + epiweeks <- get_wildcard_equivalent_dates(epiweeks, "week") + assert_character_param("regions", regions) assert_timeset_param("epiweeks", epiweeks) assert_timeset_param("issues", issues, required = FALSE) @@ -1367,7 +1416,7 @@ pub_fluview_meta <- function(fetch_args = fetch_args_list()) { #' on. Full list link below. #' @param epiweeks [`timeset`]. Epiweeks to fetch in the form #' `epirange(startweek, endweek)`, where startweek and endweek are of the form -#' YYYYWW (string or numeric). +#' YYYYWW (string or numeric). Defaults to all ("*") dates. #' @param ... not used for values, forces later arguments to bind by name #' @param issues [`timeset`]. Optionally, the issues to fetch. If not set, the #' most recent issue is returned. Mutually exclusive with `lag`. @@ -1381,7 +1430,7 @@ pub_fluview_meta <- function(fetch_args = fetch_args_list()) { #' @export pub_fluview <- function( regions, - epiweeks, + epiweeks = "*", ..., issues = NULL, lag = NULL, @@ -1389,6 +1438,8 @@ pub_fluview <- function( fetch_args = fetch_args_list()) { rlang::check_dots_empty() + epiweeks <- get_wildcard_equivalent_dates(epiweeks, "week") + assert_character_param("regions", regions) assert_timeset_param("epiweeks", epiweeks) assert_timeset_param("issues", issues, required = FALSE) @@ -1451,13 +1502,18 @@ pub_fluview <- function( #' pub_gft(locations = "hhs1", epiweeks = epirange(201201, 202001)) #' } #' @param locations character. Locations to fetch. -#' @param epiweeks [`timeset`] Epiweeks to fetch. +#' @param epiweeks [`timeset`] Epiweeks to fetch. Defaults to all ("*") dates. #' @param fetch_args [`fetch_args`]. Additional arguments to pass to `fetch()`. #' #' @return [`tibble::tibble`] #' @keywords endpoint #' @export -pub_gft <- function(locations, epiweeks, fetch_args = fetch_args_list()) { +pub_gft <- function( + locations, + epiweeks = "*", + fetch_args = fetch_args_list()) { + epiweeks <- get_wildcard_equivalent_dates(epiweeks, "week") + assert_character_param("locations", locations) assert_timeset_param("epiweeks", epiweeks) epiweeks <- parse_timeset_input(epiweeks) @@ -1491,13 +1547,20 @@ pub_gft <- function(locations, epiweeks, fetch_args = fetch_args_list()) { #' } #' @param auth string. Restricted access key (not the same as API key). #' @param locations character. Locations to fetch. -#' @param epiweeks [`timeset`]. Epiweeks to fetch. +#' @param epiweeks [`timeset`]. Epiweeks to fetch. Defaults to all ("*") dates. #' @param query string. The query to be fetched. #' @param fetch_args [`fetch_args`]. Additional arguments to pass to `fetch()`. #' @return [`tibble::tibble`] #' @keywords endpoint #' @export -pvt_ght <- function(auth, locations, epiweeks, query, fetch_args = fetch_args_list()) { +pvt_ght <- function( + auth, + locations, + epiweeks = "*", + query, + fetch_args = fetch_args_list()) { + epiweeks <- get_wildcard_equivalent_dates(epiweeks, "week") + assert_character_param("auth", auth, len = 1) assert_character_param("locations", locations) assert_timeset_param("epiweeks", epiweeks) @@ -1529,7 +1592,7 @@ pvt_ght <- function(auth, locations, epiweeks, query, fetch_args = fetch_args_li #' pub_kcdc_ili(regions = "ROK", epiweeks = 200436) #' } #' @param regions character. Regions to fetch. -#' @param epiweeks [`timeset`]. Epiweeks to fetch. +#' @param epiweeks [`timeset`]. Epiweeks to fetch. Defaults to all ("*") dates. #' @param ... not used for values, forces later arguments to bind by name #' @param issues [`timeset`]. Optionally, the issues to fetch. If not set, the #' most recent issue is returned. Mutually exclusive with `lag`. @@ -1539,9 +1602,17 @@ pvt_ght <- function(auth, locations, epiweeks, query, fetch_args = fetch_args_li #' @return [`tibble::tibble`] #' @keywords endpoint #' @export -pub_kcdc_ili <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, fetch_args = fetch_args_list()) { +pub_kcdc_ili <- function( + regions, + epiweeks = "*", + ..., + issues = NULL, + lag = NULL, + fetch_args = fetch_args_list()) { rlang::check_dots_empty() + epiweeks <- get_wildcard_equivalent_dates(epiweeks, "week") + assert_character_param("regions", regions) assert_timeset_param("epiweeks", epiweeks) assert_timeset_param("issues", issues, required = FALSE) @@ -1626,13 +1697,18 @@ pub_meta <- function(fetch_args = fetch_args_list()) { #' pub_nidss_dengue(locations = "taipei", epiweeks = epirange(201201, 201301)) #' } #' @param locations character. Locations to fetch. -#' @param epiweeks [`timeset`]. Epiweeks to fetch. +#' @param epiweeks [`timeset`]. Epiweeks to fetch. Defaults to all ("*") dates. #' @param fetch_args [`fetch_args`]. Additional arguments to pass to `fetch()`. #' #' @return [`tibble::tibble`] #' @keywords endpoint #' @export -pub_nidss_dengue <- function(locations, epiweeks, fetch_args = fetch_args_list()) { +pub_nidss_dengue <- function( + locations, + epiweeks = "*", + fetch_args = fetch_args_list()) { + epiweeks <- get_wildcard_equivalent_dates(epiweeks, "week") + assert_character_param("locations", locations) assert_timeset_param("epiweeks", epiweeks) epiweeks <- parse_timeset_input(epiweeks) @@ -1661,7 +1737,7 @@ pub_nidss_dengue <- function(locations, epiweeks, fetch_args = fetch_args_list() #' pub_nidss_flu(regions = "taipei", epiweeks = epirange(201501, 201601)) #' } #' @param regions character. Regions to fetch. -#' @param epiweeks [`timeset`]. Epiweeks to fetch. +#' @param epiweeks [`timeset`]. Epiweeks to fetch. Defaults to all ("*") dates. #' @param ... not used for values, forces later arguments to bind by name #' @param issues [`timeset`]. Optionally, the issues to fetch. If not set, the #' most recent issue is returned. Mutually exclusive with `lag`. @@ -1671,9 +1747,17 @@ pub_nidss_dengue <- function(locations, epiweeks, fetch_args = fetch_args_list() #' @return [`tibble::tibble`] #' @keywords endpoint #' @export -pub_nidss_flu <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, fetch_args = fetch_args_list()) { +pub_nidss_flu <- function( + regions, + epiweeks = "*", + ..., + issues = NULL, + lag = NULL, + fetch_args = fetch_args_list()) { rlang::check_dots_empty() + epiweeks <- get_wildcard_equivalent_dates(epiweeks, "week") + assert_character_param("regions", regions) assert_timeset_param("epiweeks", epiweeks) assert_timeset_param("issues", issues, required = FALSE) @@ -1725,12 +1809,18 @@ pub_nidss_flu <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, fet #' } #' @param auth string. Your authentication key. #' @param locations character. Locations to fetch. -#' @param epiweeks [`timeset`]. Epiweeks to fetch. +#' @param epiweeks [`timeset`]. Epiweeks to fetch. Defaults to all ("*") dates. #' @param fetch_args [`fetch_args`]. Additional arguments to pass to `fetch()`. #' @return [`tibble::tibble`] #' @keywords endpoint #' @export -pvt_norostat <- function(auth, locations, epiweeks, fetch_args = fetch_args_list()) { +pvt_norostat <- function( + auth, + locations, + epiweeks = "*", + fetch_args = fetch_args_list()) { + epiweeks <- get_wildcard_equivalent_dates(epiweeks, "week") + assert_character_param("auth", auth, len = 1) assert_character_param("locations", locations, len = 1) assert_timeset_param("epiweeks", epiweeks) @@ -1765,12 +1855,17 @@ pvt_norostat <- function(auth, locations, epiweeks, fetch_args = fetch_args_list #' pub_nowcast(locations = "ca", epiweeks = epirange(201201, 201301)) #' } #' @param locations character. Locations to fetch. -#' @param epiweeks [`timeset`]. Epiweeks to fetch. +#' @param epiweeks [`timeset`]. Epiweeks to fetch. Defaults to all ("*") dates. #' @param fetch_args [`fetch_args`]. Additional arguments to pass to `fetch()`. #' @return [`tibble::tibble`] #' @keywords endpoint #' @export -pub_nowcast <- function(locations, epiweeks, fetch_args = fetch_args_list()) { +pub_nowcast <- function( + locations, + epiweeks = "*", + fetch_args = fetch_args_list()) { + epiweeks <- get_wildcard_equivalent_dates(epiweeks, "week") + assert_character_param("locations", locations) assert_timeset_param("epiweeks", epiweeks) epiweeks <- parse_timeset_input(epiweeks) @@ -1796,7 +1891,7 @@ pub_nowcast <- function(locations, epiweeks, fetch_args = fetch_args_list()) { #' pub_paho_dengue(regions = "ca", epiweeks = epirange(201401, 201501)) #' } #' @param regions character. Regions to fetch. -#' @param epiweeks [`timeset`]. Epiweeks to fetch. +#' @param epiweeks [`timeset`]. Epiweeks to fetch. Defaults to all ("*") dates. #' @param ... not used for values, forces later arguments to bind by name #' @param issues [`timeset`]. Optionally, the issues to fetch. If not set, the #' most recent issue is returned. Mutually exclusive with `lag`. @@ -1806,9 +1901,17 @@ pub_nowcast <- function(locations, epiweeks, fetch_args = fetch_args_list()) { #' @return [`tibble::tibble`] #' @keywords endpoint #' @export -pub_paho_dengue <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, fetch_args = fetch_args_list()) { +pub_paho_dengue <- function( + regions, + epiweeks = "*", + ..., + issues = NULL, + lag = NULL, + fetch_args = fetch_args_list()) { rlang::check_dots_empty() + epiweeks <- get_wildcard_equivalent_dates(epiweeks, "week") + assert_character_param("regions", regions) assert_timeset_param("epiweeks", epiweeks) assert_timeset_param("issues", issues, required = FALSE) @@ -1856,12 +1959,18 @@ pub_paho_dengue <- function(regions, epiweeks, ..., issues = NULL, lag = NULL, f #' } #' @param auth string. Restricted access key (not the same as API key). #' @param locations character. Locations to fetch. -#' @param epiweeks [`timeset`]. Epiweeks to fetch. +#' @param epiweeks [`timeset`]. Epiweeks to fetch. Defaults to all ("*") dates. #' @param fetch_args [`fetch_args`]. Additional arguments to pass to `fetch()`. #' @return [`tibble::tibble`] #' @keywords endpoint #' @export -pvt_quidel <- function(auth, locations, epiweeks, fetch_args = fetch_args_list()) { +pvt_quidel <- function( + auth, + locations, + epiweeks = "*", + fetch_args = fetch_args_list()) { + epiweeks <- get_wildcard_equivalent_dates(epiweeks, "week") + assert_character_param("auth", auth, len = 1) assert_character_param("locations", locations) assert_timeset_param("epiweeks", epiweeks) @@ -1909,12 +2018,19 @@ pvt_quidel <- function(auth, locations, epiweeks, fetch_args = fetch_args_list() #' @param auth string. Restricted access key (not the same as API key). #' @param names character. Sensor names to fetch. #' @param locations character. Locations to fetch. -#' @param epiweeks [`timeset`]. Epiweeks to fetch. +#' @param epiweeks [`timeset`]. Epiweeks to fetch. Defaults to all ("*") dates. #' @param fetch_args [`fetch_args`]. Additional arguments to pass to `fetch()`. #' @return [`tibble::tibble`] #' @keywords endpoint #' @export -pvt_sensors <- function(auth, names, locations, epiweeks, fetch_args = fetch_args_list()) { +pvt_sensors <- function( + auth, + names, + locations, + epiweeks = "*", + fetch_args = fetch_args_list()) { + epiweeks <- get_wildcard_equivalent_dates(epiweeks, "week") + assert_character_param("auth", auth, len = 1) assert_character_param("names", names) assert_character_param("locations", locations) @@ -1963,7 +2079,13 @@ pvt_sensors <- function(auth, names, locations, epiweeks, fetch_args = fetch_arg #' @return [`tibble::tibble`] #' @keywords endpoint #' @export -pvt_twitter <- function(auth, locations, ..., dates = NULL, epiweeks = NULL, fetch_args = fetch_args_list()) { +pvt_twitter <- function( + auth, + locations, + ..., + dates = NULL, + epiweeks = NULL, + fetch_args = fetch_args_list()) { rlang::check_dots_empty() assert_character_param("auth", auth, len = 1) diff --git a/R/utils.R b/R/utils.R index eed7c88f..705ff368 100644 --- a/R/utils.R +++ b/R/utils.R @@ -44,3 +44,20 @@ check_is_cachable <- function(epidata_call, fetch_args) { ) return(is_cachable) } + +#' helper to convert a date wildcard ("*") to an appropriate epirange +#' +#' @keywords internal +get_wildcard_equivalent_dates <- function(time_value, time_type = c("day", "week")) { + time_type <- match.arg(time_type) + + if (identical(time_value, "*")) { + if (time_type == "day") { + # To get all dates, set start and end dates to extreme values. + time_value <- epirange(10000101, 30000101) + } else if (time_type == "week") { + time_value <- epirange(100001, 300001) + } + } + return(time_value) +} diff --git a/man/get_wildcard_equivalent_dates.Rd b/man/get_wildcard_equivalent_dates.Rd new file mode 100644 index 00000000..590a4745 --- /dev/null +++ b/man/get_wildcard_equivalent_dates.Rd @@ -0,0 +1,12 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{get_wildcard_equivalent_dates} +\alias{get_wildcard_equivalent_dates} +\title{helper to convert a date wildcard ("*") to an appropriate epirange} +\usage{ +get_wildcard_equivalent_dates(time_value, time_type = c("day", "week")) +} +\description{ +helper to convert a date wildcard ("*") to an appropriate epirange +} +\keyword{internal} diff --git a/man/pub_covid_hosp_facility.Rd b/man/pub_covid_hosp_facility.Rd index 46d6f51e..a18097ef 100644 --- a/man/pub_covid_hosp_facility.Rd +++ b/man/pub_covid_hosp_facility.Rd @@ -6,7 +6,7 @@ \usage{ pub_covid_hosp_facility( hospital_pks, - collection_weeks, + collection_weeks = "*", ..., publication_dates = NULL, fetch_args = fetch_args_list() @@ -15,7 +15,7 @@ pub_covid_hosp_facility( \arguments{ \item{hospital_pks}{character. Facility identifiers.} -\item{collection_weeks}{\code{\link{timeset}}. Epiweeks to fetch.} +\item{collection_weeks}{\code{\link{timeset}}. Epiweeks to fetch. Defaults to all ("*") dates.} \item{...}{not used for values, forces later arguments to bind by name} diff --git a/man/pub_covid_hosp_state_timeseries.Rd b/man/pub_covid_hosp_state_timeseries.Rd index 2823f6da..246bf7b1 100644 --- a/man/pub_covid_hosp_state_timeseries.Rd +++ b/man/pub_covid_hosp_state_timeseries.Rd @@ -6,7 +6,7 @@ \usage{ pub_covid_hosp_state_timeseries( states, - dates, + dates = "*", ..., as_of = NULL, issues = NULL, @@ -16,7 +16,7 @@ pub_covid_hosp_state_timeseries( \arguments{ \item{states}{character. Two letter state abbreviations.} -\item{dates}{\code{\link{timeset}}. Dates to fetch.} +\item{dates}{\code{\link{timeset}}. Dates to fetch. Defaults to all ("*") dates.} \item{...}{not used for values, forces later arguments to bind by name} diff --git a/man/pub_covidcast.Rd b/man/pub_covidcast.Rd index 0d87bcd6..65fb736f 100644 --- a/man/pub_covidcast.Rd +++ b/man/pub_covidcast.Rd @@ -9,8 +9,8 @@ pub_covidcast( signals, geo_type, time_type, - geo_values, - time_values, + geo_values = "*", + time_values = "*", ..., as_of = NULL, issues = NULL, @@ -35,7 +35,7 @@ pub_covidcast( all. (See: \url{https://cmu-delphi.github.io/delphi-epidata/api/covidcast_geography.html}.)} -\item{time_values}{\code{\link{timeset}}. Dates to fetch.} +\item{time_values}{\code{\link{timeset}}. Dates to fetch. Defaults to all ("*") dates.} \item{...}{not used for values, forces later arguments to bind by name} diff --git a/man/pub_delphi.Rd b/man/pub_delphi.Rd index 4613ad6c..282c93c7 100644 --- a/man/pub_delphi.Rd +++ b/man/pub_delphi.Rd @@ -9,7 +9,7 @@ pub_delphi(system, epiweek, fetch_args = fetch_args_list()) \arguments{ \item{system}{character. System name to fetch.} -\item{epiweek}{\code{\link{timeset}}. Epiweeks to fetch.} +\item{epiweek}{\code{\link{timeset}}. Epiweek to fetch. Does not support multiple dates.} \item{fetch_args}{\code{\link{fetch_args}}. Additional arguments to pass to \code{fetch()}.} } diff --git a/man/pub_dengue_nowcast.Rd b/man/pub_dengue_nowcast.Rd index f3709faf..e1c2573c 100644 --- a/man/pub_dengue_nowcast.Rd +++ b/man/pub_dengue_nowcast.Rd @@ -4,12 +4,12 @@ \alias{pub_dengue_nowcast} \title{Delphi's PAHO dengue nowcasts (North and South America)} \usage{ -pub_dengue_nowcast(locations, epiweeks, fetch_args = fetch_args_list()) +pub_dengue_nowcast(locations, epiweeks = "*", fetch_args = fetch_args_list()) } \arguments{ \item{locations}{character. Locations to fetch.} -\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch.} +\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch. Defaults to all ("*") dates.} \item{fetch_args}{\code{\link{fetch_args}}. Additional arguments to pass to \code{fetch()}.} } diff --git a/man/pub_ecdc_ili.Rd b/man/pub_ecdc_ili.Rd index 7546d28f..d71b5651 100644 --- a/man/pub_ecdc_ili.Rd +++ b/man/pub_ecdc_ili.Rd @@ -6,7 +6,7 @@ \usage{ pub_ecdc_ili( regions, - epiweeks, + epiweeks = "*", ..., issues = NULL, lag = NULL, @@ -16,7 +16,7 @@ pub_ecdc_ili( \arguments{ \item{regions}{character. Regions to fetch.} -\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch.} +\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch. Defaults to all ("*") dates.} \item{...}{not used for values, forces later arguments to bind by name} diff --git a/man/pub_flusurv.Rd b/man/pub_flusurv.Rd index 8d15ccfb..e8fd5bb0 100644 --- a/man/pub_flusurv.Rd +++ b/man/pub_flusurv.Rd @@ -6,7 +6,7 @@ \usage{ pub_flusurv( locations, - epiweeks, + epiweeks = "*", ..., issues = NULL, lag = NULL, @@ -16,7 +16,7 @@ pub_flusurv( \arguments{ \item{locations}{character. Character vector indicating location.} -\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch.} +\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch. Defaults to all ("*") dates.} \item{...}{not used for values, forces later arguments to bind by name} diff --git a/man/pub_fluview.Rd b/man/pub_fluview.Rd index 30c47449..61ba357a 100644 --- a/man/pub_fluview.Rd +++ b/man/pub_fluview.Rd @@ -6,7 +6,7 @@ \usage{ pub_fluview( regions, - epiweeks, + epiweeks = "*", ..., issues = NULL, lag = NULL, @@ -21,7 +21,7 @@ on. Full list link below.} \item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch in the form \code{epirange(startweek, endweek)}, where startweek and endweek are of the form -YYYYWW (string or numeric).} +YYYYWW (string or numeric). Defaults to all ("*") dates.} \item{...}{not used for values, forces later arguments to bind by name} diff --git a/man/pub_fluview_clinical.Rd b/man/pub_fluview_clinical.Rd index db2eccbf..a4017c76 100644 --- a/man/pub_fluview_clinical.Rd +++ b/man/pub_fluview_clinical.Rd @@ -6,7 +6,7 @@ \usage{ pub_fluview_clinical( regions, - epiweeks, + epiweeks = "*", ..., issues = NULL, lag = NULL, @@ -18,7 +18,7 @@ pub_fluview_clinical( \item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch in the form epirange(startweek,endweek), where startweek and endweek are of the form -YYYYWW (string or numeric).} +YYYYWW (string or numeric). Defaults to all ("*") dates.} \item{...}{not used for values, forces later arguments to bind by name} diff --git a/man/pub_gft.Rd b/man/pub_gft.Rd index ed736232..c80d8d9a 100644 --- a/man/pub_gft.Rd +++ b/man/pub_gft.Rd @@ -4,12 +4,12 @@ \alias{pub_gft} \title{Google Flu Trends flu search volume} \usage{ -pub_gft(locations, epiweeks, fetch_args = fetch_args_list()) +pub_gft(locations, epiweeks = "*", fetch_args = fetch_args_list()) } \arguments{ \item{locations}{character. Locations to fetch.} -\item{epiweeks}{\code{\link{timeset}} Epiweeks to fetch.} +\item{epiweeks}{\code{\link{timeset}} Epiweeks to fetch. Defaults to all ("*") dates.} \item{fetch_args}{\code{\link{fetch_args}}. Additional arguments to pass to \code{fetch()}.} } diff --git a/man/pub_kcdc_ili.Rd b/man/pub_kcdc_ili.Rd index c6f4ab8e..0c8b70f4 100644 --- a/man/pub_kcdc_ili.Rd +++ b/man/pub_kcdc_ili.Rd @@ -6,7 +6,7 @@ \usage{ pub_kcdc_ili( regions, - epiweeks, + epiweeks = "*", ..., issues = NULL, lag = NULL, @@ -16,7 +16,7 @@ pub_kcdc_ili( \arguments{ \item{regions}{character. Regions to fetch.} -\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch.} +\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch. Defaults to all ("*") dates.} \item{...}{not used for values, forces later arguments to bind by name} diff --git a/man/pub_nidss_dengue.Rd b/man/pub_nidss_dengue.Rd index 2f390ac8..67be9c94 100644 --- a/man/pub_nidss_dengue.Rd +++ b/man/pub_nidss_dengue.Rd @@ -4,12 +4,12 @@ \alias{pub_nidss_dengue} \title{NIDSS dengue cases (Taiwan)} \usage{ -pub_nidss_dengue(locations, epiweeks, fetch_args = fetch_args_list()) +pub_nidss_dengue(locations, epiweeks = "*", fetch_args = fetch_args_list()) } \arguments{ \item{locations}{character. Locations to fetch.} -\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch.} +\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch. Defaults to all ("*") dates.} \item{fetch_args}{\code{\link{fetch_args}}. Additional arguments to pass to \code{fetch()}.} } diff --git a/man/pub_nidss_flu.Rd b/man/pub_nidss_flu.Rd index fc0e7d6d..946a1b87 100644 --- a/man/pub_nidss_flu.Rd +++ b/man/pub_nidss_flu.Rd @@ -6,7 +6,7 @@ \usage{ pub_nidss_flu( regions, - epiweeks, + epiweeks = "*", ..., issues = NULL, lag = NULL, @@ -16,7 +16,7 @@ pub_nidss_flu( \arguments{ \item{regions}{character. Regions to fetch.} -\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch.} +\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch. Defaults to all ("*") dates.} \item{...}{not used for values, forces later arguments to bind by name} diff --git a/man/pub_nowcast.Rd b/man/pub_nowcast.Rd index 13aa1a22..306c37f1 100644 --- a/man/pub_nowcast.Rd +++ b/man/pub_nowcast.Rd @@ -4,12 +4,12 @@ \alias{pub_nowcast} \title{Delphi's ILI Nearby nowcasts} \usage{ -pub_nowcast(locations, epiweeks, fetch_args = fetch_args_list()) +pub_nowcast(locations, epiweeks = "*", fetch_args = fetch_args_list()) } \arguments{ \item{locations}{character. Locations to fetch.} -\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch.} +\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch. Defaults to all ("*") dates.} \item{fetch_args}{\code{\link{fetch_args}}. Additional arguments to pass to \code{fetch()}.} } diff --git a/man/pub_paho_dengue.Rd b/man/pub_paho_dengue.Rd index 773927b7..0d643f44 100644 --- a/man/pub_paho_dengue.Rd +++ b/man/pub_paho_dengue.Rd @@ -6,7 +6,7 @@ \usage{ pub_paho_dengue( regions, - epiweeks, + epiweeks = "*", ..., issues = NULL, lag = NULL, @@ -16,7 +16,7 @@ pub_paho_dengue( \arguments{ \item{regions}{character. Regions to fetch.} -\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch.} +\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch. Defaults to all ("*") dates.} \item{...}{not used for values, forces later arguments to bind by name} diff --git a/man/pvt_cdc.Rd b/man/pvt_cdc.Rd index 74497b29..35cc555b 100644 --- a/man/pvt_cdc.Rd +++ b/man/pvt_cdc.Rd @@ -4,14 +4,14 @@ \alias{pvt_cdc} \title{CDC total and by topic webpage visits} \usage{ -pvt_cdc(auth, locations, epiweeks, fetch_args = fetch_args_list()) +pvt_cdc(auth, locations, epiweeks = "*", fetch_args = fetch_args_list()) } \arguments{ \item{auth}{string. Restricted access key (not the same as API key).} \item{locations}{character. Locations to fetch.} -\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch.} +\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch. Defaults to all ("*") dates.} \item{fetch_args}{\code{\link{fetch_args}}. Additional arguments to pass to \code{fetch()}. See \code{fetch_args_list()} for details.} diff --git a/man/pvt_dengue_sensors.Rd b/man/pvt_dengue_sensors.Rd index 560e9e4b..2ff7eb30 100644 --- a/man/pvt_dengue_sensors.Rd +++ b/man/pvt_dengue_sensors.Rd @@ -8,7 +8,7 @@ pvt_dengue_sensors( auth, names, locations, - epiweeks, + epiweeks = "*", fetch_args = fetch_args_list() ) } @@ -19,7 +19,7 @@ pvt_dengue_sensors( \item{locations}{character. Locations to fetch.} -\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch.} +\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch. Defaults to all ("*") dates.} \item{fetch_args}{\code{\link{fetch_args}}. Additional arguments to pass to \code{fetch()}.} } diff --git a/man/pvt_ght.Rd b/man/pvt_ght.Rd index cfa1038c..7a16f10c 100644 --- a/man/pvt_ght.Rd +++ b/man/pvt_ght.Rd @@ -4,14 +4,14 @@ \alias{pvt_ght} \title{Google Health Trends health topics search volume} \usage{ -pvt_ght(auth, locations, epiweeks, query, fetch_args = fetch_args_list()) +pvt_ght(auth, locations, epiweeks = "*", query, fetch_args = fetch_args_list()) } \arguments{ \item{auth}{string. Restricted access key (not the same as API key).} \item{locations}{character. Locations to fetch.} -\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch.} +\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch. Defaults to all ("*") dates.} \item{query}{string. The query to be fetched.} diff --git a/man/pvt_norostat.Rd b/man/pvt_norostat.Rd index 8cf4ed10..324e9d9e 100644 --- a/man/pvt_norostat.Rd +++ b/man/pvt_norostat.Rd @@ -4,14 +4,14 @@ \alias{pvt_norostat} \title{CDC NoroSTAT norovirus outbreaks} \usage{ -pvt_norostat(auth, locations, epiweeks, fetch_args = fetch_args_list()) +pvt_norostat(auth, locations, epiweeks = "*", fetch_args = fetch_args_list()) } \arguments{ \item{auth}{string. Your authentication key.} \item{locations}{character. Locations to fetch.} -\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch.} +\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch. Defaults to all ("*") dates.} \item{fetch_args}{\code{\link{fetch_args}}. Additional arguments to pass to \code{fetch()}.} } diff --git a/man/pvt_quidel.Rd b/man/pvt_quidel.Rd index 909df751..10ca3c0a 100644 --- a/man/pvt_quidel.Rd +++ b/man/pvt_quidel.Rd @@ -4,14 +4,14 @@ \alias{pvt_quidel} \title{Quidel COVID-19 and influenza testing data} \usage{ -pvt_quidel(auth, locations, epiweeks, fetch_args = fetch_args_list()) +pvt_quidel(auth, locations, epiweeks = "*", fetch_args = fetch_args_list()) } \arguments{ \item{auth}{string. Restricted access key (not the same as API key).} \item{locations}{character. Locations to fetch.} -\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch.} +\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch. Defaults to all ("*") dates.} \item{fetch_args}{\code{\link{fetch_args}}. Additional arguments to pass to \code{fetch()}.} } diff --git a/man/pvt_sensors.Rd b/man/pvt_sensors.Rd index ec536fdf..218239fe 100644 --- a/man/pvt_sensors.Rd +++ b/man/pvt_sensors.Rd @@ -4,7 +4,13 @@ \alias{pvt_sensors} \title{Influenza and dengue digital surveillance sensors} \usage{ -pvt_sensors(auth, names, locations, epiweeks, fetch_args = fetch_args_list()) +pvt_sensors( + auth, + names, + locations, + epiweeks = "*", + fetch_args = fetch_args_list() +) } \arguments{ \item{auth}{string. Restricted access key (not the same as API key).} @@ -13,7 +19,7 @@ pvt_sensors(auth, names, locations, epiweeks, fetch_args = fetch_args_list()) \item{locations}{character. Locations to fetch.} -\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch.} +\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch. Defaults to all ("*") dates.} \item{fetch_args}{\code{\link{fetch_args}}. Additional arguments to pass to \code{fetch()}.} } From 3aee83ba617c2c571f025315040126f40bf3ee67 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 5 Jan 2024 14:34:54 -0500 Subject: [PATCH 131/189] pub_covid_hosp_facility supports epiweeks and days `pub_covid_hosp_facility` says and implies it takes weeks for the arg `collection_weeks`, but it actually only takes days (corresponding to weeks) and will error if given weeks. Given the misleading name and behavior, and differing behavior compared to other endpoints with weekly data, allow users to supply weeks -- these will be converted to dates. --- R/endpoints.R | 20 ++++++++++++++++++-- R/model.R | 31 +++++++++++++++++++++++++++++++ man/pub_covid_hosp_facility.Rd | 8 +++++++- man/pub_delphi.Rd | 3 ++- 4 files changed, 58 insertions(+), 4 deletions(-) diff --git a/R/endpoints.R b/R/endpoints.R index 9d9bf162..4b38988b 100644 --- a/R/endpoints.R +++ b/R/endpoints.R @@ -161,14 +161,22 @@ pub_covid_hosp_facility_lookup <- function( #' hospital_pks = "100075", #' collection_weeks = epirange(20200101, 20200501) #' ) +#' +#' pub_covid_hosp_facility( +#' hospital_pks = "100075", +#' collection_weeks = epirange(202001, 202005) +#' ) #' } #' @param hospital_pks character. Facility identifiers. -#' @param collection_weeks [`timeset`]. Epiweeks to fetch. Defaults to all ("*") dates. +#' @param collection_weeks [`timeset`]. Dates (corresponding to epiweeks) to +#' fetch. Defaults to all ("*") dates. #' @param ... not used for values, forces later arguments to bind by name #' @param publication_dates [`timeset`]. Publication dates to fetch. #' @param fetch_args [`fetch_args`]. Additional arguments to pass to `fetch()`. #' @return [`tibble::tibble`] #' +#' @importFrom checkmate test_class +#' #' @seealso [`pub_covid_hosp_facility()`], [`epirange()`] #' @keywords endpoint #' @export @@ -181,7 +189,7 @@ pub_covid_hosp_facility <- function( fetch_args = fetch_args_list()) { rlang::check_dots_empty() - collection_weeks <- get_wildcard_equivalent_dates(collection_weeks, "week") + collection_weeks <- get_wildcard_equivalent_dates(collection_weeks, "day") assert_character_param("hospital_pks", hospital_pks) assert_timeset_param("collection_weeks", collection_weeks) @@ -189,6 +197,13 @@ pub_covid_hosp_facility <- function( collection_weeks <- parse_timeset_input(collection_weeks) publication_dates <- parse_timeset_input(publication_dates) + # Confusingly, the endpoint expects `collection_weeks` to be in day format, + # but correspond to epiweeks. Allow `collection_weeks` to be provided in + # either day or week format. + if (test_class(collection_weeks, "EpiRange")) { + collection_weeks <- convert_epirange_format(collection_weeks, to_type = "day") + } + create_epidata_call( "covid_hosp_facility/", list( @@ -1047,6 +1062,7 @@ pub_covidcast <- function( #' } #' @param system character. System name to fetch. #' @param epiweek [`timeset`]. Epiweek to fetch. Does not support multiple dates. +#' Make separate calls to fetch data for multiple epiweeks. #' @param fetch_args [`fetch_args`]. Additional arguments to pass to `fetch()`. #' @return [`list`] #' @keywords endpoint diff --git a/R/model.R b/R/model.R index 8ba7a2b6..705f862f 100644 --- a/R/model.R +++ b/R/model.R @@ -61,6 +61,37 @@ epirange <- function(from, to) { structure(list(from = from, to = to), class = "EpiRange") } +#' helper to reformat an epirange from week to day or vice versa +#' +#' @keywords internal +convert_epirange_format <- function(epirange, to_type = c("day", "week")) { + to_type <- match.arg(to_type) + + # Day format + if (nchar(epirange$from) == 8) { + if (to_type == "week") { + from_components <- MMWRweek::MMWRweek(as.Date(as.character(epirange$from), "%Y%m%d")) + to_components <- MMWRweek::MMWRweek(as.Date(as.character(epirange$to), "%Y%m%d")) + + epirange$from <- as.numeric(paste0( + from_components$MMWRyear, + formatC(from_components$MMWRweek, width = 2, flag = 0) + )) + epirange$to <- as.numeric(paste0( + to_components$MMWRyear, + formatC(to_components$MMWRweek, width = 2, flag = 0) + )) + } + # Week format + } else { + if (to_type == "day") { + epirange$from <- parse_api_week(epirange$from) + epirange$to <- parse_api_week(epirange$to) + } + } + + return(epirange) +} #' Timeset formats for specifying dates #' diff --git a/man/pub_covid_hosp_facility.Rd b/man/pub_covid_hosp_facility.Rd index a18097ef..59f4ff9b 100644 --- a/man/pub_covid_hosp_facility.Rd +++ b/man/pub_covid_hosp_facility.Rd @@ -15,7 +15,8 @@ pub_covid_hosp_facility( \arguments{ \item{hospital_pks}{character. Facility identifiers.} -\item{collection_weeks}{\code{\link{timeset}}. Epiweeks to fetch. Defaults to all ("*") dates.} +\item{collection_weeks}{\code{\link{timeset}}. Dates (corresponding to epiweeks) to +fetch. Defaults to all ("*") dates.} \item{...}{not used for values, forces later arguments to bind by name} @@ -45,6 +46,11 @@ pub_covid_hosp_facility( hospital_pks = "100075", collection_weeks = epirange(20200101, 20200501) ) + +pub_covid_hosp_facility( + hospital_pks = "100075", + collection_weeks = epirange(202001, 202005) +) } } \seealso{ diff --git a/man/pub_delphi.Rd b/man/pub_delphi.Rd index 282c93c7..fe278beb 100644 --- a/man/pub_delphi.Rd +++ b/man/pub_delphi.Rd @@ -9,7 +9,8 @@ pub_delphi(system, epiweek, fetch_args = fetch_args_list()) \arguments{ \item{system}{character. System name to fetch.} -\item{epiweek}{\code{\link{timeset}}. Epiweek to fetch. Does not support multiple dates.} +\item{epiweek}{\code{\link{timeset}}. Epiweek to fetch. Does not support multiple dates. +Make separate calls to fetch data for multiple epiweeks.} \item{fetch_args}{\code{\link{fetch_args}}. Additional arguments to pass to \code{fetch()}.} } From 6a85f428766a928e683cb1affe6977620834656e Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 5 Jan 2024 14:49:12 -0500 Subject: [PATCH 132/189] warn about week conversion; handle single week date refactor reformat_epirange; add date_to_epiweek helper fn better collection_weeks message --- NAMESPACE | 1 + R/endpoints.R | 17 ++++++++++++--- R/model.R | 45 ++++++++++++++++++++-------------------- man/date_to_epiweek.Rd | 18 ++++++++++++++++ man/reformat_epirange.Rd | 12 +++++++++++ 5 files changed, 68 insertions(+), 25 deletions(-) create mode 100644 man/date_to_epiweek.Rd create mode 100644 man/reformat_epirange.Rd diff --git a/NAMESPACE b/NAMESPACE index 9b5b245c..754c7f63 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -48,6 +48,7 @@ export(save_api_key) export(set_cache) import(cachem) import(glue) +importFrom(MMWRweek,MMWRweek) importFrom(MMWRweek,MMWRweek2Date) importFrom(checkmate,assert) importFrom(checkmate,assert_character) diff --git a/R/endpoints.R b/R/endpoints.R index 4b38988b..2f24611f 100644 --- a/R/endpoints.R +++ b/R/endpoints.R @@ -175,7 +175,7 @@ pub_covid_hosp_facility_lookup <- function( #' @param fetch_args [`fetch_args`]. Additional arguments to pass to `fetch()`. #' @return [`tibble::tibble`] #' -#' @importFrom checkmate test_class +#' @importFrom checkmate test_class test_integerish test_character #' #' @seealso [`pub_covid_hosp_facility()`], [`epirange()`] #' @keywords endpoint @@ -200,8 +200,19 @@ pub_covid_hosp_facility <- function( # Confusingly, the endpoint expects `collection_weeks` to be in day format, # but correspond to epiweeks. Allow `collection_weeks` to be provided in # either day or week format. - if (test_class(collection_weeks, "EpiRange")) { - collection_weeks <- convert_epirange_format(collection_weeks, to_type = "day") + coercion_msg <- c( + "`collection_weeks` is in week format but `pub_covid_hosp_facility` + expects day format; dates will be converted to day format but may not + correspond exactly to desired time range" + ) + if (test_class(collection_weeks, "EpiRange") && nchar(collection_weeks$from) == 6) { + cli::cli_warn(coercion_msg, class = "epidatr__epirange_week_coercion") + collection_weeks <- reformat_epirange(collection_weeks, to_type = "day") + # Single week date. + } else if ((test_integerish(collection_weeks) || test_character(collection_weeks)) && + nchar(collection_weeks) == 6) { + cli::cli_warn(coercion_msg, class = "epidatr__single_week_coercion") + collection_weeks <- parse_api_week(collection_weeks) } create_epidata_call( diff --git a/R/model.R b/R/model.R index 705f862f..81bb9e9c 100644 --- a/R/model.R +++ b/R/model.R @@ -64,30 +64,17 @@ epirange <- function(from, to) { #' helper to reformat an epirange from week to day or vice versa #' #' @keywords internal -convert_epirange_format <- function(epirange, to_type = c("day", "week")) { +reformat_epirange <- function(epirange, to_type = c("day", "week")) { to_type <- match.arg(to_type) - # Day format - if (nchar(epirange$from) == 8) { - if (to_type == "week") { - from_components <- MMWRweek::MMWRweek(as.Date(as.character(epirange$from), "%Y%m%d")) - to_components <- MMWRweek::MMWRweek(as.Date(as.character(epirange$to), "%Y%m%d")) - - epirange$from <- as.numeric(paste0( - from_components$MMWRyear, - formatC(from_components$MMWRweek, width = 2, flag = 0) - )) - epirange$to <- as.numeric(paste0( - to_components$MMWRyear, - formatC(to_components$MMWRweek, width = 2, flag = 0) - )) - } - # Week format - } else { - if (to_type == "day") { - epirange$from <- parse_api_week(epirange$from) - epirange$to <- parse_api_week(epirange$to) - } + # Day format -> week + if (nchar(epirange$from) == 8 && to_type == "week") { + epirange$from <- date_to_epiweek(epirange$from) + epirange$to <- date_to_epiweek(epirange$to) + # Week format -> day + } else if (nchar(epirange$from) == 6 && to_type == "day") { + epirange$from <- parse_api_week(epirange$from) + epirange$to <- parse_api_week(epirange$to) } return(epirange) @@ -203,6 +190,20 @@ parse_data_frame <- function(epidata_call, df, disable_date_parsing = FALSE) { df } +#' Converts a date (integer or character) to an epiweek +#' @param value date (integer or character, with format YYYYMMDD) to be converted to an epiweek +#' @return an integer representing an epiweek, in the format YYYYWW +#' @importFrom MMWRweek MMWRweek +#' @keywords internal +date_to_epiweek <- function(value) { + date_components <- MMWRweek::MMWRweek(as.Date(as.character(value), "%Y%m%d")) + as.numeric(paste0( + date_components$MMWRyear, + # Pad with zeroes up to 2 digits (x -> 0x) + formatC(date_components$MMWRweek, width = 2, flag = 0) + )) +} + #' @keywords internal parse_api_date <- function(value) { as.Date(as.character(value), tryFormats = c("%Y%m%d", "%Y-%m-%d")) diff --git a/man/date_to_epiweek.Rd b/man/date_to_epiweek.Rd new file mode 100644 index 00000000..7f1f4262 --- /dev/null +++ b/man/date_to_epiweek.Rd @@ -0,0 +1,18 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/model.R +\name{date_to_epiweek} +\alias{date_to_epiweek} +\title{Converts a date (integer or character) to an epiweek} +\usage{ +date_to_epiweek(value) +} +\arguments{ +\item{value}{date (integer or character, with format YYYYMMDD) to be converted to an epiweek} +} +\value{ +an integer representing an epiweek, in the format YYYYWW +} +\description{ +Converts a date (integer or character) to an epiweek +} +\keyword{internal} diff --git a/man/reformat_epirange.Rd b/man/reformat_epirange.Rd new file mode 100644 index 00000000..7a6e1e54 --- /dev/null +++ b/man/reformat_epirange.Rd @@ -0,0 +1,12 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/model.R +\name{reformat_epirange} +\alias{reformat_epirange} +\title{helper to reformat an epirange from week to day or vice versa} +\usage{ +reformat_epirange(epirange, to_type = c("day", "week")) +} +\description{ +helper to reformat an epirange from week to day or vice versa +} +\keyword{internal} From a3e8f5fd0e9d6615bf6b2d5eab6b7af044a85a7b Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Mon, 8 Jan 2024 13:20:36 -0500 Subject: [PATCH 133/189] test helper function behavior --- R/model.R | 10 +++++---- tests/testthat/test-model.R | 44 +++++++++++++++++++++++++++++++++++++ tests/testthat/test-utils.R | 24 ++++++++++++++++++++ 3 files changed, 74 insertions(+), 4 deletions(-) diff --git a/R/model.R b/R/model.R index 81bb9e9c..e1831534 100644 --- a/R/model.R +++ b/R/model.R @@ -69,12 +69,14 @@ reformat_epirange <- function(epirange, to_type = c("day", "week")) { # Day format -> week if (nchar(epirange$from) == 8 && to_type == "week") { - epirange$from <- date_to_epiweek(epirange$from) - epirange$to <- date_to_epiweek(epirange$to) + return( + epirange(date_to_epiweek(epirange$from), date_to_epiweek(epirange$to)) + ) # Week format -> day } else if (nchar(epirange$from) == 6 && to_type == "day") { - epirange$from <- parse_api_week(epirange$from) - epirange$to <- parse_api_week(epirange$to) + return( + epirange(parse_api_week(epirange$from), parse_api_week(epirange$to)) + ) } return(epirange) diff --git a/tests/testthat/test-model.R b/tests/testthat/test-model.R index 9f9b739c..453db0be 100644 --- a/tests/testthat/test-model.R +++ b/tests/testthat/test-model.R @@ -113,3 +113,47 @@ test_that("parse_api_date accepts YYYYMMDD and YYYY-MM-DD", { test_that("parse_api_date handles missing values appropriately", { expect_identical(parse_api_date(NA), as.Date(NA)) }) + +test_that("date_to_epiweek accepts str and int input", { + expect_identical(date_to_epiweek("20200101"), 202001) + expect_identical(date_to_epiweek(20200101), 202001) +}) + +test_that("date_to_epiweek accepts single and double-digit weeks", { + expect_identical(date_to_epiweek(20201101), 202045) + expect_identical(date_to_epiweek(20200109), 202002) +}) + +test_that("reformat_epirange works in basic cases", { + # Week to week + result <- reformat_epirange(epirange(202002, 202013), "week") + expect_identical(result, epirange(202002, 202013)) + + result <- reformat_epirange(epirange("202002", "202013"), "week") + expect_identical(result, epirange("202002", "202013")) + + # Week to day + # Across year boundary + result <- reformat_epirange(epirange(202001, 202013), "day") + expect_identical(result, epirange(20191229, 20200322)) + + result <- reformat_epirange(epirange(202002, 202013), "day") + expect_identical(result, epirange(20200105, 20200322)) + + result <- reformat_epirange(epirange("202002", "202013"), "day") + expect_identical(result, epirange(20200105, 20200322)) + + # Day to week + result <- reformat_epirange(epirange(20200201, 20201031), "week") + expect_identical(result, epirange(202005, 202044)) + + result <- reformat_epirange(epirange("20200201", "20201031"), "week") + expect_identical(result, epirange(202005, 202044)) + + # Day to day + result <- reformat_epirange(epirange(20200201, 20201031), "day") + expect_identical(result, epirange(20200201, 20201031)) + + result <- reformat_epirange(epirange("20200201", "20201031"), "day") + expect_identical(result, epirange("20200201", "20201031")) +}) diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index fb5cfbe5..a95fbfe0 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -64,3 +64,27 @@ test_that("check_is_cachable can handle both str and date inputs of various leng epidata_call$params$issues <- epirange(as.Date("2022-01-01"), as.Date("2022-02-01")) expect_no_error(check_is_cachable(epidata_call, fetch_args)) }) + +test_that("get_wildcard_equivalent_dates works in basic cases", { + # Week date + result <- get_wildcard_equivalent_dates(epirange(202002, 202013), "week") + expect_identical(result, epirange(202002, 202013)) + + result <- get_wildcard_equivalent_dates(epirange("202002", "202013"), "week") + expect_identical(result, epirange("202002", "202013")) + + # Week wildcard + result <- get_wildcard_equivalent_dates("*", "week") + expect_identical(result, epirange(100001, 300001)) + + # Day date + result <- get_wildcard_equivalent_dates(epirange(20200201, 20201031), "day") + expect_identical(result, epirange(20200201, 20201031)) + + result <- get_wildcard_equivalent_dates(epirange("20200201", "20201031"), "day") + expect_identical(result, epirange("20200201", "20201031")) + + # Day wildcard + result <- get_wildcard_equivalent_dates("*", "day") + expect_identical(result, epirange(10000101, 30000101)) +}) From b5e58c7cd2207dba25f8edd3455101b37528395e Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Tue, 9 Jan 2024 14:51:37 -0500 Subject: [PATCH 134/189] test wildcard --- tests/testthat/test-endpoints.R | 177 ++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) diff --git a/tests/testthat/test-endpoints.R b/tests/testthat/test-endpoints.R index 53aca4cf..b6da6a25 100644 --- a/tests/testthat/test-endpoints.R +++ b/tests/testthat/test-endpoints.R @@ -147,6 +147,183 @@ test_that("basic_epidata_call", { ) %>% request_url()) }) +test_that("endoints accept wildcard for date parameter", { + expect_no_error(call <- pvt_cdc( + auth = "yourkey", + "fl,ca", + "*", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$epiweeks$from, 100001) + expect_identical(call$params$epiweeks$to, 300001) + + expect_identical(call$params$epiweeks$from, 100001) + expect_identical(call$params$epiweeks$to, 300001) + + expect_no_error(call <- pub_covid_hosp_facility( + hospital_pks = "100075", + collection_weeks = "*", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$collection_weeks$from, 10000101) + expect_identical(call$params$collection_weeks$to, 30000101) + + expect_no_error(call <- pub_covid_hosp_state_timeseries( + states = "fl", + dates = "*", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$dates$from, 10000101) + expect_identical(call$params$dates$to, 30000101) + + expect_no_error(call <- pub_covidcast( + source = "jhu-csse", + signals = "confirmed_7dav_incidence_prop", + time_type = "day", + geo_type = "state", + time_values = "*", + geo_values = "ca,fl", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$time_values, "*") + + expect_no_error(call <- pub_dengue_nowcast( + locations = "ca", + epiweeks = "*", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$epiweeks$from, 100001) + expect_identical(call$params$epiweeks$to, 300001) + + expect_no_error(call <- pvt_dengue_sensors( + auth = "yourkey", + names = "ght", + locations = "ag", + epiweeks = "*", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$epiweeks$from, 100001) + expect_identical(call$params$epiweeks$to, 300001) + + expect_no_error(call <- pub_ecdc_ili( + regions = "austria", + epiweeks = "*", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$epiweeks$from, 100001) + expect_identical(call$params$epiweeks$to, 300001) + + expect_no_error(call <- pub_flusurv( + locations = "CA", + epiweeks = "*", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$epiweeks$from, 100001) + expect_identical(call$params$epiweeks$to, 300001) + + expect_no_error(call <- pub_fluview_clinical( + regions = "nat", + epiweeks = "*", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$epiweeks$from, 100001) + expect_identical(call$params$epiweeks$to, 300001) + + expect_no_error(call <- pub_fluview( + regions = "nat", + epiweeks = "*", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$epiweeks$from, 100001) + expect_identical(call$params$epiweeks$to, 300001) + + expect_no_error(call <- pub_gft( + locations = "hhs1", + epiweeks = "*", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$epiweeks$from, 100001) + expect_identical(call$params$epiweeks$to, 300001) + + expect_no_error(call <- pvt_ght( + auth = "yourkey", + locations = "ca", + epiweeks = "*", + query = "how to get over the flu", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$epiweeks$from, 100001) + expect_identical(call$params$epiweeks$to, 300001) + + expect_no_error(call <- pub_kcdc_ili( + regions = "ROK", + epiweeks = "*", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$epiweeks$from, 100001) + expect_identical(call$params$epiweeks$to, 300001) + + expect_no_error(call <- pub_nidss_dengue( + locations = "taipei", + epiweeks = "*", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$epiweeks$from, 100001) + expect_identical(call$params$epiweeks$to, 300001) + + expect_no_error(call <- pub_nidss_flu( + regions = "taipei", + epiweeks = "*", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$epiweeks$from, 100001) + expect_identical(call$params$epiweeks$to, 300001) + + expect_no_error(call <- pvt_norostat( + auth = "yourkey", + locations = "Minnesota, Ohio, Oregon, Tennessee, and Wisconsin", + epiweeks = "*", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$epiweeks$from, 100001) + expect_identical(call$params$epiweeks$to, 300001) + + expect_no_error(call <- pub_nowcast( + locations = "ca", + epiweeks = "*", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$epiweeks$from, 100001) + expect_identical(call$params$epiweeks$to, 300001) + + expect_no_error(call <- pub_paho_dengue( + regions = "ca", + epiweeks = "*", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$epiweeks$from, 100001) + expect_identical(call$params$epiweeks$to, 300001) + + expect_no_error(call <- pvt_quidel( + auth = "yourkey", + locations = "hhs1", + epiweeks = "*", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$epiweeks$from, 100001) + expect_identical(call$params$epiweeks$to, 300001) + + expect_no_error(call <- pvt_sensors( + auth = "yourkey", + names = "sar3", + locations = "nat", + epiweeks = "*", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$epiweeks$from, 100001) + expect_identical(call$params$epiweeks$to, 300001) +}) + test_that("endpoints fail when given args via dots", { dots_error <- "`...` must be empty" From 9ec5fa04736d3146ef4876df30bba2961f3abbff Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Tue, 9 Jan 2024 17:28:53 -0500 Subject: [PATCH 135/189] linting --- R/endpoints.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/endpoints.R b/R/endpoints.R index a0b3a77e..26e0dd3a 100644 --- a/R/endpoints.R +++ b/R/endpoints.R @@ -210,7 +210,7 @@ pub_covid_hosp_facility <- function( collection_weeks <- reformat_epirange(collection_weeks, to_type = "day") # Single week date. } else if ((test_integerish(collection_weeks) || test_character(collection_weeks)) && - nchar(collection_weeks) == 6) { + nchar(collection_weeks) == 6) { cli::cli_warn(coercion_msg, class = "epidatr__single_week_coercion") collection_weeks <- parse_api_week(collection_weeks) } From d9def9f35af32b0763cd9392917ce9e359f9c894 Mon Sep 17 00:00:00 2001 From: nmdefries Date: Tue, 9 Jan 2024 22:30:24 +0000 Subject: [PATCH 136/189] style: styler (GHA) --- R/endpoints.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/endpoints.R b/R/endpoints.R index 26e0dd3a..a0b3a77e 100644 --- a/R/endpoints.R +++ b/R/endpoints.R @@ -210,7 +210,7 @@ pub_covid_hosp_facility <- function( collection_weeks <- reformat_epirange(collection_weeks, to_type = "day") # Single week date. } else if ((test_integerish(collection_weeks) || test_character(collection_weeks)) && - nchar(collection_weeks) == 6) { + nchar(collection_weeks) == 6) { cli::cli_warn(coercion_msg, class = "epidatr__single_week_coercion") collection_weeks <- parse_api_week(collection_weeks) } From d1db44569b0ed2fef380f2d43686e9086ecd2bcf Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 5 Jan 2024 16:30:25 -0500 Subject: [PATCH 137/189] combine epiweek and date into time_type and time_value for pub_wiki This makes the pub_wiki interfaces better match that of the other endpoints. Also build in time_values default of "*". --- R/endpoints.R | 33 ++++++++++++++++++++++++--------- man/pub_wiki.Rd | 17 +++++++++++------ tests/testthat/test-endpoints.R | 4 +++- vignettes/signal-discovery.Rmd | 7 ++++++- 4 files changed, 44 insertions(+), 17 deletions(-) diff --git a/R/endpoints.R b/R/endpoints.R index a0b3a77e..a1da8889 100644 --- a/R/endpoints.R +++ b/R/endpoints.R @@ -2163,13 +2163,18 @@ pvt_twitter <- function( #' #' @examples #' \dontrun{ -#' pub_wiki(articles = "avian_influenza", epiweeks = epirange(201501, 201601)) +#' pub_wiki( +#' articles = "avian_influenza", +#' time_type = "week", +#' time_values = epirange(201501, 201601) +#' ) #' } #' @param articles character. Articles to fetch. #' @param ... not used for values, forces later arguments to bind by name -#' @param dates [`timeset`]. Dates to fetch. Mutually exclusive with `epiweeks`. -#' @param epiweeks [`timeset`]. Epiweeks to fetch. Mutually exclusive with -#' `dates`. +#' @param time_type string. The temporal resolution of the data (either "day" or +#' "week", depending on signal). +#' @param time_values [`timeset`]. Dates or epiweeks to fetch. Defaults to all +#' ("*") dates. #' @param language string. Language to fetch. #' @param hours integer. Optionally, the hours to fetch. #' @param fetch_args [`fetch_args`]. Additional arguments to pass to `fetch()`. @@ -2179,14 +2184,27 @@ pvt_twitter <- function( pub_wiki <- function( articles, ..., - dates = NULL, - epiweeks = NULL, + time_type = c("day", "week"), + time_values = "*", hours = NULL, language = "en", fetch_args = fetch_args_list()) { rlang::check_dots_empty() + time_type <- match.arg(time_type) + if (time_type == "day") { + dates <- time_values + epiweeks <- NULL + dates <- get_wildcard_equivalent_dates(dates, "day") + } else { + dates <- NULL + epiweeks <- time_values + epiweeks <- get_wildcard_equivalent_dates(epiweeks, "week") + } + assert_character_param("articles", articles) + assert_character_param("time_type", time_type, len = 1) + assert_timeset_param("time_values", time_values) assert_timeset_param("dates", dates, required = FALSE) assert_timeset_param("epiweeks", epiweeks, required = FALSE) assert_integerish_param("hours", hours, required = FALSE) @@ -2194,9 +2212,6 @@ pub_wiki <- function( dates <- parse_timeset_input(dates) epiweeks <- parse_timeset_input(epiweeks) - if (!xor(is.null(dates), is.null(epiweeks))) { - stop("exactly one of `dates` and `epiweeks` is required") - } time_field <- if (!is.null(dates)) { create_epidata_field_info("date", "date") } else { diff --git a/man/pub_wiki.Rd b/man/pub_wiki.Rd index 2669ff1a..8e294185 100644 --- a/man/pub_wiki.Rd +++ b/man/pub_wiki.Rd @@ -7,8 +7,8 @@ pub_wiki( articles, ..., - dates = NULL, - epiweeks = NULL, + time_type = c("day", "week"), + time_values = "*", hours = NULL, language = "en", fetch_args = fetch_args_list() @@ -19,10 +19,11 @@ pub_wiki( \item{...}{not used for values, forces later arguments to bind by name} -\item{dates}{\code{\link{timeset}}. Dates to fetch. Mutually exclusive with \code{epiweeks}.} +\item{time_type}{string. The temporal resolution of the data (either "day" or +"week", depending on signal).} -\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch. Mutually exclusive with -\code{dates}.} +\item{time_values}{\code{\link{timeset}}. Dates or epiweeks to fetch. Defaults to all +("*") dates.} \item{hours}{integer. Optionally, the hours to fetch.} @@ -46,7 +47,11 @@ Number of page visits for selected English, Influenza-related wikipedia articles } \examples{ \dontrun{ -pub_wiki(articles = "avian_influenza", epiweeks = epirange(201501, 201601)) +pub_wiki( + articles = "avian_influenza", + time_type = "week", + time_values = epirange(201501, 201601) +) } } \keyword{endpoint} diff --git a/tests/testthat/test-endpoints.R b/tests/testthat/test-endpoints.R index b6da6a25..7d7c12b4 100644 --- a/tests/testthat/test-endpoints.R +++ b/tests/testthat/test-endpoints.R @@ -142,7 +142,8 @@ test_that("basic_epidata_call", { ) %>% request_url()) expect_no_error(pub_wiki( articles = "avian_influenza", - epiweeks = epirange(201501, 202001), + time_type = "week", + time_values = epirange(201501, 202001), fetch_args = fetch_args_list(dry_run = TRUE) ) %>% request_url()) }) @@ -420,6 +421,7 @@ test_that("endpoints fail when given args via dots", { expect_error( pub_wiki( articles = "avian_influenza", + time_type = "week", date_range = epirange(201501, 202001) ), regexp = dots_error diff --git a/vignettes/signal-discovery.Rmd b/vignettes/signal-discovery.Rmd index 8ed0aac9..bbea800a 100644 --- a/vignettes/signal-discovery.Rmd +++ b/vignettes/signal-discovery.Rmd @@ -282,7 +282,12 @@ pub_paho_dengue(regions = "ca", epiweeks = epirange(200201, 202319)) API docs: ```{r, eval = FALSE} -pub_wiki(language = "en", articles = "influenza", epiweeks = epirange(202001, 202319)) +pub_wiki( + language = "en", + articles = "influenza", + time_type = "week", + time_values = epirange(202001, 202319) +) ``` ### Private methods From 83e7ce3b9db775e390f914dcf824229ee643bacb Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Fri, 5 Jan 2024 17:07:24 -0500 Subject: [PATCH 138/189] combine epiweek and date into time_type and time_value for pvt_twitter --- R/endpoints.R | 36 ++++++++++++++++++++++----------- man/pub_wiki.Rd | 6 +++--- man/pvt_twitter.Rd | 14 +++++++------ tests/testthat/test-endpoints.R | 6 ++++-- vignettes/signal-discovery.Rmd | 3 ++- 5 files changed, 41 insertions(+), 24 deletions(-) diff --git a/R/endpoints.R b/R/endpoints.R index a1da8889..f6500e27 100644 --- a/R/endpoints.R +++ b/R/endpoints.R @@ -2094,15 +2094,17 @@ pvt_sensors <- function( #' pvt_twitter( #' auth = Sys.getenv("SECRET_API_AUTH_TWITTER"), #' locations = "CA", -#' epiweeks = epirange(201501, 202001) +#' time_type = "week", +#' time_values = epirange(201501, 202001) #' ) #' } #' @param auth string. Restricted access key (not the same as API key). #' @param locations character. Locations to fetch. #' @param ... not used for values, forces later arguments to bind by name -#' @param dates [`timeset`]. Dates to fetch. Mutually exclusive with `epiweeks`. -#' @param epiweeks [`timeset`]. Epiweeks to fetch. Mutually exclusive with -#' `dates`. +#' @param time_type string. The temporal resolution of the data (either "day" or +#' "week", depending on signal). +#' @param time_values [`timeset`]. Dates or epiweeks to fetch. Defaults to all +#' ("*") dates. #' @param fetch_args [`fetch_args`]. Additional arguments to pass to `fetch()`. #' @return [`tibble::tibble`] #' @keywords endpoint @@ -2111,21 +2113,31 @@ pvt_twitter <- function( auth, locations, ..., - dates = NULL, - epiweeks = NULL, + time_type = c("day", "week"), + time_values = "*", fetch_args = fetch_args_list()) { rlang::check_dots_empty() + time_type <- match.arg(time_type) + if (time_type == "day") { + dates <- time_values + epiweeks <- NULL + dates <- get_wildcard_equivalent_dates(dates, "day") + } else { + dates <- NULL + epiweeks <- time_values + epiweeks <- get_wildcard_equivalent_dates(epiweeks, "week") + } + assert_character_param("auth", auth, len = 1) assert_character_param("locations", locations) + assert_character_param("time_type", time_type, len = 1) + assert_timeset_param("time_values", time_values) assert_timeset_param("dates", dates, required = FALSE) assert_timeset_param("epiweeks", epiweeks, required = FALSE) dates <- parse_timeset_input(dates) epiweeks <- parse_timeset_input(epiweeks) - if (!xor(is.null(dates), is.null(epiweeks))) { - stop("exactly one of `dates` and `epiweeks` is required") - } time_field <- if (!is.null(dates)) { create_epidata_field_info("date", "date") } else { @@ -2164,9 +2176,9 @@ pvt_twitter <- function( #' @examples #' \dontrun{ #' pub_wiki( -#' articles = "avian_influenza", -#' time_type = "week", -#' time_values = epirange(201501, 201601) +#' articles = "avian_influenza", +#' time_type = "week", +#' time_values = epirange(201501, 201601) #' ) #' } #' @param articles character. Articles to fetch. diff --git a/man/pub_wiki.Rd b/man/pub_wiki.Rd index 8e294185..278dca58 100644 --- a/man/pub_wiki.Rd +++ b/man/pub_wiki.Rd @@ -48,9 +48,9 @@ Number of page visits for selected English, Influenza-related wikipedia articles \examples{ \dontrun{ pub_wiki( - articles = "avian_influenza", - time_type = "week", - time_values = epirange(201501, 201601) + articles = "avian_influenza", + time_type = "week", + time_values = epirange(201501, 201601) ) } } diff --git a/man/pvt_twitter.Rd b/man/pvt_twitter.Rd index ffee87b2..b6c6e95f 100644 --- a/man/pvt_twitter.Rd +++ b/man/pvt_twitter.Rd @@ -8,8 +8,8 @@ pvt_twitter( auth, locations, ..., - dates = NULL, - epiweeks = NULL, + time_type = c("day", "week"), + time_values = "*", fetch_args = fetch_args_list() ) } @@ -20,10 +20,11 @@ pvt_twitter( \item{...}{not used for values, forces later arguments to bind by name} -\item{dates}{\code{\link{timeset}}. Dates to fetch. Mutually exclusive with \code{epiweeks}.} +\item{time_type}{string. The temporal resolution of the data (either "day" or +"week", depending on signal).} -\item{epiweeks}{\code{\link{timeset}}. Epiweeks to fetch. Mutually exclusive with -\code{dates}.} +\item{time_values}{\code{\link{timeset}}. Dates or epiweeks to fetch. Defaults to all +("*") dates.} \item{fetch_args}{\code{\link{fetch_args}}. Additional arguments to pass to \code{fetch()}.} } @@ -42,7 +43,8 @@ Delphi’s epidemiological data. Sourced from pvt_twitter( auth = Sys.getenv("SECRET_API_AUTH_TWITTER"), locations = "CA", - epiweeks = epirange(201501, 202001) + time_type = "week", + time_values = epirange(201501, 202001) ) } } diff --git a/tests/testthat/test-endpoints.R b/tests/testthat/test-endpoints.R index 7d7c12b4..5a06be09 100644 --- a/tests/testthat/test-endpoints.R +++ b/tests/testthat/test-endpoints.R @@ -137,7 +137,8 @@ test_that("basic_epidata_call", { expect_no_error(pvt_twitter( auth = "yourkey", locations = "CA", - epiweeks = epirange(201501, 202001), + time_type = "week", + time_values = epirange(201501, 202001), fetch_args = fetch_args_list(dry_run = TRUE) ) %>% request_url()) expect_no_error(pub_wiki( @@ -414,7 +415,8 @@ test_that("endpoints fail when given args via dots", { pvt_twitter( auth = "yourkey", locations = "CA", - date_range = epirange(201501, 202001) + time_type = "week", + time_range = epirange(201501, 202001) ), regexp = dots_error ) diff --git a/vignettes/signal-discovery.Rmd b/vignettes/signal-discovery.Rmd index bbea800a..70a081ae 100644 --- a/vignettes/signal-discovery.Rmd +++ b/vignettes/signal-discovery.Rmd @@ -378,7 +378,8 @@ API docs: pvt_twitter( auth = Sys.getenv("SECRET_API_AUTH_TWITTER"), locations = "nat", - epiweeks = epirange(200301, 202105) + time_type = "week", + time_values = epirange(200301, 202105) ) ``` From 5311e0c0d9d6fd065ad447eab8b23961fbb8544c Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Tue, 9 Jan 2024 17:44:54 -0500 Subject: [PATCH 139/189] test wildcard and day/week support --- R/endpoints.R | 6 ++-- tests/testthat/test-endpoints.R | 51 +++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/R/endpoints.R b/R/endpoints.R index f6500e27..0146ca64 100644 --- a/R/endpoints.R +++ b/R/endpoints.R @@ -209,8 +209,10 @@ pub_covid_hosp_facility <- function( cli::cli_warn(coercion_msg, class = "epidatr__epirange_week_coercion") collection_weeks <- reformat_epirange(collection_weeks, to_type = "day") # Single week date. - } else if ((test_integerish(collection_weeks) || test_character(collection_weeks)) && - nchar(collection_weeks) == 6) { + } else if ( + (test_integerish(collection_weeks) || test_character(collection_weeks)) && + nchar(collection_weeks) == 6 + ) { cli::cli_warn(coercion_msg, class = "epidatr__single_week_coercion") collection_weeks <- parse_api_week(collection_weeks) } diff --git a/tests/testthat/test-endpoints.R b/tests/testthat/test-endpoints.R index 5a06be09..39194535 100644 --- a/tests/testthat/test-endpoints.R +++ b/tests/testthat/test-endpoints.R @@ -141,12 +141,25 @@ test_that("basic_epidata_call", { time_values = epirange(201501, 202001), fetch_args = fetch_args_list(dry_run = TRUE) ) %>% request_url()) + expect_no_error(pvt_twitter( + auth = "yourkey", + locations = "CA", + time_type = "day", + time_values = epirange(20150101, 20200101), + fetch_args = fetch_args_list(dry_run = TRUE) + ) %>% request_url()) expect_no_error(pub_wiki( articles = "avian_influenza", time_type = "week", time_values = epirange(201501, 202001), fetch_args = fetch_args_list(dry_run = TRUE) ) %>% request_url()) + expect_no_error(pub_wiki( + articles = "avian_influenza", + time_type = "day", + time_values = epirange(20150101, 20200101), + fetch_args = fetch_args_list(dry_run = TRUE) + ) %>% request_url()) }) test_that("endoints accept wildcard for date parameter", { @@ -324,6 +337,44 @@ test_that("endoints accept wildcard for date parameter", { )) expect_identical(call$params$epiweeks$from, 100001) expect_identical(call$params$epiweeks$to, 300001) + + expect_no_error(call <- pvt_twitter( + auth = "yourkey", + locations = "CA", + time_type = "week", + time_values = "*", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$epiweeks$from, 100001) + expect_identical(call$params$epiweeks$to, 300001) + + expect_no_error(call <- pvt_twitter( + auth = "yourkey", + locations = "CA", + time_type = "day", + time_values = "*", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$dates$from, 10000101) + expect_identical(call$params$dates$to, 30000101) + + expect_no_error(call <- pub_wiki( + articles = "avian_influenza", + time_type = "week", + time_values = "*", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$epiweeks$from, 100001) + expect_identical(call$params$epiweeks$to, 300001) + + expect_no_error(call <- pub_wiki( + articles = "avian_influenza", + time_type = "day", + time_values = "*", + fetch_args = fetch_args_list(dry_run = TRUE) + )) + expect_identical(call$params$dates$from, 10000101) + expect_identical(call$params$dates$to, 30000101) }) test_that("endpoints fail when given args via dots", { From 543951c8691609c8a27da9f4b41c9e09692c5f4d Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Wed, 10 Jan 2024 11:53:46 -0500 Subject: [PATCH 140/189] parse int as double so large values don't get set to NA --- R/model.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/R/model.R b/R/model.R index a14f8960..bb3f0d50 100644 --- a/R/model.R +++ b/R/model.R @@ -156,7 +156,8 @@ parse_value <- function(info, value, disable_date_parsing = FALSE) { } else if (info$type == "bool") { return(as.logical(value)) } else if (info$type == "int") { - return(as.integer(value)) + # Int doesn't have enough capacity to store some weekly `pub_wiki` values. + return(as.double(value)) } else if (info$type == "float") { return(as.double(value)) } else if (info$type == "categorical") { From 0cdd4e99ddf2b447bd63380c1a66c4705ec75a9d Mon Sep 17 00:00:00 2001 From: nmdefries Date: Wed, 10 Jan 2024 16:55:33 +0000 Subject: [PATCH 141/189] docs: document (GHA) --- man/covidcast_epidata.Rd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/man/covidcast_epidata.Rd b/man/covidcast_epidata.Rd index 2ca1d0cf..9fe31718 100644 --- a/man/covidcast_epidata.Rd +++ b/man/covidcast_epidata.Rd @@ -69,7 +69,7 @@ the \code{pub_covidcast()} function. Simply use the \verb{$call} attribute of th #> 4 pa smoothed_~ fb-su~ state day 2021-04-08 NA 2021-04-13 #> 5 pa smoothed_~ fb-su~ state day 2021-04-09 NA 2021-04-14 #> 6 pa smoothed_~ fb-su~ state day 2021-04-10 NA 2021-04-15 -#> # i 7 more variables: lag , missing_value , missing_stderr , -#> # missing_sample_size , value , stderr , sample_size +#> # i 7 more variables: lag , missing_value , missing_stderr , +#> # missing_sample_size , value , stderr , sample_size }\if{html}{\out{
}} } From bac1ea296b418d1630ad186234316f227a3daa2c Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Wed, 10 Jan 2024 13:19:22 -0500 Subject: [PATCH 142/189] warn if rounding changes int value; tests --- R/model.R | 13 ++++++++++++- tests/testthat/test-model.R | 24 ++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/R/model.R b/R/model.R index bb3f0d50..334ce648 100644 --- a/R/model.R +++ b/R/model.R @@ -157,7 +157,18 @@ parse_value <- function(info, value, disable_date_parsing = FALSE) { return(as.logical(value)) } else if (info$type == "int") { # Int doesn't have enough capacity to store some weekly `pub_wiki` values. - return(as.double(value)) + value <- as.double(value) + if (any(value != round(value))) { + cli::cli_warn( + c( + "Values in {info$name} were expected to be integers but contain a decimal component", + "i" = "Decimal components are returned as-is" + ), + class = "epidatr__int_nonzero_decimal_digits" + ) + } + + return(value) } else if (info$type == "float") { return(as.double(value)) } else if (info$type == "categorical") { diff --git a/tests/testthat/test-model.R b/tests/testthat/test-model.R index 9f9b739c..0564b75c 100644 --- a/tests/testthat/test-model.R +++ b/tests/testthat/test-model.R @@ -100,6 +100,30 @@ test_that("parse_data_frame warns when df contains fields not listed in meta", { expect_no_warning(parse_data_frame(epidata_call, mock_df)) }) +test_that("parse_data_frame warns when df contains int values with decimal component", { + epidata_call <- pub_flusurv( + locations = "ca", + epiweeks = 202001, + fetch_args = fetch_args_list(dry_run = TRUE) + ) + # see generate_test_data.R + mock_df <- as.data.frame(readr::read_rds(testthat::test_path("data/flusurv-epiweeks.rds"))) + + # Int fields are returned as double + result <- parse_data_frame(epidata_call, mock_df) + expect_type(result$lag, "double") + + + # Replace int fields with decimal + mock_df$lag <- 4.3 + + # Warning when int values have a decimal component + expect_warning( + parse_data_frame(epidata_call, mock_df), + class = "epidatr__int_nonzero_decimal_digits" + ) +}) + test_that("parse_api_date accepts str and int input", { expect_identical(parse_api_date("20200101"), as.Date("2020-01-01")) expect_identical(parse_api_date(20200101), as.Date("2020-01-01")) From 312f8f110958ada9d8cf2f37be2f6a8db5d4cf0b Mon Sep 17 00:00:00 2001 From: nmdefries Date: Wed, 10 Jan 2024 18:21:27 +0000 Subject: [PATCH 143/189] style: styler (GHA) --- tests/testthat/test-model.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testthat/test-model.R b/tests/testthat/test-model.R index 0564b75c..4888ac90 100644 --- a/tests/testthat/test-model.R +++ b/tests/testthat/test-model.R @@ -113,10 +113,10 @@ test_that("parse_data_frame warns when df contains int values with decimal compo result <- parse_data_frame(epidata_call, mock_df) expect_type(result$lag, "double") - + # Replace int fields with decimal mock_df$lag <- 4.3 - + # Warning when int values have a decimal component expect_warning( parse_data_frame(epidata_call, mock_df), From a25797fccf0382266192fc1f0141c5918470b175 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Wed, 10 Jan 2024 13:35:50 -0500 Subject: [PATCH 144/189] linting --- tests/testthat/test-model.R | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/testthat/test-model.R b/tests/testthat/test-model.R index 4888ac90..c57f8034 100644 --- a/tests/testthat/test-model.R +++ b/tests/testthat/test-model.R @@ -113,7 +113,6 @@ test_that("parse_data_frame warns when df contains int values with decimal compo result <- parse_data_frame(epidata_call, mock_df) expect_type(result$lag, "double") - # Replace int fields with decimal mock_df$lag <- 4.3 From 61e57424ed5e600e04714938d733123a2ed37827 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Thu, 18 Jan 2024 17:39:28 -0500 Subject: [PATCH 145/189] changelog --- NEWS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS.md b/NEWS.md index e41e8fc6..5fda1448 100644 --- a/NEWS.md +++ b/NEWS.md @@ -20,6 +20,7 @@ - `get_api_key` no longer reads from R options and only uses environment variables (#217). - Fix documentation related to CRAN submission. - Fix some errors from passing "" as a key. +- `pvt_twitter` and `pub_wiki` now use `time_type` and `time_values` args instead of mutually exclusive `dates` and `epiweeks` (#236). This matches the interface of the `pub_covidcast` endpoint. # epidatr 1.0.0 From d2778021ea48d8d970e3dcea7c6bc61cc71ee52d Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Thu, 18 Jan 2024 17:40:55 -0500 Subject: [PATCH 146/189] changelog --- NEWS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS.md b/NEWS.md index e41e8fc6..0f0f3d81 100644 --- a/NEWS.md +++ b/NEWS.md @@ -20,6 +20,7 @@ - `get_api_key` no longer reads from R options and only uses environment variables (#217). - Fix documentation related to CRAN submission. - Fix some errors from passing "" as a key. +- All endpoints now support the use of "\*" as a wildcard to fetch all dates or epiweeks (#234). # epidatr 1.0.0 From d8d9f9efc4d76fac20f9ca66e928f99de930e871 Mon Sep 17 00:00:00 2001 From: nmdefries Date: Thu, 18 Jan 2024 22:46:19 +0000 Subject: [PATCH 147/189] docs: document (GHA) --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 3e1fc47e..77db02e0 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -39,7 +39,7 @@ Imports: tibble, usethis, xml2 -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.0 Suggests: dplyr, ggplot2, From 8d93b449d54b17cb5702881824169b00e8be98bc Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Wed, 31 Jan 2024 11:52:31 -0800 Subject: [PATCH 148/189] fix: NAs in int field bug #243 --- NEWS.md | 1 + R/model.R | 2 +- tests/testthat/test-model.R | 11 +++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index fe957aa9..021d9522 100644 --- a/NEWS.md +++ b/NEWS.md @@ -22,6 +22,7 @@ - Fix some errors from passing "" as a key. - `pvt_twitter` and `pub_wiki` now use `time_type` and `time_values` args instead of mutually exclusive `dates` and `epiweeks` (#236). This matches the interface of the `pub_covidcast` endpoint. - All endpoints now support the use of "\*" as a wildcard to fetch all dates or epiweeks (#234). +- Fixed bug with NAs when parsing ints (#243). # epidatr 1.0.0 diff --git a/R/model.R b/R/model.R index 2d25cbfd..e88b8e7a 100644 --- a/R/model.R +++ b/R/model.R @@ -179,7 +179,7 @@ parse_value <- function(info, value, disable_date_parsing = FALSE) { } else if (info$type == "int") { # Int doesn't have enough capacity to store some weekly `pub_wiki` values. value <- as.double(value) - if (any(value != round(value))) { + if (any(na.omit(value != round(value)))) { cli::cli_warn( c( "Values in {info$name} were expected to be integers but contain a decimal component", diff --git a/tests/testthat/test-model.R b/tests/testthat/test-model.R index fef97e36..5444eb5e 100644 --- a/tests/testthat/test-model.R +++ b/tests/testthat/test-model.R @@ -123,6 +123,17 @@ test_that("parse_data_frame warns when df contains int values with decimal compo ) }) +test_that("parse_value can handle NA/NULL values in an int field", { + info <- create_epidata_field_info( + name = "test", + type = "int" + ) + expect_warning( + parse_value(info, c(1, 1.5, NA, NULL)), + class = "epidatr__int_nonzero_decimal_digits" + ) +}) + test_that("parse_api_date accepts str and int input", { expect_identical(parse_api_date("20200101"), as.Date("2020-01-01")) expect_identical(parse_api_date(20200101), as.Date("2020-01-01")) From 539e95857202cfb3053341f65201a176453dc89e Mon Sep 17 00:00:00 2001 From: dshemetov Date: Wed, 31 Jan 2024 19:55:14 +0000 Subject: [PATCH 149/189] docs: document (GHA) --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 77db02e0..ad7a8b5e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -39,7 +39,7 @@ Imports: tibble, usethis, xml2 -RoxygenNote: 7.3.0 +RoxygenNote: 7.3.1 Suggests: dplyr, ggplot2, From 81818dd7e888685018844aa23dff5959cc3c55ba Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Thu, 15 Feb 2024 17:21:59 -0800 Subject: [PATCH 150/189] docs: fix doc page colors, match with epipredict --- _pkgdown.yml | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/_pkgdown.yml b/_pkgdown.yml index 754469d1..f923ad58 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -1,37 +1,29 @@ +# Colors should stay consistent across epipredict & epidatr, using Carnegie +# Red https://www.cmu.edu/brand/brand-guidelines/visual-identity/colors.html template: bootstrap: 5 bootswatch: cosmo bslib: font_scale: 1.0 - primary: '#C41230' - link-color: '#C41230' - navbar-bg: '#C41230' - navbar-fg: '#f8f8f8' - -development: - mode: auto + primary: "#C41230" + link-color: "#C41230" navbar: - bg: '#C41230' - fg: '#f8f8f8' + bg: primary + type: dark home: links: - text: Get the Python client href: https://github.com/cmu-delphi/epidatpy/ - - text: View the Delphi Website href: https://delphi.cmu.edu/ - - text: Introduction to Delphi's Tooling Work href: https://cmu-delphi.github.io/delphi-tooling-book/ - - text: The epiprocess R package href: https://cmu-delphi.github.io/epiprocess/ - - text: The epipredict R package href: https://cmu-delphi.github.io/epipredict/ - - text: The epidatasets R package href: https://cmu-delphi.github.io/epidatasets/ From c3105897b78bc50fff6bcbeb25cfc441ead6db13 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Thu, 15 Feb 2024 17:22:10 -0800 Subject: [PATCH 151/189] repo: update .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 2ecf9b05..5a928afe 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,6 @@ env /Meta/ .secrets epidatr.Rproj +renv.lock +renv/ +.Rprofile \ No newline at end of file From 440efa9bf0c39ab5c35ffacc1ae01bfd3f2f293c Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Thu, 15 Feb 2024 17:22:39 -0800 Subject: [PATCH 152/189] ci: match pkgdown with epiprocess --- .github/workflows/pkgdown.yaml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index e67a789c..6e2d0169 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -41,7 +41,13 @@ jobs: - name: Build site env: DELPHI_EPIDATA_KEY: ${{ secrets.SECRET_EPIDATR_GHACTIONS_DELPHI_EPIDATA_KEY }} - run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) + run: | + if (startsWith("${{ github.event_name }}", "pull_request")) { + mode <- ifelse("${{ github.base_ref }}" == "main", "release", "devel") + } else { + mode <- ifelse("${{ github.ref_name }}" == "main", "release", "devel") + } + pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE, override=list(PKGDOWN_DEV_MODE=mode)) shell: Rscript {0} - name: Deploy to GitHub pages 🚀 From 0039280e19cbf20632b792cff6edb2ae9075aa39 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Fri, 16 Feb 2024 10:17:26 -0800 Subject: [PATCH 153/189] ci: add build README.md to document.yaml --- .github/workflows/document.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/document.yaml b/.github/workflows/document.yaml index fb1ee6b5..0608a2f2 100644 --- a/.github/workflows/document.yaml +++ b/.github/workflows/document.yaml @@ -33,6 +33,9 @@ jobs: run: roxygen2::roxygenise() shell: Rscript {0} + - name: Build README.md from README.Rmd + run: Rscript -e 'devtools::build_readme()' + - name: Commit and push changes run: | git config --local user.name "$GITHUB_ACTOR" From eb3f91c11e8401c8e48dfc3906748e672f045502 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Fri, 16 Feb 2024 11:56:20 -0800 Subject: [PATCH 154/189] repo+doc: follow version conventions from epiprocess --- DESCRIPTION | 2 +- NEWS.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index ad7a8b5e..febe8e4a 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: epidatr Type: Package Title: Client for Delphi's 'Epidata' API -Version: 1.0.0.9000 +Version: 1.0.1 Date: 2023-12-07 Authors@R: c( diff --git a/NEWS.md b/NEWS.md index 021d9522..41c461ec 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -# epidatr 1.0.0.9000 +# epidatr 1.1.0 - Function reference now displays commonly-used functions first (#205). - Endpoints now fail when passed misspelled arguments (#187, #201). From 7ece8677dfc351ca16352872858fa67186625180 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Fri, 16 Feb 2024 12:12:28 -0800 Subject: [PATCH 155/189] doc: update development guide --- DEVELOPMENT.md | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 095c25d7..d5c463ef 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -5,7 +5,6 @@ install.packages(c('devtools', 'pkgdown', 'styler', 'lintr')) # install dev depe devtools::install_deps(dependencies = TRUE) # install package dependencies devtools::document() # generate package meta data and man files devtools::build() # build package - ``` ## Validating the package @@ -20,41 +19,39 @@ devtools::check() # check package for errors ## Developing the documentation site -The [documentation site](https://cmu-delphi.github.io/epidatr/) is built off of the `main` branch. The `dev` version of the site is available at https://cmu-delphi.github.io/epidatr/dev. +Our CI is setup to build the [main documentation site](https://cmu-delphi.github.io/epidatr/) off of the `main` branch, while the [`dev` version of the site](https://cmu-delphi.github.io/epidatr/dev) is built off the `dev` branch. -The documentation site can be previewed locally by running in R +The documentation site can be previewed locally by running in R: ```r +# Should automatically open a browser pkgdown::build_site(preview=TRUE) ``` -The `main` version is available at `file:////epidatr/docs/index.html` and `dev` at `file:////epidatr/docs/dev/index.html`. +If the above does not open a browser, you can try using a Python server from the command line: -You can also build the docs manually and launch the site with python. From the terminal, this looks like ```bash R -e 'devtools::document()' +R -e 'pkgdown::build_site()' python -m http.server -d docs ``` -For `pkgdown` to correctly generate both public (`main`) and `dev` documentation sites, the package version in `DESCRIPTION` on `dev` must have four components, and be of the format `x.x.x.9000`. The package version on `main` must be in the format `x.x.x`. +## Versioning -The documentation website is updated on push or pull request to the `main` and `dev` branches. +Please follow the guidelines in the PR template document (reproduced here): -## Release process +- [ ] Make sure this PR is against "dev", not "main". +- [ ] Request a review from one of the current epiprocess main reviewers: + brookslogan, nmdefries. +- [ ] Makes sure to bump the version number in `DESCRIPTION` and `NEWS.md`. + Always increment the patch version number (the third number), unless you are + making a release PR from dev to main, in which case increment the minor + version number (the second number). +- [ ] Describe changes made in NEWS.md, making sure breaking changes + (backwards-incompatible changes to the documented interface) are noted. + Collect the changes under the next release number (e.g. if you are on + 0.7.2, then write your changes under the 0.8 heading). -### Manual +## Release process TBD - -### Automated (currently unavailable) - -The release consists of multiple steps which can be all done via the GitHub website: - -1. Go to [create_release GitHub Action](https://github.com/cmu-delphi/epidatr/actions/workflows/create_release.yml) and click the `Run workflow` button. Enter the next version number or one of the magic keywords (patch, minor, major) and hit the green `Run workflow` button. -2. The action will prepare a new release and will end up with a new [Pull Request](https://github.com/cmu-delphi/epidatr/pulls) -3. Let the code owner review the PR and its changes and let the CI check whether everything builds successfully -4. Once approved and merged, another GitHub action job starts which automatically will - 1. create a git tag - 2. create another [Pull Request](https://github.com/cmu-delphi/epidatr/pulls) to merge the changes back to the `dev` branch - 3. create a [GitHub release](https://github.com/cmu-delphi/epidatr/releases) with automatically derived release notes -5. Release to CRAN From cfb6578dac6a9d0e3e408718bd40615ee12fd317 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Fri, 16 Feb 2024 12:14:43 -0800 Subject: [PATCH 156/189] ci: add pull request template from epiprocess --- .github/pull_request_template.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..9a0edceb --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,21 @@ +### Checklist + +Please: + +- [ ] Make sure this PR is against "dev", not "main". +- [ ] Request a review from one of the current epiprocess main reviewers: + brookslogan, nmdefries. +- [ ] Makes sure to bump the version number in `DESCRIPTION` and `NEWS.md`. + Always increment the patch version number (the third number), unless you are + making a release PR from dev to main, in which case increment the minor + version number (the second number). +- [ ] Describe changes made in NEWS.md, making sure breaking changes + (backwards-incompatible changes to the documented interface) are noted. + Collect the changes under the next release number (e.g. if you are on + 1.7.2, then write your changes under the 1.8 heading). + +### Change explanations for reviewer + +### Magic GitHub syntax to mark associated Issue(s) as resolved when this is merged into the default branch + +- Resolves #{issue number} From b9f064a83126a04fa9b4a1515fe4c42c99023ea7 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Fri, 16 Feb 2024 10:01:47 -0800 Subject: [PATCH 157/189] doc: update README with epidatr blog post revisions --- README.Rmd | 81 ++++++++++++++++++++++++++++---- README.md | 135 ++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 164 insertions(+), 52 deletions(-) diff --git a/README.Rmd b/README.Rmd index 792ed89f..8829f907 100644 --- a/README.Rmd +++ b/README.Rmd @@ -21,19 +21,82 @@ ggplot2::theme_set(ggplot2::theme_bw()) [![codecov](https://codecov.io/gh/dsweber2/epidatr/branch/dev/graph/badge.svg?token=jVHL9eHZNZ)](https://app.codecov.io/gh/dsweber2/epidatr) -The [Delphi `epidatr` package](https://cmu-delphi.github.io/epidatr/) is an R front-end for the [Delphi Epidata API](https://cmu-delphi.github.io/delphi-epidata/), which provides real-time access to epidemiological surveillance data for influenza, COVID-19, and other diseases. `epidatr` is built and maintained by the Carnegie Mellon University [Delphi research group](https://delphi.cmu.edu/). - -Data is available for the United States and a handful of other countries at various geographical resolutions, both from official government sources such as the [US Center for Disease Control (CDC)](https://www.cdc.gov/datastatistics/index.html), and private partners such as [Facebook](https://delphi.cmu.edu/blog/2020/08/26/covid-19-symptom-surveys-through-facebook/) and [Change Healthcare](https://www.changehealthcare.com/). The API stores a historical record of all data, including corrections and updates, which is particularly useful for accurately backtesting forecasting models. - -`epidatr` is designed to streamline the downloading and usage of data from the Epidata API. The package provides a simple R interface to the API, including functions for downloading data, parsing the results, and converting the data into a tidy format. We also provide the [epiprocess](https://github.com/cmu-delphi/epiprocess) package for downstream data processing and [epipredict](https://github.com/cmu-delphi/epipredict) for modeling. +The [Delphi Epidata API](https://cmu-delphi.github.io/delphi-epidata/) provides +real-time access to epidemiological surveillance data for influenza, COVID-19, +and other diseases from both official government sources such as the [Centers +for Disease Control and Prevention +(CDC)](https://www.cdc.gov/datastatistics/index.html), private partners such as +[Facebook (now +Meta)](https://delphi.cmu.edu/blog/2020/08/26/covid-19-symptom-surveys-through-facebook/) +and [Change Healthcare](https://www.changehealthcare.com/), and other public +datasets like [Google +Trends](https://console.cloud.google.com/marketplace/product/bigquery-public-datasets/covid19-search-trends). +It is built and maintained by the Carnegie Mellon University [Delphi Research +Group](https://delphi.cmu.edu/). + +This package is designed to streamline the downloading and usage of data from +the Delphi Epidata API. It provides a simple R interface to the API, including +functions for downloading data, parsing the results, and converting the data +into a tidy format. The API stores a historical record of all data, including +corrections and updates, which is particularly useful for accurately backtesting +forecasting models. We also provide packages for downstream data processing +([epiprocess](https://github.com/cmu-delphi/epiprocess)) and modeling +([epipredict](https://github.com/cmu-delphi/epipredict)). + +## Usage + +```{r} +library(epidatr) +# Obtain the smoothed covid-like illness (CLI) signal from Delphi's US COVID-19 +# Trends and Impact Survey (CTIS), in partnership with Facebook, as it was on +# April 10, 2021 for the US at the national level +epidata <- pub_covidcast( + source = "fb-survey", + signals = "smoothed_cli", + geo_type = "nation", + time_type = "day", + geo_values = "us", + time_values = epirange(20210101, 20210601), + as_of = 20210601 +) +epidata +``` -Consult the [Epidata API documentation](https://cmu-delphi.github.io/delphi-epidata/) for details on the data included in the API, API key registration, licensing, and how to cite this data in your work. The documentation lists all the data sources and signals available through this API for [COVID-19](https://cmu-delphi.github.io/delphi-epidata/api/covidcast_signals.html) and for [other diseases](https://cmu-delphi.github.io/delphi-epidata/api/README.html#source-specific-parameters). +## Installation -**To get started** using this package, view the Getting Started guide at `vignette("epidatr")`. +Installing the package is straightforward. -## For users of the `covidcast` R package +```R +# Install the CRAN version +pak::pkg_install("epidatr") +# Install the development version from the GitHub dev branch +pak::pkg_install("cmu-delphi/epidatr@dev") +``` -`epidatr` is a complete rewrite of the [`covidcast` package](https://cmu-delphi.github.io/covidcast/covidcastR/), with a focus on speed, reliability, and ease of use. The `covidcast` package is deprecated and will no longer be updated. +### API Keys + +The Delphi API requires a (free) API key for full functionality. To generate +your key, register for a pseudo-anonymous account +[here](https://api.delphi.cmu.edu/epidata/admin/registration_form) and see more +discussion on the [general API +website](https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html). The +`epidatr` client will automatically look for this key in the environment +variable `DELPHI_EPIDATA_KEY`. We recommend storing your key in your `.Renviron` +file, which R will read by default. + +Note that for the time being, the private endpoints (i.e. those prefixed with +`pvt`) will require a separate key that needs to be passed as an argument. + +## For users of the covidcast R package + +The `covidcast` package is deprecated and will no longer be updated. The +`epidatr` package is a complete rewrite of the [`covidcast` +package](https://cmu-delphi.github.io/covidcast/covidcastR/), with a focus on +speed, reliability, and ease of use. It also supports more endpoints and data +sources than `covidcast`. When migrating from that package, you will need to use +the +[`pub_covidcast`](https://cmu-delphi.github.io/epidatr/reference/pub_covidcast.html) +function in `epidatr`. ## Get updates diff --git a/README.md b/README.md index c44270a8..ac2dace0 100644 --- a/README.md +++ b/README.md @@ -12,51 +12,100 @@ Actions](https://github.com/cmu-delphi/epidatr/workflows/ci/badge.svg)](https:// [![codecov](https://codecov.io/gh/dsweber2/epidatr/branch/dev/graph/badge.svg?token=jVHL9eHZNZ)](https://app.codecov.io/gh/dsweber2/epidatr) -The [Delphi `epidatr` package](https://cmu-delphi.github.io/epidatr/) is -an R front-end for the [Delphi Epidata -API](https://cmu-delphi.github.io/delphi-epidata/), which provides -real-time access to epidemiological surveillance data for influenza, -COVID-19, and other diseases. `epidatr` is built and maintained by the -Carnegie Mellon University [Delphi research -group](https://delphi.cmu.edu/). - -Data is available for the United States and a handful of other countries -at various geographical resolutions, both from official government -sources such as the [US Center for Disease Control -(CDC)](https://www.cdc.gov/datastatistics/index.html), and private -partners such as -[Facebook](https://delphi.cmu.edu/blog/2020/08/26/covid-19-symptom-surveys-through-facebook/) -and [Change Healthcare](https://www.changehealthcare.com/). The API -stores a historical record of all data, including corrections and -updates, which is particularly useful for accurately backtesting -forecasting models. - -`epidatr` is designed to streamline the downloading and usage of data -from the Epidata API. The package provides a simple R interface to the +The [Delphi Epidata API](https://cmu-delphi.github.io/delphi-epidata/) +provides real-time access to epidemiological surveillance data for +influenza, COVID-19, and other diseases from both official government +sources such as the [Centers for Disease Control and Prevention +(CDC)](https://www.cdc.gov/datastatistics/index.html), private partners +such as [Facebook (now +Meta)](https://delphi.cmu.edu/blog/2020/08/26/covid-19-symptom-surveys-through-facebook/) +and [Change Healthcare](https://www.changehealthcare.com/), and other +public datasets like [Google +Trends](https://console.cloud.google.com/marketplace/product/bigquery-public-datasets/covid19-search-trends). +It is built and maintained by the Carnegie Mellon University [Delphi +Research Group](https://delphi.cmu.edu/). + +This package is designed to streamline the downloading and usage of data +from the Delphi Epidata API. It provides a simple R interface to the API, including functions for downloading data, parsing the results, and -converting the data into a tidy format. We also provide the -[epiprocess](https://github.com/cmu-delphi/epiprocess) package for -downstream data processing and -[epipredict](https://github.com/cmu-delphi/epipredict) for modeling. - -Consult the [Epidata API -documentation](https://cmu-delphi.github.io/delphi-epidata/) for details -on the data included in the API, API key registration, licensing, and -how to cite this data in your work. The documentation lists all the data -sources and signals available through this API for -[COVID-19](https://cmu-delphi.github.io/delphi-epidata/api/covidcast_signals.html) -and for [other -diseases](https://cmu-delphi.github.io/delphi-epidata/api/README.html#source-specific-parameters). - -**To get started** using this package, view the Getting Started guide at -`vignette("epidatr")`. - -## For users of the `covidcast` R package - -`epidatr` is a complete rewrite of the [`covidcast` +converting the data into a tidy format. The API stores a historical +record of all data, including corrections and updates, which is +particularly useful for accurately backtesting forecasting models. We +also provide packages for downstream data processing +([epiprocess](https://github.com/cmu-delphi/epiprocess)) and modeling +([epipredict](https://github.com/cmu-delphi/epipredict)). + +## Usage + +``` r +library(epidatr) +# Obtain the smoothed covid-like illness (CLI) signal from Delphi's US COVID-19 +# Trends and Impact Survey (CTIS), in partnership with Facebook, as it was on +# April 10, 2021 for the US at the national level +epidata <- pub_covidcast( + source = "fb-survey", + signals = "smoothed_cli", + geo_type = "nation", + time_type = "day", + geo_values = "us", + time_values = epirange(20210101, 20210601), + as_of = 20210601 +) +epidata +#> # A tibble: 151 × 15 +#> geo_value signal source geo_type time_type time_value direction issue +#> +#> 1 us smoothed… fb-su… nation day 2021-01-01 NA 2021-01-06 +#> 2 us smoothed… fb-su… nation day 2021-01-02 NA 2021-01-07 +#> 3 us smoothed… fb-su… nation day 2021-01-03 NA 2021-01-08 +#> 4 us smoothed… fb-su… nation day 2021-01-04 NA 2021-01-09 +#> 5 us smoothed… fb-su… nation day 2021-01-05 NA 2021-01-10 +#> 6 us smoothed… fb-su… nation day 2021-01-06 NA 2021-01-29 +#> 7 us smoothed… fb-su… nation day 2021-01-07 NA 2021-01-29 +#> 8 us smoothed… fb-su… nation day 2021-01-08 NA 2021-01-29 +#> 9 us smoothed… fb-su… nation day 2021-01-09 NA 2021-01-29 +#> 10 us smoothed… fb-su… nation day 2021-01-10 NA 2021-01-29 +#> # ℹ 141 more rows +#> # ℹ 7 more variables: lag , missing_value , missing_stderr , +#> # missing_sample_size , value , stderr , sample_size +``` + +## Installation + +Installing the package is straightforward. + +``` r +# Install the CRAN version +pak::pkg_install("epidatr") +# Install the development version from the GitHub dev branch +pak::pkg_install("cmu-delphi/epidatr@dev") +``` + +### API Keys + +The Delphi API requires a (free) API key for full functionality. To +generate your key, register for a pseudo-anonymous account +[here](https://api.delphi.cmu.edu/epidata/admin/registration_form) and +see more discussion on the [general API +website](https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html). +The `epidatr` client will automatically look for this key in the +environment variable `DELPHI_EPIDATA_KEY`. We recommend storing your key +in your `.Renviron` file, which R will read by default. + +Note that for the time being, the private endpoints (i.e. those prefixed +with `pvt`) will require a separate key that needs to be passed as an +argument. + +## For users of the covidcast R package + +The `covidcast` package is deprecated and will no longer be updated. The +`epidatr` package is a complete rewrite of the [`covidcast` package](https://cmu-delphi.github.io/covidcast/covidcastR/), with a -focus on speed, reliability, and ease of use. The `covidcast` package is -deprecated and will no longer be updated. +focus on speed, reliability, and ease of use. It also supports more +endpoints and data sources than `covidcast`. When migrating from that +package, you will need to use the +[`pub_covidcast`](https://cmu-delphi.github.io/epidatr/reference/pub_covidcast.html) +function in `epidatr`. ## Get updates From 4a73d0eb8bb837f5a6e00a7d58b58e674f8d5436 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Fri, 23 Feb 2024 14:16:22 -0800 Subject: [PATCH 158/189] doc: update DEVELOPMENT.md --- DEVELOPMENT.md | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index d5c463ef..e8223c9c 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -19,7 +19,10 @@ devtools::check() # check package for errors ## Developing the documentation site -Our CI is setup to build the [main documentation site](https://cmu-delphi.github.io/epidatr/) off of the `main` branch, while the [`dev` version of the site](https://cmu-delphi.github.io/epidatr/dev) is built off the `dev` branch. +Our CI builds two version of the documentation: + +- https://cmu-delphi.github.io/epidatr/ from the `main` branch and +- https://cmu-delphi.github.io/epidatr/dev from the `dev` branch. The documentation site can be previewed locally by running in R: @@ -28,7 +31,8 @@ The documentation site can be previewed locally by running in R: pkgdown::build_site(preview=TRUE) ``` -If the above does not open a browser, you can try using a Python server from the command line: +If the above does not open a browser, you can try using a Python server from the +command line: ```bash R -e 'devtools::document()' @@ -38,19 +42,7 @@ python -m http.server -d docs ## Versioning -Please follow the guidelines in the PR template document (reproduced here): - -- [ ] Make sure this PR is against "dev", not "main". -- [ ] Request a review from one of the current epiprocess main reviewers: - brookslogan, nmdefries. -- [ ] Makes sure to bump the version number in `DESCRIPTION` and `NEWS.md`. - Always increment the patch version number (the third number), unless you are - making a release PR from dev to main, in which case increment the minor - version number (the second number). -- [ ] Describe changes made in NEWS.md, making sure breaking changes - (backwards-incompatible changes to the documented interface) are noted. - Collect the changes under the next release number (e.g. if you are on - 0.7.2, then write your changes under the 0.8 heading). +Please follow the guidelines in the [PR template document](.github/pull_request_template.md). ## Release process From 75a6ec819f30f22681fb997ddcfd3b4be19b8d89 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Fri, 16 Feb 2024 09:49:50 -0800 Subject: [PATCH 159/189] feat: make set_cache more verbose --- R/cache.R | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/R/cache.R b/R/cache.R index cd94c92b..51337abc 100644 --- a/R/cache.R +++ b/R/cache.R @@ -154,7 +154,6 @@ set_cache <- function(cache_dir = NULL, } } - if (!cache_usable) { print(glue::glue( "The directory at {cache_dir} is not accessible; check permissions and/or use a different ", @@ -168,6 +167,13 @@ set_cache <- function(cache_dir = NULL, logfile = file.path(cache_dir, logfile) ) } + + cli::cli_inform(c( + "!" = "epidatr cache is being used (set env var EPIDATR_USE_CACHE=FALSE if not intended).", + "i" = "The cache directory is {cache_dir}.", + "i" = "The cache will be cleared after {days} days and will be pruned if it exceeds {max_size} MB.", + "i" = "The log of cache transactions is stored at {file.path(cache_dir, logfile)}." + )) } #' Manually reset the cache, deleting all currently saved data and starting afresh From 78e97ed4695731aa34fbe7858a57253489f3b6a3 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Sat, 24 Feb 2024 09:59:31 -0800 Subject: [PATCH 160/189] refactor+doc: update default timeout_seconds to 15 minutes. Also remove some timeout_seconds-related defaults from a few internal request functions, since they almost always receive a default value from upstream, to reduce the number of places the default value is hardcoded. Fix all calls to those functions to include arguments. --- .github/pull_request_template.md | 11 ++++++----- DESCRIPTION | 2 +- NEWS.md | 1 + R/epidatacall.R | 10 +++++----- R/request.R | 2 +- man/do_request.Rd | 2 +- man/fetch_args_list.Rd | 2 +- man/request_impl.Rd | 2 +- tests/testthat/generate_test_data.R | 6 ++++-- tests/testthat/test-epidatacall.R | 14 +++++++++++--- tests/testthat/test-request.R | 2 +- 11 files changed, 33 insertions(+), 21 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 9a0edceb..14a572e7 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -2,13 +2,14 @@ Please: -- [ ] Make sure this PR is against "dev", not "main". +- [ ] Make sure this PR is against "dev", not "main" (unless this is a release + PR). - [ ] Request a review from one of the current epiprocess main reviewers: brookslogan, nmdefries. -- [ ] Makes sure to bump the version number in `DESCRIPTION` and `NEWS.md`. - Always increment the patch version number (the third number), unless you are - making a release PR from dev to main, in which case increment the minor - version number (the second number). +- [ ] Makes sure to bump the version number in `DESCRIPTION`. Always increment + the patch version number (the third number), unless you are making a + release PR from dev to main, in which case increment the minor version + number (the second number). - [ ] Describe changes made in NEWS.md, making sure breaking changes (backwards-incompatible changes to the documented interface) are noted. Collect the changes under the next release number (e.g. if you are on diff --git a/DESCRIPTION b/DESCRIPTION index febe8e4a..61d97ec7 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: epidatr Type: Package Title: Client for Delphi's 'Epidata' API -Version: 1.0.1 +Version: 1.0.2 Date: 2023-12-07 Authors@R: c( diff --git a/NEWS.md b/NEWS.md index 41c461ec..41ef133d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -23,6 +23,7 @@ - `pvt_twitter` and `pub_wiki` now use `time_type` and `time_values` args instead of mutually exclusive `dates` and `epiweeks` (#236). This matches the interface of the `pub_covidcast` endpoint. - All endpoints now support the use of "\*" as a wildcard to fetch all dates or epiweeks (#234). - Fixed bug with NAs when parsing ints (#243). +- Updated the default `timeout_seconds` to 15 minutes to allow large queries by default. # epidatr 1.0.0 diff --git a/R/epidatacall.R b/R/epidatacall.R index cde20c9b..958e00aa 100644 --- a/R/epidatacall.R +++ b/R/epidatacall.R @@ -89,7 +89,7 @@ create_epidata_call <- function(endpoint, params, meta = NULL, } #' @importFrom checkmate test_class test_list -request_arguments <- function(epidata_call, format_type, fields = NULL) { +request_arguments <- function(epidata_call, format_type, fields) { stopifnot(inherits(epidata_call, "epidata_call")) stopifnot(format_type %in% c("json", "csv", "classic")) stopifnot(is.null(fields) || is.character(fields)) @@ -164,7 +164,7 @@ fetch_args_list <- function( disable_date_parsing = FALSE, disable_data_frame_parsing = FALSE, return_empty = FALSE, - timeout_seconds = 30, + timeout_seconds = 15 * 60, base_url = NULL, dry_run = FALSE, debug = FALSE, @@ -288,7 +288,7 @@ fetch_classic <- function(epidata_call, fetch_args = fetch_args_list()) { stopifnot(inherits(epidata_call, "epidata_call")) stopifnot(inherits(fetch_args, "fetch_args")) - response_content <- request_impl(epidata_call, "classic", fetch_args$fields, fetch_args$timeout_seconds) %>% + response_content <- request_impl(epidata_call, "classic", fetch_args$timeout_seconds, fetch_args$fields) %>% httr::content(as = "text", encoding = "UTF-8") %>% jsonlite::fromJSON(simplifyDataFrame = !fetch_args$disable_data_frame_parsing) @@ -318,7 +318,7 @@ fetch_debug <- function(epidata_call, fetch_args = fetch_args_list()) { stopifnot(inherits(epidata_call, "epidata_call")) stopifnot(inherits(fetch_args, "fetch_args")) - response <- request_impl(epidata_call, fetch_args$format_type, fetch_args$fields, fetch_args$timeout_seconds) + response <- request_impl(epidata_call, fetch_args$format_type, fetch_args$timeout_seconds, fetch_args$fields) content <- httr::content(response, "text", encoding = "UTF-8") content } @@ -366,7 +366,7 @@ with_base_url <- function(epidata_call, base_url) { #' @importFrom httr stop_for_status content http_type #' @importFrom xml2 read_html xml_find_all xml_text #' @keywords internal -request_impl <- function(epidata_call, format_type, fields = NULL, timeout_seconds = 30) { +request_impl <- function(epidata_call, format_type, timeout_seconds, fields) { stopifnot(inherits(epidata_call, "epidata_call")) stopifnot(format_type %in% c("json", "csv", "classic")) diff --git a/R/request.R b/R/request.R index 1e3be1b4..603e7bd3 100644 --- a/R/request.R +++ b/R/request.R @@ -22,7 +22,7 @@ join_url <- function(url, endpoint) { #' #' @importFrom httr RETRY #' @keywords internal -do_request <- function(url, params, timeout_seconds = 30) { +do_request <- function(url, params, timeout_seconds) { # don't retry in case of certain status codes key <- get_api_key() if (key != "") { diff --git a/man/do_request.Rd b/man/do_request.Rd index 7add7b85..e5cd7995 100644 --- a/man/do_request.Rd +++ b/man/do_request.Rd @@ -4,7 +4,7 @@ \alias{do_request} \title{performs the request} \usage{ -do_request(url, params, timeout_seconds = 30) +do_request(url, params, timeout_seconds) } \description{ You can test the authentication headers like so: diff --git a/man/fetch_args_list.Rd b/man/fetch_args_list.Rd index 9f7a2be4..ca6f7dcf 100644 --- a/man/fetch_args_list.Rd +++ b/man/fetch_args_list.Rd @@ -11,7 +11,7 @@ fetch_args_list( disable_date_parsing = FALSE, disable_data_frame_parsing = FALSE, return_empty = FALSE, - timeout_seconds = 30, + timeout_seconds = 15 * 60, base_url = NULL, dry_run = FALSE, debug = FALSE, diff --git a/man/request_impl.Rd b/man/request_impl.Rd index 476c7ee2..d6ad7669 100644 --- a/man/request_impl.Rd +++ b/man/request_impl.Rd @@ -5,7 +5,7 @@ \title{Makes a request to the API and returns the response, catching HTTP errors and forwarding the HTTP body in R errors} \usage{ -request_impl(epidata_call, format_type, fields = NULL, timeout_seconds = 30) +request_impl(epidata_call, format_type, timeout_seconds, fields) } \description{ Makes a request to the API and returns the response, catching diff --git a/tests/testthat/generate_test_data.R b/tests/testthat/generate_test_data.R index 1aac8393..834de416 100644 --- a/tests/testthat/generate_test_data.R +++ b/tests/testthat/generate_test_data.R @@ -4,7 +4,8 @@ epidata_call %>% url <- full_url(epidata_call) params <- request_arguments(epidata_call, "csv", NULL) -result <- do_request(url, params) %>% readr::write_rds(testthat::test_path("data/test-http401.rds")) +result <- do_request(url, params, timeout_seconds = 10 * 60) %>% + readr::write_rds(testthat::test_path("data/test-http401.rds")) epidata_call <- pvt_afhsb( auth = Sys.getenv("SECRET_API_AUTH_AFHSB"), @@ -14,7 +15,8 @@ epidata_call <- pvt_afhsb( ) url <- full_url(epidata_call) params <- request_arguments(epidata_call, "csv", NULL) -response <- do_request(url, params) %>% readr::write_rds(testthat::test_path("data/test-http500.rds")) +response <- do_request(url, params, timeout_seconds = 10 * 60) %>% + readr::write_rds(testthat::test_path("data/test-http500.rds")) epidata_call %>% fetch_debug(format_type = "classic") %>% diff --git a/tests/testthat/test-epidatacall.R b/tests/testthat/test-epidatacall.R index 642c609d..028ba1f4 100644 --- a/tests/testthat/test-epidatacall.R +++ b/tests/testthat/test-epidatacall.R @@ -10,7 +10,11 @@ test_that("request_impl http errors", { # see generate_test_data.R do_request = function(...) readRDS(testthat::test_path("data/test-http401.rds")), ) - expect_error(response <- epidata_call %>% request_impl("csv"), class = "http_401") + expect_error( + response <- epidata_call %>% + request_impl("csv", timeout_seconds = 30, fields = NULL), + class = "http_401" + ) # should give a 500 error (the afhsb endpoint is removed) @@ -18,7 +22,11 @@ test_that("request_impl http errors", { local_mocked_bindings( do_request = function(...) readRDS(testthat::test_path("data/test-http500.rds")) ) - expect_error(response <- epidata_call %>% request_impl("csv"), class = "http_500") + expect_error( + response <- epidata_call %>% + request_impl("csv", timeout_seconds = 30, fields = NULL), + class = "http_500" + ) }) test_that("fetch_args", { @@ -30,7 +38,7 @@ test_that("fetch_args", { disable_date_parsing = FALSE, disable_data_frame_parsing = FALSE, return_empty = FALSE, - timeout_seconds = 30, + timeout_seconds = 15 * 60, base_url = NULL, dry_run = FALSE, debug = FALSE, diff --git a/tests/testthat/test-request.R b/tests/testthat/test-request.R index da09f858..6a3d6536 100644 --- a/tests/testthat/test-request.R +++ b/tests/testthat/test-request.R @@ -1,4 +1,4 @@ test_that("requesting works", { - res <- do_request("https://httpbin.org/status/414", list()) + res <- do_request("https://httpbin.org/status/414", list(), timeout_seconds = 10 * 60) expect_equal(res$status_code, 414) }) From 1917e27c6d567967fac21892c193ae0c2acfa0ff Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Sat, 24 Feb 2024 10:05:53 -0800 Subject: [PATCH 161/189] ci: fix missing devtools dependency --- .github/workflows/document.yaml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/document.yaml b/.github/workflows/document.yaml index 0608a2f2..9926fff3 100644 --- a/.github/workflows/document.yaml +++ b/.github/workflows/document.yaml @@ -26,8 +26,12 @@ jobs: - name: Install dependencies uses: r-lib/actions/setup-r-dependencies@v2 with: - extra-packages: any::roxygen2 - needs: roxygen2 + extra-packages: | + any::devtools + any::roxygen2 + needs: | + devtools + roxygen2 - name: Document run: roxygen2::roxygenise() From 4ef7429cb8c3692ffb7c08bb7a2e9a07596d9c61 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Thu, 15 Feb 2024 17:37:40 -0800 Subject: [PATCH 162/189] feat: make default cache directory R version portable with rappdirs::user_cache_dir() --- DESCRIPTION | 1 + R/cache.R | 10 +++++----- man/clear_cache.Rd | 6 +++--- man/set_cache.Rd | 6 +++--- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 61d97ec7..6d678434 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -35,6 +35,7 @@ Imports: MMWRweek, purrr, openssl, + rappdirs, readr, tibble, usethis, diff --git a/R/cache.R b/R/cache.R index 51337abc..75c9473f 100644 --- a/R/cache.R +++ b/R/cache.R @@ -76,9 +76,9 @@ cache_environ$epidatr_cache <- NULL #' ) #' #' @param cache_dir the directory in which the cache is stored. By default, this -#' is `tools::R_user_dir()` if on R 4.0+, but must be specified for earlier -#' versions of R. The path can be either relative or absolute. The -#' environmental variable is `EPIDATR_CACHE_DIR`. +#' is `rappdirs::user_cache_dir("R", version = "epidatr")`. The path can be +#' either relative or absolute. The environmental variable is +#' `EPIDATR_CACHE_DIR`. #' @param days the maximum length of time in days to keep any particular cached #' call. By default this is `1`. The environmental variable is #' `EPIDATR_CACHE_MAX_AGE_DAYS`. @@ -103,8 +103,8 @@ set_cache <- function(cache_dir = NULL, max_size = NULL, logfile = NULL, confirm = TRUE) { - if (is.null(cache_dir) && sessionInfo()$R.version$major >= 4) { - cache_dir <- Sys.getenv("EPIDATR_CACHE_DIR", unset = tools::R_user_dir("epidatr")) + if (is.null(cache_dir)) { + cache_dir <- Sys.getenv("EPIDATR_CACHE_DIR", unset = rappdirs::user_cache_dir("R", version = "epidatr")) } else if (is.null(cache_dir)) { # earlier version, so no tools cache_dir <- Sys.getenv("EPIDATR_CACHE_DIR") diff --git a/man/clear_cache.Rd b/man/clear_cache.Rd index f53148ad..e84740f8 100644 --- a/man/clear_cache.Rd +++ b/man/clear_cache.Rd @@ -11,9 +11,9 @@ clear_cache(..., disable = FALSE) Arguments passed on to \code{\link[=set_cache]{set_cache}} \describe{ \item{\code{cache_dir}}{the directory in which the cache is stored. By default, this -is \code{tools::R_user_dir()} if on R 4.0+, but must be specified for earlier -versions of R. The path can be either relative or absolute. The -environmental variable is \code{EPIDATR_CACHE_DIR}.} +is \code{rappdirs::user_cache_dir("R", version = "epidatr")}. The path can be +either relative or absolute. The environmental variable is +\code{EPIDATR_CACHE_DIR}.} \item{\code{days}}{the maximum length of time in days to keep any particular cached call. By default this is \code{1}. The environmental variable is \code{EPIDATR_CACHE_MAX_AGE_DAYS}.} diff --git a/man/set_cache.Rd b/man/set_cache.Rd index a3b42a1e..72bc0847 100644 --- a/man/set_cache.Rd +++ b/man/set_cache.Rd @@ -14,9 +14,9 @@ set_cache( } \arguments{ \item{cache_dir}{the directory in which the cache is stored. By default, this -is \code{tools::R_user_dir()} if on R 4.0+, but must be specified for earlier -versions of R. The path can be either relative or absolute. The -environmental variable is \code{EPIDATR_CACHE_DIR}.} +is \code{rappdirs::user_cache_dir("R", version = "epidatr")}. The path can be +either relative or absolute. The environmental variable is +\code{EPIDATR_CACHE_DIR}.} \item{days}{the maximum length of time in days to keep any particular cached call. By default this is \code{1}. The environmental variable is From 6e7f0cd9a551ee6aac7d95cf83de3391e1bc337e Mon Sep 17 00:00:00 2001 From: dsweber2 Date: Mon, 26 Feb 2024 11:54:10 -0800 Subject: [PATCH 163/189] 1 days -> 1 day --- R/cache.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/R/cache.R b/R/cache.R index 75c9473f..8acf0475 100644 --- a/R/cache.R +++ b/R/cache.R @@ -168,10 +168,11 @@ set_cache <- function(cache_dir = NULL, ) } + rlang::inform(cli::format_inline(msg), class = "packageStartupMessage") cli::cli_inform(c( "!" = "epidatr cache is being used (set env var EPIDATR_USE_CACHE=FALSE if not intended).", "i" = "The cache directory is {cache_dir}.", - "i" = "The cache will be cleared after {days} days and will be pruned if it exceeds {max_size} MB.", + "i" = "The cache will be cleared after {days} day{ifelse(days>1,'s','')} and will be pruned if it exceeds {max_size} MB.", "i" = "The log of cache transactions is stored at {file.path(cache_dir, logfile)}." )) } From 22114398ece9a522436ef99e335b94125923c347 Mon Sep 17 00:00:00 2001 From: dsweber2 Date: Mon, 26 Feb 2024 13:09:14 -0800 Subject: [PATCH 164/189] make check happy --- DESCRIPTION | 2 +- DEVELOPMENT.md | 17 ++++++++++++++++- NAMESPACE | 1 + R/cache.R | 12 ++++++------ R/model.R | 1 + R/utils.R | 6 ++++++ man/release_bullets.Rd | 12 ++++++++++++ 7 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 man/release_bullets.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 6d678434..a995fa46 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: epidatr Type: Package Title: Client for Delphi's 'Epidata' API -Version: 1.0.2 +Version: 1.1.0 Date: 2023-12-07 Authors@R: c( diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index e8223c9c..b3205386 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -45,5 +45,20 @@ python -m http.server -d docs Please follow the guidelines in the [PR template document](.github/pull_request_template.md). ## Release process +First, there's a handy function that makes a github issue; for example, at the time of writing we were doing: +```R +usethis::use_release_issue(version = "1.0.2") +``` +If you want to extend it, add to the `release_bullets` function in [utils.R](https://github.com/cmu-delphi/epidatr/blob/dev/R/utils.R). + First, make sure that all the checks pass + +```R +devtools::check(".", manual = TRUE, env_vars =c(NOT_CRAN = "false")) +``` -TBD +Aim for 10/10, no notes. + +When this has gone smoothly enough, release to CRAN via +```R +devtools::release(check = TRUE) +``` diff --git a/NAMESPACE b/NAMESPACE index d0907cfd..c6fed522 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -81,6 +81,7 @@ importFrom(openssl,md5) importFrom(purrr,map_chr) importFrom(purrr,map_lgl) importFrom(readr,read_csv) +importFrom(stats,na.omit) importFrom(tibble,as_tibble) importFrom(tibble,tibble) importFrom(utils,help.search) diff --git a/R/cache.R b/R/cache.R index 8acf0475..189ddcec 100644 --- a/R/cache.R +++ b/R/cache.R @@ -168,13 +168,13 @@ set_cache <- function(cache_dir = NULL, ) } + # this is effectively a startup message, and for some reason, cli_inform doesn't support start suppression, so we're on our own + # https://github.com/r-lib/cli/issues/589 when this closes we can go back. + msg <-"{cli::symbol$warn} epidatr cache is being used (set env var EPIDATR_USE_CACHE=FALSE if not intended). + {cli::symbol$info} The cache directory is {cache_dir}. + {cli::symbol$info} The cache will be cleared after {days} day{ifelse(days>1,'s','')} and will be pruned if it exceeds {max_size} MB. + {cli::symbol$info} The log of cache transactions is stored at {file.path(cache_dir, logfile)}." rlang::inform(cli::format_inline(msg), class = "packageStartupMessage") - cli::cli_inform(c( - "!" = "epidatr cache is being used (set env var EPIDATR_USE_CACHE=FALSE if not intended).", - "i" = "The cache directory is {cache_dir}.", - "i" = "The cache will be cleared after {days} day{ifelse(days>1,'s','')} and will be pruned if it exceeds {max_size} MB.", - "i" = "The log of cache transactions is stored at {file.path(cache_dir, logfile)}." - )) } #' Manually reset the cache, deleting all currently saved data and starting afresh diff --git a/R/model.R b/R/model.R index e88b8e7a..90bddd51 100644 --- a/R/model.R +++ b/R/model.R @@ -165,6 +165,7 @@ print.EpidataFieldInfo <- function(x, ...) { cli::cli_dl(x[attr(x, "names")]) } +#' @importFrom stats na.omit parse_value <- function(info, value, disable_date_parsing = FALSE) { stopifnot(inherits(info, "EpidataFieldInfo")) diff --git a/R/utils.R b/R/utils.R index 705ff368..5fbe5cbb 100644 --- a/R/utils.R +++ b/R/utils.R @@ -61,3 +61,9 @@ get_wildcard_equivalent_dates <- function(time_value, time_type = c("day", "week } return(time_value) } + +#' inserts each string as a bullet at the end of the "Prepare for release" section +#' @keywords internal +release_bullets <- function() { + c("merge to main") +} diff --git a/man/release_bullets.Rd b/man/release_bullets.Rd new file mode 100644 index 00000000..64e1341b --- /dev/null +++ b/man/release_bullets.Rd @@ -0,0 +1,12 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{release_bullets} +\alias{release_bullets} +\title{inserts each string as a bullet at the end of the "Prepare for release" section} +\usage{ +release_bullets() +} +\description{ +inserts each string as a bullet at the end of the "Prepare for release" section +} +\keyword{internal} From d53a6f73a65935ef6cf6a58ed829ae9af0796606 Mon Sep 17 00:00:00 2001 From: dsweber2 Date: Mon, 26 Feb 2024 13:19:18 -0800 Subject: [PATCH 165/189] epiprocess-> epidatr --- .github/pull_request_template.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 14a572e7..ee44a838 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -4,8 +4,8 @@ Please: - [ ] Make sure this PR is against "dev", not "main" (unless this is a release PR). -- [ ] Request a review from one of the current epiprocess main reviewers: - brookslogan, nmdefries. +- [ ] Request a review from one of the current epidatr main reviewers: + brookslogan, dshemetov, nmdefries, dsweber2. - [ ] Makes sure to bump the version number in `DESCRIPTION`. Always increment the patch version number (the third number), unless you are making a release PR from dev to main, in which case increment the minor version From 7d0eddd9286663405625651d335c68a257e529f2 Mon Sep 17 00:00:00 2001 From: dsweber2 Date: Mon, 26 Feb 2024 21:21:21 +0000 Subject: [PATCH 166/189] style: styler (GHA) --- R/cache.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/cache.R b/R/cache.R index 189ddcec..61238001 100644 --- a/R/cache.R +++ b/R/cache.R @@ -170,7 +170,7 @@ set_cache <- function(cache_dir = NULL, # this is effectively a startup message, and for some reason, cli_inform doesn't support start suppression, so we're on our own # https://github.com/r-lib/cli/issues/589 when this closes we can go back. - msg <-"{cli::symbol$warn} epidatr cache is being used (set env var EPIDATR_USE_CACHE=FALSE if not intended). + msg <- "{cli::symbol$warn} epidatr cache is being used (set env var EPIDATR_USE_CACHE=FALSE if not intended). {cli::symbol$info} The cache directory is {cache_dir}. {cli::symbol$info} The cache will be cleared after {days} day{ifelse(days>1,'s','')} and will be pruned if it exceeds {max_size} MB. {cli::symbol$info} The log of cache transactions is stored at {file.path(cache_dir, logfile)}." From 07a297e39f35ab6ee7c18984ba6cfb5769c84596 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Mon, 26 Feb 2024 14:48:31 -0800 Subject: [PATCH 167/189] fix: make cli_inform suppressible in a simpler way --- R/cache.R | 16 ++++++++++------ R/epidatr-package.R | 2 +- man/clear_cache.Rd | 2 ++ man/set_cache.Rd | 6 +++++- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/R/cache.R b/R/cache.R index 61238001..2120bd44 100644 --- a/R/cache.R +++ b/R/cache.R @@ -90,6 +90,8 @@ cache_environ$epidatr_cache <- NULL #' variable is `EPIDATR_CACHE_LOGFILE`. #' @param confirm whether to confirm directory creation. default is `TRUE`; #' should only be set in non-interactive scripts +#' @param startup indicates whether the function is being called on +#' startup. Affects suppressability of the messages. Default is `FALSE`. #' @return [`NULL`] no return value, all effects are stored in the package #' environment #' @seealso [`clear_cache`] to delete the old cache while making a new one, @@ -102,7 +104,8 @@ set_cache <- function(cache_dir = NULL, days = NULL, max_size = NULL, logfile = NULL, - confirm = TRUE) { + confirm = TRUE, + startup = FALSE) { if (is.null(cache_dir)) { cache_dir <- Sys.getenv("EPIDATR_CACHE_DIR", unset = rappdirs::user_cache_dir("R", version = "epidatr")) } else if (is.null(cache_dir)) { @@ -170,11 +173,12 @@ set_cache <- function(cache_dir = NULL, # this is effectively a startup message, and for some reason, cli_inform doesn't support start suppression, so we're on our own # https://github.com/r-lib/cli/issues/589 when this closes we can go back. - msg <- "{cli::symbol$warn} epidatr cache is being used (set env var EPIDATR_USE_CACHE=FALSE if not intended). - {cli::symbol$info} The cache directory is {cache_dir}. - {cli::symbol$info} The cache will be cleared after {days} day{ifelse(days>1,'s','')} and will be pruned if it exceeds {max_size} MB. - {cli::symbol$info} The log of cache transactions is stored at {file.path(cache_dir, logfile)}." - rlang::inform(cli::format_inline(msg), class = "packageStartupMessage") + cli::cli_inform(c( + "!" = "epidatr cache is being used (set env var EPIDATR_USE_CACHE=FALSE if not intended).", + "i" = "The cache directory is {cache_dir}.", + "i" = "The cache will be cleared after {days} day{ifelse(days>1,'s','')} and will be pruned if it exceeds {max_size} MB.", + "i" = "The log of cache transactions is stored at {file.path(cache_dir, logfile)}." + ), class = if (startup) "packageStartupMessage" else NULL) } #' Manually reset the cache, deleting all currently saved data and starting afresh diff --git a/R/epidatr-package.R b/R/epidatr-package.R index ad1ed5da..1b22c9e4 100644 --- a/R/epidatr-package.R +++ b/R/epidatr-package.R @@ -11,6 +11,6 @@ cache_environ$use_cache <- Sys.getenv("EPIDATR_USE_CACHE", unset = FALSE) cache_environ$use_cache <- (cache_environ$use_cache == "TRUE") if (cache_environ$use_cache) { - set_cache() + set_cache(startup = TRUE) } } diff --git a/man/clear_cache.Rd b/man/clear_cache.Rd index e84740f8..f5d232b9 100644 --- a/man/clear_cache.Rd +++ b/man/clear_cache.Rd @@ -25,6 +25,8 @@ cache directory. By default, it is \code{"logfile.txt"}. The environmental variable is \code{EPIDATR_CACHE_LOGFILE}.} \item{\code{confirm}}{whether to confirm directory creation. default is \code{TRUE}; should only be set in non-interactive scripts} + \item{\code{startup}}{indicates whether the function is being called on +startup. Affects suppressability of the messages. Default is \code{FALSE}.} }} \item{disable}{instead of setting a new cache, disable caching entirely; diff --git a/man/set_cache.Rd b/man/set_cache.Rd index 72bc0847..6787edf0 100644 --- a/man/set_cache.Rd +++ b/man/set_cache.Rd @@ -9,7 +9,8 @@ set_cache( days = NULL, max_size = NULL, logfile = NULL, - confirm = TRUE + confirm = TRUE, + startup = FALSE ) } \arguments{ @@ -32,6 +33,9 @@ variable is \code{EPIDATR_CACHE_LOGFILE}.} \item{confirm}{whether to confirm directory creation. default is \code{TRUE}; should only be set in non-interactive scripts} + +\item{startup}{indicates whether the function is being called on +startup. Affects suppressability of the messages. Default is \code{FALSE}.} } \value{ \code{\link{NULL}} no return value, all effects are stored in the package From 95211e1b2ffa672bfee635958b24eb56bea28d43 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Mon, 26 Feb 2024 14:56:36 -0800 Subject: [PATCH 168/189] style: long lines --- R/cache.R | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/R/cache.R b/R/cache.R index 2120bd44..bc30b48f 100644 --- a/R/cache.R +++ b/R/cache.R @@ -171,12 +171,11 @@ set_cache <- function(cache_dir = NULL, ) } - # this is effectively a startup message, and for some reason, cli_inform doesn't support start suppression, so we're on our own - # https://github.com/r-lib/cli/issues/589 when this closes we can go back. cli::cli_inform(c( "!" = "epidatr cache is being used (set env var EPIDATR_USE_CACHE=FALSE if not intended).", "i" = "The cache directory is {cache_dir}.", - "i" = "The cache will be cleared after {days} day{ifelse(days>1,'s','')} and will be pruned if it exceeds {max_size} MB.", + "i" = "The cache will be cleared after {days} day{ifelse(days>1,'s','')} + and will be pruned if it exceeds {max_size} MB.", "i" = "The log of cache transactions is stored at {file.path(cache_dir, logfile)}." ), class = if (startup) "packageStartupMessage" else NULL) } From cc7a4a39dedbc15a4321f410e0e5232ea583a210 Mon Sep 17 00:00:00 2001 From: dsweber2 Date: Mon, 26 Feb 2024 21:48:40 -0800 Subject: [PATCH 169/189] news structure --- NEWS.md | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/NEWS.md b/NEWS.md index 41ef133d..10626ad3 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,29 +1,32 @@ # epidatr 1.1.0 +## Changes +- `pub_covid_hosp_state_timeseries` now supports use of the `as_of` parameter (#209). +- `release_date` and `latest_update` fields are now parsed as `Date`, rather + than as text. This change impacts several endpoints. +- `get_auth_key` renamed to `get_api_key` (#181). +- `get_api_key` no longer reads from R options and only uses environment variables (#217). +- `pvt_twitter` and `pub_wiki` now use `time_type` and `time_values` args instead of mutually exclusive `dates` and `epiweeks` (#236). This matches the interface of the `pub_covidcast` endpoint. +- Updated the default `timeout_seconds` to 15 minutes to allow large queries by default. +## Features - Function reference now displays commonly-used functions first (#205). +- Support `Date` objects passed to version arguments `as_of` and `issues` in + endpoints (#192, #194). +- `clear_cache` now handles positional arguments just like `set_cache` (#197). +- `set_api_key` now available to help persist API key environment variables (#181, #217). +- All endpoints now support the use of "\*" as a wildcard to fetch all dates or epiweeks (#234). +## Patches - Endpoints now fail when passed misspelled arguments (#187, #201). - `pub_fluview_meta` fixed to `fetch` the response automatically. -- `pub_covid_hosp_state_timeseries` now supports use of the `as_of` parameter (#209). - `pub_covid_hosp_state_timeseries` now correctly parses the `issue` field, instead of returning a missing value (#202). -- `release_date` and `latest_update` fields are now parsed as `Date`, rather - than as text. This change impacts several endpoints.. - In `pub_fluview_meta`, `latest_issue` field is now parsed as epiweek, rather than being parsed as `Date` and returning a missing value. -- Support `Date` objects passed to version arguments `as_of` and `issues` in - endpoints (#192, #194). - `set_cache` cache size no longer runs into integer overflow (#189). -- `clear_cache` now handles positional arguments just like `set_cache` (#197). - Improve line-wrapping of warning messages (#191). -- `set_api_key` now available to help persist API key environment variables (#181, #217). -- `get_auth_key` renamed to `get_api_key` (#181). -- `get_api_key` no longer reads from R options and only uses environment variables (#217). - Fix documentation related to CRAN submission. - Fix some errors from passing "" as a key. -- `pvt_twitter` and `pub_wiki` now use `time_type` and `time_values` args instead of mutually exclusive `dates` and `epiweeks` (#236). This matches the interface of the `pub_covidcast` endpoint. -- All endpoints now support the use of "\*" as a wildcard to fetch all dates or epiweeks (#234). - Fixed bug with NAs when parsing ints (#243). -- Updated the default `timeout_seconds` to 15 minutes to allow large queries by default. # epidatr 1.0.0 From d39fb2020d30af0faa16f865faa9abfc4f79a8cc Mon Sep 17 00:00:00 2001 From: dsweber2 Date: Mon, 26 Feb 2024 22:32:39 -0800 Subject: [PATCH 170/189] DESC Date unneeded, some compiling --- .Rbuildignore | 1 + DESCRIPTION | 1 - DEVELOPMENT.md | 2 +- README.Rmd | 2 +- README.md | 9 ++++++++- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/.Rbuildignore b/.Rbuildignore index 9815dfff..697d8b52 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -23,3 +23,4 @@ ^README\.Rmd$ ^CRAN-SUBMISSION$ ^LICENSE\.md$ +^revdep$ diff --git a/DESCRIPTION b/DESCRIPTION index a995fa46..89fe1ad4 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -2,7 +2,6 @@ Package: epidatr Type: Package Title: Client for Delphi's 'Epidata' API Version: 1.1.0 -Date: 2023-12-07 Authors@R: c( person("Logan", "Brooks", email = "lcbrooks@andrew.cmu.edu", role = c("aut")), diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index b3205386..63e3340f 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -56,7 +56,7 @@ If you want to extend it, add to the `release_bullets` function in [utils.R](htt devtools::check(".", manual = TRUE, env_vars =c(NOT_CRAN = "false")) ``` -Aim for 10/10, no notes. +Aim for 10/10, no notes. Generally, follow the issue. `revdep_check` is likely to fail but doesn't seem to be terribly important. So for now ignore it. When this has gone smoothly enough, release to CRAN via ```R diff --git a/README.Rmd b/README.Rmd index 8829f907..319cf4fa 100644 --- a/README.Rmd +++ b/README.Rmd @@ -112,6 +112,6 @@ See also the [Terms of Use](https://delphi.cmu.edu/covidcast/terms-of-use/), not [mit-image]: https://img.shields.io/badge/License-MIT-yellow.svg -[mit-url]: https://opensource.org/license/mit/ +[mit-url]: https://opensource.org/license/mit [github-actions-image]: https://github.com/cmu-delphi/epidatr/workflows/ci/badge.svg [github-actions-url]: https://github.com/cmu-delphi/epidatr/actions diff --git a/README.md b/README.md index ac2dace0..31b1305e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![License: -MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/license/mit/) +MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/license/mit) [![Github Actions](https://github.com/cmu-delphi/epidatr/workflows/ci/badge.svg)](https://github.com/cmu-delphi/epidatr/actions) [![codecov](https://codecov.io/gh/dsweber2/epidatr/branch/dev/graph/badge.svg?token=jVHL9eHZNZ)](https://app.codecov.io/gh/dsweber2/epidatr) @@ -39,6 +39,13 @@ also provide packages for downstream data processing ``` r library(epidatr) +#> ! epidatr cache is being used (set env var EPIDATR_USE_CACHE=FALSE if not +#> intended). +#> ℹ The cache directory is /fasterHome/workingDataDir/epidatr. +#> ℹ The cache will be cleared after 1 day and will be pruned if it exceeds 1024 +#> MB. +#> ℹ The log of cache transactions is stored at +#> /fasterHome/workingDataDir/epidatr/logfile.txt. # Obtain the smoothed covid-like illness (CLI) signal from Delphi's US COVID-19 # Trends and Impact Survey (CTIS), in partnership with Facebook, as it was on # April 10, 2021 for the US at the national level From 81dc5a5dc71a4b5e92d467ba105bfb31f8db6c34 Mon Sep 17 00:00:00 2001 From: dsweber2 Date: Mon, 26 Feb 2024 22:47:47 -0800 Subject: [PATCH 171/189] docs also includes the readme --- .github/workflows/document.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/document.yaml b/.github/workflows/document.yaml index 9926fff3..80672c74 100644 --- a/.github/workflows/document.yaml +++ b/.github/workflows/document.yaml @@ -44,6 +44,7 @@ jobs: run: | git config --local user.name "$GITHUB_ACTOR" git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" + git add README.md git add man/\* NAMESPACE DESCRIPTION git commit -m "docs: document (GHA)" || echo "No changes to commit" git pull --rebase From 3ba1990361e700fddaec0c6cb20851e4d5291e1c Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Tue, 27 Feb 2024 11:54:46 -0800 Subject: [PATCH 172/189] doc: remove cache messsage from README --- README.Rmd | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.Rmd b/README.Rmd index 319cf4fa..51f3670c 100644 --- a/README.Rmd +++ b/README.Rmd @@ -45,6 +45,12 @@ forecasting models. We also provide packages for downstream data processing ## Usage +```{r, echo=FALSE} +# This is so that if you have USE_EPIDATR_CACHE=TRUE in your .Renviron, the +# startup message does not get included in the README.md when you build this. +suppressPackageStartupMessages(library(epidatr)) +``` + ```{r} library(epidatr) # Obtain the smoothed covid-like illness (CLI) signal from Delphi's US COVID-19 From 80997493d138e2d7501428d040b0a8aaf7a3d533 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Tue, 27 Feb 2024 11:55:14 -0800 Subject: [PATCH 173/189] ci: add workflow_dispatch to all, trigger document on README.Rmd --- .github/workflows/R-CMD-check.yaml | 1 + .github/workflows/document.yaml | 3 ++- .github/workflows/lint.yaml | 1 + .github/workflows/style.yaml | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index 338f93d4..a0b910bd 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -5,6 +5,7 @@ on: branches: [main, dev] pull_request: branches: [main, dev] + workflow_dispatch: name: R-CMD-check diff --git a/.github/workflows/document.yaml b/.github/workflows/document.yaml index 80672c74..17a85104 100644 --- a/.github/workflows/document.yaml +++ b/.github/workflows/document.yaml @@ -2,7 +2,8 @@ # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help on: push: - paths: ["R/**"] + paths: ["R/**", "README.Rmd"] + workflow_dispatch: name: Document diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index afd9fdbe..4eda2fd3 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -5,6 +5,7 @@ on: branches: [main, dev] pull_request: branches: [main, dev] + workflow_dispatch: name: lint diff --git a/.github/workflows/style.yaml b/.github/workflows/style.yaml index c01a2da9..acdc0470 100644 --- a/.github/workflows/style.yaml +++ b/.github/workflows/style.yaml @@ -10,6 +10,7 @@ on: "**.[rR]nw", "**.[rR]profile", ] + workflow_dispatch: name: Style From aff0c5253492fb86a1c9037fe3a737ca668508d0 Mon Sep 17 00:00:00 2001 From: dshemetov Date: Tue, 27 Feb 2024 19:57:19 +0000 Subject: [PATCH 174/189] docs: document (GHA) --- README.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/README.md b/README.md index 31b1305e..e849ac2d 100644 --- a/README.md +++ b/README.md @@ -39,13 +39,6 @@ also provide packages for downstream data processing ``` r library(epidatr) -#> ! epidatr cache is being used (set env var EPIDATR_USE_CACHE=FALSE if not -#> intended). -#> ℹ The cache directory is /fasterHome/workingDataDir/epidatr. -#> ℹ The cache will be cleared after 1 day and will be pruned if it exceeds 1024 -#> MB. -#> ℹ The log of cache transactions is stored at -#> /fasterHome/workingDataDir/epidatr/logfile.txt. # Obtain the smoothed covid-like illness (CLI) signal from Delphi's US COVID-19 # Trends and Impact Survey (CTIS), in partnership with Facebook, as it was on # April 10, 2021 for the US at the national level From d791ff860e7ea658cfa9b556bdacacfe7b37a66d Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Thu, 29 Feb 2024 17:34:26 -0500 Subject: [PATCH 175/189] if as_of passed as date, check_is_recent should compare explicitly to a date --- R/utils.R | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/R/utils.R b/R/utils.R index 5fbe5cbb..5f7ab3d3 100644 --- a/R/utils.R +++ b/R/utils.R @@ -22,7 +22,12 @@ format_list <- function(values) { #' #' @keywords internal check_is_recent <- function(dates, max_age) { - (!is.null(dates) && any(dates >= format(Sys.Date() - max_age, format = "%Y%m%d"))) + if (inherits(dates, "Date")) { + threshold <- Sys.Date() - max_age + } else { + threshold <- format(Sys.Date() - max_age, format = "%Y%m%d") + } + (!is.null(dates) && any(dates >= threshold)) } #' helper that checks whether a call is actually cachable From 9b97af449743778072eb56b6269b0a1d68927024 Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Thu, 29 Feb 2024 17:43:51 -0500 Subject: [PATCH 176/189] test --- tests/testthat/test-utils.R | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index a95fbfe0..1ed8fbe6 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -65,6 +65,33 @@ test_that("check_is_cachable can handle both str and date inputs of various leng expect_no_error(check_is_cachable(epidata_call, fetch_args)) }) +test_that("check_is_recent can handle both str and date inputs of various lengths", { + # NULL + as_of <- NULL + expect_no_error(result <- check_is_recent(as_of, 10)) + expect_identical(result, FALSE) + + # as_of single string + as_of <- "2022-01-01" + expect_no_error(result <- check_is_recent(as_of, 10)) + expect_identical(result, FALSE) + + # as_of string vector + as_of <- c("2022-01-01", "3000-01-02", "3000-01-03") + expect_no_error(result <- check_is_recent(as_of, 10)) + expect_identical(result, TRUE) + + # as_of single date + as_of <- as.Date("2022-01-01") + expect_no_error(result <- check_is_recent(as_of, 10)) + expect_identical(result, FALSE) + + # as_of date vector + as_of <- as.Date(c("2022-01-01", "3000-01-02", "3000-01-03")) + expect_no_error(result <- check_is_recent(as_of, 10)) + expect_identical(result, TRUE) +}) + test_that("get_wildcard_equivalent_dates works in basic cases", { # Week date result <- get_wildcard_equivalent_dates(epirange(202002, 202013), "week") From c10b065152186f064870515bb1a5a0521ac977df Mon Sep 17 00:00:00 2001 From: Nat DeFries <42820733+nmdefries@users.noreply.github.com> Date: Thu, 29 Feb 2024 18:00:19 -0500 Subject: [PATCH 177/189] version and news --- DESCRIPTION | 2 +- NEWS.md | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 89fe1ad4..b478a352 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: epidatr Type: Package Title: Client for Delphi's 'Epidata' API -Version: 1.1.0 +Version: 1.1.1 Authors@R: c( person("Logan", "Brooks", email = "lcbrooks@andrew.cmu.edu", role = c("aut")), diff --git a/NEWS.md b/NEWS.md index 10626ad3..432de12f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,13 @@ +# epidatr 1.2.0 + +## Changes + +## Features + +## Patches +- Fixed failure when passing `as_of` values in `Date` format to + `pub_covidcast` while caching is enabled (#259) + # epidatr 1.1.0 ## Changes From 739eebd7836bd653fa5331b88ec318119b74739e Mon Sep 17 00:00:00 2001 From: nmdefries <42820733+nmdefries@users.noreply.github.com> Date: Thu, 29 Feb 2024 18:07:07 -0500 Subject: [PATCH 178/189] Lower news version number Co-authored-by: David Weber --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 432de12f..25512ee5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -# epidatr 1.2.0 +# epidatr 1.1.1 ## Changes From 6f4ddb0a7012460137c5f1f094011db942cb2c4a Mon Sep 17 00:00:00 2001 From: dsweber2 Date: Thu, 29 Feb 2024 15:19:42 -0800 Subject: [PATCH 179/189] CRAN submission --- CRAN-SUBMISSION | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CRAN-SUBMISSION b/CRAN-SUBMISSION index a0b6ffc6..7716e2f9 100644 --- a/CRAN-SUBMISSION +++ b/CRAN-SUBMISSION @@ -1,3 +1,3 @@ -Version: 1.0.0 -Date: 2023-09-12 08:00:50 UTC -SHA: 52436eb250eab1f9c70b250bf4ca1ab25cc48316 +Version: 1.1.0 +Date: 2024-02-27 20:25:04 UTC +SHA: 693c04bd80d3ffe0b3c012281303c4878de08c70 From 3440c7fde643914facb422ee04fe1f023e6b5885 Mon Sep 17 00:00:00 2001 From: dsweber2 Date: Fri, 1 Mar 2024 11:14:27 -0800 Subject: [PATCH 180/189] pkgdown: wrote custom build_site_github_pages --- .github/workflows/pkgdown.yaml | 11 ++++++++--- R/utils.R | 4 +++- _pkgdown.yml | 2 ++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index 6e2d0169..b0ccff8e 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -43,11 +43,16 @@ jobs: DELPHI_EPIDATA_KEY: ${{ secrets.SECRET_EPIDATR_GHACTIONS_DELPHI_EPIDATA_KEY }} run: | if (startsWith("${{ github.event_name }}", "pull_request")) { - mode <- ifelse("${{ github.base_ref }}" == "main", "release", "devel") + mode_ref <- ifelse("${{ github.base_ref }}" == "main", "release", "devel") } else { - mode <- ifelse("${{ github.ref_name }}" == "main", "release", "devel") + mode_ref <- ifelse("${{ github.ref_name }}" == "main", "release", "devel") } - pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE, override=list(PKGDOWN_DEV_MODE=mode)) + library(pkgdown) + pkg <- as_pkgdown(".", overide = list(destination = ifelse(mode_ref == "release", "docs", "docs/dev", PKGDOWN_DEV_MODE = mode_ref))) + cli::cli_rule("Cleaning files from odl site") + clean_site(pkg) + build_site(pkg, preview = FALSE, install = FALSE, new_process = FALSE) + build_github_pages(pkg) shell: Rscript {0} - name: Deploy to GitHub pages 🚀 diff --git a/R/utils.R b/R/utils.R index 5f7ab3d3..1216379e 100644 --- a/R/utils.R +++ b/R/utils.R @@ -70,5 +70,7 @@ get_wildcard_equivalent_dates <- function(time_value, time_type = c("day", "week #' inserts each string as a bullet at the end of the "Prepare for release" section #' @keywords internal release_bullets <- function() { - c("merge to main") + c("merge to main", "don't use_version('patch') in the next section", "`use_version('patch')` is redundant because we do this in PRs","`use_dev_version` is also redundant.") } + +pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE, override=list(PKGDOWN_DEV_MODE=mode_ref)) diff --git a/_pkgdown.yml b/_pkgdown.yml index f923ad58..1d71aea0 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -1,5 +1,7 @@ # Colors should stay consistent across epipredict & epidatr, using Carnegie # Red https://www.cmu.edu/brand/brand-guidelines/visual-identity/colors.html +development: + mode: devel template: bootstrap: 5 bootswatch: cosmo From bdc2031904fef3059d62a9d8f83f5f719cfbea79 Mon Sep 17 00:00:00 2001 From: dsweber2 Date: Fri, 1 Mar 2024 11:38:08 -0800 Subject: [PATCH 181/189] parentheses, accidental line --- .github/workflows/pkgdown.yaml | 2 +- R/utils.R | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index b0ccff8e..0506dfad 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -48,7 +48,7 @@ jobs: mode_ref <- ifelse("${{ github.ref_name }}" == "main", "release", "devel") } library(pkgdown) - pkg <- as_pkgdown(".", overide = list(destination = ifelse(mode_ref == "release", "docs", "docs/dev", PKGDOWN_DEV_MODE = mode_ref))) + pkg <- as_pkgdown(".", overide = list(destination = ifelse(mode_ref == "release", "docs", "docs/dev"), PKGDOWN_DEV_MODE = mode_ref)) cli::cli_rule("Cleaning files from odl site") clean_site(pkg) build_site(pkg, preview = FALSE, install = FALSE, new_process = FALSE) diff --git a/R/utils.R b/R/utils.R index 1216379e..93b13b3d 100644 --- a/R/utils.R +++ b/R/utils.R @@ -72,5 +72,3 @@ get_wildcard_equivalent_dates <- function(time_value, time_type = c("day", "week release_bullets <- function() { c("merge to main", "don't use_version('patch') in the next section", "`use_version('patch')` is redundant because we do this in PRs","`use_dev_version` is also redundant.") } - -pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE, override=list(PKGDOWN_DEV_MODE=mode_ref)) From 5ed99a9f91c8da51a60e0089b2cfecd8a30aa74d Mon Sep 17 00:00:00 2001 From: dsweber2 Date: Fri, 1 Mar 2024 11:40:35 -0800 Subject: [PATCH 182/189] overide!=override --- .github/workflows/pkgdown.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index 0506dfad..c134973c 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -48,7 +48,7 @@ jobs: mode_ref <- ifelse("${{ github.ref_name }}" == "main", "release", "devel") } library(pkgdown) - pkg <- as_pkgdown(".", overide = list(destination = ifelse(mode_ref == "release", "docs", "docs/dev"), PKGDOWN_DEV_MODE = mode_ref)) + pkg <- as_pkgdown(".", override = list(destination = ifelse(mode_ref == "release", "docs", "docs/dev"), PKGDOWN_DEV_MODE = mode_ref)) cli::cli_rule("Cleaning files from odl site") clean_site(pkg) build_site(pkg, preview = FALSE, install = FALSE, new_process = FALSE) From e5b7918d0dd9465c27005a91e9bc540500865fa5 Mon Sep 17 00:00:00 2001 From: dsweber2 Date: Fri, 1 Mar 2024 19:41:28 +0000 Subject: [PATCH 183/189] style: styler (GHA) --- R/utils.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/utils.R b/R/utils.R index 93b13b3d..ab868cac 100644 --- a/R/utils.R +++ b/R/utils.R @@ -70,5 +70,5 @@ get_wildcard_equivalent_dates <- function(time_value, time_type = c("day", "week #' inserts each string as a bullet at the end of the "Prepare for release" section #' @keywords internal release_bullets <- function() { - c("merge to main", "don't use_version('patch') in the next section", "`use_version('patch')` is redundant because we do this in PRs","`use_dev_version` is also redundant.") + c("merge to main", "don't use_version('patch') in the next section", "`use_version('patch')` is redundant because we do this in PRs", "`use_dev_version` is also redundant.") } From 3d44b2dde41ebaafa6d05e3db99a73c12d87385a Mon Sep 17 00:00:00 2001 From: dsweber2 Date: Fri, 1 Mar 2024 11:48:32 -0800 Subject: [PATCH 184/189] speeling and not overwriting existing function --- .github/workflows/pkgdown.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index c134973c..4576eb58 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -49,7 +49,7 @@ jobs: } library(pkgdown) pkg <- as_pkgdown(".", override = list(destination = ifelse(mode_ref == "release", "docs", "docs/dev"), PKGDOWN_DEV_MODE = mode_ref)) - cli::cli_rule("Cleaning files from odl site") + cli::cli_rule("Cleaning files from old site") clean_site(pkg) build_site(pkg, preview = FALSE, install = FALSE, new_process = FALSE) build_github_pages(pkg) From e51e2a2323790d0fb0300b9523e72a2b691fc6c5 Mon Sep 17 00:00:00 2001 From: dsweber2 Date: Fri, 1 Mar 2024 11:57:40 -0800 Subject: [PATCH 185/189] build_github_pages is internal to pkgdown, so import --- .github/workflows/pkgdown.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index 4576eb58..b6758373 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -52,7 +52,7 @@ jobs: cli::cli_rule("Cleaning files from old site") clean_site(pkg) build_site(pkg, preview = FALSE, install = FALSE, new_process = FALSE) - build_github_pages(pkg) + pkgdown:::build_github_pages(pkg) shell: Rscript {0} - name: Deploy to GitHub pages 🚀 From 282eace17fa54ef8fc14962f73692d286cbcce92 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Fri, 1 Mar 2024 14:44:28 -0800 Subject: [PATCH 186/189] ci: use a single epidatr key env var --- .github/workflows/pkgdown.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index b6758373..017aaad4 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -23,7 +23,7 @@ jobs: group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - DELPHI_EPIDATA_KEY: ${{ secrets.DELPHI_GITHUB_ACTIONS_EPIDATA_API_KEY }} + DELPHI_EPIDATA_KEY: ${{ secrets.SECRET_EPIDATR_GHACTIONS_DELPHI_EPIDATA_KEY }} steps: - uses: actions/checkout@v3 @@ -39,8 +39,6 @@ jobs: needs: website - name: Build site - env: - DELPHI_EPIDATA_KEY: ${{ secrets.SECRET_EPIDATR_GHACTIONS_DELPHI_EPIDATA_KEY }} run: | if (startsWith("${{ github.event_name }}", "pull_request")) { mode_ref <- ifelse("${{ github.base_ref }}" == "main", "release", "devel") From d6df787d9fd0a12eacc6057693ecd3c24c775257 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Fri, 1 Mar 2024 14:46:13 -0800 Subject: [PATCH 187/189] ci: add cli dependency --- .github/workflows/pkgdown.yaml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index 017aaad4..5cad4a9a 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -35,7 +35,7 @@ jobs: - uses: r-lib/actions/setup-r-dependencies@v2 with: - extra-packages: any::pkgdown, local::. + extra-packages: any::pkgdown, local::., any::cli needs: website - name: Build site @@ -45,11 +45,10 @@ jobs: } else { mode_ref <- ifelse("${{ github.ref_name }}" == "main", "release", "devel") } - library(pkgdown) - pkg <- as_pkgdown(".", override = list(destination = ifelse(mode_ref == "release", "docs", "docs/dev"), PKGDOWN_DEV_MODE = mode_ref)) - cli::cli_rule("Cleaning files from old site") - clean_site(pkg) - build_site(pkg, preview = FALSE, install = FALSE, new_process = FALSE) + pkg <- pkgdown::as_pkgdown(".", override = list(destination = ifelse(mode_ref == "release", "docs", "docs/dev"), PKGDOWN_DEV_MODE = mode_ref)) + cli::cli_rule("Cleaning files from old site...") + pkgdown::clean_site(pkg) + pkgdown::build_site(pkg, preview = FALSE, install = FALSE, new_process = FALSE) pkgdown:::build_github_pages(pkg) shell: Rscript {0} From e63a926299367c04be326910d33d3fce8862b272 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Fri, 1 Mar 2024 14:51:48 -0800 Subject: [PATCH 188/189] style: styler --- R/utils.R | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/R/utils.R b/R/utils.R index ab868cac..15356734 100644 --- a/R/utils.R +++ b/R/utils.R @@ -70,5 +70,10 @@ get_wildcard_equivalent_dates <- function(time_value, time_type = c("day", "week #' inserts each string as a bullet at the end of the "Prepare for release" section #' @keywords internal release_bullets <- function() { - c("merge to main", "don't use_version('patch') in the next section", "`use_version('patch')` is redundant because we do this in PRs", "`use_dev_version` is also redundant.") + c( + "merge to main", + "don't use_version('patch') in the next section", + "`use_version('patch')` is redundant because we do this in PRs", + "`use_dev_version` is also redundant." + ) } From c8fa2938c406bad7d8054d7dbf7f03e4d32e73c0 Mon Sep 17 00:00:00 2001 From: Dmitry Shemetov Date: Fri, 1 Mar 2024 16:16:50 -0800 Subject: [PATCH 189/189] ci: fix pkgdown and improve colors --- .github/workflows/pkgdown.yaml | 16 ++++++++++++---- _pkgdown.yml | 7 +++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index 5cad4a9a..f7bf0f93 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -40,12 +40,20 @@ jobs: - name: Build site run: | - if (startsWith("${{ github.event_name }}", "pull_request")) { - mode_ref <- ifelse("${{ github.base_ref }}" == "main", "release", "devel") + override <- if (startsWith("${{ github.event_name }}", "pull_request")) { + if ("${{ github.base_ref }}" == "main") { + list(development = list(mode = "release", version_label = "light")) + } else { + list(development = list(mode = "devel", version_label = "success")) + } } else { - mode_ref <- ifelse("${{ github.ref_name }}" == "main", "release", "devel") + if ("${{ github.ref_name }}" == "main") { + list(development = list(mode = "release", version_label = "light")) + } else { + list(development = list(mode = "devel", version_label = "success")) + } } - pkg <- pkgdown::as_pkgdown(".", override = list(destination = ifelse(mode_ref == "release", "docs", "docs/dev"), PKGDOWN_DEV_MODE = mode_ref)) + pkg <- pkgdown::as_pkgdown(".", override = override) cli::cli_rule("Cleaning files from old site...") pkgdown::clean_site(pkg) pkgdown::build_site(pkg, preview = FALSE, install = FALSE, new_process = FALSE) diff --git a/_pkgdown.yml b/_pkgdown.yml index 1d71aea0..98124004 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -1,7 +1,14 @@ # Colors should stay consistent across epipredict & epidatr, using Carnegie # Red https://www.cmu.edu/brand/brand-guidelines/visual-identity/colors.html + +# This is to give a default value to the `mode` parameter in the +# `pkgdown::build_site` function. This is useful when building the site locally, +# as it will default to `devel` mode. In practice, this should all be handled +# dynamically by the CI/CD pipeline. development: mode: devel + version_label: success + template: bootstrap: 5 bootswatch: cosmo