├── R ├── raqdm.R ├── getAQDMavailable.R ├── setAQDMuser.R ├── getAQDMrequest.R ├── setAQDMdefaults.R ├── getAQDMlist.R ├── getAQDMdata.R ├── variables.R ├── misc.R └── openAQDMgui.R ├── .Rbuildignore ├── .gitignore ├── inst ├── defaults.rda └── tests │ ├── test.R │ ├── tcltk.R │ └── openAQDMgui.R ├── NAMESPACE ├── raqdm.Rproj ├── DESCRIPTION ├── man ├── setAQDMuser.Rd ├── getAQDMrequest.Rd ├── getAQDMlist.Rd ├── openAQDMgui.Rd ├── setAQDMdefaults.Rd ├── getAQDMdata.Rd └── AQDM-Variables.Rd └── README.md /R/raqdm.R: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | -------------------------------------------------------------------------------- /inst/defaults.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebailey78/raqdm/HEAD/inst/defaults.rda -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2 (4.1.1): do not edit by hand 2 | 3 | S3method(print,AQDMrequest) 4 | export(getAQDMdata) 5 | export(getAQDMlist) 6 | export(getAQDMrequest) 7 | export(openAQDMgui) 8 | export(setAQDMdefaults) 9 | export(setAQDMuser) 10 | -------------------------------------------------------------------------------- /inst/tests/test.R: -------------------------------------------------------------------------------- 1 | setAQDMdefaults(user = "ebailey@idem.in.gov", pw = "bolefox64", param = 44201, state = "18", county = "89", bdate=as.Date('2013-01-01'), edate='20131231', save = TRUE) 2 | 3 | request <- getAQDMdata(format = "AQS") 4 | y <- getAQDMrequest(request, stringsAsFactors = FALSE) 5 | -------------------------------------------------------------------------------- /raqdm.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | BuildType: Package 16 | PackageUseDevtools: Yes 17 | PackageInstallArgs: --no-multiarch --with-keep.source 18 | PackageCheckArgs: --as-cran 19 | PackageRoxygenize: rd,namespace 20 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: raqdm 2 | Type: Package 3 | Title: Access data from U.S. EPA's Air Quality Data Mart in R 4 | Version: 0.1 5 | Date: 2015-04-02 6 | Author: Who wrote it 7 | Maintainer: Eric Bailey 8 | Imports: 9 | httr, 10 | tcltk 11 | Description: Provides a direct interface to U.S. EPA's Air Quality Data Mart in R. 12 | Import data directly from EPA into R for further analysis. Requires a username 13 | and passward from EPA. 14 | License: GPL-3 15 | -------------------------------------------------------------------------------- /R/getAQDMavailable.R: -------------------------------------------------------------------------------- 1 | # #'getAQDMavailable 2 | # #' 3 | # #'A function to check the availability of EPA's AQDM web service 4 | # #' 5 | # #'@details 6 | # #'Makes use of AQDM's serviceAvailable service to check the status of AQDM. 7 | # #' 8 | # #'@return 9 | # #'Returns \code{TRUE} if the service reports READY, otherwise returns \code{FALSE}. 10 | # #'@examples 11 | # #'if(getAQDMavailable()) print("The service is available!") 12 | # #'@export 13 | # getAQDMavailable <- function() { 14 | # x <- httr::content(httr::GET(paste0(baseURL, "serviceAvailable"))) 15 | # return(grepl("^READY", x)) 16 | # } -------------------------------------------------------------------------------- /man/setAQDMuser.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/setAQDMuser.R 3 | \name{setAQDMuser} 4 | \alias{setAQDMuser} 5 | \title{setAQDMuser} 6 | \usage{ 7 | setAQDMuser(username, password, save = FALSE) 8 | } 9 | \arguments{ 10 | \item{username}{Your AQDM username (your email address)} 11 | 12 | \item{password}{Your AQDM password} 13 | 14 | \item{save}{\code{logical} Should the username/password be saved for future sessions?} 15 | } 16 | \value{ 17 | This function returns \code{TRUE} invisibly if there are no problems. 18 | } 19 | \description{ 20 | Convienince function for setting your username and password for accessing the 21 | Air Quality Data Mart. 22 | } 23 | \details{ 24 | You can set user and pw from the \code{\link{setAQDMdefaults}} function also. 25 | } 26 | \examples{ 27 | setAQDMuser("fake@email.com", "pass123") 28 | } 29 | \seealso{ 30 | \href{http://www.epa.gov/airdata/toc.html}{Query Air Data (QAD) User's Guide} 31 | } 32 | 33 | -------------------------------------------------------------------------------- /man/getAQDMrequest.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/getAQDMrequest.R 3 | \name{getAQDMrequest} 4 | \alias{getAQDMrequest} 5 | \title{getAQDMrequest} 6 | \usage{ 7 | getAQDMrequest(request, ...) 8 | } 9 | \arguments{ 10 | \item{request}{an object of the type \code{AQDMrequest} produced by \code{\link{getAQDMdata}}.} 11 | 12 | \item{\dots}{Additional arguments to be passed to \code{\link{read.table}}.} 13 | } 14 | \value{ 15 | A data.frame containing the data requested by \code{\link{getAQDMdata}}. 16 | } 17 | \description{ 18 | Retrieve a data.frame requested with \code{getAQDMdata(synchronous = FALSE)} 19 | } 20 | \examples{ 21 | \dontrun{ 22 | # Send a request to AQDM 23 | x <- getAQDMdata(user = "me@email.com", pw = "abc123", param = "44201", 24 | state = 18, county = 89, bdate = "20140101", 25 | edate = "20141231") 26 | 27 | # Once you get an email for EPA saying the data is ready: 28 | df <- getAQDMrequest(x) 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /R/setAQDMuser.R: -------------------------------------------------------------------------------- 1 | #'setAQDMuser 2 | #' 3 | #'Convienince function for setting your username and password for accessing the 4 | #'Air Quality Data Mart. 5 | #' 6 | #'@param username Your AQDM username (your email address) 7 | #'@param password Your AQDM password 8 | #'@param save \code{logical} Should the username/password be saved for future sessions? 9 | #' 10 | #'@details 11 | #'You can set user and pw from the \code{\link{setAQDMdefaults}} function also. 12 | #' 13 | #'@return 14 | #'This function returns \code{TRUE} invisibly if there are no problems. 15 | #' 16 | #'@examples 17 | #' setAQDMuser("fake@@email.com", "pass123") 18 | #' 19 | #'@seealso 20 | #' \href{http://www.epa.gov/airdata/toc.html}{Query Air Data (QAD) User's Guide} 21 | #' 22 | #'@export 23 | setAQDMuser <- function(username, password, save = FALSE) { 24 | 25 | aqdmDefaults <- getOption("raqdmOptions") 26 | 27 | aqdmDefaults$user <- username 28 | aqdmDefaults$pw <- password 29 | 30 | if(save) { 31 | save(aqdmDefaults, file = defaultsPath) 32 | } 33 | 34 | options(raqdmOptions = aqdmDefaults) 35 | 36 | message("\nAQDM user information set for ", username, ".") 37 | 38 | return(invisible(TRUE)) 39 | 40 | } 41 | 42 | -------------------------------------------------------------------------------- /man/getAQDMlist.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/getAQDMlist.R 3 | \name{getAQDMlist} 4 | \alias{getAQDMlist} 5 | \title{getAQDMlist} 6 | \usage{ 7 | getAQDMlist(name, ...) 8 | } 9 | \arguments{ 10 | \item{name}{The name of the variable for which you want the list of valid values.} 11 | 12 | \item{\dots}{name/value pairs for subsetting the requested data. (See details)} 13 | } 14 | \value{ 15 | Returns a \code{data.frame} with 2 columns. The first column contains the valide code, the 16 | second column contains a description of that code. 17 | } 18 | \description{ 19 | Function for request a list of valid values for a given parameter from 20 | U.S. EPA's Air Quality Data Mart. 21 | } 22 | \details{ 23 | If the variable requires other variables when querying for data you must provide 24 | those other variables to \code{getAQDMlist} as well. (e.g., you must provide a \code{state} 25 | code if \code{name = 'county'}. 26 | } 27 | \examples{ 28 | \dontrun{ 29 | #Get a data.frame of counties in Indiana 30 | counties <- getAQDMlist("county", state = "18") 31 | 32 | #Get a list of criteria pollutants 33 | crit <- getAQDMlist("param", pc = "CRITERIA") 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /R/getAQDMrequest.R: -------------------------------------------------------------------------------- 1 | #'getAQDMrequest 2 | #' 3 | #'Retrieve a data.frame requested with \code{getAQDMdata(synchronous = FALSE)} 4 | #' 5 | #'@param request an object of the type \code{AQDMrequest} produced by \code{\link{getAQDMdata}}. 6 | #'@param \dots Additional arguments to be passed to \code{\link{read.table}}. 7 | #' 8 | #'@return 9 | #' A data.frame containing the data requested by \code{\link{getAQDMdata}}. 10 | #' 11 | #'@examples 12 | #'\dontrun{ 13 | #' # Send a request to AQDM 14 | #' x <- getAQDMdata(user = "me@@email.com", pw = "abc123", param = "44201", 15 | #' state = 18, county = 89, bdate = "20140101", 16 | #' edate = "20141231") 17 | #' 18 | #' # Once you get an email for EPA saying the data is ready: 19 | #' df <- getAQDMrequest(x) 20 | #'} 21 | #'@export 22 | getAQDMrequest <- function(request, ...) { 23 | 24 | if(class(request) != "AQDMrequest") { 25 | stop("You must provide an 'AQDMrequest' object.") 26 | } 27 | 28 | URL <- paste0(baseURL, "retrieve?id=", request$requestID) 29 | 30 | tf <- tempfile() 31 | if(class(try(download.file(URL, tf, quiet = TRUE), silent = TRUE)) != "try-error") { 32 | 33 | return(readFile(tf, request$format)) 34 | 35 | } else { 36 | warning("Data not available yet. Try again shortly, or wait for an email from aqdmrs@epa.gov.") 37 | return(invisible(FALSE)) 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /man/openAQDMgui.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/openAQDMgui.R 3 | \name{openAQDMgui} 4 | \alias{openAQDMgui} 5 | \title{openAQDMgui} 6 | \usage{ 7 | openAQDMgui() 8 | } 9 | \value{ 10 | The returned value depends on selections made by the user. 11 | 12 | If request type is asynchronous 13 | and the "Request Data" button is clicked, an \code{AQDMrequest} object will be returned (See 14 | \code{\link{getAQDMrequest}}). 15 | 16 | If request type is synchronous and the "Request Data" button is clicked, 17 | the requested data.frame will be returned once it is returned from the server. 18 | (currently disabled by EPA). 19 | 20 | If the "Set Defaults" button in clicked, \code{NULL} will be returned invisibly, and 21 | \code{\link{setAQDMdefaults}} will be run with the selected values. 22 | 23 | If the "Copy Function" button is clicked, a character vector of length one will be returned 24 | container the text of a function that would make the selected request. 25 | 26 | If the dialog is canceled in any way, \code{NULL} will be returned invisibly. 27 | } 28 | \description{ 29 | Open a simple GUI to facilitate requesting data from U.S. EPA's Air Quality 30 | Data Mart 31 | } 32 | \details{ 33 | \code{openAQDMgui} opens a dialog that the user can use to manipulate the variables 34 | needed to request data from AQDM. 35 | } 36 | \examples{ 37 | \dontrun{ 38 | x <- openAQDMgui() 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /man/setAQDMdefaults.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/setAQDMdefaults.R 3 | \name{setAQDMdefaults} 4 | \alias{setAQDMdefaults} 5 | \title{setAQDMdefaults} 6 | \usage{ 7 | setAQDMdefaults(..., save = TRUE) 8 | } 9 | \arguments{ 10 | \item{save}{\code{logical} Should the username/password be saved for future sessions?} 11 | 12 | \item{\dots}{name/value pairs for querying AQDM (See \link{AQDM Variables})} 13 | } 14 | \value{ 15 | This function returns \code{TRUE} invisibly if there are no problems. 16 | } 17 | \description{ 18 | Convienince function for setting default values for querying the Air Quality 19 | Data Mart. 20 | } 21 | \details{ 22 | \code{raqdm} creates an R option called \code{raqdmOptions}. This holds a list of 23 | default values for query parameters passed to \code{\link{getAQDMdata}}. You can 24 | use this function to set default values so they don't have to be entered each time 25 | you run a query. 26 | } 27 | \examples{ 28 | # Sets raqdm to request criteria pollutant data from Indiana by default. 29 | setAQDMdefaults(pc = "CRITERIA", state = "18") 30 | 31 | \dontrun{ 32 | # You can then use a shortened request to get data for specific county and 33 | # raqdm will enter the default values automatically. 34 | x <- getAQDMdata(county = "089", bdate = "20130101", edate = "20130228") 35 | } 36 | } 37 | \seealso{ 38 | \href{http://www.epa.gov/airdata/toc.html}{Query Air Data (QAD) User's Guide} 39 | } 40 | 41 | -------------------------------------------------------------------------------- /man/getAQDMdata.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/getAQDMdata.R 3 | \name{getAQDMdata} 4 | \alias{getAQDMdata} 5 | \title{getAQDMdata} 6 | \usage{ 7 | getAQDMdata(..., synchronous = FALSE) 8 | } 9 | \arguments{ 10 | \item{synchronous}{Should a synchronous request be sent (See details)} 11 | 12 | \item{\dots}{named query parameters to be sent to AQDM.} 13 | } 14 | \value{ 15 | If \code{synchonous = TRUE} a \code{data.frame} is returned with the requested 16 | data. If \code{synchonous = FALSE} an \code{AQDMrequest} object is returned. 17 | The \code{AQDMrequest} object can be used with \code{\link{getAQDMrequest}} to 18 | retrieve the data once it is ready. 19 | } 20 | \description{ 21 | Function for requesting monitoring data from U.S. EPA's Air Quality Data Mart. 22 | } 23 | \details{ 24 | \dots should be a set of name/value pairs where the names correspond to the 25 | variables used by the AQDM web service. 26 | 27 | If \code{synchronous = TRUE} then a synchronous request is sent to AQDM. This 28 | will result in raw data being immediatiately returned to R. EPA is more strict 29 | on the size of the request when using the synchonous service, so for larger 30 | data pulls \code{synchonous = FALSE} may be required. 31 | 32 | When \code{synchonous = FALSE} then an asynchronous request is sent tp AQDM. 33 | This will create an object of class \code{AQDMrequest} being returned. This 34 | object can then be used to retrieve the data from the server when it is ready. 35 | } 36 | \examples{ 37 | \dontrun{ 38 | x <- getAQDMdata(user = "me@email.com", pw = "abc123", param = "44201", 39 | state = 18, county = 89, bdate = "20140101", 40 | edate = "20141231") 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /R/setAQDMdefaults.R: -------------------------------------------------------------------------------- 1 | #'setAQDMdefaults 2 | #' 3 | #'Convienince function for setting default values for querying the Air Quality 4 | #'Data Mart. 5 | #' 6 | #'@param \dots name/value pairs for querying AQDM (See \link{AQDM Variables}) 7 | #'@param save \code{logical} Should the username/password be saved for future sessions? 8 | #' 9 | #'@details 10 | #'\code{raqdm} creates an R option called \code{raqdmOptions}. This holds a list of 11 | #'default values for query parameters passed to \code{\link{getAQDMdata}}. You can 12 | #'use this function to set default values so they don't have to be entered each time 13 | #'you run a query. 14 | #' 15 | #'@return 16 | #'This function returns \code{TRUE} invisibly if there are no problems. 17 | #' 18 | #'@examples 19 | #' # Sets raqdm to request criteria pollutant data from Indiana by default. 20 | #' setAQDMdefaults(pc = "CRITERIA", state = "18") 21 | #' 22 | #'\dontrun{ 23 | #' # You can then use a shortened request to get data for specific county and 24 | #' # raqdm will enter the default values automatically. 25 | #' x <- getAQDMdata(county = "089", bdate = "20130101", edate = "20130228") 26 | #'} 27 | #' 28 | #'@seealso 29 | #' \href{http://www.epa.gov/airdata/toc.html}{Query Air Data (QAD) User's Guide} 30 | #' 31 | #'@export 32 | setAQDMdefaults <- function(..., save = TRUE) { 33 | 34 | x <- list(...) 35 | 36 | if(length(x) == 1 & length(x[[1]]) > 1 & is.list(x[[1]])) { 37 | x <- x[[1]] 38 | } 39 | 40 | aqdmDefaults <- getOption("raqdmOptions") 41 | 42 | for(i in seq(length(x))) { 43 | if(names(x)[i] %in% validNames) { 44 | aqdmDefaults[[names(x)[i]]] <- x[[i]] 45 | } else { 46 | warning(names(x)[i], " not a valid AQDM parameter. Skipping...") 47 | } 48 | } 49 | 50 | aqdmDefaults <- verifyVariables(aqdmDefaults, for.request = FALSE) 51 | 52 | options("raqdmOptions" = aqdmDefaults) 53 | 54 | if(save) { 55 | save(aqdmDefaults, file = defaultsPath) 56 | } 57 | 58 | return(invisible(TRUE)) 59 | 60 | } 61 | -------------------------------------------------------------------------------- /R/getAQDMlist.R: -------------------------------------------------------------------------------- 1 | #'getAQDMlist 2 | #' 3 | #'Function for request a list of valid values for a given parameter from 4 | #'U.S. EPA's Air Quality Data Mart. 5 | #' 6 | #'@param name The name of the variable for which you want the list of valid values. 7 | #'@param \dots name/value pairs for subsetting the requested data. (See details) 8 | #' 9 | #'@details 10 | #' If the variable requires other variables when querying for data you must provide 11 | #' those other variables to \code{getAQDMlist} as well. (e.g., you must provide a \code{state} 12 | #' code if \code{name = 'county'}. 13 | #' 14 | #'@return 15 | #' Returns a \code{data.frame} with 2 columns. The first column contains the valide code, the 16 | #' second column contains a description of that code. 17 | #' 18 | #'@examples 19 | #'\dontrun{ 20 | #' #Get a data.frame of counties in Indiana 21 | #' counties <- getAQDMlist("county", state = "18") 22 | #' 23 | #' #Get a list of criteria pollutants 24 | #' crit <- getAQDMlist("param", pc = "CRITERIA") 25 | #'} 26 | #'@export 27 | getAQDMlist <- function(name, ...) { 28 | 29 | qualifiers <- list(...) 30 | 31 | if(name %in% validLists) { 32 | if(name == "county" & !("state" %in% names(qualifiers))) { 33 | stop("You must provide a state ID to retrieve a list of counties.") 34 | } else if(name == "site" & (!("state" %in% names(qualifiers)) | !("county" %in% names(qualifiers)))) { 35 | stop("You must provide a state ID and a county ID to retrieve a list of sites.") 36 | } else { 37 | 38 | # Add any missing 0s to the front of state or county qualifiers 39 | if("state" %in% names(qualifiers)) { 40 | qualifiers$state = sprintf("%02i", as.integer(qualifiers$state)) 41 | } 42 | if("county" %in% names(qualifiers)) { 43 | qualifiers$county = sprintf("%03i", as.integer(qualifiers$county)) 44 | } 45 | 46 | quals <- paste(names(qualifiers), qualifiers, sep = "=", collapse = "&") 47 | URL <- paste0(baseURL, "list?name=", name, "&", quals, "&resource=rawData") 48 | 49 | f <- file() 50 | if(class(try(cat(httr::content(httr::GET(URL)), file = f), silent = TRUE)) != "try-error") { 51 | x <- read.delim(f, header= FALSE, colClasses = "character") 52 | } else { 53 | stop("There was an error connecting to the AQDM service.") 54 | } 55 | 56 | close(f) 57 | return(x) 58 | 59 | } 60 | 61 | } else { 62 | stop("Valid names include:", paste(validLists, collapse = ", ")) 63 | } 64 | 65 | } 66 | 67 | -------------------------------------------------------------------------------- /R/getAQDMdata.R: -------------------------------------------------------------------------------- 1 | #'getAQDMdata 2 | #' 3 | #'Function for requesting monitoring data from U.S. EPA's Air Quality Data Mart. 4 | #' 5 | #'@param \dots named query parameters to be sent to AQDM. 6 | #'@param synchronous Should a synchronous request be sent (See details) 7 | #' 8 | #'@details 9 | #'\dots should be a set of name/value pairs where the names correspond to the 10 | #'variables used by the AQDM web service. 11 | #' 12 | #'If \code{synchronous = TRUE} then a synchronous request is sent to AQDM. This 13 | #'will result in raw data being immediatiately returned to R. EPA is more strict 14 | #'on the size of the request when using the synchonous service, so for larger 15 | #'data pulls \code{synchonous = FALSE} may be required. 16 | #' 17 | #'When \code{synchonous = FALSE} then an asynchronous request is sent tp AQDM. 18 | #'This will create an object of class \code{AQDMrequest} being returned. This 19 | #'object can then be used to retrieve the data from the server when it is ready. 20 | #' 21 | #'@return 22 | #'If \code{synchonous = TRUE} a \code{data.frame} is returned with the requested 23 | #'data. If \code{synchonous = FALSE} an \code{AQDMrequest} object is returned. 24 | #'The \code{AQDMrequest} object can be used with \code{\link{getAQDMrequest}} to 25 | #'retrieve the data once it is ready. 26 | #' 27 | #'@examples 28 | #'\dontrun{ 29 | #' x <- getAQDMdata(user = "me@@email.com", pw = "abc123", param = "44201", 30 | #' state = 18, county = 89, bdate = "20140101", 31 | #' edate = "20141231") 32 | #'} 33 | #'@export 34 | getAQDMdata <- function(..., synchronous = FALSE) { 35 | 36 | if(synchronous) { 37 | type = "rawData" 38 | } else { 39 | type = "rawDataNotify" 40 | } 41 | 42 | format <- getOption("raqdmOptions")$format 43 | if(!is.null(list(...)$format)) { 44 | format <- list(...)$format 45 | } 46 | if(is.null(format)) { 47 | format = "DMCSV" 48 | } 49 | 50 | URL <- constructURL(constructAQDMQueryString(...), type) 51 | 52 | x <- try(httr::content(httr::GET(URL), type = "text")) 53 | 54 | if(class(x) != "try-error") { 55 | 56 | if(synchronous) { 57 | 58 | 59 | return(readFile(textConnection(x), format)) 60 | #stop("Synchronous Requests are currently disabled by EPA") 61 | 62 | } else { 63 | 64 | request <- list(requestID = x, type = type, format = format, url = URL, 65 | time = Sys.time()) 66 | class(request) <- "AQDMrequest" 67 | return(request) 68 | 69 | } 70 | 71 | } 72 | 73 | } 74 | 75 | constructURL <- function(queryString, type = "rawData") { 76 | 77 | return(paste0(baseURL, type, "?", queryString)) 78 | 79 | } 80 | 81 | constructAQDMQueryString <- function(...) { 82 | 83 | p <- list(...) 84 | n <- names(p) 85 | params <- getOption("raqdmOptions") 86 | 87 | for(i in seq_along(p)) { 88 | if(n[i] %in% validNames) { 89 | params[[n[i]]] <- p[[i]] 90 | } 91 | } 92 | 93 | params <- verifyVariables(params) 94 | 95 | x <- paste(names(params), params, sep="=", collapse = "&") 96 | 97 | x <- gsub("&frmonly=n", "", x, fixed = TRUE) 98 | 99 | return(x) 100 | 101 | } -------------------------------------------------------------------------------- /inst/tests/tcltk.R: -------------------------------------------------------------------------------- 1 | library(tcltk) 2 | library(raqdm) 3 | setAQDMdefaults(user = "ebailey@idem.in.gov", pw = "bolefox64", param = 44201, state = "18", county = "89", bdate=as.Date('2013-01-01'), edate='20131231') 4 | 5 | aqdm <- new.env() 6 | 7 | validLists <- c("state", "pc", "param", "format", "cbsa", "csa", "dur") 8 | env.var <- ls(aqdm) 9 | def.var <- getOption("raqdmOptions") 10 | 11 | for(l in validLists) { 12 | 13 | if(!(l %in% env.var)) { 14 | aqdm[[l]] <- getAQDMlist(l) 15 | } 16 | 17 | } 18 | 19 | user <- try(tclVar(def.var$user), silent = TRUE) 20 | if(class(user) == "try-error") user <- tclVar("") 21 | pw <- try(tclVar(def.var$pw), silent = TRUE) 22 | if(class(pw) == "try-error") pw <- tclVar("") 23 | pc <- def.var$pc 24 | if(!is.null(pc)) { 25 | r <- aqdm$pc[aqdm$pc[,1] == pc, ] 26 | pc <- tclVar(paste(r[, 1], "-", r[,2])) 27 | } else { 28 | pc <- tclVar("") 29 | } 30 | if(class(pc) == "try-error") pc <- tclVar("") 31 | param <- def.var$param 32 | if(!is.null(param)) { 33 | r <- aqdm$param[aqdm$param[,1] == param, ] 34 | param <- tclVar(paste(r[,1], "-", r[,2])) 35 | } else { 36 | param <- tclVar("") 37 | } 38 | 39 | 40 | 41 | 42 | createWidget <- function(parent, type = "entry", label, value, options, width = "40") { 43 | 44 | frm <- ttkframe(parent) 45 | lbl <- tklabel(frm, text = label, anchor = "e", width = nchar(label) + 1) 46 | if(type == "entry") { 47 | wgt <- ttkentry(frm, textvariable = value, width = width) 48 | } else if(type == "combo") { 49 | wgt <- ttkcombobox(frm, textvariable = value, values = options, width = width) 50 | } 51 | tkgrid(lbl, wgt) 52 | tkpack(frm, anchor = "e") 53 | return(wgt) 54 | 55 | } 56 | 57 | paramUpdate <- function() { 58 | 59 | x <- tclvalue(pc) 60 | param <- tclvalue(param) 61 | 62 | if(x != "") { 63 | x <- strsplit(x, " - ")[[1]][1] 64 | params <- getAQDMlist("param", pc = x) 65 | } 66 | 67 | newParams <- paste(params[, 1], params[,2], sep = " - ") 68 | tkconfigure(widgets$param, values = newParams) 69 | 70 | if(!(param %in% newParams)) { 71 | tclvalue(param) <- "" 72 | } 73 | 74 | } 75 | 76 | widgets <- list() 77 | 78 | window <- tktoplevel() 79 | tkwm.title(window, "AQDM Data Request") 80 | frame <- ttkframe(window, padding = 10) 81 | tkpack(frame, expand = TRUE, fill = "both") 82 | 83 | authframe <- ttklabelframe(frame, padding = 5, relief = "flat", text = "Authentication") 84 | tkpack(authframe, expand = TRUE, fill = "x") 85 | 86 | widgets$user <- createWidget(authframe, "entry", "Username:", user) 87 | widgets$pw <- createWidget(authframe, "entry", "Password:", pw) 88 | 89 | parframe <- ttklabelframe(frame, padding = 5, relief = "flat", text = "Parameters") 90 | tkpack(parframe, expand = TRUE, fill = "x") 91 | 92 | widgets$pc <- createWidget(parframe, "combo", "Parameter Class:", pc, paste(aqdm$pc[, 1], "-", aqdm$pc[, 2])) 93 | widgets$param <- createWidget(parframe, "combo", "Parameter:", param, paste(aqdm$param[, 1], "-", aqdm$param[, 2])) 94 | tkbind(widgets$pc, "<>", paramUpdate) 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | timeframe <- ttklabelframe(frame, padding = 5, relief = "flat", text = "Time") 104 | tkpack(timeframe, expand = TRUE, fill = "x") 105 | 106 | sdate <- ttkentry(timeframe, width = 12) 107 | edate <- ttkentry(timeframe, width = 12) 108 | csdate <- ttkentry(timeframe, width = 12) 109 | cedate <- ttkentry(timeframe, width = 12) 110 | tkgrid(tklabel(timeframe, text = "Sampling Dates: "), sdate, edate) 111 | tkgrid(tklabel(timeframe, text = "Change Dates: "), csdate, cedate) 112 | 113 | 114 | 115 | tcl(button, "state", "disabled") 116 | tcl(button, "state", "!disabled") 117 | -------------------------------------------------------------------------------- /R/variables.R: -------------------------------------------------------------------------------- 1 | #'AQDM Variables 2 | #' 3 | #'U.S. EPA's AQDM requires that you define 3 things in order to request data from 4 | #'the service: 5 | #'\itemize{ 6 | #' \item Parameter of Interest 7 | #' \item Time Period of Interest 8 | #' \item Geographic Area of Interest 9 | #'} 10 | #'They provide several options to define each of these, but some definition of 11 | #'each is required. 12 | #' 13 | #'@section Parameter of Interest: 14 | #'You can define your parameters of interest in two ways: 15 | #'\describe{ 16 | #' \item{Paramater Class}{\code{pc} (Parameter Class) allows you to select a set of parameters that you are 17 | #' interested in. (e.g., \code{HAPS} or \code{CRITERIA})} 18 | #' \item{Parameter Code}{\code{param} (Parameter Code) allows you to select a specific parameter that you 19 | #' are interesting in. (e.g., \code{44201} for Ozone or \code{45201} 20 | #' for Benzene)} 21 | #'} 22 | #' 23 | #'@section Time Period of Interest: 24 | #'You can define your time period by the sampling date, the change date, or both. 25 | #'\describe{ 26 | #' \item{Sampling Date}{Use \code{bdate} (Begin Date) and \code{edate} (End Date)to define 27 | #' the beginning and end of the sampling date range in which you are interested. 28 | #' AQDM requires a specific format for dates but as long as you use an unambiguous 29 | #' date format \code{raqdm} will convert your dates to the proper format before 30 | #' sending the query.} 31 | #' \item{Change Date}{Use \code{cbdate} (Change Begin Date) and \code{cedate} (Change End Date) to define 32 | #' the beginning and end of the change date range in which you are interested. 33 | #' AQDM requires a specific format for dates but as long as you use an unambiguous 34 | #' date format \code{raqdm} will convert your dates to the proper format before 35 | #' sending the query.} 36 | #'} 37 | #' 38 | #'@section Geographic Area of Interest: 39 | #'AQDM offers many ways to define a geography of interest. 40 | #'\describe{ 41 | #' \item{State/County/Site}{You can specify a \code{state} (State code), 42 | #' \code{county} (County code), and \code{site} (Site ID) 43 | #' to define your geographic area of interest. You need all the less-specific variables 44 | #' in order to use the more specific variables. So to request data from a specific site 45 | #' you must provide \code{state} and \code{county}. To request all data from a specfic 46 | #' county, you must provide \code{state} also.} 47 | #' \item{CBSA}{You can request all data from a Core-Based Statistical Area using the \code{cbsa} variable.} 48 | #' \item{CSA}{You can request all data from a Consolidated Statistical Area using the \code{csa} variable.} 49 | #' \item{Latitude/Longitude}{You can request all data from within a geographic bounding 50 | #' box. Use \code{minlat} (Minimum Latitude), \code{maxlat} (Maximum Latitude), \code{minlon} 51 | #' (Minimum Longitude), and \code{maxlon} (Maximum Longitude) to define the bounding box. All 52 | #' latutudes and longitudes should be in decimal degrees.} 53 | #'} 54 | #' 55 | #'@section Other Variables: 56 | #'There are several other variables that you can use in your AQDM query. 57 | #'\describe{ 58 | #' \item{Username/Password}{\code{user} (Username) and \code{pw} (Password) are required to access AQDM.} 59 | #' \item{Output Format}{\code{format} defines the type of output you want. This defaults to \code{DMCSV}. This can 60 | #' affect the type of data you get back from AQDM, though \code{raqdm} will convert all returned values to \code{data.frame}.} 61 | #' \item{Duration}{\code{dur} allows you to request a specific a sample duration. If omitted, AQDM will return all available data.} 62 | #' \item{FRM Only}{\code{frmonly} allows you to request only FRM/FEM data be returned in the query. If omitted, all available data will be returned.} 63 | #'} 64 | #'@name AQDM Variables 65 | NULL -------------------------------------------------------------------------------- /man/AQDM-Variables.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/variables.R 3 | \name{AQDM Variables} 4 | \alias{AQDM Variables} 5 | \title{AQDM Variables} 6 | \description{ 7 | U.S. EPA's AQDM requires that you define 3 things in order to request data from 8 | the service: 9 | \itemize{ 10 | \item Parameter of Interest 11 | \item Time Period of Interest 12 | \item Geographic Area of Interest 13 | } 14 | They provide several options to define each of these, but some definition of 15 | each is required. 16 | } 17 | \section{Parameter of Interest}{ 18 | 19 | You can define your parameters of interest in two ways: 20 | \describe{ 21 | \item{Paramater Class}{\code{pc} (Parameter Class) allows you to select a set of parameters that you are 22 | interested in. (e.g., \code{HAPS} or \code{CRITERIA})} 23 | \item{Parameter Code}{\code{param} (Parameter Code) allows you to select a specific parameter that you 24 | are interesting in. (e.g., \code{44201} for Ozone or \code{45201} 25 | for Benzene)} 26 | } 27 | } 28 | 29 | \section{Time Period of Interest}{ 30 | 31 | You can define your time period by the sampling date, the change date, or both. 32 | \describe{ 33 | \item{Sampling Date}{Use \code{bdate} (Begin Date) and \code{edate} (End Date)to define 34 | the beginning and end of the sampling date range in which you are interested. 35 | AQDM requires a specific format for dates but as long as you use an unambiguous 36 | date format \code{raqdm} will convert your dates to the proper format before 37 | sending the query.} 38 | \item{Change Date}{Use \code{cbdate} (Change Begin Date) and \code{cedate} (Change End Date) to define 39 | the beginning and end of the change date range in which you are interested. 40 | AQDM requires a specific format for dates but as long as you use an unambiguous 41 | date format \code{raqdm} will convert your dates to the proper format before 42 | sending the query.} 43 | } 44 | } 45 | 46 | \section{Geographic Area of Interest}{ 47 | 48 | AQDM offers many ways to define a geography of interest. 49 | \describe{ 50 | \item{State/County/Site}{You can specify a \code{state} (State code), 51 | \code{county} (County code), and \code{site} (Site ID) 52 | to define your geographic area of interest. You need all the less-specific variables 53 | in order to use the more specific variables. So to request data from a specific site 54 | you must provide \code{state} and \code{county}. To request all data from a specfic 55 | county, you must provide \code{state} also.} 56 | \item{CBSA}{You can request all data from a Core-Based Statistical Area using the \code{cbsa} variable.} 57 | \item{CSA}{You can request all data from a Consolidated Statistical Area using the \code{csa} variable.} 58 | \item{Latitude/Longitude}{You can request all data from within a geographic bounding 59 | box. Use \code{minlat} (Minimum Latitude), \code{maxlat} (Maximum Latitude), \code{minlon} 60 | (Minimum Longitude), and \code{maxlon} (Maximum Longitude) to define the bounding box. All 61 | latutudes and longitudes should be in decimal degrees.} 62 | } 63 | } 64 | 65 | \section{Other Variables}{ 66 | 67 | There are several other variables that you can use in your AQDM query. 68 | \describe{ 69 | \item{Username/Password}{\code{user} (Username) and \code{pw} (Password) are required to access AQDM.} 70 | \item{Output Format}{\code{format} defines the type of output you want. This defaults to \code{DMCSV}. This can 71 | affect the type of data you get back from AQDM, though \code{raqdm} will convert all returned values to \code{data.frame}.} 72 | \item{Duration}{\code{dur} allows you to request a specific a sample duration. If omitted, AQDM will return all available data.} 73 | \item{FRM Only}{\code{frmonly} allows you to request only FRM/FEM data be returned in the query. If omitted, all available data will be returned.} 74 | } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /inst/tests/openAQDMgui.R: -------------------------------------------------------------------------------- 1 | library(tcltk) 2 | library(raqdm) 3 | 4 | 5 | openAQDMgui <- function() { 6 | 7 | # List of variables in the AQDM environment 8 | env.variables <- ls(aqdm) 9 | # Any default variables that have been set 10 | def.variables <- getOption("raqdmOptions") 11 | 12 | # List of all the tcl variables that are linked to widgets. 13 | tcl.variables <- list() 14 | 15 | tk.widgets <- list() 16 | 17 | # Loop through lists and if they haven't already been requested this session 18 | # request them and add them to the aqdm environment. 19 | for(l in validLists) { 20 | if(!(l %in% env.variables) & !(l %in% c("site", "county"))) { 21 | aqdm[[l]] <- getAQDMlist(l) 22 | } else if(l == "county" & !is.null(def.variables$state)) { 23 | aqdm[[l]] <- getAQDMlist(l, state = def.variables$state) 24 | } else if(l == "site" & !is.null(def.variables$state) & !is.null(def.variables$county)) { 25 | aqdm[[l]] <- getAQDMlist(l, state = def.variables$state, county = def.variables$county) 26 | } else { 27 | aqdm[[l]] <- NULL 28 | } 29 | } 30 | 31 | # Loop through all variables making tcl variables and asign their default value, 32 | # if present. 33 | for(i in seq_along(validNames)) { 34 | 35 | n <- validNames[i] 36 | d <- def.variables[[n]] 37 | type <- "entry" 38 | 39 | if(!is.null(d)) { 40 | if(n %in% validLists) { 41 | r <- aqdm[[n]][aqdm[[n]][, 1] == d, ] 42 | d <- paste(r[, 1], r[, 2], sep = " - ") 43 | type <- "combo" 44 | } 45 | } else { 46 | d = "" 47 | } 48 | 49 | tcl.variables[[n]] <- try(tclVar(d), silent = TRUE) 50 | if(class(tcl.variables[[n]]) == "try-error") tcl.variables[[n]] <- tclVar("") 51 | 52 | } 53 | 54 | # Function to subset parameter combobox by pc combobox selection 55 | paramUpdate <- function() { 56 | 57 | x <- tclvalue(values$pc) 58 | p <- tclvalue(values$param) 59 | 60 | if(x != "") { 61 | x <- strsplit(x, " - ")[[1]][1] 62 | params <- getAQDMlist("param", pc = x) 63 | } 64 | 65 | newParams <- paste(params[, 1], params[,2], sep = " - ") 66 | tkconfigure(widgets$param, values = newParams) 67 | 68 | if(!(p %in% newParams)) { 69 | tclvalue(values$param) <- "" 70 | } 71 | 72 | } 73 | 74 | 75 | 76 | window <- tktoplevel() 77 | tkwm.deiconify(window) 78 | tkgrab.set(window) 79 | tkfocus(window) 80 | tkwm.title(window, "AQDM Data Request") 81 | frame <- ttkframe(window, padding = 10) 82 | tkpack(frame, expand = TRUE, fill = "both") 83 | 84 | # Code for creating the Authentication Inputs 85 | authframe <- ttklabelframe(frame, padding = 5, relief = "flat", text = "Authentication") 86 | tkpack(authframe, expand = TRUE, fill = "x") 87 | 88 | tk.widgets$user <- createWidget(authframe, "entry", "Username:", tcl.variables$user) 89 | tk.widgets$pw <- createWidget(authframe, "entry", "Password:", tcl.variables$pw) 90 | 91 | parframe <- ttklabelframe(frame, padding = 5, relief = "flat", text = "Parameters") 92 | tkpack(parframe, expand = TRUE, fill = "x") 93 | 94 | tk.widgets$pc <- createWidget(parframe, "combo", "Parameter Class:", tcl.variables$pc, paste(aqdm$pc[, 1], "-", aqdm$pc[, 2])) 95 | tk.widgets$param <- createWidget(parframe, "combo", "Parameter:", tcl.variables$param, paste(aqdm$param[, 1], "-", aqdm$param[, 2])) 96 | tkbind(tk.widgets$pc, "<>", paramUpdate) 97 | 98 | timeframe <- ttklabelframe(frame, padding = 5, relief = "flat", text = "Time") 99 | tkpack(timeframe, expand = TRUE, fill = "x") 100 | 101 | sdate <- ttkentry(timeframe, width = 12) 102 | edate <- ttkentry(timeframe, width = 12) 103 | csdate <- ttkentry(timeframe, width = 12) 104 | cedate <- ttkentry(timeframe, width = 12) 105 | tkgrid(tklabel(timeframe, text = "Sampling Dates: "), sdate, edate) 106 | tkgrid(tklabel(timeframe, text = "Change Dates: "), csdate, cedate) 107 | tkwait.window(window) 108 | 109 | } -------------------------------------------------------------------------------- /R/misc.R: -------------------------------------------------------------------------------- 1 | validNames <- c("user", "pw", "state", "county", "site", "pc", "param", 2 | "format", "cbsa", "csa", "dur", "bdate", "edate", "cbdate", 3 | "cedate", "minlat", "maxlat", "minlon", "maxlon", "frmonly") 4 | validLists <- c("state", "county", "site", "pc", "param", "format", "cbsa", "csa", "dur") 5 | defaultsPath <- normalizePath(paste0(system.file(package="raqdm"), "/defaults.rda")) 6 | #baseURL <- "https://ofmext.epa.gov/AQDMRS/ws/" 7 | baseURL <- "https://aqs.epa.gov/api/" 8 | aqdm <- new.env() 9 | 10 | .onLoad <- function(...) { 11 | 12 | aqdmDefaults = NULL 13 | load(defaultsPath) 14 | options("raqdmOptions" = aqdmDefaults) 15 | 16 | } 17 | 18 | .onAttach <- function(...) { 19 | 20 | packageStartupMessage("\nU.S. EPA's Air Quality Data Mart requires free registration. Please visit\n\n", 21 | " http://www.epa.gov/airdata/tas_Data_Mart_Registration.html\n\n", 22 | "for information on registering. Once registered use\n\n", 23 | " setAQDMuser()\n\n", 24 | "to set your username and password for use with raqdm.") 25 | 26 | } 27 | 28 | verifyVariables <- function(params, for.request = TRUE) { 29 | 30 | formatDate <- function(d) { 31 | 32 | if("Date" %in% class(d) | "POSIXt" %in% class(d)) { 33 | op <- format(d, "%Y%m%d") 34 | } else if(is.character(d)) { 35 | if(is.na(as.numeric(d))) { 36 | stop("Did not recognize date format.", call. = FALSE) 37 | } else if(nchar(d) != 8) { 38 | stop("If providing dates in character format please use YYYYMMDD.", call. = FALSE) 39 | } else { 40 | td <- try(as.Date(d, "%Y%m%d")) 41 | if(class(td) == "try-error") { 42 | stop("At least one date cannot be interpreted as a date.", call. = FALSE) 43 | } else { 44 | op <- d 45 | } 46 | } 47 | } 48 | 49 | return(op) 50 | 51 | } 52 | 53 | np <- names(params) 54 | 55 | if(for.request == TRUE) { 56 | if(!("user" %in% np & "pw" %in% np)) { 57 | stop("You must provide a username and password to access this feature.", call. = FALSE) 58 | } 59 | 60 | if(!("pc" %in% np | "param" %in% np)) { 61 | stop("You must define a parameter of interest with either 'pc' or 'param'.", call. = FALSE) 62 | } 63 | 64 | if(!("bdate" %in% np & "edate" %in% np) & !("cbdate" %in% np & "cedate" %in% np)) { 65 | stop("You must define both a start date and end date (either sampling or change) with 'bdate', 'edate', 'cbdate' and/or 'cedate'.", call. = FALSE) 66 | } 67 | 68 | geoOK <- FALSE 69 | 70 | if("cbsa" %in% np) geoOK = TRUE 71 | if("csa" %in% np) geoOK = TRUE 72 | if("state" %in% np) geoOK = TRUE 73 | if("county" %in% np & "state" %in% np) geoOK = TRUE 74 | if("site" %in% np & "county" %in% np & "state" %in% np) geoOK = TRUE 75 | if("minlat" %in% np & "maxlat" %in% np & "minlon" %in% np & "maxlon" %in% np) geoOK = TRUE 76 | 77 | 78 | if(!geoOK) { 79 | stop("You have not adequately defined your geographic area of interest.", call. = FALSE) 80 | } 81 | 82 | } 83 | 84 | for(i in c("bdate", "edate", "cbdate", "cedate")) { 85 | if(i %in% np) { 86 | params[[i]] = formatDate(params[[i]]) 87 | } 88 | } 89 | 90 | geolength <- list(state = 2, county = 3, site = 4, cbsa = 5, csa = 3) 91 | for(i in names(geolength)) { 92 | if(i %in% np) { 93 | params[[i]] <- sprintf(paste0("%0", geolength[[i]], "i"), as.integer(params[[i]])) 94 | } 95 | } 96 | 97 | if(!is.null(params$frmonly)) { 98 | frm <- params$frmonly 99 | if(frm == TRUE | frm %in% c("y", "Y", "yes", "YES", "Yes", "true", "True", "1")) { 100 | frm = "y" 101 | } else { 102 | frm = "n" 103 | } 104 | params$frmonly = frm 105 | } 106 | 107 | return(params) 108 | 109 | } 110 | 111 | #'@export 112 | print.AQDMrequest <- function(x, ...) { 113 | 114 | op <- paste0("AQDM Request #", x$requestID, " - Requested: ", 115 | x$time, " in ", x$format, " format") 116 | print(op) 117 | 118 | } 119 | 120 | readFile <- function(file, type, ...) { 121 | 122 | if(type == "DMCSV") { 123 | x <- try(read.csv(file, ...), silent = FALSE) 124 | } else if(type == "AQS") { 125 | x <- try(read.delim(file, sep = "|", fill = TRUE, comment.char = ""), silent = FALSE) 126 | if(class(x) != "try-error") { 127 | colnames(x)[1] <- "Transation.Type" 128 | } 129 | } else if(type == "AQCSV") { 130 | x <- try(read.csv(file, ...), silent = FALSE) 131 | } else { 132 | stop("Unrecognized request format") 133 | } 134 | 135 | if(class(x) == "try-error") { 136 | stop("Problem accessing data...") 137 | return(FALSE) 138 | } else { 139 | if(x[nrow(x), 1] == "END OF FILE") { 140 | x <- x[-nrow(x), ] 141 | } 142 | return(x) 143 | } 144 | 145 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | raqdm 2 | ===== 3 | 4 | Access data from EPA's Air Quality Data Mart in R 5 | 6 | raqdm is an R package for directly accessing data from U.S. EPA's Air Quality Data Mart (AQDM). It uses the web interface described [here](http://www.epa.gov/airdata/toc.html) to query the service and returns the results as a `data.frame`. Data can be queried synchronously or asynchronously, default values can be saved across R sessions, and a simple GUI is available to make it easier to make requests. 7 | 8 | ### What's New - October 17, 2015 9 | 10 | * Updated to new AQS Data Mart endpoint, https://aqs.epa.gov/api/ 11 | * Added support for synchronous data requests 12 | * Removed getAQDMavailable() because it appears to no longer be supported by the new endpoint 13 | 14 | ### Installing 15 | 16 | You can install from github with `devtools`: 17 | 18 | ```R 19 | devtools::install_github("ebailey78/raqdm") 20 | ``` 21 | 22 | ### Getting Access 23 | You will need a username and password from EPA to access the actual data. You can visit the [Air Quality Data Mart](http://www.epa.gov/airdata/tas_Data_Mart_Registration.html) for information on registering. It's free! 24 | 25 | ### GUI 26 | ![raqdm GUI](http://i.imgur.com/1mSZaCk.png) 27 | 28 | Use the GUI to make requests, set defaults, or create custom function calls to use later. 29 | 30 | ### Setting Defaults 31 | `setAQDMdefaults` is used to set default values for any of AQDM's query parameters: 32 | 33 | ```R 34 | setAQDMdefaults(user = "myemail@example.com", pw = "niftymint56", 35 | param = "44201", frmonly = TRUE) 36 | ``` 37 | In this example we set defaults for username, password, param, and frmonly. Any request you make can skip these parameters and raqdm will insert them for you and any time you open the GUI these parameters will be entered by default. 38 | 39 | raqdm will also save these default values and reload them the next time you load the package, preventing you from having to reenter the same information over and over. 40 | 41 | ### Requesting data 42 | 43 | #### Synchronous (rawData) 44 | This option is currently disabled by EPA. 45 | 46 | #### Asynchronous (rawDataNotify) 47 | Use `getAQDMdata()` with `synchronous = FALSE` to make an asynchronous data request. This will return a `AQDMrequest` object. When the data is available, use `getAQDMrequest()` to retrieve the data from the server: 48 | 49 | ```R 50 | 51 | request <- getAQDMdata(bdate = "20140101", edate = "20140531", 52 | state = "18", county = "089") 53 | 54 | ## Once the request is processed on the server: 55 | 56 | data <- getAQDMrequest(request, stringsAsFactors = FALSE) 57 | 58 | ``` 59 | 60 | ### Using raqdm 61 | 62 | The Data Mart offers two services for retrieving data from AQS synchronous and asynchronous. The synchronous service return data directly to you after it is complete. The asynchronous method returns an id number that you can use to retrieve the data later. The synchronous service is offline for upgrades but the asynchronous service is available and how you can get data with `raqdm` for right now. When you make a data request to EPA with raqdm, EPA sends back the id number and raqdm saves it in a variable. You then use that variable to retrieve that requested data later. 63 | 64 | The first thing you should do is set your username and password. `raqdm` can remember your username and password and will automatically insert it into any request you make. All the future examples assume you have set your username and password. 65 | 66 | ```R 67 | setAQDMuser("ebailey@idem.in.gov", "my_password", save = TRUE) 68 | ``` 69 | Adding `save = TRUE` will cause `raqdm` to save a file on your computer with your username and password. The next time you use raqdm it will look for this file and load your username and password automatically. 70 | 71 | Once you have set your username/password you can start requesting data. We will start with a non-GUI based example. You make data requests with the `getAQDMdata()` function: 72 | 73 | ```R 74 | x <- getAQDMdata(state = "55", pc = "CRITERIA", param = "42602", format = "DMCSV", 75 | bdate = "20140101", edate = "20141231", synchronous = FALSE) 76 | ``` 77 | 78 | In this example we are requesting all 2014 NO2 data for Wisconsin. Notice that we did not provide a username and password in this example because we set them with `setAQDMuser()`. *raqdm* will insert them into the request automatically. `x <-` is assigning the request id generated by EPA to the variable `x`. We will need this later when we retrieve the data. You can use any valid variable name to store the request id. 79 | 80 | When AQDM completes the request it sends you an email with a link to the data. Once you get this email you can use the `getAQDMrequest()` function to retrieve the data from the server rather than downloading it from the link in the email. You need to provide the request id stored in `x` to the `getAQDMrequest()` function so that it knows which data to download. 81 | 82 | ```R 83 | d <- getAQDMrequest(x) 84 | ``` 85 | 86 | Assuming everything went okay, `d` now represents a `data.frame` that contains the data you requested. 87 | 88 | ### Using the GUI 89 | 90 | The GUI is a convientient way to make data requests or set defaults parameter values. It is divided into several sections to make it easier to navigate. 91 | 92 | #### Authentication 93 | ![raqdm Authentication](http://i.imgur.com/lbadJNB.png)
94 | If you used `setAQDMuser()` this section should already be filled out. If not, enter the username and password provided by AQDM. 95 | 96 | #### Date Ranges 97 | ![raqdm Date Ranges](http://i.imgur.com/qsF6puT.png)
98 | Use these boxes to narrow the timeframe of your request. Sample Dates are the actual sampling dates while Change Dates represent the last time the data was changed in AQS. The first box on the row is for the start date and the second box is for the end date. The format should be YYYYMMDD with no dashes, slashes, or spaces. 99 | 100 | #### Parameters 101 | ![raqdm Parameters](http://i.imgur.com/xIYuXu0.png)
102 | Use these boxes to select which measured parameters you are interested in. Parameter Class lets you select whole classes of parameters like HAPS, or CRITERIA. Parameter lets you select a single parameter. If you make a selection in Parameter Class, the choices in Parameter will update to reflect only parameters in that class. 103 | 104 | #### Geography 105 | There are several different ways to define a geographic area in your data request. The Geography section has been divided into 3 tabs to differentiate these ways. 106 | 107 | ##### State/County/Site 108 | ![raqdm State/County/Site](http://i.imgur.com/SJ6ueDj.png)
109 | Selecting a state will update the county box with counties in that state. Selecting a county will update the sites box with sites in that county. You must select a state to select a county and you must select a county to select a site. 110 | 111 | ##### Latitude/Longitude 112 | ![raqdm Latitude/Longitude](http://i.imgur.com/g0IDgGE.png)
113 | You can define a geographic bounding box from this tab. There are restrictions on how large a bounding box can be. Refer to [AQDM Query Limits](http://www.epa.gov/airdata/con_Query_Limits.html#Query_Limits) for more information. 114 | 115 | ##### Other Geography 116 | ![raqdm Other Geography](http://i.imgur.com/hNexhvk.png)
117 | You can select a CBSA or CSA from this tab. They are mutually exclusive and are only grouped together because I didn't want to make seperate tabs for them. 118 | 119 | #### Options 120 | ![raqdm Other Geography](http://i.imgur.com/a8OTfgZ.png)
121 | This is a collection of other options that can be set. 122 | * **Request Type** - Currently limited to only rawDataNotify. 123 | * **Output Format** - Allows you to select the format of the returned data. 124 | * **Duration** - Allows you limit results to those of a specific duration. 125 | * **FRM/FEM Only** If checked on FRM/FEM results will be returned. 126 | 127 | #### Buttons 128 | ![raqdm Buttons](http://i.imgur.com/eoVE72y.png)
129 | These buttons provided access to several ways to use the GUI. 130 | * **Cancel** - Close the GUI without returning any result 131 | * **Create Function** - Create a function call that would request the selected data. The result will be printed to the console and returned as a string. This could be used to build function calls to include in your workflow. 132 | * **Set Defaults** - This will call `setAQDMdefaults` with the selected options causing them to because default selections. For example, if you were going to be pulling data for several different parameters for one county, you could set defaults for the state, county, and date range. Then you could make several `getAQDMdata()` requests while only passing the parameter each time. 133 | * **Request Data** - This will use your selection to make a data request to AQDM with `getAQDMdata()`. If using this button, be sure to assign the `openAQDMgui()` function to a variable so that the request id can be used to retrieve the data later. For example 134 | ```R 135 | x <- openAQDMgui() 136 | ``` 137 | will return the request id to `x` after you click **Request Data***. 138 | 139 | ### Examples 140 | 141 | ```R 142 | library(raqdm) 143 | 144 | # Set my username and password for the AQDM service 145 | setAQDMuser("ebailey@idem.in.gov", "my_password", save = TRUE) 146 | 147 | # Set defaults for Wisconsin in 2014 148 | setAQDMdefaults(state = "55", bdate = "20140101", edate = "20141231") 149 | 150 | # Request 2014 Benzene Data from Wisconsin 151 | x <- getAQDMdata(param="45201") 152 | 153 | # Request 2014 NO2 Data from Wisconsin 154 | y <- getAQDMdata(param="42602") 155 | 156 | # Request 2014 Ozone Data from Wisconsin 157 | z <- getAQDMdata(param="44201") 158 | 159 | # Retrieve the benzene data 160 | benz <- getAQDMrequest(x) 161 | 162 | # Retrieve the NO2 data 163 | no2 <- getAQDMrequest(y) 164 | 165 | # Retrieve the Ozone data 166 | o3 <- getAQDMrequest(z) 167 | 168 | ``` 169 | 170 | ```R 171 | # Example showing how to loops to do the same thing as previous example 172 | 173 | library(raqdm) 174 | 175 | # Set my username and password for the AQDM service 176 | setAQDMuser("ebailey@idem.in.gov", "my_password", save = TRUE) 177 | 178 | # Set defaults for Wisconsin in 2014 179 | setAQDMdefaults(state = "55", bdate = "20140101", edate = "20141231") 180 | 181 | # Create a vector with the parameters you are interested in 182 | params <- c("45201", "42602", "44201") 183 | 184 | # Use lapply to loop through the params vector, requesting each one from AQDM. A list of requests will be returned to the x variable 185 | x <- lapply(params, function(p) { 186 | return(getAQDMdata(param=p)) 187 | }) 188 | 189 | # now loop through the requests to retrieve the data 190 | y <- lapply(x, function(r) { 191 | return(getAQDMrequest(r)) 192 | }) 193 | 194 | # You could then use do.call and rbind to combine them into one data.frame 195 | d <- do.call(rbind, y) 196 | 197 | ``` 198 | 199 | 200 | ### More Info 201 | 202 | If you have any questions about this package, or you find a error, please contact me at the email address in my profile or open an issue [here](https://github.com/ebailey78/raqdm/issues). 203 | -------------------------------------------------------------------------------- /R/openAQDMgui.R: -------------------------------------------------------------------------------- 1 | #'openAQDMgui 2 | #' 3 | #'Open a simple GUI to facilitate requesting data from U.S. EPA's Air Quality 4 | #'Data Mart 5 | #' 6 | #'@details 7 | #' 8 | #'\code{openAQDMgui} opens a dialog that the user can use to manipulate the variables 9 | #'needed to request data from AQDM. 10 | #' 11 | #'@return 12 | #'The returned value depends on selections made by the user. 13 | #' 14 | #'If request type is asynchronous 15 | #'and the "Request Data" button is clicked, an \code{AQDMrequest} object will be returned (See 16 | #'\code{\link{getAQDMrequest}}). 17 | #' 18 | #'If request type is synchronous and the "Request Data" button is clicked, 19 | #'the requested data.frame will be returned once it is returned from the server. 20 | #'(currently disabled by EPA). 21 | #' 22 | #'If the "Set Defaults" button in clicked, \code{NULL} will be returned invisibly, and 23 | #'\code{\link{setAQDMdefaults}} will be run with the selected values. 24 | #' 25 | #'If the "Copy Function" button is clicked, a character vector of length one will be returned 26 | #'container the text of a function that would make the selected request. 27 | #' 28 | #'If the dialog is canceled in any way, \code{NULL} will be returned invisibly. 29 | #' 30 | #'@examples 31 | #'\dontrun{ 32 | #' x <- openAQDMgui() 33 | #'} 34 | #' 35 | #'@export 36 | openAQDMgui <- function() { 37 | 38 | ##### Stuff to set up variables ##### 39 | 40 | # List to hold widgets 41 | wid <- list() 42 | # List to hold frames 43 | frames <- list() 44 | # List to hold tclvalues 45 | values <- list() 46 | 47 | # List of variables in the AQDM environment 48 | env.variables <- ls(aqdm) 49 | 50 | # Any default variables that have been set 51 | def.variables <- getOption("raqdmOptions") 52 | 53 | comboValues <- function(df) { 54 | 55 | x <- paste(df[,1], df[,2], sep = " - ") 56 | x <- c("", x) 57 | 58 | return(x) 59 | 60 | } 61 | 62 | # Loop through lists and if they haven't already been requested this session 63 | # request them and add them to the aqdm environment. 64 | for(l in validLists) { 65 | if(!(l %in% env.variables) & !(l %in% c("site", "county"))) { 66 | aqdm[[l]] <- getAQDMlist(l) 67 | } else if(l %in% c("site", "county")) { 68 | if(l == "county" & !is.null(def.variables$state)) { 69 | aqdm[[l]] <- getAQDMlist(l, state = def.variables$state) 70 | } else if(l == "site" & !is.null(def.variables$state) & !is.null(def.variables$county)) { 71 | aqdm[[l]] <- getAQDMlist(l, state = def.variables$state, county = def.variables$county) 72 | } else { 73 | aqdm[[l]] <- NULL 74 | } 75 | } 76 | } 77 | 78 | # Loop through all variables making tcl variables and asign their default value, 79 | # if present. 80 | for(i in seq_along(validNames)) { 81 | 82 | n <- validNames[i] 83 | d <- def.variables[[n]] 84 | 85 | if(!is.null(d)) { 86 | if(n %in% validLists) { 87 | r <- aqdm[[n]][aqdm[[n]][, 1] == d, ] 88 | d <- paste(r[, 1], r[, 2], sep = " - ") 89 | } 90 | } else { 91 | d = "" 92 | } 93 | 94 | if(n == "frmonly") { 95 | if(d == "y") { 96 | d = TRUE 97 | } else { 98 | d = FALSE 99 | } 100 | } 101 | 102 | if("Date" %in% class(d) | "POSIXt" %in% class(d)) { 103 | d <- format(d, "%Y%m%d") 104 | } 105 | 106 | values[[n]] <- try(tcltk::tclVar(d), silent = TRUE) 107 | if(class(values[[n]]) == "try-error") values[[n]] <- tcltk::tclVar("") 108 | 109 | } 110 | 111 | 112 | ##### Callbacks to control interaction in the GUI ##### 113 | 114 | # Function to subset parameter combobox by pc combobox selection 115 | paramUpdate <- function() { 116 | 117 | x <- tcltk::tclvalue(values$pc) 118 | print(x) 119 | p <- tcltk::tclvalue(values$param) 120 | 121 | if(x != "") { 122 | x <- strsplit(x, " - ")[[1]][1] 123 | params <- getAQDMlist("param", pc = x) 124 | } else { 125 | params <- aqdm$param 126 | } 127 | 128 | newParams <- paste(params[, 1], params[,2], sep = " - ") 129 | tcltk::tkconfigure(wid$param, values = newParams) 130 | 131 | if(!(p %in% newParams)) { 132 | tcltk::tclvalue(values$param) <- "" 133 | } 134 | 135 | } 136 | 137 | countyUpdate <- function() { 138 | 139 | x <- tcltk::tclvalue(values$state) 140 | p <- tcltk::tclvalue(values$county) 141 | 142 | if(x != "") { 143 | x <- strsplit(x, " - ")[[1]][1] 144 | counties <- getAQDMlist("county", state = x) 145 | } else { 146 | counties <- c() 147 | } 148 | 149 | newCounties <- paste(counties[, 1], counties[, 2], sep = " - ") 150 | tcltk::tkconfigure(wid$county, values = newCounties) 151 | 152 | if(!(p %in% newCounties)) { 153 | tcltk::tclvalue(values$county) <- "" 154 | } 155 | 156 | siteUpdate() 157 | 158 | } 159 | 160 | siteUpdate <- function() { 161 | 162 | x <- tcltk::tclvalue(values$state) 163 | y <- tcltk::tclvalue(values$county) 164 | p <- tcltk::tclvalue(values$site) 165 | 166 | if(x != "" & y != "") { 167 | x <- strsplit(x, " - ")[[1]][1] 168 | y <- strsplit(y, " - ")[[1]][1] 169 | sites <- getAQDMlist("site", state = x, county = y) 170 | } else { 171 | sites <- c() 172 | } 173 | 174 | newSites <- paste(sites[, 1], sites[, 2], sep = " - ") 175 | tcltk::tkconfigure(wid$site, values = newSites) 176 | 177 | if(!(p %in% newSites)) { 178 | tcltk::tclvalue(values$site) <- "" 179 | } 180 | 181 | } 182 | 183 | ##### Build the actual GUI #### 184 | 185 | window <- tcltk::tktoplevel() 186 | tcltk::tkwm.title(window, "rAQDM Data Interface") 187 | frame <- tcltk::ttkframe(window, padding = 10) 188 | tcltk::tkpack(frame, expand = TRUE, fill = "both") 189 | 190 | authFrame <- tcltk::ttklabelframe(frame, text = "Authentication", padding = 5) 191 | 192 | frame$user <- tcltk::ttkframe(authFrame) 193 | wid$user <- tcltk::ttkentry(frame$user, width = 30, textvariable = values$user) 194 | tcltk::tkgrid(tcltk::ttklabel(frame$user, text = "Username:", anchor = "e"), wid$user) 195 | tcltk::tkpack(frame$user, anchor = "e") 196 | 197 | frame$pw <- tcltk::ttkframe(authFrame) 198 | wid$pw <- tcltk::ttkentry(frame$pw, width = 30, textvariable = values$pw) 199 | tcltk::tkgrid(tcltk::ttklabel(frame$pw, text = "Password:", anchor = "e"), wid$pw) 200 | tcltk::tkpack(frame$pw, anchor = "e") 201 | 202 | tcltk::tkgrid(authFrame, row = 0, column = 0, sticky = "we", padx = c(0, 5)) 203 | 204 | 205 | dateFrame <- tcltk::ttklabelframe(frame, text = "Date Ranges", padding = 5) 206 | 207 | frame$sampDate <- tcltk::ttkframe(dateFrame) 208 | wid$bdate <- tcltk::ttkentry(frame$sampDate, width = 10, textvariable = values$bdate) 209 | wid$edate <- tcltk::ttkentry(frame$sampDate, width = 10, textvariable = values$edate) 210 | tcltk::tkgrid(tcltk::ttklabel(frame$sampDate, text = "Sampling Dates:", anchor = "e"), wid$bdate, wid$edate) 211 | tcltk::tkpack(frame$sampDate, anchor = "e") 212 | 213 | frame$changeDate <- tcltk::ttkframe(dateFrame) 214 | wid$cbdate <- tcltk::ttkentry(frame$changeDate, width = 10, textvariable = values$cbdate) 215 | wid$cedate <- tcltk::ttkentry(frame$changeDate, width = 10, textvariable = values$cedate) 216 | tcltk::tkgrid(tcltk::ttklabel(frame$changeDate, text = "Change Dates:", anchor = "e"), wid$cbdate, wid$cedate) 217 | tcltk::tkpack(frame$changeDate, anchor = "e") 218 | 219 | tcltk::tkgrid(dateFrame, row = 0, column = 1, sticky = "we", padx = c(0, 5)) 220 | 221 | optFrame <- tcltk::ttklabelframe(frame, text = "Options", padding = 5) 222 | 223 | frame$requestType <- tcltk::ttklabelframe(optFrame, text = "Request Type", padding = 5) 224 | values$requestType <- tcltk::tclVar("rawDataNotify") 225 | tcltk::tkpack(tcltk::ttkradiobutton(frame$requestType, variable = values$requestType, 226 | text = "rawData (synchronous)", value = "rawData"), 227 | anchor = "w") 228 | tcltk::tkpack(tcltk::ttkradiobutton(frame$requestType, variable = values$requestType, 229 | text = "rawDataNotify (asynchronous)", value = "rawDataNotify"), 230 | anchor = "w") 231 | tcltk::tkpack(frame$requestType, expand = TRUE, fill = "x", anchor = "n") 232 | 233 | frame$format <- tcltk::ttklabelframe(optFrame, text = "Output Format", padding = 5) 234 | if(tcltk::tclvalue(values$format) == "") tcltk::tclvalue(values$format) <- "DMCSV" 235 | sapply(seq(nrow(aqdm$format)), function(i) { 236 | tcltk::tkpack(tcltk::ttkradiobutton(frame$format, variable = values$format, 237 | text = paste(aqdm$format[i,1], aqdm$format[i, 2], sep = " - "), 238 | value = aqdm$format[i, 1]), anchor = "w") 239 | }) 240 | tcltk::tkpack(frame$format, expand = TRUE, fill = "x", anchor = "n") 241 | 242 | frame$dur <- tcltk::ttkframe(optFrame) 243 | # This cleans up the dur values so they look nicer in the gui 244 | v <- comboValues(aqdm[["dur"]]) 245 | v <- gsub(" \\(.*\\)", "", v) 246 | ip <- grepl("PASSIVE", v) 247 | v <- gsub("INT.*IVE ", "", v) 248 | v[ip] <- paste(v[ip], "INTEGRATED PASSIVE") 249 | wid$dur <- tcltk::ttkcombobox(frame$dur, width = 20, textvariable = values$dur, values = v) 250 | tcltk::tkgrid(tcltk::ttklabel(frame$dur, text = "Duration:", anchor = "e", width = 8), row = 0, column = 0) 251 | tcltk::tkgrid(wid$dur, row = 0, column = 1, sticky = "we") 252 | tcltk::tkpack(frame$dur, anchor = "e", expand = TRUE, fill = "x") 253 | tcltk::tkgrid.columnconfigure(frame$dur, 0, weight = 0) 254 | tcltk::tkgrid.columnconfigure(frame$dur, 1, weight = 1) 255 | 256 | frame$frmonly <- tcltk::ttkframe(optFrame) 257 | wid$frmonly <- tcltk::ttkcheckbutton(frame$frmonly, variable = values$frmonly, 258 | text = "FRM/FEM Only") 259 | tcltk::tkpack(wid$frmonly, anchor = "w") 260 | tcltk::tkpack(frame$frmonly, anchor = "n", expand = TRUE, fill = "x") 261 | 262 | tcltk::tkgrid(optFrame, row = 0, column = 2, rowspan = 3, sticky = "news") 263 | 264 | parFrame <- tcltk::ttklabelframe(frame, text = "Parameters", padding = 5) 265 | 266 | frame$pc <- tcltk::ttkframe(parFrame) 267 | wid$pc <- tcltk::ttkcombobox(frame$pc, width = 40, textvariable = values$pc, values = comboValues(aqdm[["pc"]])) 268 | tcltk::tkgrid(wid$pc, row = 0, column = 1, sticky = "we") 269 | tcltk::tkgrid(tcltk::ttklabel(frame$pc, text = "Parameter Class:", anchor = "e", width = 18), row = 0, column = 0) 270 | tcltk::tkpack(frame$pc, anchor = "e", expand = TRUE, fill = "x") 271 | tcltk::tkgrid.columnconfigure(frame$pc, 0, weight = 0) 272 | tcltk::tkgrid.columnconfigure(frame$pc, 1, weight = 1) 273 | 274 | frame$param <- tcltk::ttkframe(parFrame) 275 | wid$param <- tcltk::ttkcombobox(frame$param, width = 40, textvariable = values$param, values = comboValues(aqdm[["param"]])) 276 | tcltk::tkgrid(tcltk::ttklabel(frame$param, text = "Parameter:", anchor = "e", width = 18), row = 0, column = 0) 277 | tcltk::tkgrid(wid$param, row = 0, column = 1, sticky = "we") 278 | tcltk::tkpack(frame$param, anchor = "e", expand = TRUE, fill = "x") 279 | tcltk::tkgrid.columnconfigure(frame$param, 0, weight = 0) 280 | tcltk::tkgrid.columnconfigure(frame$param, 1, weight = 1) 281 | 282 | tcltk::tkgrid(parFrame , row = 1, column = 0, columnspan = 2, sticky = "we", padx = c(0, 5)) 283 | 284 | # Bind Parameter Frame Callbacks 285 | tcltk::tkbind(wid$pc, "<>", paramUpdate) 286 | 287 | geoFrame <- tcltk::ttklabelframe(frame, text = "Geography", padding = 5) 288 | 289 | geonotebook <- tcltk::ttknotebook(geoFrame) 290 | 291 | frame$scs <- tcltk::ttkframe(geonotebook, padding = 10) 292 | 293 | frame$state <- tcltk::ttkframe(frame$scs) 294 | wid$state <- tcltk::ttkcombobox(frame$state, textvariable = values$state, values = comboValues(aqdm[["state"]])) 295 | tcltk::tkgrid(wid$state, row = 0, column = 1, sticky = "we") 296 | tcltk::tkgrid(tcltk::ttklabel(frame$state, text = "State:", anchor = "e", width = 15), row = 0, column = 0) 297 | tcltk::tkpack(frame$state, anchor = "e", expand = TRUE, fill = "x") 298 | tcltk::tkgrid.columnconfigure(frame$state, 0, weight = 0) 299 | tcltk::tkgrid.columnconfigure(frame$state, 1, weight = 1) 300 | 301 | frame$county <- tcltk::ttkframe(frame$scs) 302 | wid$county <- tcltk::ttkcombobox(frame$county, textvariable = values$county, values = comboValues(aqdm[["county"]])) 303 | tcltk::tkgrid(wid$county, row = 0, column = 1, sticky = "we") 304 | tcltk::tkgrid(tcltk::ttklabel(frame$county, text = "County:", anchor = "e", width = 15), row = 0, column = 0) 305 | tcltk::tkpack(frame$county, anchor = "e", expand = TRUE, fill = "x") 306 | tcltk::tkgrid.columnconfigure(frame$county, 0, weight = 0) 307 | tcltk::tkgrid.columnconfigure(frame$county, 1, weight = 1) 308 | 309 | frame$site <- tcltk::ttkframe(frame$scs) 310 | wid$site <- tcltk::ttkcombobox(frame$site, textvariable = values$site, values = comboValues(aqdm[["site"]])) 311 | tcltk::tkgrid(wid$site, row = 0, column = 1, sticky = "we") 312 | tcltk::tkgrid(tcltk::ttklabel(frame$site, text = "Site ID:", anchor = "e", width = 15), row = 0, column = 0) 313 | tcltk::tkpack(frame$site, anchor = "e", expand = TRUE, fill = "x") 314 | tcltk::tkgrid.columnconfigure(frame$site, 0, weight = 0) 315 | tcltk::tkgrid.columnconfigure(frame$site, 1, weight = 1) 316 | 317 | # Bind scs Frame Callbacks 318 | tcltk::tkbind(wid$state, "<>", countyUpdate) 319 | tcltk::tkbind(wid$county, "<>", siteUpdate) 320 | 321 | tcltk::tkadd(geonotebook, frame$scs, text = "State/County/Site") 322 | 323 | frame$latlon <- tcltk::ttkframe(geonotebook, padding = 10) 324 | 325 | frame$maxlat <- tcltk::ttkframe(frame$latlon) 326 | wid$maxlat <- tcltk::ttkentry(frame$maxlat, width = 10, textvariable = values$maxlat) 327 | tcltk::tkgrid(tcltk::ttklabel(frame$maxlat, text = "Max Latitude:", anchor = "e", width = 13), wid$maxlat) 328 | 329 | frame$minlat <- tcltk::ttkframe(frame$latlon) 330 | wid$minlat <- tcltk::ttkentry(frame$minlat, width = 10, textvariable = values$minlat) 331 | tcltk::tkgrid(tcltk::ttklabel(frame$minlat, text = "Min Latitude:", anchor = "e", width = 13), wid$minlat) 332 | 333 | frame$maxlon <- tcltk::ttkframe(frame$latlon) 334 | wid$maxlon <- tcltk::ttkentry(frame$maxlon, width = 10, textvariable = values$maxlon) 335 | tcltk::tkgrid(tcltk::ttklabel(frame$maxlon, text = "Max Longitude:", anchor = "e", width = 13), wid$maxlon) 336 | 337 | frame$minlon <- tcltk::ttkframe(frame$latlon) 338 | wid$minlon <- tcltk::ttkentry(frame$minlon, width = 10, textvariable = values$minlon) 339 | tcltk::tkgrid(tcltk::ttklabel(frame$minlon, text = "Min Longitude:", anchor = "e", width = 13), wid$minlon) 340 | 341 | tcltk::tkgrid(frame$maxlat, row = 0, column = 1) 342 | tcltk::tkgrid(frame$maxlon, row = 1, column = 0) 343 | tcltk::tkgrid(frame$minlon, row = 1, column = 2) 344 | tcltk::tkgrid(frame$minlat, row = 2, column = 1) 345 | 346 | tcltk::tkadd(geonotebook, frame$latlon, text = "Latitude/Longitude") 347 | 348 | frame$geoother <- tcltk::ttkframe(geonotebook, padding = 10) 349 | 350 | frame$cbsa <- tcltk::ttkframe(frame$geoother) 351 | wid$cbsa <- tcltk::ttkcombobox(frame$cbsa, textvariable = values$cbsa, values = comboValues(aqdm[["cbsa"]])) 352 | tcltk::tkgrid(wid$cbsa, row = 0, column = 1, sticky = "we") 353 | tcltk::tkgrid(tcltk::ttklabel(frame$cbsa, text = "CBSA:", anchor = "e", width = 15), row = 0, column = 0) 354 | tcltk::tkpack(frame$cbsa, anchor = "e", expand = TRUE, fill = "x") 355 | tcltk::tkgrid.columnconfigure(frame$cbsa, 0, weight = 0) 356 | tcltk::tkgrid.columnconfigure(frame$cbsa, 1, weight = 1) 357 | 358 | frame$csa <- tcltk::ttkframe(frame$geoother) 359 | wid$csa <- tcltk::ttkcombobox(frame$csa, textvariable = values$csa, values = comboValues(aqdm[["csa"]])) 360 | tcltk::tkgrid(wid$csa, row = 0, column = 1, sticky = "we") 361 | tcltk::tkgrid(tcltk::ttklabel(frame$csa, text = "CSA:", anchor = "e", width = 15), row = 0, column = 0) 362 | tcltk::tkpack(frame$csa, anchor = "e", expand = TRUE, fill = "x") 363 | tcltk::tkgrid.columnconfigure(frame$csa, 0, weight = 0) 364 | tcltk::tkgrid.columnconfigure(frame$csa, 1, weight = 1) 365 | 366 | tcltk::tkadd(geonotebook, frame$geoother, text = "Other Geography") 367 | 368 | tcltk::tkpack(geonotebook, expand = TRUE, fill = "both") 369 | 370 | tcltk::tkgrid(geoFrame , row = 2, column = 0, columnspan = 2, sticky = "we", padx = c(0, 5)) 371 | 372 | 373 | buttFrame <- tcltk::ttkframe(frame, padding = 5) 374 | 375 | frame$butt <- tcltk::ttkframe(buttFrame) 376 | wid$cancel <- tcltk::ttkbutton(frame$butt, text = "Cancel", width = 15, command = function() tcltk::tkdestroy(window)) 377 | wid$copy <- tcltk::ttkbutton(frame$butt, text = "Create Function", width = 15, command = function() tcltk::tclvalue(done) <- 2) 378 | wid$defaults <- tcltk::ttkbutton(frame$butt, text = "Set Defaults", width = 15, command = function() tcltk::tclvalue(done) <- 3) 379 | wid$request <- tcltk::ttkbutton(frame$butt, text = "Request Data", width = 15, command = function() tcltk::tclvalue(done) <- 4) 380 | 381 | tcltk::tkgrid(wid$cancel, wid$copy, wid$defaults, wid$request, sticky = "e") 382 | 383 | tcltk::tkpack(frame$butt, anchor = "e") 384 | 385 | 386 | tcltk::tkgrid(buttFrame, row = 3, column = 0, columnspan = 3, sticky = "we") 387 | 388 | ##### Control Output from the GUI ##### 389 | 390 | # Variable to store gui state 391 | done <- tcltk::tclVar(0); 392 | tcltk::tkbind(window, "", function() tcltk::tclvalue(done) <- 1) 393 | tcltk::tkraise(window) 394 | tcltk::tkfocus(window) 395 | tcltk::tcl("wm", "attributes", window, topmost=TRUE) 396 | tcltk::tcl("wm", "attributes", window, topmost=FALSE) 397 | tcltk::tkwait.variable(done) 398 | 399 | done <- tcltk::tclvalue(done) 400 | 401 | if(done == 1) { 402 | op <- NULL 403 | } else { 404 | 405 | params <- lapply(validNames, function(n) { 406 | x <- tcltk::tclvalue(values[[n]]) 407 | x <- strsplit(x, " - ")[[1]][1] 408 | return(x) 409 | }) 410 | names(params) <- validNames 411 | params <- params[!is.na(params)] 412 | params <- verifyVariables(params) 413 | 414 | func <- paste0("getAQDMdata(", paste(names(params), params, sep = " = \"", collapse = "\", "), "\"") 415 | if(tcltk::tclvalue(values$requestType) == "rawData") { 416 | func <- paste0(func, ", synchronous = TRUE)") 417 | } else { 418 | func <- paste0(func, ", synchronous = FALSE)") 419 | } 420 | 421 | if(done == 2) { 422 | message("Function text returned") 423 | op <- func 424 | message(op) 425 | 426 | } else if(done == 3) { 427 | message("Defaults Set") 428 | setAQDMdefaults(params) 429 | op <- NULL 430 | 431 | } else if(done == 4) { 432 | message("Data Requested") 433 | op <- eval(parse(text = func)) 434 | 435 | } else { 436 | op <- NULL 437 | 438 | } 439 | 440 | tcltk::tkdestroy(window) 441 | 442 | } 443 | 444 | return(invisible(op)) 445 | 446 | 447 | ##### END openAQDMgui ##### 448 | } 449 | --------------------------------------------------------------------------------