Introduction

RStudio lets you access ESSENCE data more securely, create your own R Markdown reports and Shiny applications, and do exploratory analyses not possible within ESSENCE. In this R Markdown document, we will provide an overview of the ESSENCE application programming interfaces (APIs) and explain how to access them through RStudio. We will also list the APIs available in ESSENCE and show basic examples of R code and packages so that you can start using RStudio.

An API is a structured and consistent way for one machine to exchange information with another machine. ESSENCE has APIs that allow you to programmatically access and further manipulate your data from outside the system. You may select the CSV format to export data, and in some instances, JSON is also supported. More information about the APIs can be found in ESSENCE under “More,” then “User Guide,” and then API Documentation. You may write API URL syntax on your own after reading the documentation, or you can let ESSENCE create the API URL by clicking the “API URL” button on an ESSENCE page after completing a query.

At the time of this writing, ESSENCE offered seven APIs:

  1. Time series data table,

  2. Time series PNG image,

  3. Table builder results,

  4. Data details (line level),

  5. Summary stats on the number of unique facilities or regions in your query results,

  6. Alert list detection table,

  7. Time series data table with stratified, historical alerts

RStudio: Securely Saving AMC Credentials

The first step is to create an R script or R Markdown file and load the necessary packages. By default, some packages might already be in your system library. But if not, you can install them yourself by clicking on the packages tab in the bottom-right quadrant of the RStudio interface and selecting the Install tab. Here are the package names and configuration statement for getting started:

To extract data from ESSENCE, you start by passing authentication information from your RStudio session to ESSENCE so that it knows what data you are allowed to see. It is bad practice to explicitly include your username and password in your code. We provide two options to do this work for us: the Rnssp or keyring package. Whenever possible, we encourage users to adopt the more secure methodology presented in Rnssp (option 1 below).

Option 1: Rnssp (preferred)

In June 2021, the Rnssp library was installed on the instance of RStudio Workbench hosted on the BioSense Platform. If you are using a local instance of RStudio, you can install the development version of Rnssp from GitHub by running devtools::install_github("cdcgov/Rnssp") in your console. The Rnssp GitHub repository can be accessed at https://github.com/CDCgov/Rnssp, with additional documentation and vignettes located at https://cdcgov.github.io/Rnssp/. Rnssp provides functionality to securely save credentials and interact with ESSENCE APIs. When you run the following code, a pop-up will appear in RStudio for you to enter your AMC username and password. This will create a user profile object of the class Credentials, designed with the R6 object system that integrates classic object-oriented programming concepts into R. To render an R Markdown document, save the myProfile object as an .rda or .rds file to your home directory. This only needs to be done once. The following code chunk is presented for demonstrative purposes only and does not need to be included in your actual R Markdown code.

library(Rnssp)

myProfile <- Credentials$new(
  username = askme("Enter your username: "),
  password = askme()
)

# rda option-----------------------------------------------------------------------------------------------------
save(myProfile, file = "~/myProfile.rda") 

# rds option-----------------------------------------------------------------------------------------------------
saveRDS(myProfile, "~/myProfile.rds")

myProfile can then be loaded by including either of the following lines of code in your introductory code chunks (just use one option):

# rda option-----------------------------------------------------------------------------------------------------
load("~/myProfile.rda") 

# rds option-----------------------------------------------------------------------------------------------------
myProfile <- readRDS("~/myProfile.rds")

Note that your username and password are fully encrypted in your user profile and are not visible when viewing or inspecting the object:

myProfile
## <NSSPCredentials>
##   Public:
##     clone: function (deep = FALSE) 
##     get_api_data: function (url, fromCSV = FALSE, ...) 
##     get_api_response: function (url) 
##     get_api_tsgraph: function (url) 
##     initialize: function (username, password) 
##   Private:
##     ..__: NSSPContainer, R6
##     ..password: NSSPContainer, R6
##     ..username: NSSPContainer, R6

The myProfile object comes with the following methods:

  • $get_api_response(): Retrieves requested information specified in the API URL from ESSENCE
  • $get_api_data(): Extracts the content (data) from the API response and parses into an R data frame
  • $get_api_tsgraph(): Retrieves an ESSENCE time series graph and saves as a PNG to a temporary directory

Option 2: keyring

Prior to the development of the Rnssp package, the keyring library was used to authenticate AMC credentials to NSSP-ESSENCE when pulling data via the APIs. While using keyring is more secure than explicitly referencing your credentials from a source file, it is less secure and efficient than the Rnssp method. In 2021, the keyring library was updated and now requires users to specify that credentials should be saved to hidden background environment variables. NSSP applied a patch in RStudio Workbench in January 2022 so that keyring can be used as it was previously. keyring will save your AMC credentials to background environment variables that will persist for the duration of an individual R session. When you run the following line of code (with your username entered in the username quotes) a pop-up will appear in RStudio where you will need to enter your password. Note: You only need to save your credentials once per session.

key_set(service = "essence", username = "msheppardoa01")

After you enter your password in the pop-up window, be sure to “comment out” this line of code by adding a hash mark before it as shown below:

# key_set(service = "essence", username = "msheppardoa01")

In each example that follows, you will see a common pattern emerge: First, the URL must be defined as an object in your RStudio session; then the API response needs to be retrieved and content extracted to an R data frame using either the Rnssp $get_api_data() method or GET from httr before further analysis. When you use this approach, R Markdown provides an easily reproducible workflow for integrating report text with code that reads in data, manipulates data as needed, and produces analyses and visualizations in such a way that can be handed off to colleagues without documenting manual actions (point/click, etc).

Time Series Data Table

In this example, we will show you how to pull a time series data table from ESSENCE into RStudio. Note: All examples use the limited details data sources available in NSSP-ESSENCE. In the code below, the first object created is the URL for the ESSENCE API endpoint of interest, which for this example is a national trend of the injury syndrome. The second object, api_response, authenticates your credentials so that ESSENCE knows you are permitted to access these data and then retrieves the requested data if authentication is successful. The next two objects process JSON-formatted data into an R data frame. By default, time series APIs pull in JSON-formatted data. The fromJSON() function converts these data to a list of length 2, where the second element of the list is a data frame that can be extracted with the pluck() function from the purrr library. Lastly, the glimpse() function from dplyr provides a quick sense of every variable in the data frame.

url <- "https://essence.syndromicsurveillance.org/nssp_essence/api/timeSeries?endDate=15Jan2022&medicalGrouping=injury&percentParam=noPercent&geographySystem=hospitaldhhsregion&datasource=va_hospdreg&detector=probrepswitch&startDate=23Oct2021&timeResolution=daily&medicalGroupingSystem=essencesyndromes&userId=455&aqtTarget=TimeSeries"

# Rnssp option---------------------------------------------------------------------------------------------------
api_response <- myProfile$get_api_response(url)
api_response_json <- content(api_response, as = "text")
## No encoding supplied: defaulting to UTF-8.
api_data <- fromJSON(api_response_json) %>%
  pluck("timeSeriesData")

# keyring option-------------------------------------------------------------------------------------------------
api_response <- GET(url, 
                    authenticate(key_list("essence")[1,2], 
                                 key_get("essence", 
                                 key_list("essence")[1,2])))

api_response_json <- content(api_response, as = "text")
## No encoding supplied: defaulting to UTF-8.
api_data <- fromJSON(api_response_json) %>%
  pluck("timeSeriesData")

