Nothing
#' @export
#'
#' @title Daily counts of values at or above a threshold
#'
#' @param monitor \emph{mts_monitor} object.
#' @param threshold AQI level name (e.g. \code{"unhealthy"}) or numerical
#' threshold at and above which a measurement is counted.
#' @param na.rm Logical value indicating whether NA values should be ignored.
#' @param minHours Minimum number of valid hourly records per day required to
#' calculate statistics. Days with fewer valid records will be assigned \code{NA}.
#' @param dayBoundary Treatment of daylight savings time: "clock" uses daylight
#' savings time as defined in the local timezone, "LST" uses "local standard time"
#' all year round.
#' @param NAAQS Version of NAAQS levels to use. See Note.
#'
#' @return A \emph{mts_monitor} object containing daily counts of hours at or above
#' a threshold value. (A list with
#' \code{meta} and \code{data} dataframes.)
#'
#' @description
#' Calculates the number of hours per day each time series in \code{monitor} was
#' at or above a given threshold.
#'
#' Because the returned \emph{mts_monitor} object is defined on a daily axis in a
#' specific time zone, it is important that the incoming \code{monitor} contain
#' only timeseries within a single time zone.
#'
#' @note
#' When \code{dayBoundary = "clock"}, the returned \code{monitor$data$datetime}
#' time axis will be defined in the local timezone (not "UTC") with days defined
#' by midnight as it appears on a clock in that timezone. The transition from
#' DST to standard time will result in a 23 hour day and standard to DST in a
#' 25 hour day.
#'
#' When \code{dayBoundary = "LST"}, the returned \code{monitor$data$datetime}
#' time axis will be defined in "UTC" with times as they \emph{appear} in standard
#' time in the local timezone. These days will be one hour off from clock
#' time during DST but every day will consist of 24 hours.
#'
#' @note
#' On February 7, 2024, EPA strengthened the National Ambient Air Quality
#' Standards for Particulate Matter (PM NAAQS) to protect millions of Americans
#' from harmful and costly health impacts, such as heart attacks and premature
#' death. Particle or soot pollution is one of the most dangerous forms of air
#' pollution, and an extensive body of science links it to a range of serious
#' and sometimes deadly illnesses. EPA is setting the level of the primary
#' (health-based) annual PM2.5 standard at 9.0 micrograms per cubic meter to
#' provide increased public health protection, consistent with the available
#' health science.
#' See \href{https://www.epa.gov/pm-pollution/final-reconsideration-national-ambient-air-quality-standards-particulate-matter-pm}{PM NAAQS update}.
#'
#' @examples
#' library(AirMonitor)
#'
#'# Hours at MODERATE or above
#' Carmel_Valley %>%
#' monitor_dailyThreshold("Moderate") %>%
#' monitor_getData()
#'
#' # Hours at MODERATE or above with the 2024 updated NAAQS
#' Carmel_Valley %>%
#' monitor_dailyThreshold("Moderate", NAAQS = "PM2.5_2024") %>%
#' monitor_getData()
#'
#'# Hours at UNHEALTHY or above
#' Carmel_Valley %>%
#' monitor_dailyThreshold("Unhealthy") %>%
#' monitor_getData()
#'
monitor_dailyThreshold <- function(
monitor = NULL,
threshold = NULL,
na.rm = TRUE,
minHours = 18,
dayBoundary = c("clock", "LST"),
NAAQS = c("PM2.5", "PM2.5_2024")
) {
# ----- Validate parameters --------------------------------------------------
MazamaCoreUtils::stopIfNull(monitor)
MazamaCoreUtils::stopIfNull(threshold)
na.rm <- MazamaCoreUtils::setIfNull(na.rm, TRUE)
MazamaCoreUtils::stopIfNull(minHours)
dayBoundary <- match.arg(dayBoundary)
NAAQS = match.arg(NAAQS)
if ( length(unique(monitor$meta$timezone)) > 1 )
stop("'monitor' has muliple timezones")
# Check if official AQI level name is provided
if ( typeof(threshold) == "character" ) {
if ( !tolower(threshold) %in% tolower(US_AQI$names_eng) )
stop(sprintf("'%s' is not a recognized AQI level. Please use one from US_AQI$names_eng.", threshold))
breaks <- US_AQI$breaks_PM2.5
# Handle the added NAAQS argument
if ( NAAQS == "PM2.5_2024" ) {
breaks <- US_AQI$breaks_PM2.5_2024
}
breaks[1] <- 0
index <- which(tolower(US_AQI$names_eng) == tolower(threshold))
threshold <- breaks[index]
}
# ----- Create threshold count -----------------------------------------------
# Threshold function
myFUN <- function(
x,
threshold,
na.rm = TRUE
) {
return(sum(x >= threshold, na.rm = na.rm))
}
# Use monitor_dailyStatistic to calculate counts
overThreshold <- monitor_dailyStatistic(
monitor = monitor,
FUN = myFUN,
na.rm = na.rm,
threshold = threshold,
minHours = minHours,
dayBoundary = dayBoundary
)
# ----- Return ---------------------------------------------------------------
return(overThreshold)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.