Nothing
# File dm2seasonal.R
# Part of the hydroTSM R package, https://github.com/hzambran/hydroTSM ;
# https://CRAN.R-project.org/package=hydroTSM
# Copyright 2009-2020 Mauricio Zambrano-Bigiarini
# Distributed under GPL 2 or later
################################################################################
# dm2seasonal: Generic function for computing seasonal values for every #
# year of a daily/monthly zoo object #
################################################################################
# Author : Mauricio Zambrano-Bigiarini #
################################################################################
# Started: 15-May-2009 ; #
# Updates: 31-Aug-2009 ; 19-Jun-2011 ; 08-Aug-2011 #
################################################################################
# 'x ' : variable of type 'zoo' or 'data.frame'
# 'season' : character, indicating the weather season to be used for selecting the data
# Valid values are:
# -) "DJF": December, January, February
# -) "MAM": March, April, May
# -) "JJA": June, July, August
# -) "SON": September, October, November
# 'FUN' : Function that will be applied to ALL the values of 'x' belonging to the given weather season
# 'na.rm' : Logical. Should missing values be removed?
# TRUE : the seasonal values are computed considering only those values different from NA
# FALSE: if there is AT LEAST one NA within a season, the corresponding values are NA
# 'out.fmt' : character indicating the format for the output time series. Possible values are:
# -) "%Y" : only the year will be used for the time. Default option. (e.g., "1961" "1962"...)
# -) "%Y-%m-%d": a complete date format will be used for the time. Default option. (e.g., "1961" "1962"...)
dm2seasonal <-function(x, ...) UseMethod("dm2seasonal")
dm2seasonal.default <- function(x, season, FUN, na.rm=TRUE, out.fmt="%Y", ...) {
# Checking that 'x' is a zoo object
if ( !is.zoo(x) ) stop("Invalid argument: 'class(x)' must be in c('zoo', 'xts')")
dm2seasonal.zoo(x=x, season=season, FUN=FUN, na.rm=na.rm, out.fmt=out.fmt, ...)
} # 'dm2seasonal.default' END
################################################################################
# Author : Mauricio Zambrano-Bigiarini #
################################################################################
# Started: 08-Aug-2011 #
# Updates: 08-Aug-2011 #
# 12-Oct-2022 #
################################################################################
dm2seasonal.zoo <- function(x, season, FUN, na.rm=TRUE, out.fmt="%Y", ...) {
# Checking that the user provied a valid argument for 'season'
if ( missing(season) ) {
stop("Missing argument: 'season' must be provided")
} else { # If 'season' is provided
seasons.default <- c("DJF", "MAM", "JJA", "SON")
seasons.FrenchPolynesia <- c("DJFM", "AM", "JJAS", "ON")
# Checking that the user provied a valid class for 'season'
valid.seasons <- valid.seasons <- union(seasons.default, seasons.FrenchPolynesia)
if (length(which(!is.na(match(season, valid.seasons )))) <= 0)
stop("Invalid argument: 'season' must be in 'c(", paste(valid.seasons, collapse=", "), ")'")
# Finding out if 'season' belongs to 'seasons.default' or to ' seasons.FrenchPolynesia'.
if ( season %in% seasons.default ) {
season.type <- "default"
} else if ( season %in% seasons.FrenchPolynesia ) {
season.type <- "FrenchPolynesia"
} # ELSE end
} # ELSE end
# Checking that the user provied a valid argument for 'FUN'
if (missing(FUN)) stop("Missing argument: 'FUN' must be provided")
# Checking the user provide a valid value for 'x'
if (sfreq(x) %in% c("quarterly", "annual"))
stop("Invalid argument: 'x' is not a sub-daily, daily, weekly or monthly ts. 'x' is a ", sfreq(x), " ts" )
# Checking 'out.fmt'
if ( is.na(match(out.fmt, c("%Y", "%Y-%m-%d") ) ) )
stop("Invalid argument: 'out.fmt' must be in c('%Y', '%Y-%m-%d')" )
# Getting the Monthly values beloonging ONLY to the desired weather season
s <- extract(x= x, trgt=season)
# Moving forward all the December values, in order that
# December of 1991 be used together with Jan/92 and Feb/92,
# instead of with Jan/91 and Feb/91
if ( (season == "DJF") | (season == "DJFM") ) {
syears <- as.numeric(format( time(s), "%Y" ))
dec.index <- which(format(time(s), "%m") == 12)
dec.years <- syears[dec.index]
dec.years <- dec.years + 1
syears[dec.index] <- dec.years
s.a <- aggregate( s, by= syears, FUN=FUN, na.rm= na.rm)
# Removing the last value of december, because it is outside of the analysis period
if ( (is.matrix(s.a)) | (is.data.frame(s.a)) ) {
s.a <- s.a[1:(nrow(s.a)-1), ]
} else s.a <- s.a[1:(length(s.a)-1)]
} else s.a <- aggregate( s, by= format( time(s), "%Y" ), FUN=FUN, na.rm= na.rm )
# Replacing the NaNs by 'NA.
# mean(NA:NA, na.rm=TRUE) == NaN
nan.index <- which(is.nan(s.a))
if ( length(nan.index) > 0 ) s.a[nan.index] <- NA
# Replacing all the Inf and -Inf by NA's
# min(NA:NA, na.rm=TRUE) == Inf ; max(NA:NA, na.rm=TRUE) == -Inf
inf.index <- which(is.infinite(s.a))
if ( length(inf.index) > 0 ) s.a[inf.index] <- NA
# If the user wants a complete data format for the output ts:
if (out.fmt == "%Y-%m-%d")
time(s.a) <- as.Date(paste( time(s.a), "-01-01", sep=""))
return(s.a)
} # 'dm2seasonal.zoo' END
################################################################################
# Author : Mauricio Zambrano-Bigiarini #
################################################################################
# Started: 15-May-2009 #
# Updates: 08-Aug-2011 #
# 29-May-2013 ; 03-Jun-2013 #
# 10-March-2020 #
################################################################################
# 'dates' : "numeric", "factor", "Date" indicating how to obtain the
# dates for correponding to the 'sname' station
# If 'dates' is a number, it indicates the index of the column in
# 'x' that stores the dates
# If 'dates' is a factor, it have to be converted into 'Date' class,
# using the date format specified by 'date.fmt'
# If 'dates' is already of Date class, the following line verifies that
# the number of days in 'dates' be equal to the number of element in the
# time series corresponding to the 'st.name' station
# 'date.fmt': character indicating the format in which the dates are stored in 'dates'.
# ONLY required when class(dates)=="factor" or "numeric"
# 'out.type': string that define the desired type of output. Possible values are
# -) "data.frame": a data.frame, with as many columns as stations
# are included in 'x'
# -) "db" : a data.frame, with 4 colums will be produced.
# The first column will store the ID of the station,
# The second column will store the Year,
# The third column will store the season
# The fouth column will contain the seasonal value, corresponding to the year specified in the second column
dm2seasonal.data.frame <- function(x, season, FUN, na.rm=TRUE,
dates=1, date.fmt="%Y-%m-%d",
out.type="data.frame",
out.fmt="%Y", ... ) {
# Checking that the user provied a valid argument for 'out.type'
if (is.na(match( out.type, c("data.frame", "db") ) ) )
stop("Invalid argument: 'out.type' must be in c('data.frame', 'db'")
# Checking that the user provied a valid argument for 'season'
if ( missing(season) ) {
stop("Missing argument: 'season' must be provided")
} else { # If 'season' is provided
seasons.default <- c("DJF", "MAM", "JJA", "SON")
seasons.FrenchPolynesia <- c("DJFM", "AM", "JJAS", "ON")
# Checking that the user provied a valid class for 'season'
valid.seasons <- valid.seasons <- union(seasons.default, seasons.FrenchPolynesia)
if (length(which(!is.na(match(season, valid.seasons )))) <= 0)
stop("Invalid argument: 'season' must be in 'c(", paste(valid.seasons, collapse=", "), ")'" )
# Finding out if 'season' belongs to 'seasons.default' or to ' seasons.FrenchPolynesia'.
if ( season %in% seasons.default ) {
season.type <- "default"
} else if ( season %in% seasons.FrenchPolynesia ) {
season.type <- "FrenchPolynesia"
} # ELSE end
} # ELSE end
# Checking that the user provied a valid argument for 'FUN'
if (missing(FUN)) stop("Missing argument: 'FUN' must be provided")
# Checking 'out.fmt'
if ( is.na(match(out.fmt, c("%Y", "%Y-%m-%d") ) ) )
stop("Invalid argument: 'out.fmt' must be in c('%Y', '%Y-%m-%d')" )
# Checking that the user provied a valid argument for 'dates'
if (is.na(match(class(dates), c("numeric", "factor", "Date"))))
stop("Invalid argument: 'dates' must be of class 'numeric', 'factor', 'Date'")
# If 'dates' is a number, it indicates the index of the column of 'x' that stores the dates
# The column with dates is then substracted form 'x' for easening the further computations
if ( is(dates, "numeric") ) {
tmp <- dates
dates <- as.Date(x[, dates], format= date.fmt)
x <- x[-tmp]
} # IF end
# If 'dates' is a factor, it have to be converted into 'Date' class,
# using the date format specified by 'date.fmt'
if ( is(dates, "factor") ) dates <- as.Date(dates, format= date.fmt)
# If 'dates' is already of Date class, the following line verifies that
# the number of days in 'dates' be equal to the number of element in the
# time series corresponding to the 'st.name' station
if ( is(dates, "Date") & (length(dates) != nrow(x) ) )
stop("Invalid argument: 'length(dates)' must be equal to 'nrow(x)'")
# Transforming 'x' into zoo
x <- zoo(x, dates)
##############################################################################
if (out.type == "data.frame") {
dm2seasonal.zoo(x=x, season=season, FUN=FUN, na.rm=na.rm, out.fmt=out.fmt, ...)
} else if (out.type == "db") {
# Amount of stations in 'x'
nstations <- ncol(x)
# ID of all the stations in 'x'
snames <- colnames(x)
# Computing the Starting and Ending Year of the analysis
Starting.Year <- as.numeric(format(range(dates)[1], "%Y"))
Ending.Year <- as.numeric(format(range(dates)[2], "%Y"))
# Amount of Years belonging to the desired season
nyears <- Ending.Year - Starting.Year + 1
message("[Starting computations...]")
# Creating a vector with the names of the field that will be used for storing the results
field.names <- c("StationID", "Year", "Season", "Value" )
# Creating the data.frame that will store the computed averages for each subcatchment
z <- as.data.frame(matrix(data = NA, nrow = nyears*nstations, ncol = 4,
byrow = TRUE, dimnames = NULL) )
colnames(z) <- field.names
y = x
for (j in 1:nstations) {
message("[ Station: ", format(snames[j], width=10, justify="left"),
" : ",format(j, width=3, justify="left"), "/",
nstations, " => ",
format(round(100*j/nstations,2), width=6, justify="left"),
"% ]" )
# Transforming the column of 'x' into a zoo object,
# using the dates provided by the user
tmp <- vector2zoo(x=x[,j], dates=dates, date.fmt=date.fmt)
# Computing the seasonal values
s.a <- dm2seasonal.default(x= tmp, season=season, FUN=FUN, na.rm=na.rm, out.fmt=out.fmt)
# Putting the annual seasonal values in the output data.frame
# The first column of 'x' corresponds to the Year
row.ini <- (j-1)*nyears + 1
row.fin <- j*nyears
z[row.ini:row.fin, 1] <- snames[j] # it is automatically repeted 'nyears' times
z[row.ini:row.fin, 2] <- Starting.Year:Ending.Year
z[row.ini:row.fin, 3] <- season # it is automatically repeted 'nyears' times
z[row.ini:row.fin, 4] <- s.a
} # FOR end
return( z )
} # IF end
} #'dm2seasonal.data.frame' END
################################################################################
# Author : Mauricio Zambrano-Bigiarini #
################################################################################
# Started: 2009 #
# Updates: 2011 #
# 29-May-2013 #
################################################################################
dm2seasonal.matrix <- function(x, season, FUN, na.rm=TRUE,
dates=1, date.fmt="%Y-%m-%d",
out.type="data.frame",
out.fmt="%Y", ... ) {
x <- as.data.frame(x)
#NextMethod("daily2annual")
dm2seasonal.data.frame(x=x, season=season, FUN=FUN, na.rm=na.rm,
dates=dates, date.fmt=date.fmt,
out.type=out.type,
out.fmt=out.fmt, ... )
} # 'dm2seasonal.matrix ' END
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.