glimpse(api_data)
## Rows: 85
## Columns: 8
## $ date     <chr> "2021-10-23", "2021-10-24", "2021-10-25", "2021-10-26", "2021…
## $ count    <dbl> 41984, 41338, 46595, 44106, 44206, 44172, 44093, 42044, 42009…
## $ expected <chr> "44703.25", "44699.214", "44664.536", "44606.571", "44057.516…
## $ levels   <chr> "0.899", "0.977", "0.186", "0.574", "0.456", "0.586", "0.589"…
## $ colorID  <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1…
## $ color    <chr> "blue", "blue", "blue", "blue", "blue", "blue", "blue", "blue…
## $ altText  <chr> "Data: Date: 23Oct21, Level: 0.899, Count: 41984, Expected: 4…
## $ details  <chr> "/nssp_essence/api/dataDetails?medicalGrouping=injury&percent…

Alternatively, with Rnssp we can pull these data with two lines of code by using the $get_api_data() method, which implicitly pulls and extracts data using the steps outlined in the example above. Occasionally there are scenarios in which retrieving the API response first is beneficial—for example, when the API response status code needs to be inspected if data are not pulling as expected.

api_data <- myProfile$get_api_data(url) %>%
  pluck("timeSeriesData")
## No encoding supplied: defaulting to UTF-8.

Time Series Graph from ESSENCE

This example shows how to retrieve the ESSENCE graph instead of the underlying data for the graph, as shown previously. Here, we use the same national injury syndrome trend as before, but notice the URL now includes ..”api/timeSeries/graph?…“. You can add a title or axes labels by adding other parameters to the URL:”&graphTitle=Injury%20Syndrome&xAxisLabel=Date&yAxisLabel=Count”.

url <- "https://essence.syndromicsurveillance.org/nssp_essence/api/timeSeries/graph?endDate=15Jan2022&medicalGrouping=injury&percentParam=noPercent&geographySystem=hospitaldhhsregion&datasource=va_hospdreg&detector=probrepswitch&startDate=23Oct2021&timeResolution=daily&medicalGroupingSystem=essencesyndromes&userId=455&aqtTarget=TimeSeries&graphTitle=National%20-%20Injury%20Syndrome%20Daily%20Counts&xAxisLabel=Date&yAxisLabel=Count"

# Rnssp option---------------------------------------------------------------------------------------------------
api_png <- myProfile$get_api_tsgraph(url)

knitr::include_graphics(api_png$tsgraph)

# keyring option-------------------------------------------------------------------------------------------------
api_response <- GET(url, 
                    authenticate(key_list("essence")[1,2], 
                                 key_get("essence", 
                                 key_list("essence")[1,2])),
                    write_disk("timeseries1.png", overwrite = TRUE))

knitr::include_graphics("timeseries1.png")

Table Builder Results

With the table builder API, ESSENCE does the heavy lifting by summarizing your query and presenting results in tabular format where you can define rows, nested rows, and column variables for output. If the query is supported in the ESSENCE query manager, you should be able to use table builder to summarize the output, which is usually more efficient than manipulating large amounts of line-level data yourself. In this example, we use the CDC Opioid Overdose v3 Chief Complaint Discharge Diagnosis (CCDD) category and create a table of counts per month by U.S. Department of Health & Human Services (HHS) region. Visits are limited to emergency department visits by selecting Has been Emergency = “Yes”. Output formats for table builder results are CSV and JSON. The CSV option will pull in data that matches the tabular format seen in the ESSENCE interface, whereas the JSON option will pull in data that is transformed to a long, pivoted format. The latter is recommended for circumventing initial data transformations into a long format and is compatible with functions/libraries based on tidyverse principles.

Example - CSV

When the CSV option is used, you will need to specify this by using the fromCSV argument as shown below. By default, $get_api_data() assumes that the JSON option was selected.

url <- "https://essence.syndromicsurveillance.org/nssp_essence/api/tableBuilder/csv?endDate=15Jan2022&ccddCategory=cdc%20opioid%20overdose%20v3&percentParam=noPercent&geographySystem=hospitaldhhsregion&datasource=va_hospdreg&detector=nodetectordetector&startDate=23Oct2021&ageNCHS=11-14&ageNCHS=15-24&ageNCHS=25-34&ageNCHS=35-44&ageNCHS=45-54&ageNCHS=55-64&ageNCHS=65-74&ageNCHS=75-84&ageNCHS=85-1000&ageNCHS=unknown&timeResolution=monthly&hasBeenE=1&medicalGroupingSystem=essencesyndromes&userId=455&aqtTarget=TableBuilder&rowFields=timeResolution&rowFields=geographyhospitaldhhsregion&columnField=ageNCHS"

# Rnssp option---------------------------------------------------------------------------------------------------
api_data <- myProfile$get_api_data(url, fromCSV = TRUE)
## Rows: 44 Columns: 12
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (2): timeResolution, geographyhospitaldhhsregion
## dbl (10): 11-14, 15-24, 25-34, 35-44, 45-54, 55-64, 65-74, 75-84, 85+, Unknown
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# keyring option-------------------------------------------------------------------------------------------------
api_response <- GET(url, 
                    authenticate(key_list("essence")[1,2], 
                                 key_get("essence", 
                                 key_list("essence")[1,2])))

api_response_csv <- content(api_response, by = "text/csv")
api_data <- read_csv(api_response_csv)
## Rows: 44 Columns: 12
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (2): timeResolution, geographyhospitaldhhsregion
## dbl (10): 11-14, 15-24, 25-34, 35-44, 45-54, 55-64, 65-74, 75-84, 85+, Unknown
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
glimpse(api_data)
## Rows: 44
## Columns: 12
## $ timeResolution              <chr> "2021-10", "2021-10", "2021-10", "2021-10"…
## $ geographyhospitaldhhsregion <chr> "OTHER_REGION", "Region 1", "Region 10", "…
## $ `11-14`                     <dbl> 0, 0, 2, 0, 1, 4, 2, 0, 0, 0, 0, 0, 0, 1, …
## $ `15-24`                     <dbl> 0, 41, 40, 31, 76, 173, 68, 43, 16, 28, 63…
## $ `25-34`                     <dbl> 0, 151, 111, 119, 201, 561, 244, 109, 25, …
## $ `35-44`                     <dbl> 0, 162, 63, 104, 170, 549, 181, 100, 16, 3…
## $ `45-54`                     <dbl> 0, 100, 59, 94, 118, 287, 144, 59, 6, 22, …
## $ `55-64`                     <dbl> 0, 90, 45, 101, 137, 255, 196, 55, 10, 19,…
## $ `65-74`                     <dbl> 0, 32, 35, 35, 50, 162, 89, 22, 6, 19, 35,…
## $ `75-84`                     <dbl> 0, 10, 10, 5, 11, 74, 19, 11, 0, 7, 8, 0, …
## $ `85+`                       <dbl> 0, 5, 6, 3, 11, 25, 2, 3, 0, 4, 7, 0, 11, …
## $ Unknown                     <dbl> 0, 2, 2, 3, 5, 13, 4, 1, 0, 1, 3, 0, 25, 6…

The following example demonstrates the necessary data transformations to achieve the long format that is output from the JSON option by default.

api_data_long <- api_data %>%
  pivot_longer(cols = -c(timeResolution, geographyhospitaldhhsregion), names_to = "ageNCHS", values_to = "count")

