importWaterML1.r 18.7 KB
Newer Older
1
#' Function to return data from the NWISWeb WaterML1.1 service
2
3
#'
#' This function accepts a url parameter that already contains the desired
Laura A DeCicco's avatar
Laura A DeCicco committed
4
#' NWIS site, parameter code, statistic, startdate and enddate. 
5
#'
Laura A DeCicco's avatar
Laura A DeCicco committed
6
#' @param obs_url character containing the url for the retrieval or a file path to the data file.
Laura A DeCicco's avatar
Laura A DeCicco committed
7
#' @param asDateTime logical, if \code{TRUE} returns date and time as POSIXct, if \code{FALSE}, Date
8
#' @param tz character to set timezone attribute of datetime. Default is an empty quote, which converts the 
9
10
11
#' datetimes to UTC (properly accounting for daylight savings times based on the data's provided tz_cd column).
#' Possible values to provide are "America/New_York","America/Chicago", "America/Denver","America/Los_Angeles",
#' "America/Anchorage","America/Honolulu","America/Jamaica","America/Managua","America/Phoenix", and "America/Metlakatla"
12
13
14
#' @return A data frame with the following columns:
#' \tabular{lll}{
#' Name \tab Type \tab Description \cr
15
16
#' agency_cd \tab character \tab The NWIS code for the agency reporting the data\cr
#' site_no \tab character \tab The USGS site number \cr
17
18
19
20
21
22
23
24
25
26
27
28
29
#' datetime \tab POSIXct \tab The date and time of the value converted to UTC (if asDateTime = TRUE), \cr 
#' \tab character \tab or raw character string (if asDateTime = FALSE) \cr
#' tz_cd \tab character \tab The time zone code for datetime \cr
#' code \tab character \tab Any codes that qualify the corresponding value\cr
#' value \tab numeric \tab The numeric value for the parameter \cr
#' }
#' Note that code and value are repeated for the parameters requested. The names are of the form 
#' X_D_P_S, where X is literal, 
#' D is an option description of the parameter, 
#' P is the parameter code, 
#' and S is the statistic code (if applicable).
#' 
#' There are also several useful attributes attached to the data frame:
Laura A DeCicco's avatar
Laura A DeCicco committed
30
#' \tabular{lll}{
31
32
33
34
35
36
37
38
39
#' Name \tab Type \tab Description \cr
#' url \tab character \tab The url used to generate the data \cr
#' siteInfo \tab data.frame \tab A data frame containing information on the requested sites \cr
#' variableInfo \tab data.frame \tab A data frame containing information on the requested parameters \cr
#' statisticInfo \tab data.frame \tab A data frame containing information on the requested statistics on the data \cr
#' queryTime \tab POSIXct \tab The time the data was returned \cr
#' }
#' 
#' @seealso \code{\link{renameNWISColumns}}
40
#' @export
41
42
43
44
45
46
47
48
49
#' @importFrom XML xmlTreeParse
#' @importFrom XML xmlRoot
#' @importFrom XML xmlToList
#' @importFrom XML xmlDoc
#' @importFrom XML xpathApply
#' @importFrom XML xpathSApply
#' @importFrom XML xmlNamespaceDefinitions
#' @importFrom XML xmlValue
#' @importFrom XML xmlAttrs
50
51
#' @import utils
#' @import stats
52
53
#' @importFrom  reshape2 melt
#' @importFrom reshape2 dcast
54
55
#' @importFrom lubridate parse_date_time
#' @importFrom dplyr full_join
56
#' @examples
57
#' siteNumber <- "02177000"
58
59
60
61
#' startDate <- "2012-09-01"
#' endDate <- "2012-10-01"
#' offering <- '00003'
#' property <- '00060'
Laura A DeCicco's avatar
Laura A DeCicco committed
62
#' obs_url <- constructNWISURL(siteNumber,property,startDate,endDate,'dv')
63
#' \dontrun{
64
#' data <- importWaterML1(obs_url, asDateTime=TRUE)
Laura A DeCicco's avatar
Laura A DeCicco committed
65
#' 
66
67
68
69
#' groundWaterSite <- "431049071324301"
#' startGW <- "2013-10-01"
#' endGW <- "2014-06-30"
#' groundwaterExampleURL <- constructNWISURL(groundWaterSite, NA,
Laura A DeCicco's avatar
Laura A DeCicco committed
70
#'           startGW,endGW, service="gwlevels")
Laura A DeCicco's avatar
Laura A DeCicco committed
71
#' groundWater <- importWaterML1(groundwaterExampleURL)
Laura A DeCicco's avatar
Laura A DeCicco committed
72
#' groundWater2 <- importWaterML1(groundwaterExampleURL, asDateTime=TRUE)
Laura A DeCicco's avatar
Laura A DeCicco committed
73
#' 
Laura A DeCicco's avatar
Laura A DeCicco committed
74
#' unitDataURL <- constructNWISURL(siteNumber,property,
Laura A DeCicco's avatar
Laura A DeCicco committed
75
#'          "2013-11-03","2013-11-03",'uv')
76
#' unitData <- importWaterML1(unitDataURL,TRUE)
Laura A DeCicco's avatar
Laura A DeCicco committed
77
78
79
80
81
82
83
84
85
86
#' 
#' # Two sites, two pcodes, one site has two data descriptors:
#' siteNumber <- c('01480015',"04085427")
#' obs_url <- constructNWISURL(siteNumber,c("00060","00010"),startDate,endDate,'dv')
#' data <- importWaterML1(obs_url)
#' data$dateTime <- as.Date(data$dateTime)
#' data <- renameNWISColumns(data)
#' names(attributes(data))
#' attr(data, "url")
#' attr(data, "disclaimer")
87
88
89
90
91
92
93
94
#' 
#' inactiveSite <- "05212700"
#' inactiveSite <- constructNWISURL(inactiveSite, "00060", "2014-01-01", "2014-01-10",'dv')
#' inactiveSite <- importWaterML1(inactiveSite)
#' 
#' inactiveAndAcitive <- c("07334200","05212700")
#' inactiveAndAcitive <- constructNWISURL(inactiveAndAcitive, "00060", "2014-01-01", "2014-01-10",'dv')
#' inactiveAndAcitive <- importWaterML1(inactiveAndAcitive)
95
#' 
96
97
98
99
100
#' Timezone change with specified local timezone:
#' tzURL <- constructNWISURL("04027000", c("00300","63680"), "2011-11-05", "2011-11-07","uv")
#' tzIssue <- importWaterML1(tzURL, TRUE, "America/Chicago")
#'
#' 
101
102
103
104
105
106
#' }
#' filePath <- system.file("extdata", package="dataRetrieval")
#' fileName <- "WaterML1Example.xml"
#' fullPath <- file.path(filePath, fileName)
#' imporFile <- importWaterML1(fullPath,TRUE)
#'
107
importWaterML1 <- function(obs_url,asDateTime=FALSE, tz=""){
108
  
Laura A DeCicco's avatar
Laura A DeCicco committed
109
  if(file.exists(obs_url)){
110
    rawData <- obs_url
111
    returnedDoc <- xmlTreeParse(rawData, getDTD = FALSE, useInternalNodes = TRUE)
Laura A DeCicco's avatar
Laura A DeCicco committed
112
  } else {
113
    returnedDoc <- getWebServiceData(obs_url, encoding='gzip')
114
  }
115

116
117
118
119
120
121
122
  if(tz != ""){
    tz <- match.arg(tz, c("America/New_York","America/Chicago",
                          "America/Denver","America/Los_Angeles",
                          "America/Anchorage","America/Honolulu",
                          "America/Jamaica","America/Managua",
                          "America/Phoenix","America/Metlakatla"))
  }
Laura A DeCicco's avatar
Laura A DeCicco committed
123
  
Laura A DeCicco's avatar
Laura A DeCicco committed
124
  doc <- xmlRoot(returnedDoc)
125
  ns <- xmlNamespaceDefinitions(doc, simplify = TRUE)  
Laura A DeCicco's avatar
Laura A DeCicco committed
126
127
128
129
130
131
132
133
134
  queryInfo <- xmlToList(xmlRoot(xmlDoc(doc[["queryInfo"]])))
  names(queryInfo) <- make.unique(names(queryInfo))
  
  noteIndex <- grep("note",names(queryInfo))
  
  noteTitles <- as.character(lapply(queryInfo[noteIndex], function(x) x$.attrs))
  notes <- as.character(lapply(queryInfo[noteIndex], function(x) x$text))
  names(notes) <- noteTitles
  
135
  timeSeries <- xpathApply(doc, "//ns1:timeSeries", namespaces = ns)
136
  
137
  if(0 == length(timeSeries)){
138
139
    df <- data.frame()
    attr(df, "queryInfo") <- queryInfo
Laura A DeCicco's avatar
Laura A DeCicco committed
140
    attr(df, "url") <- obs_url
141
    return(df)
142
143
  }
  
Laura A DeCicco's avatar
Laura A DeCicco committed
144
  attList <- list()
145
146
  dataColumns <- c()
  qualColumns <- c()
147
  mergedDF <- NULL
Laura A DeCicco's avatar
Laura A DeCicco committed
148
  
149
  for (i in 1:length(timeSeries)){
150
    
151
152
    chunk <- xmlDoc(timeSeries[[i]])
    chunk <- xmlRoot(chunk)
153
154
    chunkNS <- xmlNamespaceDefinitions(chunk, simplify = TRUE)  
      
Laura A DeCicco's avatar
Laura A DeCicco committed
155
    uniqueName <- as.character(xpathApply(chunk, "@name", namespaces = chunkNS))
156
157
    site <- as.character(xpathApply(chunk, "ns1:sourceInfo/ns1:siteCode", namespaces = chunkNS, xmlValue))
    agency <- as.character(xpathApply(chunk, "ns1:sourceInfo/ns1:siteCode/@agencyCode", namespaces = chunkNS))
158
    pCode <-as.character(xpathApply(chunk, "ns1:variable/ns1:variableCode", namespaces = chunkNS, xmlValue))
159
160
    statCd <- as.character(xpathApply(chunk, "ns1:variable/ns1:options/ns1:option[@name='Statistic']/@optionCode", namespaces = chunkNS))
    statName <- as.character(xpathApply(chunk, "ns1:variable/ns1:options/ns1:option[@name='Statistic']", namespaces = chunkNS, xmlValue))
161
162
    noValue <- as.numeric(xpathApply(chunk, "ns1:variable/ns1:noDataValue", namespaces = chunkNS, xmlValue))
    
Laura A DeCicco's avatar
Laura A DeCicco committed
163
164
165
    extraSiteData <-  xmlToList(xmlRoot(xmlDoc(chunk[["sourceInfo"]])))
    extraVariableData <-  xmlToList(xmlRoot(xmlDoc(chunk[["variable"]])))
    
166
    valuesIndex <- as.numeric(which("values" == names(chunk)))
167
168

        
Laura A DeCicco's avatar
Laura A DeCicco committed
169
170
171
    zoneAbbrievs <- c(as.character(xpathApply(chunk, "ns1:sourceInfo/ns1:timeZoneInfo/ns1:defaultTimeZone/@zoneAbbreviation", namespaces = chunkNS)),
                      as.character(xpathApply(chunk, "ns1:sourceInfo/ns1:timeZoneInfo/ns1:daylightSavingsTimeZone/@zoneAbbreviation", namespaces = chunkNS)))
    names(zoneAbbrievs) <- c(as.character(xpathApply(chunk, "ns1:sourceInfo/ns1:timeZoneInfo/ns1:defaultTimeZone/@zoneOffset", namespaces = chunkNS)),
172
                      as.character(xpathApply(chunk, "ns1:sourceInfo/ns1:timeZoneInfo/ns1:daylightSavingsTimeZone/@zoneOffset", namespaces = chunkNS)))
Laura A DeCicco's avatar
Laura A DeCicco committed
173
    
174

175
176
    for (j in valuesIndex){
      subChunk <- xmlRoot(xmlDoc(chunk[[j]]))
177
178
      
      methodID <- as.character(xpathSApply(subChunk, "ns1:method/@methodID", namespaces = chunkNS))
179
      
180
      methodID <- zeroPad(methodID,2)
181
      
182
      value <- as.numeric(xpathSApply(subChunk, "ns1:value",namespaces = chunkNS, xmlValue))  
Laura A DeCicco's avatar
Laura A DeCicco committed
183
      
184
      if(length(value)!=0){
185

186
187
188
189
190
191
192
193
194
195
        attNames <- xpathSApply(subChunk, "ns1:value/@*",namespaces = chunkNS)
        attributeNames <- unique(names(attNames))
  
        x <- lapply(attributeNames, function(x) xpathSApply(subChunk, paste0("ns1:value/@",x),namespaces = chunkNS))
        
        
        methodDescription <- as.character(xpathApply(subChunk, "ns1:method/ns1:methodDescription", namespaces = chunkNS, xmlValue))
        
        valueName <- paste("X",pCode,statCd,sep="_")
        
Laura A DeCicco's avatar
Laura A DeCicco committed
196
197
        if(length(methodDescription) > 0 && methodDescription != ""){
          valueName <- paste("X",methodDescription,pCode,statCd,sep="_") 
198
        }
199
200
201
         
        assign(valueName,value)
        
202
        df <- data.frame(agency_cd = rep(agency,length(value)),
203
204
205
206
207
208
209
210
211
212
213
214
215
                         site_no = rep(site,length(value)),
                         stringsAsFactors=FALSE)
        
        if(length(attributeNames) > 0){
          for(k in 1:length(attributeNames)){
            attVal <- as.character(x[[k]])
            if(length(attVal) == nrow(df)){
              df$temp <- as.character(x[[k]])
              
            } else {
              attrList <- xpathApply(subChunk, "ns1:value", namespaces = chunkNS, xmlAttrs)
              df$temp <- sapply(1:nrow(df),function(x) as.character(attrList[[x]][attributeNames[k]]))
              df$temp[is.na(df$temp)] <- ""
216
            }
217
218
            names(df)[which(names(df) %in% "temp")] <- attributeNames[k]
            
219
          }
220
221
222
223
224
225
226
        }
        
        df <- cbind(df, get(valueName))
        names(df)[length(df)] <- valueName
        
        if("qualifiers" %in% names(df)){
          qualName <- paste(valueName,"cd",sep="_")
227
228
          names(df)[which(names(df) == "qualifiers")] <- qualName
          qualColumns <- c(qualColumns, qualName)
229
230
        }
        
231
232
        dataColumns <- c(dataColumns, valueName)
        
233
        if("dateTime" %in% attributeNames){
Laura A DeCicco's avatar
Laura A DeCicco committed
234
235
          
          datetime <- xpathSApply(subChunk, "ns1:value/@dateTime",namespaces = chunkNS)
236

237
238
          if(asDateTime){
            
239
240
241
242
243
244
245
246
247
248
249
            numChar <- nchar(datetime)
            
            datetime <- parse_date_time(datetime, c("%Y","%Y-%m-%d","%Y-%m-%dT%H:%M",
                                                    "%Y-%m-%dT%H:%M:%S","%Y-%m-%dT%H:%M:%OS",
                                                    "%Y-%m-%dT%H:%M:%OS%z"), exact = TRUE)
            
            if(any(numChar < 20) & any(numChar > 16)){
              
              offsetLibrary <- data.frame(offset=c(5, 4, 6, 5, 7, 6, 8, 7, 9, 8, 10, 10, 0),
                                          code=c("EST","EDT","CST","CDT","MST","MDT","PST","PDT","AKST","AKDT","HAST","HST",""),
                                          stringsAsFactors = FALSE)
Laura A DeCicco's avatar
Laura A DeCicco committed
250
              
251
              datetime[numChar < 20 & numChar > 16] <- datetime[numChar < 20 & numChar > 16] + offsetLibrary[offsetLibrary$code == zoneAbbrievs[1],"offset"]*60*60
252
            }
253
254
            
            
255
          } else {
Laura A DeCicco's avatar
Laura A DeCicco committed
256
257
            
            datetime <- as.character(datetime)
258
            numChar <- nchar(datetime) 
Laura A DeCicco's avatar
Laura A DeCicco committed
259
260
            if(any(numChar) == 29){
              tzOffset <- as.character(substr(datetime,24,numChar))
261
              df$tz_cd <- as.character(zoneAbbrievs[tzOffset])
Laura A DeCicco's avatar
Laura A DeCicco committed
262
263
264
265
266
              df$tz_cd[is.na(df$tz_cd)] <- zoneAbbrievs[1]
            } else {
              df$tz_cd <- zoneAbbrievs[1]
            }
            
267
          }
268
          
269
          df$dateTime <- datetime     
270
          
271
272
273
274
275
        }
        
        colNames <- names(df)
        
        if( exists("qualName")){
276
          columnsOrdered <- c("agency_cd","site_no","dateTime","tz_cd",attributeNames[attributeNames != "dateTime"],qualName,valueName)
277
        } else {
278
          columnsOrdered <- c("agency_cd","site_no","dateTime","tz_cd",attributeNames[attributeNames != "dateTime"],valueName)
279
        }
280
        
281
282
        columnsOrderd <- columnsOrdered[columnsOrdered %in% names(df)]
        df <- df[,columnsOrderd]
283
                        
284
        if (is.null(mergedDF)){
285
          mergedDF <- df          
286
287
        } else {
          similarNames <- intersect(names(mergedDF), names(df))
288
289
          # mergedDF <- merge(mergedDF, df,by=similarNames,all=TRUE)
          mergedDF <- full_join(mergedDF, df, by=similarNames)
290
        }
291
292
293
294
295
        
      } else {
        if (1 == i & valuesIndex[1] == j){
          mergedDF <- NULL
        } 
296
      }
297

298
    }
299
300
301
302
303
304
305
306

    ######################
    names(extraSiteData) <- make.unique(names(extraSiteData))
    
    sitePropertyIndex <- grep("siteProperty",names(extraSiteData))
    
    siteInfo <- data.frame(station_nm=extraSiteData$siteName,
                           site_no=extraSiteData$siteCode$text,
307
                           agency_cd=extraSiteData$siteCode$.attrs[["agencyCode"]],
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
                           timeZoneOffset=extraSiteData$timeZoneInfo$defaultTimeZone[1],
                           timeZoneAbbreviation=extraSiteData$timeZoneInfo$defaultTimeZone[2],
                           dec_lat_va=as.numeric(extraSiteData$geoLocation$geogLocation$latitude),
                           dec_lon_va=as.numeric(extraSiteData$geoLocation$geogLocation$longitude),
                           srs=extraSiteData$geoLocation$geogLocation$.attrs[["srs"]],
                           stringsAsFactors=FALSE)
    
    properties <- as.character(lapply(extraSiteData[sitePropertyIndex], function(x) {
      if(".attrs" %in% names(x)){
        x$.attrs
      } else {
        NA
      }              
    }))
    
    propertyValues <- as.character(lapply(extraSiteData[sitePropertyIndex], function(x) {
      if("text" %in% names(x)){
        x$text
      } else {
        NA
      }              
    }))
    
    names(propertyValues) <- properties
    propertyValues <- propertyValues[propertyValues != "NA"]
    siteInfo <- cbind(siteInfo, t(propertyValues))            
    
    names(extraVariableData) <- make.unique(names(extraVariableData))
336
337
    
    variableInfo <- c(parameterCd=extraVariableData$variableCode$text,
338
339
340
                               parameter_nm=extraVariableData$variableName,
                               parameter_desc=extraVariableData$variableDescription,
                               valueType=extraVariableData$valueType,
341
342
343
                               param_units=extraVariableData$unit$unitCode)
    
    variableInfo <- data.frame(t(variableInfo), stringsAsFactors=FALSE)
344
345
346
347
348
349
350
351
352
353
354
355
    
    statInfo <- data.frame(statisticName=statName,
                           statisticCd=statCd,
                           stringsAsFactors=FALSE)

    if (1 == i){
      siteInformation <- siteInfo
      variableInformation <- variableInfo
      statInformation <- statInfo
      
    } else {
      similarSites <- intersect(names(siteInformation), names(siteInfo))
356
357
      # siteInformation <- merge(siteInformation, siteInfo, by=similarSites, all=TRUE)
      siteInformation <- full_join(siteInformation, siteInfo, by=similarSites)
358
359
360
361
362
363
364
365
      
      similarVariables <- intersect(names(variableInformation),names(variableInfo))
      variableInformation <- merge(variableInformation, variableInfo, by=similarVariables, all=TRUE)
      
      similarStats <- intersect(names(statInformation), names(statInfo))
      statInformation <- merge(statInformation, statInfo, by=similarStats, all=TRUE)
    }

Laura A DeCicco's avatar
Laura A DeCicco committed
366
    attList[[uniqueName]] <- list(extraSiteData, extraVariableData)
367
  }
368
369

  if(!is.null(mergedDF)){
Laura A DeCicco's avatar
Laura A DeCicco committed
370
  
371
372
373
374
    dataColumns <- unique(dataColumns)
    qualColumns <- unique(qualColumns)
    
    sortingColumns <- names(mergedDF)[!(names(mergedDF) %in% c(dataColumns,qualColumns))]
375
376
377
378
379

    meltedmergedDF <- reshape2::melt(mergedDF, measure.vars =  c(dataColumns,qualColumns),
                            variable.name = "variable", value.name = "value", na.rm = FALSE)
    rownames(meltedmergedDF) <- NULL
    # meltedmergedDF  <- reshape2::melt(mergedDF,id.vars=sortingColumns)
380
    meltedmergedDF  <- meltedmergedDF[!is.na(meltedmergedDF$value),] 
381
    
382
    meltedmergedDF <- meltedmergedDF[!duplicated(meltedmergedDF),]
383
    castFormula <- as.formula(paste(paste(sortingColumns, collapse="+"),"variable",sep="~"))
384
385
386
387
388
389
390
    
    #Check for duplicated sorting columns (2 qualifier problem):
    qualDups <- meltedmergedDF[duplicated(meltedmergedDF[,c(sortingColumns,"variable")]),]
    qualDups <- qualDups[grep("cd",qualDups$variable),]
    indexDups <- as.numeric(row.names(qualDups))
  
    if(length(indexDups) > 0){
391
      mergedDF2 <- reshape2::dcast(meltedmergedDF[-indexDups,], castFormula, drop=FALSE, value.var = "value")
392
393
394
395
396
397
398
399
400
401
      
      # Need to get value....
      dupInfo <- meltedmergedDF[indexDups, sortingColumns]
      valDF <- meltedmergedDF[meltedmergedDF$variable != meltedmergedDF[indexDups,"variable" ],]
      dupVals <- valDF[,sortingColumns]
      
      matchIndexes <- merge(dupInfo, transform(dupVals, rownum=1:nrow(dupVals)))$rownum

      newRows <- rbind(meltedmergedDF[indexDups, ], valDF[matchIndexes,])
      
402
      mergedDF3 <- dcast(newRows, castFormula, drop=FALSE, value.var = "value")
403
404
405
406
407
408
      mergedDF2 <- rbind(mergedDF2, mergedDF3)
      mergedDF2 <- mergedDF2[order(mergedDF2$dateTime),]
      
      dataColumns2 <- !(names(mergedDF2) %in% sortingColumns)
      
    } else {
Laura A DeCicco's avatar
Laura A DeCicco committed
409
      mergedDF2 <- reshape2::dcast(meltedmergedDF, castFormula, drop=FALSE, value.var = "value")
410
411
412
      dataColumns2 <- !(names(mergedDF2) %in% sortingColumns)
    }
    
413
414
415
416
417
418
419
420
    if(sum(dataColumns2) == 1){
      mergedDF <- mergedDF2[!is.na(mergedDF2[,dataColumns2]),]
    } else {
      mergedDF <- mergedDF2[rowSums(is.na(mergedDF2[,dataColumns2])) != sum(dataColumns2),]
    }
    
    if(length(dataColumns) > 1){
      mergedDF[,dataColumns] <- lapply(mergedDF[,dataColumns], function(x) as.numeric(x))
421
      mergedDF[dataColumns][!is.na(mergedDF[,dataColumns]) & mergedDF[,dataColumns] == noValue] <- NA
422
423
    } else {
      mergedDF[,dataColumns] <- as.numeric(mergedDF[,dataColumns])
424
      mergedDF[!is.na(mergedDF[,dataColumns]) & mergedDF[,dataColumns] == noValue,dataColumns] <- NA
425
426
427
    }
    
    names(mergedDF) <- make.names(names(mergedDF))
428
  } else {
429
    mergedDF <- data.frame()
430
  }
431

432
433
434
435
436
437
438
439
  if(asDateTime){
    if(tz != ""){
      attr(mergedDF$dateTime, "tzone") <- tz
      mergedDF$tz_cd <- rep(tz, nrow(mergedDF))
    } else {
      attr(mergedDF$dateTime, "tzone") <- "UTC"
      mergedDF$tz_cd <- rep("UTC", nrow(mergedDF))
    }
440
  }
441
  variableInformation$noDataValue <- rep(NA, nrow(variableInformation))
Laura A DeCicco's avatar
Laura A DeCicco committed
442
  
Laura A DeCicco's avatar
Laura A DeCicco committed
443
444
445
446
447
  row.names(mergedDF) <- NULL
  attr(mergedDF, "url") <- obs_url
  attr(mergedDF, "siteInfo") <- siteInformation
  attr(mergedDF, "variableInfo") <- variableInformation
  attr(mergedDF, "disclaimer") <- notes["disclaimer"]
448
  attr(mergedDF, "statisticInfo") <- statInformation
Laura A DeCicco's avatar
Laura A DeCicco committed
449
  attr(mergedDF, "queryTime") <- Sys.time()
450
  return (mergedDF)
451
}