R Example

This page shows functions to extract data from Frost using the R language.

#########################################################################################################################
# Get hourly data from Frost. This function gets hourly data from a given period. Gaps in the time series are set to NA
##########################################################################################################################
GetHourly <- function(from_date, to_date, stnr, Welements, TimeRes, client_id) {

  url <- paste("https://", client_id, "@frost.met.no/observations/v0.jsonld?",
               "sources=", paste(stnr,collapse=",") ,
               "&referencetime=", from_date, "/", to_date,
               "&elements=", paste(Welements,collapse=","),
               "&timeresolutions=", paste(TimeRes),
               sep = "", collapse= "")
  
  # Henter ut data via API  
  xs <- scan(url, what="")
  
  a  <- grep("referenceTime", xs, fixed=TRUE)
  b  <- grep("sourceId", xs, fixed=TRUE)
  d <- grep(Welements, xs, fixed=TRUE)
  
  # Fjerner førte element i vektor dersom den viser til en streng som er forskjellig fra parameternavn
  if (xs[d[1]] != Welements) {d <- d[2:length(d)]} 
  
  # Stasjonsnummer   
  Serie <- as.character(xs[b+2])
  
  # Fjern komma bak verdi og gjør om til numerisk
  Param <- as.character(xs[d+4])
  Param <- substring(Param,1,nchar(Param)-1)
  Param <- as.numeric(Param)
  
  # Tidspunkter fra Frost i tekstformat
  datetime <- strptime(x = as.character(xs[a+2]), format = "%Y-%m-%dT%H:%M:%S")
  datetimeCh <- substring(datetime,1,13)
  
  # Alle dagene i perioden, må fjerne siste dag ettersom til dato er kl 00
  DayPeriod <- seq(as.Date(from_date), as.Date(to_date), by = "day") 
  DayPeriod <-  DayPeriod[-length(DayPeriod)]
  DayPeriod <- as.character(DayPeriod)
  
  # Lager vektor med alle timer i tidsrom
  HoursPeriod <- c(1:(24*length(DayPeriod)))
  i <- 0
  for (dag in 1 : length(DayPeriod)) {
    DenneDag <- as.character(DayPeriod[dag])
    for (time in 0 : 23) {
      i <- i+1
      if (time < 10) {DenneTime <- paste("0",time, sep="")} else {DenneTime <- as.character(time)}
      HoursPeriod[i] <- paste(DenneDag, DenneTime, sep=" ") 
    }
  }
  
  StID = substring(Serie, 0, (nchar(Serie) - 2))
  
  # Denne legger inn manglende timer i en tidsserie. 
  # Sjekker først time separat før man løper gjennom resten
  if (datetimeCh[1] !=  HoursPeriod[1]) {
    datetimeCh <- append(HoursPeriod[1], datetimeCh) 
    Param <- append(NA, Param)
    Serie <- append(Serie[1], Serie)
  }
  
  
  for (time in 1:length(HoursPeriod)){
    
    if (datetimeCh[time] != HoursPeriod[time]) {
      
      # Legg til et element i OBS data
      datetimeCh <- append(datetimeCh, HoursPeriod[time], after=(time-1))
      Param <- append(Param, NA, after=(time-1))
      Serie <- append(Serie, Serie[1], after=(time-1))
      
    }
  }
  
  # Time series is stored in a frame and returned
  stTable <- data.frame(datetimeCh, Serie, Param, pri = substring(Serie, nchar(Serie), nchar(Serie)), stringsAsFactors=FALSE)
  names(stTable) <- c("Time", "Source", "Value", "Pri")
  return(stTable)
  
} # End of fucntion GetHourly
############################################################################################################################