api_data_long
## # A tibble: 440 × 4
##    timeResolution geographyhospitaldhhsregion ageNCHS count
##    <chr>          <chr>                       <chr>   <dbl>
##  1 2021-10        OTHER_REGION                11-14       0
##  2 2021-10        OTHER_REGION                15-24       0
##  3 2021-10        OTHER_REGION                25-34       0
##  4 2021-10        OTHER_REGION                35-44       0
##  5 2021-10        OTHER_REGION                45-54       0
##  6 2021-10        OTHER_REGION                55-64       0
##  7 2021-10        OTHER_REGION                65-74       0
##  8 2021-10        OTHER_REGION                75-84       0
##  9 2021-10        OTHER_REGION                85+         0
## 10 2021-10        OTHER_REGION                Unknown     0
## # … with 430 more rows

Example - JSON

If the JSON option is selected, the only difference from the API URL for the CSV option is that the string “/csv” is missing after “api/tableBuilder”.

url <- "https://essence2.syndromicsurveillance.org/nssp_essence/api/tableBuilder?endDate=15Jan2022&ccddCategory=cdc%20opioid%20overdose%20v3&percentParam=noPercent&geographySystem=hospitaldhhsregion&datasource=va_hospdreg&detector=nodetectordetector&startDate=23Oct2021&ageNCHS=11-14&ageNCHS=15-24&ageNCHS=25-34&ageNCHS=35-44&ageNCHS=45-54&ageNCHS=55-64&ageNCHS=65-74&ageNCHS=75-84&ageNCHS=85-1000&ageNCHS=unknown&timeResolution=monthly&hasBeenE=1&medicalGroupingSystem=essencesyndromes&userId=2362&aqtTarget=TableBuilder&rowFields=timeResolution&rowFields=geographyhospitaldhhsregion&columnField=ageNCHS"

# Rnssp option---------------------------------------------------------------------------------------------------
api_data <- myProfile$get_api_data(url)

# keyring option-------------------------------------------------------------------------------------------------
api_response <- GET(url, 
                    authenticate(key_list("essence")[1,2], 
                                 key_get("essence", 
                                 key_list("essence")[1,2])))

api_response_json <- content(api_response, as = "text")
api_data <- fromJSON(api_response_json)

glimpse(api_data)
## Rows: 440
## Columns: 4
## $ timeResolution              <chr> "2021-10", "2021-10", "2021-10", "2021-10"…
## $ geographyhospitaldhhsregion <chr> "OTHER_REGION", "OTHER_REGION", "OTHER_REG…
## $ ageNCHS                     <chr> "11-14", "15-24", "25-34", "35-44", "45-54…
## $ count                       <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 151, …

You may have noticed that the table builder in the ESSENCE user interface is limited to creating tables of up to 30,000 cells. A table this large should suffice in most cases. Keep in mind, however, that the table builder API does not impose a limit on the output table size. To create the API yourself instead of having ESSENCE create it for you, use the “API URLs” button. Familiarize yourself with the structure of the API, and then add parameters that follow the structure. To help with this, look at some examples where ESSENCE has created API URLs for you using the available buttons.

Data Details (line-level limited details)

Sometimes you just need line-level data, and this example describes how to extract those data from ESSENCE. This method will create a very large data set quickly. As with any query with potential to create large data sets, first test the query on a small amount of data. Consider multiple calls of smaller time ranges before combining the separate data frames to create a final data set. This API gives you those options. You can specify the variables to include and whether you want a data set with raw or reference values. Downloads with reference values take longer to stream into RStudio because ESSENCE must create those reference values. Output formats for data details are CSV and JSON.

Example 1 - CSV

url <- "https://essence.syndromicsurveillance.org/nssp_essence/api/dataDetails/csv?medicalGrouping=injury&geography=region%20i&percentParam=noPercent&geographySystem=hospitaldhhsregion&datasource=va_hospdreg&detector=probrepswitch&timeResolution=daily&medicalGroupingSystem=essencesyndromes&userId=455&aqtTarget=dataDetails&startDate=14Jan2022&endDate=15Jan2022"

# Rnssp option---------------------------------------------------------------------------------------------------
api_data <- myProfile$get_api_data(url, fromCSV = TRUE)
## Rows: 4342 Columns: 21
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (12): Date, Category_flat, SubCategory_flat, Patient_Class, HospitalDHH...
## dbl   (8): HasBeenE, HasBeenI, HasBeenO, DDAvailable, DDInformative, CCAvail...
## dttm  (1): FirstDateTimeAdded
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# keyring option-------------------------------------------------------------------------------------------------
api_response <- GET(url, 
                    authenticate(key_list("essence")[1,2], 
                                 key_get("essence", 
                                 key_list("essence")[1,2])))

api_data <- content(api_response, by = "csv/text") %>%
  read_csv() 
## Rows: 4342 Columns: 21
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (12): Date, Category_flat, SubCategory_flat, Patient_Class, HospitalDHH...
## dbl   (8): HasBeenE, HasBeenI, HasBeenO, DDAvailable, DDInformative, CCAvail...
## dttm  (1): FirstDateTimeAdded
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
glimpse(api_data)
## Rows: 4,342
## Columns: 21
## $ Date                       <chr> "01/15/2022", "01/15/2022", "01/15/2022", "…
## $ Category_flat              <chr> ";Injury;", ";Injury;", ";Injury;", ";Injur…
## $ SubCategory_flat           <chr> ";BiteOrSting;", ";Fall;", ";CutOrPierce;Fa…
## $ Patient_Class              <chr> "E", "E", "O", "E", "E", "E", "E", "E", "E"…
## $ HospitalDHHSRegion         <chr> "Region I", "Region I", "Region I", "Region…
## $ dhhsregion                 <chr> "Region I", "Region I", "Region I", "Region…
## $ AgeGroup                   <chr> "00-04", "00-04", "00-04", "00-04", "00-04"…
## $ Sex                        <chr> "F", "F", "M", "F", "F", "F", "M", "F", "F"…
## $ DispositionCategory        <chr> "DISCHARGED", "DISCHARGED", "DISCHARGED", "…
## $ AdmissionTypeCategory      <chr> "NR", "NR", "E", "NR", "UNK", "NR", "NR", "…
## $ HasBeenE                   <dbl> 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ HasBeenI                   <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ HasBeenO                   <dbl> 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ DDAvailable                <dbl> 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ DDInformative              <dbl> 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ CCAvailable                <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ CCInformative              <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ FirstDateTimeAdded         <dttm> 2022-01-15 05:52:10, 2022-01-16 00:32:18, …
## $ HasBeenAdmitted            <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ CRace_CEth_Combined_Broad  <chr> "Race and Ethnicity Unknown", "Race and Eth…
## $ CRace_CEth_Combined_Narrow <chr> "Race and Ethnicity Unknown", "Race and Eth…

Example 2 - CSV limited to specified fields

To reduce the file size, you can specify only the variables you need and by adding additional parameters into the URL, like, for example, “&field=Date&field=HospitalDHHSRegion&field=AgeGroup&field=Sex” as shown below. In this example, only the date, HHS region, age group, and patient sex fields are included. Limiting to a subset of desired fields is much more efficient when pulling line-level data from the full details data sources, which includes 201 fields as of January 2022.

url <- "https://essence.syndromicsurveillance.org/nssp_essence/api/dataDetails/csv?medicalGrouping=injury&geography=region%20i&percentParam=noPercent&geographySystem=hospitaldhhsregion&datasource=va_hospdreg&detector=probrepswitch&timeResolution=daily&medicalGroupingSystem=essencesyndromes&userId=455&aqtTarget=dataDetails&startDate=14Jan2022&endDate=15Jan2022&field=Date&field=HospitalDHHSRegion&field=AgeGroup&field=Sex"

# Rnssp option---------------------------------------------------------------------------------------------------
api_data <- myProfile$get_api_data(url, fromCSV = TRUE)
## Rows: 4342 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (4): Date, HospitalDHHSRegion, AgeGroup, Sex
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# keyring option-------------------------------------------------------------------------------------------------
api_response <- GET(url, 
                    authenticate(key_list("essence")[1,2], 
                                 key_get("essence", 
                                 key_list("essence")[1,2])))

api_data <- content(api_response, by = "csv/text") %>%
  read_csv() 
## Rows: 4342 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (4): Date, HospitalDHHSRegion, AgeGroup, Sex
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
glimpse(api_data)
## Rows: 4,342
## Columns: 4
## $ Date               <chr> "01/15/2022", "01/15/2022", "01/15/2022", "01/15/20…
## $ HospitalDHHSRegion <chr> "Region I", "Region I", "Region I", "Region I", "Re…
## $ AgeGroup           <chr> "00-04", "00-04", "00-04", "00-04", "00-04", "00-04…
## $ Sex                <chr> "F", "F", "M", "F", "F", "F", "M", "F", "F", "F", "…

Example 3 - JSON

url <- "https://essence.syndromicsurveillance.org/nssp_essence/api/dataDetails?medicalGrouping=injury&geography=region%20i&percentParam=noPercent&geographySystem=hospitaldhhsregion&datasource=va_hospdreg&detector=probrepswitch&timeResolution=daily&medicalGroupingSystem=essencesyndromes&userId=455&aqtTarget=dataDetails&startDate=14Jan2022&endDate=15Jan2022"

# Rnssp option---------------------------------------------------------------------------------------------------
api_data <- myProfile$get_api_data(url)
## No encoding supplied: defaulting to UTF-8.
# keyring option-------------------------------------------------------------------------------------------------
api_response <- GET(url, 
                    authenticate(key_list("essence")[1,2], 
                                 key_get("essence", 
                                 key_list("essence")[1,2])))

api_response_json <- content(api_response, as = "text") 
## No encoding supplied: defaulting to UTF-8.
api_data <- fromJSON(api_response_json) %>%
  pluck("dataDetails")

glimpse(api_data)
## Rows: 4,342
## Columns: 21
## $ Date                       <chr> "01/15/2022", "01/15/2022", "01/15/2022", "…
## $ Category_flat              <chr> ";Injury;", ";Injury;", ";Injury;", ";Injur…
## $ SubCategory_flat           <chr> ";BiteOrSting;", ";Fall;", ";CutOrPierce;Fa…
## $ Patient_Class              <chr> "E", "E", "O", "E", "E", "E", "E", "E", "E"…
## $ HospitalDHHSRegion         <chr> "Region I", "Region I", "Region I", "Region…
## $ dhhsregion                 <chr> "Region I", "Region I", "Region I", "Region…
## $ AgeGroup                   <chr> "00-04", "00-04", "00-04", "00-04", "00-04"…
## $ Sex                        <chr> "F", "F", "M", "F", "F", "F", "M", "F", "F"…
## $ DispositionCategory        <chr> "DISCHARGED", "DISCHARGED", "DISCHARGED", "…
## $ AdmissionTypeCategory      <chr> "NR", "NR", "E", "NR", "UNK", "NR", "NR", "…
## $ HasBeenE                   <chr> "1", "1", "0", "1", "1", "1", "1", "1", "1"…
## $ HasBeenI                   <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0"…
## $ HasBeenO                   <chr> "0", "0", "1", "0", "0", "0", "0", "0", "0"…
## $ DDAvailable                <chr> "1", "1", "1", "0", "1", "1", "1", "1", "1"…
## $ DDInformative              <chr> "1", "1", "1", "0", "1", "1", "1", "1", "1"…
## $ CCAvailable                <chr> "1", "1", "1", "1", "1", "1", "1", "1", "1"…
## $ CCInformative              <chr> "1", "1", "1", "1", "1", "1", "1", "1", "1"…
## $ FirstDateTimeAdded         <chr> "2022-01-15 05:52:10.557", "2022-01-16 00:3…
## $ HasBeenAdmitted            <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0"…
## $ CRace_CEth_Combined_Broad  <chr> "Race and Ethnicity Unknown", "Race and Eth…
## $ CRace_CEth_Combined_Narrow <chr> "Race and Ethnicity Unknown", "Race and Eth…

Example 4 - Time Chunked Pulls with JSON Option

If you are pulling line-level data details over a longer range of time (i.e., months or a year), it is ideal to time chunk your API data pulls to reduce the amount of strain put on the ESSENCE system. Please keep in mind that heavy data pulls can affect all ESSENCE users. The following example is meant for demonstrative purposes and only pulls data for 4 days. This can be used as a template to pull data for longer periods of time.

api_data <- data.frame(
  date = seq.Date(from = as.Date("2022-01-12"), to = as.Date("2022-01-15"), by = "1 day")
) %>%
  mutate(
    date = format(date, "%d%b%Y"),
    url = paste0("https://essence.syndromicsurveillance.org/nssp_essence/api/dataDetails?medicalGrouping=injury&geography=region%20i&percentParam=noPercent&geographySystem=hospitaldhhsregion&datasource=va_hospdreg&detector=probrepswitch&timeResolution=daily&medicalGroupingSystem=essencesyndromes&userId=455&aqtTarget=dataDetails&startDate=", date, "&endDate=", date),
    chunk = row_number()
  ) %>%
  nest(data = -chunk) %>%
  mutate(
    pull = map(.x = data, .f = function (.x) {
      
      myProfile$get_api_data(.x$url) %>%
        pluck("dataDetails")
      
    })
  ) %>%
  select(-data) %>%
  unnest(pull)
## No encoding supplied: defaulting to UTF-8.
## No encoding supplied: defaulting to UTF-8.
## No encoding supplied: defaulting to UTF-8.
## No encoding supplied: defaulting to UTF-8.
nrow(api_data)
## [1] 8971

Summary Stats

The Summary Stats ESSENCE API counts regions (or, “counties,” in ESSENCE) and facilities in your query by whatever time resolution you define (daily, weekly, monthly, quarterly, or yearly). One difference between this API and others is that it is only available on full details data sources (the only data sources that expose this level of information). This API is particularly useful for understanding the number of hospitals with results for your query.

url <- "https://essence.syndromicsurveillance.org/nssp_essence/api/summaryData?endDate=15Jan2022&medicalGrouping=injury&geography=region%20i&percentParam=noPercent&geographySystem=hospitaldhhsregion&datasource=va_hosp&detector=probrepswitch&startDate=12Jan2022&timeResolution=daily&medicalGroupingSystem=essencesyndromes&userId=455&aqtTarget=TimeSeries"

# Rnssp option---------------------------------------------------------------------------------------------------
api_data <- myProfile$get_api_data(url)

# keyring option-------------------------------------------------------------------------------------------------
api_response <- GET(url, 
                    authenticate(key_list("essence")[1,2], 
                                 key_get("essence", 
                                 key_list("essence")[1,2])))

api_response_json <- content(api_response, as = "text")
api_data <- fromJSON(api_response_json) %>%
  pluck("summaryData")