############################################################################################################################
# Get daily data from Frost
# This function gets hourly data from a given period. Gaps in the time series are set to Na.
#############################################################################################################################
GetDaily <- function(from_date, to_date, stnr, Welements, client_id) {
  
    
  url <- paste("https://", client_id, "@frost.met.no/observations/v0.jsonld?",
               "sources=", paste(stnr,collapse=",") ,
               "&referencetime=", from_date, "/", to_date,
               "&elements=", paste(Welements,collapse=","),
               sep = "", collapse= "")
  
  # Henter ut data via API  
  xs <- scan(url, what="")
  
  a  <- grep("referenceTime", xs, fixed=TRUE)
  b  <- grep("sourceId", xs, fixed=TRUE)
  d <- grep(Welements, xs, fixed=TRUE)  # Funker hit
  
  # Stasjonsnummer   
  Serie <- as.character(xs[b+2])
  
  # Fjern komma bak verdi og gjør om til numerisk
  Param <- as.character(xs[d+4])
  Param <- substring(Param,1,nchar(Param)-1)
  Param <- as.numeric(Param)
  
  # Tidspunkter fra Frost i tekstformat
  datetime <- strptime(x = as.character(xs[a+2]), format = "%Y-%m-%dT%H:%M:%S")
  datetimeCh <- substring(datetime,1,11)
  
  # Alle dagene i perioden, må fjerne siste dag ettersom til dato er kl 00
  DayPeriod <- seq(as.Date(from_date), as.Date(to_date), by = "day") 
  DayPeriod <-  DayPeriod[-length(DayPeriod)]
  DayPeriod <- as.character(DayPeriod)
  
  StID = substring(Serie, 0, (nchar(Serie) - 2))
  
  # Denne legger inn manglende dager i en tidsserie. 
  # Første dag må sjekkes separat, deretter løper man gjennom hele perioden.
  if (!is.na(datetimeCh[1])) {
   if (datetimeCh[1] != DayPeriod[1]) {
     datetimeCh <- append(DayPeriod[1], datetimeCh) 
     Param <- append(NA, Param)
     Serie <- append(Serie[1], Serie)
   }
  }  
      
  for (dag in 1:length(DayPeriod)){
    
    if (!is.na(datetimeCh[dag])) {
     if (datetimeCh[dag] != DayPeriod[dag]) {
      
       # Legg til et element i OBS data
       datetimeCh <- append(datetimeCh, DayPeriod[dag], after=(dag-1))
       Param <- append(Param, NA, after=(dag-1))
       Serie <- append(Serie, Serie[1], after=(dag-1))
      }
     }
  }
  
  stTable <- data.frame(datetimeCh, Serie, Param, pri = substring(Serie, nchar(Serie), nchar(Serie)), stringsAsFactors=FALSE)
  names(stTable) <- c("Time", "Source", "Value", "Pri")
  return(stTable)
  
}  # End of function GetDaily


######################################################################################
# Get hourly data between two given dates from Frost
# Data are retruned in a data frame, and missing values are set to NA
# Only one element and one station a time.
# If perdiod os longer than one year, period is split
# Function GetHourly is called
######################################################################################
GetHourlyDataFrost <- function(start_date, stop_date, stnr, Welements, TimeRes, client_id) {

StartAar <- as.numeric(substring(start_date,1,4))
EndAar <- as.numeric(substring(stop_date,1,4))

if (StartAar == EndAar) { # Less than a year, no loop required
  stTable <- GetHourly(start_date, stop_date, stnr, Welements, TimeRes, client_id)
  return(stTable) } 
 else {
     # Henter data for maks et år av gangen og legger inn i dataframe
  for (yy in StartAar:(EndAar-1)) {

   if (yy == StartAar) {from_date <- start_date} else {from_date <- sprintf("%d-01-01T00:00", yy) } 
   if (yy == (EndAar-1))  {to_date <- stop_date}  else {to_date <- sprintf("%d-01-01T00:00", yy+1) }    
   
    if (yy == StartAar) {
     stTable <- GetHourly(from_date, to_date, stnr, Welements, TimeRes, client_id)
    } else {
     TempTable <- GetHourly(from_date, to_date, stnr, Welements, TimeRes, client_id)
     stTable <- rbind(stTable, TempTable)
   }
  }
 } 
 return(stTable)

} # Funksjonen slutter
################################################################################################################


######################################################################################
# Get dailydata between two given dates from Frost
# Data are retruned in a data frame, and missing values are set to NA
# Only one element and one station a time.
# If perdiod os longer than one year, period is split
# Function GetDaily is called
######################################################################################

GetDailyDataFrost <- function(start_date, stop_date, stnr, Welements, client_id) {
  
  StartAar <- as.numeric(substring(start_date,1,4))
  EndAar <- as.numeric(substring(stop_date,1,4))
  
  if (StartAar == EndAar) { # Less than a year, no loop required
    stTable <- GetDaily(start_date, stop_date, stnr, Welements, client_id)
    return(stTable) } 
  else {
    # Henter data for maks et år av gangen og legger inn i dataframe
    for (yy in StartAar:(EndAar-1)) {
      
      if (yy == StartAar) {from_date <- start_date} else {from_date <- sprintf("%d-01-01T00:00", yy) }   # Hva med from to_date
      if (yy == (EndAar-1))  {to_date <- stop_date}  else {to_date <- sprintf("%d-01-01T00:00", yy+1) }    
      
      if (yy == StartAar) {
        stTable <- GetDaily(from_date, to_date, stnr, Welements, client_id)
      } else {
        TempTable <- GetDaily(from_date, to_date, stnr, Welements, client_id)
        stTable <- rbind(stTable, TempTable)
      }
    }
  } 
  return(stTable)
  
} # Funksjonen slutter
####


   
 

Side note: ESD is an R-package for climate and weather analysis developed at MET Norway. Try it out!