glimpse(api_data)
## Rows: 4
## Columns: 5
## $ date          <chr> "12Jan22", "13Jan22", "14Jan22", "15Jan22"
## $ HospitalState <dbl> 6, 6, 6, 6
## $ State         <dbl> 25, 21, 28, 17
## $ Region        <dbl> 105, 106, 103, 105
## $ Hospital      <dbl> 202, 201, 197, 199

Alert List Detection Table

The Alert List API gives you programmatic access to the alert list tables in the ESSENCE user interface. Temporal alert tables based on syndrome definitions are available at the region (or, “county”) and county Federal Information Processing Standards (FIPS) code approximation levels.

The results in these tables are updated a few times daily. Alert lists based on patient location include:

  1. Patient Region - Syndrome: “Region/Syndrome”
  2. Patient FIPS Approximation - Syndrome: “FIPS/Syndrome”
  3. Patient Region - Subsyndrome: “Region/SubSyndrome”
  4. Patient FIPS Approximation - Subsyndrome: “FIPS/SubSyndrome”
  5. Patient Region - CCDD: “Region/CCDD”
  6. Patient FIPS Approximation - CCDD: “FIPS/CCDD”

Alert lists based on facility location include:

  1. Facility Region - Syndrome: “Hospital/Syndrome”
  2. Facility FIPS Approximation - Syndrome: “FacilityFIPS/Syndrome”
  3. Facility FIPS Approximation - Subsyndrome: “FacilityFIPS/SubSyndrome”
  4. Facility FIPS Approximation - CCDD: “FacilityFIPS/CCDD”

Additionally, term-based alerts became available in ESSENCE2 as of July 2021. Examples of pulling word alerts using the Alert List API are presented in the New Functionality Section. The majority of the alert lists only maintain alerts from the last 30 days. If historical data exceeding this time range are pulled, an empty (NULL) data frame will be returned. Note: All users have access to patient and hospital region-level alerts. You will only be able to drill down to live-level data details for alerts occurring in regions from which you have data access.

Patient Region

url <- "https://essence2.syndromicsurveillance.org/nssp_essence/api/alerts/regionSyndromeAlerts?end_date=15Jan2022&start_date=12Jan2022"

# Rnssp option---------------------------------------------------------------------------------------------------
api_data <- myProfile$get_api_data(url) %>%
  pluck("regionSyndromeAlerts")

# keyring option-------------------------------------------------------------------------------------------------
api_response <- GET(url, 
                    authenticate(key_list("essence")[1,2], 
                                 key_get("essence", 
                                 key_list("essence")[1,2])))

api_response_json <- content(api_response, as = "text")
api_data <- fromJSON(api_response_json) %>%
  pluck("regionSyndromeAlerts")

glimpse(api_data)
## Rows: 31,059
## Columns: 12
## $ date                <chr> "2022-01-13", "2022-01-14", "2022-01-15", "2022-01…
## $ datasource          <chr> "va_er", "va_er", "va_er", "va_er", "va_er", "va_e…
## $ age                 <chr> "all", "all", "all", "all", "all", "00-04", "05-17…
## $ sex                 <chr> "all", "all", "all", "all", "all", "all", "all", "…
## $ detector            <chr> "probrepswitch", "probrepswitch", "probrepswitch",…
## $ level               <dbl> 0.0119224359, 0.0004759516, 0.0410813828, 0.040183…
## $ count               <int> 25, 28, 17, 40, 5, 5, 8, 5, 7, 8, 5, 11, 8, 17, 28…
## $ expected            <dbl> 14.42857143, 14.25000000, 14.50000000, 29.57142857…
## $ region              <chr> "AL_Shelby", "AL_Shelby", "AL_Shelby", "AL_Shelby"…
## $ syndrome            <chr> "Neuro", "Neuro", "Neuro", "Injury", "Shk_coma", "…
## $ timeResolution      <chr> "daily", "daily", "daily", "daily", "daily", "dail…
## $ `observed/expected` <dbl> 1.732673, 1.964912, 1.172414, 1.352657, 1.818182, …

Hospital Region

url <- "https://essence2.syndromicsurveillance.org/nssp_essence/api/alerts/hospitalSyndromeAlerts?end_date=15Jan2022&start_date=12Jan2022"

# Rnssp option---------------------------------------------------------------------------------------------------
api_data <- myProfile$get_api_data(url) %>%
  pluck("hospitalSyndromeAlerts")

# keyring option-------------------------------------------------------------------------------------------------
api_response <- GET(url, 
                    authenticate(key_list("essence")[1,2], 
                                 key_get("essence", 
                                 key_list("essence")[1,2])))

api_response_json <- content(api_response, as = "text")
api_data <- fromJSON(api_response_json) %>%
  pluck("hospitalSyndromeAlerts")

glimpse(api_data)
## Rows: 50,027
## Columns: 13
## $ date             <chr> "2022-01-13", "2022-01-15", "2022-01-13", "2022-01-13…
## $ datasource       <chr> "va_hosp", "va_hosp", "va_hosp", "va_hosp", "va_hosp"…
## $ age              <chr> "00-04", "05-17", "45-64", "65-1000", "00-04", "05-17…
## $ sex              <chr> "all", "all", "all", "all", "all", "all", "all", "all…
## $ detector         <chr> "probrepswitch", "probrepswitch", "probrepswitch", "p…
## $ level            <dbl> 0.0351834664, 0.0483190815, 0.0111626098, 0.032078617…
## $ count            <int> 2, 3, 6, 2, 3, 3, 1, 1, 17, 14, 1, 6, 3, 11, 1, 3, 1,…
## $ expected         <dbl> 0.50000000, 1.03571429, 2.07692308, 0.50000000, 0.464…
## $ hospitalName     <chr> "CT-Milford Hospital", "CT-Milford Hospital", "CT-Mid…
## $ regionOfHospital <chr> "CT_New Haven", "CT_New Haven", "CT_New Haven", "CT_N…
## $ syndrome         <chr> "Injury", "Injury", "Bot_Like", "Shk_coma", "GI", "In…
## $ hospital         <chr> "27999", "27999", "27998", "27998", "28000", "28000",…
## $ timeResolution   <chr> "daily", "daily", "daily", "daily", "daily", "daily",…

New Functionality

Pulling Query Field Values (Added November 2021)

Users can now pull values for available query fields in ESSENCE2 via the APIs. As an example, you may want to pull the list of all current CCDD categories, syndromes, and subsyndromes. The Syndrome Subsyndrome CCDD Combined Category query field in ESSENCE2 provides a complete list of all existing syndrome definitions. The following API URL can be used as a template to pull values from other query fields. Metadata will be pulled in JSON format.

url <- "https://essence2.syndromicsurveillance.org/nssp_essence/QueryWizard/ParamMetaData.json?action=getParameterMetaData&datasourceId=va_er&paramName=combinedCategory&parentParamValue=&parentParamName=&filterParamValList="

syndromes <- myProfile$get_api_data(url) %>%
  pluck("valueDisplayFields")
## No encoding supplied: defaulting to UTF-8.
head(syndromes, 10)
##                                           valueField
## 1  a_ccdd_air quality-related respiratory illness v1
## 2                      a_ccdd_all traffic related v1
## 3                      a_ccdd_all traffic related v2
## 4                    a_ccdd_cdc acute hepatitis c v1
## 5         a_ccdd_cdc afm broad v1-limit to pediatric
## 6        a_ccdd_cdc afm narrow v1-limit to pediatric
## 7                              a_ccdd_cdc alcohol v1
## 8                             a_ccdd_cdc all drug v1
## 9                             a_ccdd_cdc all drug v2
## 10    a_ccdd_cdc anxiety disorders (without f419) v1
##                                       displayField
## 1  CCDD Air Quality-related Respiratory Illness v1
## 2                      CCDD All Traffic Related v1
## 3                      CCDD All Traffic Related v2
## 4                    CCDD CDC Acute Hepatitis C v1
## 5         CCDD CDC AFM Broad v1-Limit to Pediatric
## 6        CCDD CDC AFM Narrow v1-Limit to Pediatric
## 7                              CCDD CDC Alcohol v1
## 8                             CCDD CDC All Drug v1
## 9                             CCDD CDC All Drug v2
## 10    CCDD CDC Anxiety Disorders (without F419) v1

Word Alerts (Added July 2021)

Term-based alerts are available in ESSENCE2. This algorithm was developed to identify unusual distributions of chief complaint terms of interest without dependence on syndrome definitions. Technical details of the word alert algorithm can be found at https://essence2.syndromicsurveillance.org/nssp_essence/usersguide/algorithms/TermBasedAlerts.jsp. You can pull word alerts from ESSENCE2 via the Alert List API. Term alert API URLs need to be defined in RStudio and are not populated in the ESSENCE2 user interface. This API requires the following parameters:

  • geo_system: region, facility, or regionFacility
  • start_date: start date in ddMMMyyy format
  • end_date: end date in ddMMMyyy format

Optional query parameters include:

  • filters: regions or facilities to limit to (defaults to all if not specified)
  • show_stop_words: Boolean indicator of whether or not standard stop words should be removed (false by default)
  • show_syndromic_words: Boolean indicator of whether or not to show syndromic terms used in syndrome definition queries (false by default)
  • show_ignored_words: Boolean indicator of whether or not ignored words should be removed (false by default).

NSSP staff with admin access will be able to add and manage additional requested stop words in a list of “ignored” terms. This list will be modified over time to optimize the identification of informative terms and word pairs.

An example of an API URL only including required parameters is shown below. Fields in the corresponding alert table include term ID, date of the alert, data source ID and name, geography system, region (or “county”), anomalous term or word pair, detector algorithm, alert color ID (red = 3), frequency of occurrence, and expected values based on the 30-day baseline used. Note: Term-based alerts are only available for data from the last 7 days.

url <- "https://essence2.syndromicsurveillance.org/nssp_essence/api/alerts/wordAlerts?geo_system=region&start_date=21Jan2022&end_date=21Jan2022"

# Rnssp option---------------------------------------------------------------------------------------------------
api_data <- myProfile$get_api_data(url) %>%
  pluck("termAlerts")

# keyring option-------------------------------------------------------------------------------------------------
api_response <- GET(url, 
                    authenticate(key_list("essence")[1,2], 
                                 key_get("essence", 
                                 key_list("essence")[1,2])))

api_response_json <- content(api_response, as = "text")
api_data <- fromJSON(api_response_json) %>%
  pluck("termAlerts")

glimpse(api_data)
## Rows: 1,591
## Columns: 13
## $ id              <int> 6, 8, 16, 37, 39, 50, 54, 58, 61, 71, 75, 90, 99, 112,…
## $ date            <chr> "01/21/2022", "01/21/2022", "01/21/2022", "01/21/2022"…
## $ timeBlock       <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
## $ datasource      <chr> "va_er", "va_er", "va_er", "va_er", "va_er", "va_er", …
## $ datasourceName  <chr> "Patient Location (Full Details)", "Patient Location (…
## $ geographySystem <chr> "Region", "Region", "Region", "Region", "Region", "Reg…
## $ region          <chr> "AK_Bethel", "AK_Bethel", "AK_Bethel", "AK_Bethel", "A…
## $ term            <chr> "DISTRESS TRIAGE", "DISTRESS", "EMERGENCY ROOM", "FEMA…
## $ detector        <chr> "fishersexacttest", "fishersexacttest", "fishersexactt…
## $ level           <dbl> 2.650804e-07, 3.819702e-06, 8.166786e-14, 2.235822e-07…
## $ color           <dbl> 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, …
## $ count           <dbl> 6, 8, 19, 9, 8, 26, 23, 24, 23, 4, 4, 4, 4, 4, 4, 4, 1…
## $ expected        <dbl> 0.14564831, 0.71556351, 1.34707158, 0.64962460, 0.3991…

This second example demonstrates how users should form the URL with optional parameters; in this case example, the parameters filter to Fairfax County, VA, and include syndromic terms.

url <- "https://essence2.syndromicsurveillance.org/nssp_essence/api/alerts/wordAlerts?geo_system=region&start_date=21Jan2022&end_date=21Jan2022&filters=va_fairfax_county&show_syndromic_words=true"

# Rnssp option----------------------------------------------------------------------------------------------------------
api_data <- myProfile$get_api_data(url) %>%
  pluck("termAlerts")

# keyring option--------------------------------------------------------------------------------------------------------
api_response <- GET(url, 
                    authenticate(key_list("essence")[1,2], 
                                 key_get("essence", 
                                 key_list("essence")[1,2])))

api_response_json <- content(api_response, as = "text")
api_data <- fromJSON(api_response_json) %>%
  pluck("termAlerts")

glimpse(api_data)
## Rows: 3
## Columns: 13
## $ id              <int> 17949, 17967, 17988
## $ date            <chr> "01/21/2022", "01/21/2022", "01/21/2022"
## $ timeBlock       <lgl> NA, NA, NA
## $ datasource      <chr> "va_er", "va_er", "va_er"
## $ datasourceName  <chr> "Patient Location (Full Details)", "Patient Location (…
## $ geographySystem <chr> "Region", "Region", "Region"
## $ region          <chr> "VA_Fairfax_County", "VA_Fairfax_County", "VA_Fairfax_…
## $ term            <chr> "URINARY", "PAIN", "LEFT"
## $ detector        <chr> "fishersexacttest", "fishersexacttest", "fishersexactt…
## $ level           <dbl> 8.171744e-06, 1.446767e-10, 1.368669e-07
## $ color           <dbl> 3, 3, 3
## $ count           <dbl> 30, 261, 52
## $ expected        <dbl> 11.61986, 161.80249, 22.28370

Time Series Data Table with Stratified Alerts (Added August 2020)

Before this update, there was not an efficient way of pulling in daily stratified alerts. This update gave users the ability to pull historic alerts across stratifications in a long, tabular format. This functionality is only available from ESSENCE2: https://essence2.syndromicsurveillance.org/. For example, a user could choose multiple CCDD categories, Has been Emergency = “Yes”, CCDD Category for “As Percent Parameter”, and within the time series interface choose a geography level such as Hospital HHS Region for “Across Graphs Stratification” and CCDD Category for “Within Graph Stratification”. After selecting these configurations, the corresponding API URL will populate the API URL box under the “Query Options” drop down menu. Note: There is no need to select the “Update” button in the user interface to generate the stratified time series or to build the time series data table because the API URL is populated immediately. Additionally, if “As Percent Parameter” is specified, the data pulled into RStudio will contain p-values and alert indicators specific to both counts and percentages. Indicators specific to counts are specified with “_dataCount” tags in the column names.

url <- "https://essence2.syndromicsurveillance.org/nssp_essence/api/timeSeries?endDate=15Jan2022&ccddCategory=cdc%20pneumonia%20ccdd%20v1&ccddCategory=cdc%20coronavirus-dd%20v1&ccddCategory=cli%20cc%20with%20cli%20dd%20and%20coronavirus%20dd%20v2&percentParam=ccddCategory&geographySystem=hospitaldhhsregion&datasource=va_hospdreg&detector=probrepswitch&startDate=23Oct2021&timeResolution=daily&hasBeenE=1&medicalGroupingSystem=essencesyndromes&userId=2362&aqtTarget=TimeSeries&stratVal=ccddCategory&multiStratVal=geography&graphOnly=true&numSeries=3&graphOptions=multipleSmall&seriesPerYear=false&nonZeroComposite=false&removeZeroSeries=true&startMonth=January&stratVal=ccddCategory&multiStratVal=geography&graphOnly=true&numSeries=3&graphOptions=multipleSmall&seriesPerYear=false&startMonth=January&nonZeroComposite=false"

# Rnssp option----------------------------------------------------------------------------------------------------------
api_data <- myProfile$get_api_data(url) %>%
  pluck("timeSeriesData")
## No encoding supplied: defaulting to UTF-8.
# keyring option--------------------------------------------------------------------------------------------------------
api_response <- GET(url, 
                    authenticate(key_list("essence")[1,2], 
                                 key_get("essence", 
                                 key_list("essence")[1,2])))

api_response_json <- content(api_response, as = "text")
## No encoding supplied: defaulting to UTF-8.
api_data <- fromJSON(api_response_json) %>%
  pluck("timeSeriesData")

glimpse(api_data)
## Rows: 2,550
## Columns: 21
## $ date                       <chr> "2021-10-23", "2021-10-24", "2021-10-25", "…
## $ count                      <dbl> 1.652523, 1.602546, 1.660083, 1.825474, 1.8…
## $ expected                   <chr> "1.67", "1.668", "1.675", "1.679", "1.679",…
## $ levels                     <chr> "0.447", "0.503", "0.515", "0.405", "0.39",…
## $ colorID                    <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ color                      <chr> "blue", "blue", "blue", "blue", "blue", "bl…
## $ altText                    <chr> "Data: Date: 23Oct21, Level: 0.447, Count: …
## $ details                    <chr> "/nssp_essence/servlet/DataDetailsServlet?g…
## $ graphType                  <chr> "percent", "percent", "percent", "percent",…
## $ dataCount                  <dbl> 296, 287, 353, 355, 342, 314, 342, 288, 331…
## $ expected_dataCount         <dbl> 339.7500, 338.8571, 340.1429, 340.4286, 339…
## $ levels_dataCount           <dbl> 0.655724816, 0.903218152, 0.424366841, 0.34…
## $ colorID_dataCount          <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ color_dataCount            <chr> "blue", "blue", "blue", "blue", "blue", "bl…
## $ allCount                   <dbl> 17912, 17909, 21264, 19447, 18993, 19075, 1…
## $ lineLabel                  <chr> "CDC Pneumonia CCDD v1 - Region 1", "CDC Pn…
## $ title                      <chr> "CDC Pneumonia CCDD v1 - Region 1", "CDC Pn…
## $ ccddCategory_id            <chr> "CDC Pneumonia CCDD v1", "CDC Pneumonia CCD…
## $ ccddCategory_display       <chr> "CDC Pneumonia CCDD v1", "CDC Pneumonia CCD…
## $ hospitaldhhsregion_id      <chr> "Region I", "Region I", "Region I", "Region…
## $ hospitaldhhsregion_display <chr> "Region 1", "Region 1", "Region 1", "Region…
names(api_data)
##  [1] "date"                       "count"                     
##  [3] "expected"                   "levels"                    
##  [5] "colorID"                    "color"                     
##  [7] "altText"                    "details"                   
##  [9] "graphType"                  "dataCount"                 
## [11] "expected_dataCount"         "levels_dataCount"          
## [13] "colorID_dataCount"          "color_dataCount"           
## [15] "allCount"                   "lineLabel"                 
## [17] "title"                      "ccddCategory_id"           
## [19] "ccddCategory_display"       "hospitaldhhsregion_id"     
## [21] "hospitaldhhsregion_display"

A benefit of pulling the data and alerts in this manner is that you can create customized figures with ggplot or plotly that can be incorporated into static or interactive R Markdown reports:

hhs_region_data <- api_data %>%
  select(
    date, 
    hhs_region = hospitaldhhsregion_display, 
    ccdd_category = ccddCategory_display, 
    percent = count, 
    color
  ) %>%
  mutate(
    date = as.Date(date),
    hhs_region = factor(hhs_region, levels = c("Region 1", "Region 2", "Region 3", "Region 4", "Region 5", 
                                               "Region 6", "Region 7", "Region 8", "Region 9", "Region 10"))
    ) %>%
  filter(ccdd_category == "CLI CC with CLI DD and Coronavirus DD v2") %>%
  arrange(date, hhs_region) 

ggplot(hhs_region_data, aes(x = date, y = percent)) + 
  geom_line(size = 0.7, color = "#046C9A") + 
  geom_point(data = subset(hhs_region_data, color == "red"), color = "red", size = 0.5) +
  geom_point(data = subset(hhs_region_data, color == "yellow"), color = "yellow", size = 0.5) + 
  theme_bw() + 
  labs(title = "CLI v2 by HHS Region", 
       x = "Date", 
       y = "Percent of ED Visits") + 
  facet_wrap(facets = ~hhs_region, nrow = 2) 

Capability of Stratifying by FIPS Code (Added July 2020)

ESSENCE2 includes facility county FIPS and patient county FIPS as available query fields (both are technically approximations since ESSENCE regions are populated by ZIP codes). Users may choose FIPS codes as a row (or column) field in the table builder. The following example assumes that a user has chosen the Facility Location (Full Details) data source, the CDC Coronavirus-DD v1, CDC Pneumonia CCDD v1, and Coronavirus-like illness (CLI) CC with CLI DD and Coronavirus DD v2 CCDD categories, “Yes” for “Has Been Emergency”, “CC and DD Category” for “As Percent Query”, and all counties within their state for Facility County FIPS Approximation. By selecting Date and Facility County FIPS Approximation for row fields and CC and DD Category for column fields, the API URL generated in the user interface will have the following structure:

url <- "https://essence2.syndromicsurveillance.org/nssp_essence/api/tableBuilder/csv?endDate=15Jan2022&facilityfips=...&percentParam=ccddCategory&datasource=va_hosp&startDate=23Oct2021&medicalGroupingSystem=essencesyndromes&userId=2362&aqtTarget=TableBuilder&ccddCategory=cdc%20coronavirus-dd%20v1&ccddCategory=cdc%20pneumonia%20ccdd%20v1&ccddCategory=cli%20cc%20with%20cli%20dd%20and%20coronavirus%20dd%20v2&geographySystem=hospital&detector=nodetectordetector&timeResolution=daily&hasBeenE=1&rowFields=timeResolution&rowFields=facilityfips&columnField=ccddCategory"

After the specifying endDate, all facility FIPS codes will be defined with the following syntax: “&facilityfips=fipscode1&facilityfips=fipscode2&…&facilityfips=fipscodeN&”. Note: Currently, users need to manually insert “&refValues=false” after specifying facilityfips as a row field in order to pull in the actual codes instead of the county names. Define this URL and API pull as follows:

url <- "https://essence2.syndromicsurveillance.org/nssp_essence/api/tableBuilder/csv?endDate=15Jan2022&facilityfips=...&percentParam=ccddCategory&datasource=va_hosp&startDate=23Oct2021&medicalGroupingSystem=essencesyndromes&userId=2362&aqtTarget=TableBuilder&ccddCategory=cdc%20coronavirus-dd%20v1&ccddCategory=cdc%20pneumonia%20ccdd%20v1&ccddCategory=cli%20cc%20with%20cli%20dd%20and%20coronavirus%20dd%20v2&geographySystem=hospital&detector=nodetectordetector&timeResolution=daily&hasBeenE=1&rowFields=timeResolution&rowFields=facilityfips&refValues=false&columnField=ccddCategory"

# Rnssp option----------------------------------------------------------------------------------------------------------
api_data <- myProfile$get_api_data(url, fromCSV = TRUE)

# keyring option--------------------------------------------------------------------------------------------------------
api_response <- GET(url, 
                    authenticate(key_list("essence")[1,2], 
                                 key_get("essence", 
                                 key_list("essence")[1,2])))

api_response_csv <- content(api_response, by = "csv/text")
api_data <- read_csv(api_response_csv)

Tips and Tricks

ESSENCE API URL Length

Occasionally, the API URL you created for the ESSENCE query will be very, VERY long. For example, you might have reason to explicitly include all facilities, all counties, or all ZIP codes for a site. In this situation, the character length of your URL might be too long to assign to the url <- object as shown in the preceding examples. When this occurs, you can split the URL into two or more strings when creating objects, and then pull them together later. In the code chunk shown below, we start with one long URL (use your imagination here) and break it into two pieces. Then, to create the object URL, we join them using the paste0() function. Unlike the paste() function, paste0() does not separate the combined character strings with a space. This final URL can be passed to ESSENCE along with your credentials to return your results. As a rule of thumb, do not exceed 20 lines of characters per URL.

url1 <- "https://essence.syndromicsurveillance.org/nssp_essence/api/very_very_very_long_URL_ver_long_use_your_imagination_here...."
url2 <- "still_going_even_longer_here..........."
url3 <- paste0(url1, url2)

# Resulting URL
print(url)
## [1] "https://essence2.syndromicsurveillance.org/nssp_essence/api/timeSeries?endDate=15Jan2022&ccddCategory=cdc%20pneumonia%20ccdd%20v1&ccddCategory=cdc%20coronavirus-dd%20v1&ccddCategory=cli%20cc%20with%20cli%20dd%20and%20coronavirus%20dd%20v2&percentParam=ccddCategory&geographySystem=hospitaldhhsregion&datasource=va_hospdreg&detector=probrepswitch&startDate=23Oct2021&timeResolution=daily&hasBeenE=1&medicalGroupingSystem=essencesyndromes&userId=2362&aqtTarget=TimeSeries&stratVal=ccddCategory&multiStratVal=geography&graphOnly=true&numSeries=3&graphOptions=multipleSmall&seriesPerYear=false&nonZeroComposite=false&removeZeroSeries=true&startMonth=January&stratVal=ccddCategory&multiStratVal=geography&graphOnly=true&numSeries=3&graphOptions=multipleSmall&seriesPerYear=false&startMonth=January&nonZeroComposite=false"

Dynamically Set Start and End Dates

For reports run weekly or daily, you can automate the start and end dates rather than change the dates in the API URL manually before knitting. There are multiple ways to do this. You may split the URL into three pieces in a similar fashion to how the URL in the previous example was split. Or you may use str_extract() and str_replace() to substitute the appropriate dates. For example, if the report is based on the most recent 90 days, the start and end date can be auto-determined by using base R’s Sys.Date() and format() to ensure appropriate date formatting. format(Sys.Date(), "%d%b%Y") will give today’s date, 21Jan2022, while format(Sys.Date() - 90, %d%b%Y") will give the start date of the recent 90 day period, 23Oct2021. You can insert the dates by splitting the URL can be split into three pieces and then pasting back together:

endDate <- format(Sys.Date(), "%d%b%Y")
startDate <- format(Sys.Date()- 90, "%d%b%Y")

url1 <- "https://essence.syndromicsurveillance.org/nssp_essence/api/timeSeries/graph?"
url2 <- paste0("endDate=", endDate, "&medicalGrouping=injury&percentParam=noPercent&geographySystem=hospitaldhhsregion&datasource=va_hospdreg&detector=probrepswitch&")
url3 <- paste0("startDate=", startDate, "&timeResolution=daily&medicalGroupingSystem=essencesyndromes&userId=455&aqtTarget=TimeSeries&graphTitle=National%20-%20Injury%20Syndrome%20Daily%20Counts&xAxisLabel=Date&yAxisLabel=Count")
url <- paste0(url1, url2, url3)

# Rnssp option----------------------------------------------------------------------------------------------------------
api_png <- myProfile$get_api_tsgraph(url)

knitr::include_graphics(api_png$tsgraph)

# keyring option--------------------------------------------------------------------------------------------------------
api_response <- GET(url, 
                    authenticate(key_list("essence")[1,2], 
                                 key_get("essence", 
                                 key_list("essence")[1,2])),
                    write_disk("timeseries3.png", overwrite = TRUE))

knitr::include_graphics("timeseries3.png")

Additionally, the URL start and end dates can remained fixed by setting up the code to simply extract and replace the old dates with new dates. The URL results will be the same.

url <- "https://essence.syndromicsurveillance.org/nssp_essence/api/timeSeries/graph?endDate=30Jun2021&medicalGrouping=injury&percentParam=noPercent&geographySystem=hospitaldhhsregion&datasource=va_hospdreg&detector=probrepswitch&startDate=1Jun2021&timeResolution=daily&medicalGroupingSystem=essencesyndromes&userId=455&aqtTarget=TimeSeries&graphTitle=National%20-%20Injury%20Syndrome%20Daily%20Counts&xAxisLabel=Date&yAxisLabel=Count"
  
endDateOld <- regmatches(url, regexpr('endDate=.+?&', url))
endDateOld <- str_extract(endDateOld, "[0-9]{1,2}[A-Z|a-z]{3}[0-9]{2,4}")
endDateNew <- format(Sys.Date(), "%d%b%Y")

startDateOld <- regmatches(url, regexpr("startDate=.+?&", url))
startDateOld <- str_extract(startDateOld, "[0-9]{1,2}[A-Z|a-z]{3}[0-9]{2,4}")
startDateNew <- format(Sys.Date() - 90, "%")

url <- str_replace(url, endDateOld, endDateNew)
url <- str_replace(url, startDateOld, startDateNew)

url
## [1] "https://essence.syndromicsurveillance.org/nssp_essence/api/timeSeries/graph?endDate=26Jan2022&medicalGrouping=injury&percentParam=noPercent&geographySystem=hospitaldhhsregion&datasource=va_hospdreg&detector=probrepswitch&startDate=%&timeResolution=daily&medicalGroupingSystem=essencesyndromes&userId=455&aqtTarget=TimeSeries&graphTitle=National%20-%20Injury%20Syndrome%20Daily%20Counts&xAxisLabel=Date&yAxisLabel=Count"

Additional Resources

The preceding examples will help you pull data into your RStudio environment, but the next steps are really up to you. If you are unfamiliar with R and RStudio, here are some open-source resources to move your analysis forward.