Title: | Seasonal Analysis and Graphics, Especially for Climatology |
---|---|
Description: | Capable of deriving seasonal statistics, such as "normals", and analysis of seasonal data, such as departures. This package also has graphics capabilities for representing seasonal data, including boxplots for seasonal parameters, and bars for summed normals. There are many specific functions related to climatology, including precipitation normals, temperature normals, cumulative precipitation departures and precipitation interarrivals. However, this package is designed to represent any time-varying parameter with a discernible seasonal signal, such as found in hydrology and ecology. |
Authors: | Mike Toews [aut, cre] |
Maintainer: | Mike Toews <[email protected]> |
License: | GPL (>= 2) |
Version: | 0.6-0 |
Built: | 2025-02-13 05:28:12 UTC |
Source: | https://github.com/mwtoews/seas |
The seas
package for the R programming environment is capable of
conveying descriptive statistics and graphics for seasonal variables, as found
in climatology, hydrology and ecology. Seasonal variables can be continuous
(i.e., temperature) or discontinuous (i.e., precipitation). An annum can be
partitioned into many arbitrary divisions, or seasonal components, such as
by month or into other fixed intervals. Boxplots are used to describe
the seasonal distributions of continuous variables. Discontinuous variables
need to be summed over time to smooth the irregularities before the variable
can evaluated and visualized. Statistics, such as precipitation normals, may
be derived from the summed variables, using the mean or median methods. Other
tools and utilities provided in the package can calculate precipitation
interarrivals, cumulative precipitation departures, find changes between two
normals, and import data from archive formats.
To get started, try some examples, such as seas.sum
,
seas.norm
. There will be more help added here someday!
Source code and issues are at https://github.com/mwtoews/seas
Mike Toews
Toews, M.W., Whitfield, P.H., and Allen, D.M. 2007. Seasonal statistics: The ‘seas’ package for R. Computers & Geosciences, 33 (7), 944–951, doi:10.1016/j.cageo.2006.11.011
# Show a list of changes to the package: file.show(system.file("ChangeLog", package="seas"))
# Show a list of changes to the package: file.show(system.file("ChangeLog", package="seas"))
Meteorological Service of Canada daily climate data (DLY archive format) from Vernon. This document also describes how to obtain data from the Canadian Daily Climate Data CD-ROMs for analysis in seas.
MSC DLY archive format (4-digit year).
The sample file name is ‘A1128551.DLY’, which contains daily
climate data from Vernon, British Columbia. Load this file using
read.msc
.
This file was created using the instructions below, with the addition of renaming the file extension from ‘*.ALL’ to ‘*.DLY’.
Two CDCD CD-ROMs are currently available for free download, which have data from 11,216 locations throughout Canada.
This procedure shows how to extract the data using ‘CDEX.EXE’,
which requires a DOS environment. There is, however, an alternative
Python module, which can batch extract data from the CD-ROMs. If you
are using a non-Microsoft platform, you could try ‘DOSBox’ to
emulate the DOS environment (tested on Debian and Mac OS X; hint:
mount the CD-ROM drive by using -t cdrom
option).
To extract data from the CD-ROM:
Insert CD-ROM, and run ‘CDEX.EXE’ (or double-click it)
Select a ‘district’; press ‘enter’
Select a ‘station’; press ‘enter’
Select ‘Elements to Convert’, and select the desired fields using the ‘space bar’; press ‘enter’
Change ‘Drive/directory of output files’ to a convenient location, for example ‘C:\TEMP’
Press ‘F10’ to extract the data (the name of the file is the 7-digit alphanumeric station number, followed by a ‘.ALL’ extension)
Repeat these steps for each meteorological station desired (if there are more).
Multiple stations can be imported and combined before or after
importing into R. Multiple files can be concatenated into one from
the system shell (e.g. DOS: COPY *.ALL new.dly
, or UNIX:
cat *.ALL > new.dly
). This cleans up the R workspace by only
using one object to refer to several stations. Stations can be
referred to functions in seas using their IDs.
To import the archive file into R:
Start R; type library(seas)
Import using dat <- read.msc("/temp/C1161661.ALL")
(note that R uses forward slashes for directories, but you could
alternatively type "C:\\TEMP\\C1161661.ALL" on a Microsoft-based
platform to ‘escape’ the back slash characters)
To export the data from R in a more convenient format for other programs,
use write.csv(dat,"out.csv")
; MS Excel users may want to turn
NA
values into the format recognized by Excel, so modify the
expression to write.csv(dat,"out.csv",na="#N/A")
.
Mike Toews
Data provided by the Meteorological Service of Canada, with permission.
This data may only be reproduced for personal use; any other reproduction is permitted only with the written consent of Environment Canada (https://weather.gc.ca/mainmenu/contact_us_e.html).
https://web.archive.org/web/20130625230337/http://climate.weatheroffice.gc.ca/prods_servs/documentation_index_e.html (archived) Technical Documentation - Documentation for the Digital Archive of Canadian Climatological Data (Surface) Identified By Element
http://climate.weatheroffice.gc.ca/prods_servs/index_e.html#cdcd
(dead link) CDCD CD-ROM download location
https://www.dosbox.com for emulating DOS on non-Microsoft platforms
https://www.intevation.de/~bernhard/archiv/uwm/canadian_climate_cdformat/ an alternative method of extracting data from the CDCD CD-ROMs using a Python module by Bernhard Reiter
fname <- system.file("extdata", "A1128551.DLY", package="seas") print(fname) dat <- read.msc(fname) head(dat) str(dat) seas.temp.plot(dat) year.plot(dat)
fname <- system.file("extdata", "A1128551.DLY", package="seas") print(fname) dat <- read.msc(fname) head(dat) str(dat) seas.temp.plot(dat) year.plot(dat)
Find seasonal and annual changes between two data sets; relative and absolute changes are found between the central tendency and spread of each seasonal state.
change(x1, x2, var1, var2 = var1, width = "mon", cent = "mean", sprd = "sd", disc = FALSE, inter = FALSE, p.cut = 0.3, start.day = 1, calendar)
change(x1, x2, var1, var2 = var1, width = "mon", cent = "mean", sprd = "sd", disc = FALSE, inter = FALSE, p.cut = 0.3, start.day = 1, calendar)
x1 |
a |
x2 |
a second |
var1 |
a variable in |
var2 |
a variable in |
width |
the width of the bins, see |
cent |
a |
sprd |
a |
disc |
if the data are discontinuous, the |
inter |
|
p.cut |
cut-off for wet/dry; see |
start.day |
starting day |
calendar |
calendar; if not specified it will try to read this
from the attributes, otherwise it is assumed to be a proleptic
Gregorian calendar; see |
This function is useful for finding changes between different states of seasonal data. Here, a state represents how seasonal data behave statistically at either a time or place. The stability of a state depends on both the variance throughout each portion of the season, as well as the number of years of observations.
For instance, seasonal and annual changes in climate can be detected in climate data series, by comparing the normals from two time periods.
Returns a complex list
of relative and absolute (if
applicable) changes of var1
/var2
between x1
and
x2
.
Seasonal and annual changes are identified independently of each
other; where annual changes have a ann
prefix.
Relative changes are not found if x$var
has values less than 0,
such as Temperature measured in degrees C or F.
Mike Toews
data(mscdata) dat1 <- mksub(mscdata, id=1108447, start=1975, end=1984) dat2 <- mksub(mscdata, id=1108447, start=1985, end=1995) # A few plot functions to make thing easy plot.ch <- function(x, main, h, col) { main <- paste(main, "between 1975-1984 and 1985-1994", sep="\n") barplot(x, main=main) abline(h=c(0, h), col=c(1, col), lty=c(1, 2)) } plot.abs <- function(x, col="red", abs="abs", ann.abs="ann.abs") { main <- sprintf("Absolute change in %s", x$long.name[[1]]) plot.ch(x[[abs]], main, x[[ann.abs]], col) } plot.rel <- function(x, col="orange", rel="rel", ann.rel="ann.rel") { main <- sprintf("Relative change in %s", x$long.name[[1]]) plot.ch(x[[rel]], main, x[[ann.rel]], col) } plot.std <- function(x, col="purple") { main <- sprintf("Relative change in the\nstandard deviation of %s", x$long.name[[1]]) plot.ch(x$sprd.rel, main, x$ann.sprd.rel, col) } # Minimum temperature ch <- change(dat1, dat2, "t_min") str(ch) plot.abs(ch) plot.std(ch) # Cannot do ch$rel ; since div/0! # Precipitation ch2 <- change(dat1, dat2, "precip", width="DJF", disc=TRUE) plot.abs(ch2, "blue") plot.rel(ch2, "purple") plot.std(ch2)
data(mscdata) dat1 <- mksub(mscdata, id=1108447, start=1975, end=1984) dat2 <- mksub(mscdata, id=1108447, start=1985, end=1995) # A few plot functions to make thing easy plot.ch <- function(x, main, h, col) { main <- paste(main, "between 1975-1984 and 1985-1994", sep="\n") barplot(x, main=main) abline(h=c(0, h), col=c(1, col), lty=c(1, 2)) } plot.abs <- function(x, col="red", abs="abs", ann.abs="ann.abs") { main <- sprintf("Absolute change in %s", x$long.name[[1]]) plot.ch(x[[abs]], main, x[[ann.abs]], col) } plot.rel <- function(x, col="orange", rel="rel", ann.rel="ann.rel") { main <- sprintf("Relative change in %s", x$long.name[[1]]) plot.ch(x[[rel]], main, x[[ann.rel]], col) } plot.std <- function(x, col="purple") { main <- sprintf("Relative change in the\nstandard deviation of %s", x$long.name[[1]]) plot.ch(x$sprd.rel, main, x$ann.sprd.rel, col) } # Minimum temperature ch <- change(dat1, dat2, "t_min") str(ch) plot.abs(ch) plot.std(ch) # Cannot do ch$rel ; since div/0! # Precipitation ch2 <- change(dat1, dat2, "precip", width="DJF", disc=TRUE) plot.abs(ch2, "blue") plot.rel(ch2, "purple") plot.std(ch2)
Converts a data.frame
with a 365-day calendar to a proleptic
Gregorian calendar, repeating data from December 30th on a leap year
to the remaining and missing December 31st.
conv365toGregorian(x)
conv365toGregorian(x)
x |
a |
This function may be expanded in the future to be more flexible.
Returns a data.frame
with Gregorian calendar dates.
Mike Toews
Homogenizes daily data from two data sets into one data set; optionally show cross-plots to examine how well correlated that data sets are.
dathomog(x1, x2, by = "date", plot = FALSE)
dathomog(x1, x2, by = "date", plot = FALSE)
x1 |
a |
x2 |
a |
by |
name of common column, usually ‘date’, which is of
class |
plot |
|
Data from x1
has priority over x2
. Where data from
x1
is either NA
or missing (outside of time range), data
from x2
will be used (if available). Otherwise data form
x1
will be used directly. Variables will be
homogenized where their names are identical, found using
names
.
The cross-plots of the data are shown only for interest. They show
useful correlation statistics, and a best-fit line using perpendicular
offsets (which are preferred in this case over traditional linear
regression). At some point, the equations for this line may be used to
adjust the values from x2
, however this can always be done
externally to this function by pre-processing x2
.
Returns a data.frame
of seasonal data required by most functions
in seas. Variable names of the structure are found by a
union
of the names of x1
and x2
.
Weather stations should be sufficiently close enough to approximate the same weather. This distance depends on the spatial distance and local climatology.
Mike Toews
http://mathworld.wolfram.com/LeastSquaresFittingPerpendicularOffsets.html
data(mscdata) dat1 <- mksub(mscdata, id=2100630) dat2 <- mksub(mscdata, id=1108447) year.plot(dat1) year.plot(dat2) newdata <- dathomog(dat1, dat2) year.plot(newdata) message(paste(c("This is a rather poor example, since the", "two stations are nowhere near each other"), collapse="\n"))
data(mscdata) dat1 <- mksub(mscdata, id=2100630) dat2 <- mksub(mscdata, id=1108447) year.plot(dat1) year.plot(dat2) newdata <- dathomog(dat1, dat2) year.plot(newdata) message(paste(c("This is a rather poor example, since the", "two stations are nowhere near each other"), collapse="\n"))
Retrieves the full name from mscstn
using an ID
getstnname(id)
getstnname(id)
id |
This function simply converts the ID used in climate data frames into
a meaningful name using mscstn
. Presently it is useful only for
Meteorological Service of Canada weather stations in BC, AB and YT,
however getstnname
can be overridden by another (similar)
function and data object for other regions.
Returns the station name(s). If the ID does not exist, returns NULL
.
Mike Toews
data(mscdata) mscdata$id[1] getstnname(mscdata$id[1]) ids <- levels(mscdata$id) data.frame(id=I(ids), name=getstnname(ids))
data(mscdata) mscdata$id[1] getstnname(mscdata$id[1]) ids <- levels(mscdata$id) data.frame(id=I(ids), name=getstnname(ids))
Graphically display a seasonal sum object, as well as the method of solution of the median/quantile “normal”
## S3 method for class 'seas.sum' image(x, var, norm = "days", start = 1, rep = 0, zlim, alim, palette = colorRampPalette(c("white", "blue"))(64), year.filter, power, contour = TRUE, show.median, main, ...)
## S3 method for class 'seas.sum' image(x, var, norm = "days", start = 1, rep = 0, zlim, alim, palette = colorRampPalette(c("white", "blue"))(64), year.filter, power, contour = TRUE, show.median, main, ...)
x |
a |
var |
the desired variable to show, otherwise will use the prime
variable, defined in |
norm |
variable to normalize by, usually |
start |
starting bin number; e.g., for monthly sums, if
|
rep |
repetition of the bins (columns) |
zlim |
range of normalized values displayed; this can be either a
single number for the maximum (minimum set to zero), or a
|
alim |
if |
palette |
colours for |
year.filter |
specifies the annual seasons to display |
power |
this transforms the normalized values for the colours to
a power ( |
contour |
|
show.median |
|
main |
main title for plot, otherwise it will automatically be
generated; |
... |
ignored |
This is a graphical representation of a seas.sum
object,
and is far more informative than a traditional precipitation
“normal” (i.e., precip.norm
or
precip.norm
)
If norm = "days"
and show.median = TRUE
(default), the
seasonal sums appear in right-hand frames. Horizontal and vertical
lines indicate a ‘normal’ from the image, whereby the sum of
the quantile is equal to the median of the annual amount. This
numerical solution is found using seas.norm
.
Mike Toews
See SeasOpts
to modify other aspects of the plot
data(mscdata) dat <- mksub(mscdata, id=1108447) dat.ss <- seas.sum(dat, width="mon") image(dat.ss) image(dat.ss, contour=FALSE) image(dat.ss, norm="active", start=6, rep=5) # different start day (not Jan 1st) dat2.ss <- seas.sum(dat, start.day=as.Date("2001-08-01")) image(dat2.ss) image(dat2.ss, power=2) image(dat2.ss, palette=rainbow(64), main=NA) # no title image(dat2.ss, palette=colorRampPalette(c("white", "darkgreen"))(16)) image(dat2.ss, "snow") image(dat2.ss, "snow", power=0.5) # growing degree days for 10 degC dat$gdd10 <- dat$t_mean - 10 dat$gdd10[dat$gdd10 < 0] <- 0 attr(dat$gdd10,"long.name") <- "growing degree days" dat3.ss <- seas.sum(dat, var="gdd10") image(dat3.ss, "gdd10", palette=colorRampPalette(c("white", "red"))(64))
data(mscdata) dat <- mksub(mscdata, id=1108447) dat.ss <- seas.sum(dat, width="mon") image(dat.ss) image(dat.ss, contour=FALSE) image(dat.ss, norm="active", start=6, rep=5) # different start day (not Jan 1st) dat2.ss <- seas.sum(dat, start.day=as.Date("2001-08-01")) image(dat2.ss) image(dat2.ss, power=2) image(dat2.ss, palette=rainbow(64), main=NA) # no title image(dat2.ss, palette=colorRampPalette(c("white", "darkgreen"))(16)) image(dat2.ss, "snow") image(dat2.ss, "snow", power=0.5) # growing degree days for 10 degC dat$gdd10 <- dat$t_mean - 10 dat$gdd10[dat$gdd10 < 0] <- 0 attr(dat$gdd10,"long.name") <- "growing degree days" dat3.ss <- seas.sum(dat, var="gdd10") image(dat3.ss, "gdd10", palette=colorRampPalette(c("white", "red"))(64))
Calculate the interarrivals (or spell periods), which are the number of days between precipitation events (dry days), and the number of days of continuous precipitation (wet days).
interarrival(x, var = "precip", p.cut = 0.3, inv = FALSE)
interarrival(x, var = "precip", p.cut = 0.3, inv = FALSE)
x |
a |
var |
a variable on to which the interarrivals are calculated;
default is |
p.cut |
days with precipitation values greater than |
inv |
|
The interarrival is the same as the spell period (i.e., dry
spell), however this function simultaneously counts the number of
dry and wet days relative to a single date. The date
represents the first day of precipitation (if inv=TRUE
, this
convention is inverted to the first day of non-precipitation).
Missing or NA
precipitation values voids the number of counted
days between and within segments, which implies that days without
precipitation need to explicitly have zeros.
interarrival
object (which inherits the data.frame
class) with date
, wet
, dry
columns.
The table has id
and name
attributes (if
available from x
).
Mike Toews
von Storch, H. and Zwiers, F.W., 1999. Statistical analysis in climate research, Cambridge: Cambridge University Press, 484 p.
data(mscdata) van.int <- interarrival(mksub(mscdata, id=1108447)) summary(van.int) van.int[which.max(van.int$dry),] van.int[which.max(van.int$wet),] plot(van.int, ylog=FALSE, maxy=30)
data(mscdata) van.int <- interarrival(mksub(mscdata, id=1108447)) summary(van.int) van.int[which.max(van.int$dry),] van.int[which.max(van.int$wet),] plot(van.int, ylog=FALSE, maxy=30)
Read and write data from the LARS-WG stochastic weather generator file formats; also convert to a format for HELP
# read synthetic or observed *.st file read.lars(stfile, year.offset = 0) # write observed climate data (*.st and/or *.sr) write.lars(x, stfile, datfile, site, lat, lon, alt) # experimental functions (may not work great; or at all!) lars2help(infile, outfile, year.offset, site) write.lars.scenario(file, x1, x2, name = "anomaly")
# read synthetic or observed *.st file read.lars(stfile, year.offset = 0) # write observed climate data (*.st and/or *.sr) write.lars(x, stfile, datfile, site, lat, lon, alt) # experimental functions (may not work great; or at all!) lars2help(infile, outfile, year.offset, site) write.lars.scenario(file, x1, x2, name = "anomaly")
stfile |
file name with ‘*.st’ extension; this is a
‘site file’ for LARS-WG which contains meta-data for the
climate data, and has the location of the the climate data file; for
|
datfile |
file name with either ‘*.sr’ or ‘*.dat’
extension; contains climate data, as described by |
file |
file name with a ‘*.sce’ extension; this is a ‘scenario’ file with absolute and relative changes of climate data |
infile |
input file |
outfile |
output file |
x |
|
x1 |
same as |
x2 |
same as |
year.offset |
offset of years between what is contained in the
data files and what is needed in R to produce a reasonable
‘ |
site |
same as ‘[SITE]’ in ‘st’ file; if missing,
this will try to read from |
name |
scenario name |
lat |
same as ‘LAT’ in ‘st’ file; if missing, this
will try to be read from |
lon |
same as ‘LON’ in ‘st’ file; if missing, this
will try to be read from |
alt |
same as ‘ALT’ in ‘st’ file; if missing, this
will try to be read from |
These functions interface with the LARS-WG files (Version 4.0), which is a stochastic weather generator by Mikhail Semenov.
The climate data files used with LARS-WG have two parts: (1)~a ‘site file’ with a ‘st’ extension, containing the meta-data; and (2)~a data file with a ‘*.sr’ or ‘*.dat’ extension, containing all the data. The variable names are translated according to the following table:
seas | LARS-WG |
year |
‘YEAR’ |
yday |
‘JDAY’ |
t_min |
‘MIN’ |
t_max |
‘MAX’ |
preicp
|
‘RAIN’ |
solar |
‘RAD’ |
sun |
‘SUN’ |
pet |
‘PET’ |
To write climate data from R to a LARS-WG file, the data.frame
names need to match those in the seas-side of the table.
Data exported from write.lars
always has legal (according to
the Gregorian calendar) and increasing sequence of days (even if there
are gaps in x$date
). Missing data values are written as
-99
.
Synthetically generated data from LARS-WG use a 365-day calendar, and
may need to be converted to a Gregorian calendar, which can be done
using conv365toGregorian
.
lars2help
and write.lars.scenario
are experimental
functions to translate data between LARS and HELP (see
write.help
for more info).
Mike Toews
LARS-WG was can be downloaded for academic and research uses from
http://resources.rothamsted.ac.uk/mas-models/larswg
Semenov, M.A. and Barrow, E.M. 1997. Use of a stochastic weather generator in the development of climate change scenarios. Climate Change, 35 (4), 397–414, doi:10.1023/A:1005342632279
write.help
, read.sdsm
,
summerland
example synthetic data,
conv365toGregorian
stfile <- system.file("extdata", "summerland.st", package="seas") print(stfile) summ <- read.lars(stfile, year.offset=1960) head(summ) str(summ) # plot temperature summ$t_mean <- rowMeans(summ[, c("t_min", "t_max")]) seas.temp.plot(summ) # plot solar radiation seas.var.plot(summ, "solar") # plot precipitation summ.ss <- seas.sum(summ) image(summ.ss) plot(seas.norm(summ.ss))
stfile <- system.file("extdata", "summerland.st", package="seas") print(stfile) summ <- read.lars(stfile, year.offset=1960) head(summ) str(summ) # plot temperature summ$t_mean <- rowMeans(summ[, c("t_min", "t_max")]) seas.temp.plot(summ) # plot solar radiation seas.var.plot(summ, "solar") # plot precipitation summ.ss <- seas.sum(summ) image(summ.ss) plot(seas.norm(summ.ss))
Discretizes a date into an annum, using a starting day to specify the start of a season, and ends in the next year.
mkann(x, start.day, calendar)
mkann(x, start.day, calendar)
x |
A It may also be a vector of |
start.day |
This is the starting day of the annum, and can be
specified as either a |
calendar |
if unspecified, it will be attempted to be read from
|
This date function finds the annual-breaks between seasons, using a
start.day
. Often, the start.day
is 1, or January 1st,
in which case simply the year is returned, since the season starts on
January 1 and ends on December 31st. Otherwise, each annual break is
set using start.day
, and the annum is identified by the range
of years, for example 1991_1992
, identifying a season starting on
start.day
in 1991, and ending in the day before
start.day
in 1992.
The length of each year depends on the calendar; see
year.length
for details.
A choice of start.day
can influence annual totals using
seas.sum
, such as annual precipitation. For instance, if
a particular winter in the Northern hemisphere has snow before and
after the new year, these would be divided counting annual sums based
on the year, whereas if start.day
were before the winter
season, the annual sum would be calculated throughout the winter
season.
Returns factor
s for each date given in x
, grouped
by each annum.
Mike Toews
https://en.wikipedia.org/wiki/Gregorian_calendar
data(mscdata) dat <- mksub(mscdata, id=1108447) dat$ann1 <- mkann(dat, start.day=1) dat$ann2 <- mkann(dat, start.day=as.Date("2000-02-01")) dat$ann3 <- mkann(dat, start.day=as.Date("2000-08-01")) table(dat$ann1) table(dat$ann2) table(dat$ann3) dat[26:36, c("date", paste("ann", 1:3, sep=""))]
data(mscdata) dat <- mksub(mscdata, id=1108447) dat$ann1 <- mkann(dat, start.day=1) dat$ann2 <- mkann(dat, start.day=as.Date("2000-02-01")) dat$ann3 <- mkann(dat, start.day=as.Date("2000-08-01")) table(dat$ann1) table(dat$ann2) table(dat$ann3) dat[26:36, c("date", paste("ann", 1:3, sep=""))]
Discretizes a date within a year into a bin (or factor
)
for analysis, such as 11-day groups or by month.
mkseas(x, width = 11, start.day = 1, calendar, year)
mkseas(x, width = 11, start.day = 1, calendar, year)
x |
A It can also be an integer specifying the Julian day (specify
If it is omitted, the full number of days will be calculated for the
year, determined by either |
width |
either |
start.day |
this is the start of the season, specified as either a
as a |
calendar |
used to determine the number of days per year and per
bin; if not specified, a proleptic Gregorian calendar is assumed;
see |
year |
required if |
This useful date function groups days of a year into discrete
bins (or into a factor
). Statistical and plotting
functions can be applied to a variable contained within each bin. An
example of this would be to find the monthly temperature averages,
where month is the bin.
If width
is integer
, the width of each bin
(except for the last) will be exactly width
days. Since the
number of days in a year are not consistent, nor are always perfectly
divisible by width
, the numbers of days in the last bin will
vary. mkseas
determines that last bin must have at least 20% of
the number of observations for a leap year, otherwise it is merged
into the second to last bin (which will have extra numbers of
days). If width
is numeric
(i.e. 366/12
),
the width of each bin varies slightly. Using width = 366/12
is
slightly different than width = "mon"
. Leap years only affect
the last bin.
Other common classifications based on the Gregorian calendar can be
used if width
is given a character
array. All of
these systems are arbitrary: having different numbers of days in each
bin, and leap years affecting the number of days in February. The most
common, of course, is by month ("mon"
). Meteorological
quarterly seasons ("DJF"
) are based on grouping three months,
starting with December. This style of grouping is commonly used in
climate literature, and is preferred over the season names
‘winter’, ‘spring’, ‘summer’, and
‘autumn’, which apply to only one hemisphere. The less common
annual quarterly divisions ("JFM"
) are similar, except that
grouping begins with January. Zodiac divisions ("zod"
) are
included for demonstrative purposes, and are based on the Tropical
birth dates (common in Western-culture horoscopes) starting with Aries
(March 21).
Here are the complete list of options for the width
argument:
numeric
: the width of each bin (or group) in days
366/n
: divide the year into n
sections
"mon"
: month intervals (abbreviated month names)
"month"
: month intervals (full month names)
"DJF"
: meteorological quarterly divisions: DJF, MAM, JJA, SON
"JFM"
: annual quarterly divisions: JFM, AMJ, JAS, OND
"JF"
: annual six divisions: JF, MA, AJ, JA, SO, ND
"zod"
: zodiac intervals (abbreviated symbol names)
"zodiac"
: zodiac intervals (full zodiac names)
If a non-Gregorian calendar is used (see year.length
),
the number of days in a year can be set using calendar
attribute in the date
column (using attr
).
For example, attr(x$date,"calendar") <- "365_day"
will set the
dates using a 365-day per year calendar, where February is always
28-days in length. If this attribute is not set, it is assumed a
normal Gregorian calendar is used. Calendars with 360-days per year
(or 30-days per month) are incorrectly handled, since February cannot
have 30 days, however this can be forced by including a duplicate
February date in x
for each year.
Returns an array of factor
s for each date given in x
.
The factor also has four attributes: width
, start.day
,
calendar
(assumed to be 366, unless from attribute set in
Date
), and an array days
showing the maximum
number of days in each bin.
See examples for its application.
Month names generated using "mon"
or "months"
are locale
specific, and depend on your operating system and system language
settings. Normally, abbreviated month names should have exactly three
characters or less, with no trailing decimals. However,
Microsoft-based operating systems have an inconsistent set of
abbreviated month names between locales. For example, abbreviated
month names in English locales have three letters with no period at
the end, while French locales have 3–4 letters with a decimal at the
end. If your OS is POSIX, you should have consistent month names in
any locale. This can be fixed by setting
options("seas.month.len") <- 3
, which forces the length of the
months to be three-characters in length.
To avoid any issues supporting locales, or to use English month names,
simply revert to a C locale: Sys.setlocale(loc="C")
.
The phase of the Gregorian solar year (begins Julian day 1, or January
1st) is not in sync with the phase of "DJF"
(begins Julian day
335/336) or "zod"
(begins Julian day 80/81). If either of these
systems are to be used, ensure that there are several years of
data, or that the phase of the data is the same as the beginning
Julian day.
For instance, if one years worth of data beginning on Julian day 1 is
factored into "DJF"
bins, the first bin will mix data from the
first three months, and from the last month. The last three bins will
have a continuous set of data. If the values are not perfectly
periodic, the first bin will have higher variance, due to the mixing
of data separated by nearly a year.
Mike Toews
https://en.wikipedia.org/wiki/Solar_calendar
# Demonstrate the number of days in each category ylab <- "Number of days" barplot(table(mkseas(width="mon", year=2005)), main="Number of days in each month", ylab=ylab) barplot(table(mkseas(width="zod", year=2005)), main="Number of days in each zodiac sign", ylab=ylab) barplot(table(mkseas(width="DJF", year=2005)), main="Number of days in each meteorological season", ylab=ylab) barplot(table(mkseas(width=5, year=2004)), main="5-day categories", ylab=ylab) barplot(table(mkseas(width=11, year=2005)), main="11-day categories", ylab=ylab) barplot(table(mkseas(width=366 / 12, year=2005)), main="Number of days in 12-section year", sub="Note: not exactly the same as months") # Application using synthetic data dat <- data.frame(date=as.Date(paste(2005, 1:365), "%Y %j"), value=(-cos(1:365 * 2 * pi / 365) * 10 + rnorm(365) * 3 + 10)) attr(dat$date, "calendar") <- "365_day" dat$d5 <- mkseas(dat, 5) dat$d11 <- mkseas(dat, 11) dat$month <- mkseas(dat, "mon") dat$DJF <- mkseas(dat, "DJF") plot(value ~ date, dat) plot(value ~ d5, dat) plot(value ~ d11, dat) plot(value ~ month, dat) plot(value ~ DJF, dat) head(dat) tapply(dat$value, dat$month, mean, na.rm=TRUE) tapply(dat$value, dat$DJF, mean, na.rm=TRUE) dat[which.max(dat$value),] dat[which.min(dat$value),] # start on a different day st.day <- as.Date("2000-06-01") dat$month <- mkseas(dat, "mon", start.day=st.day) dat$d11 <- mkseas(dat, 11, start.day=st.day) dat$DJF <- mkseas(dat, "DJF", start.day=st.day) plot(value ~ d11, dat, main=.seasxlab(11, start.day=st.day)) plot(value ~ month, dat, main=.seasxlab("mon", start.day=st.day)) plot(value ~ DJF, dat, main=.seasxlab("DJF", start.day=st.day))
# Demonstrate the number of days in each category ylab <- "Number of days" barplot(table(mkseas(width="mon", year=2005)), main="Number of days in each month", ylab=ylab) barplot(table(mkseas(width="zod", year=2005)), main="Number of days in each zodiac sign", ylab=ylab) barplot(table(mkseas(width="DJF", year=2005)), main="Number of days in each meteorological season", ylab=ylab) barplot(table(mkseas(width=5, year=2004)), main="5-day categories", ylab=ylab) barplot(table(mkseas(width=11, year=2005)), main="11-day categories", ylab=ylab) barplot(table(mkseas(width=366 / 12, year=2005)), main="Number of days in 12-section year", sub="Note: not exactly the same as months") # Application using synthetic data dat <- data.frame(date=as.Date(paste(2005, 1:365), "%Y %j"), value=(-cos(1:365 * 2 * pi / 365) * 10 + rnorm(365) * 3 + 10)) attr(dat$date, "calendar") <- "365_day" dat$d5 <- mkseas(dat, 5) dat$d11 <- mkseas(dat, 11) dat$month <- mkseas(dat, "mon") dat$DJF <- mkseas(dat, "DJF") plot(value ~ date, dat) plot(value ~ d5, dat) plot(value ~ d11, dat) plot(value ~ month, dat) plot(value ~ DJF, dat) head(dat) tapply(dat$value, dat$month, mean, na.rm=TRUE) tapply(dat$value, dat$DJF, mean, na.rm=TRUE) dat[which.max(dat$value),] dat[which.min(dat$value),] # start on a different day st.day <- as.Date("2000-06-01") dat$month <- mkseas(dat, "mon", start.day=st.day) dat$d11 <- mkseas(dat, 11, start.day=st.day) dat$DJF <- mkseas(dat, "DJF", start.day=st.day) plot(value ~ d11, dat, main=.seasxlab(11, start.day=st.day)) plot(value ~ month, dat, main=.seasxlab("mon", start.day=st.day)) plot(value ~ DJF, dat, main=.seasxlab("DJF", start.day=st.day))
Creates a subset of a data.frame
with temporal observations,
using IDs and start and ending dates or years.
mksub(x, start, end, id)
mksub(x, start, end, id)
x |
a data frame with temporal observations |
start |
either a starting |
end |
either an ending |
id |
unique station identifier (if present), which is assumed to
be a column of |
This utility function is useful for creating temporal subsets of
seasonal data and for extracting a single station out of a
data.frame
with multiple stations or sets. The x
object can have many columns, representing measured variables for each
day, which will be returned with their original attributes.
If id
is used, that station will be extracted from
x
. If id
is not provided, but there are more than one
unique IDs in x$id
, the first unique ID will be extracted, with
a warning.
Returns a subset of a data.frame
with the same columns
and attributes as x
, except id
, which will be retained
as an attribute (e.g., attr(x,"id")
).
Mike Toews
data(mscdata) # All available data from one station summary(mksub(mscdata, id=1108447)) # One year str(mksub(mscdata, id=1108447, start=1980)) # A range of years str(mksub(mscdata, id=1108447, start=1980, end=1989)) # A range of dates summary(mksub(mscdata, id=1108447, start=as.Date("1975-08-01"), end=as.Date("2000-07-31")))
data(mscdata) # All available data from one station summary(mksub(mscdata, id=1108447)) # One year str(mksub(mscdata, id=1108447, start=1980)) # A range of years str(mksub(mscdata, id=1108447, start=1980, end=1989)) # A range of dates summary(mksub(mscdata, id=1108447, start=as.Date("1975-08-01"), end=as.Date("2000-07-31")))
Sample climate data from the Meteorological Service of Canada (MSC) climate stations in western Canada.
data(mscdata)
data(mscdata)
A data.frame
with 26358 daily observations on the
following 10 variables (metric units of ‘°C’
and ‘mm’ per day):
id
:factor
used to distinguish multiple
stations within a single data frame
year
:integer
year
yday
:integer
day of year; 1–365 or
1–366
date
:Date
class
t_max
:daily maximum temperature
t_min
:daily minimum temperature
t_mean
:daily mean temperature
precip
:total daily precipitation
rain
:total daily liquid-phase precipitation
snow
:total daily solid-phase precipitation
The climate variables have attributes (attr
of
units
and long.name
to identify their units and long
names for plotting labels.
There are three climate stations in this data frame from:
ID | Station Location | Province |
1096450 | Prince George | BC |
1108447 | Vancouver | BC |
2100630 | Haines Junction | YT |
All data spans from 1975 to 2004 for each station. Missing values are present.
The field id
is optional, but very handy when handling multiple
stations. Also, the day of year (yday
) and year
are
optional, since these are stored in the date
, using dat$date <- as.Date(paste(dat$year,dat$yday),"%Y %j")
.
The units
and long.name
attributes stored in the climate
variables are optional, but help annotate the graphics.
Mike Toews
Data provided by the Meteorological Service of Canada, with
permission. This data may only be reproduced for personal use; any
other reproduction is permitted only with the written consent of
Environment Canada.
https://weather.gc.ca/
https://weather.gc.ca/mainmenu/contact_us_e.html
mscstn
has MSC station ID codes, locations and names;
mksub
produces subsets of data; read.msc
reads MSC archive files, such as A1128551.DLY
data(mscstn) data(mscdata) par.orig <- par(no.readonly=TRUE) # structure in R str(mscdata) # first few rows head(mscdata) # here are all the station IDs stnids <- levels(mscdata$id) # show all data rng.p <- range(mscdata$precip, na.rm=TRUE) rng.t <- range(mscdata$t_mean, na.rm=TRUE) par(mfcol=c(2, 3), mgp=c(2, 1, 0), mar=c(3, 3, 3, 1), bty="l") for (n in levels(mscdata$id)) { dat <- mscdata[mscdata$id == n,] plot(t_mean ~ date, dat, "l", col="red", ylim=rng.t) abline(h=0) plot(precip ~ date, dat, "l", col="blue", ylim=rng.p, main=n) } par(par.orig) # show stations and station names available in this data frame data.frame(stnids, name=getstnname(stnids)) dat <- mksub(mscdata, id=1108447) dat$month <- mkseas(dat, "mon") plot(t_mean ~ date, dat, "l") plot(t_mean ~ date, dat, subset=(month == "Dec")) seas.temp.plot(dat) year.plot(dat) # plot high-resolution statistics dly.tmp <- tapply(dat$t_mean, dat$yday, quantile, c(5, 25, 50, 75, 95) / 100, na.rm=TRUE) dly <- data.frame(yday=1:366, t(matrix(unlist(dly.tmp), nrow=5))) names(dly) <- c("yday", "d5", "d25", "median", "d75", "d95") plot(median ~ yday, dly, "n", ylim=c(-5, 25), ylab="mean temperature", xlab="day of year") polygon(c(1:366, 366:1), c(dly$d5, rev(dly$d95)), border=FALSE, col="grey80") polygon(c(1:366, 366:1), c(dly$d25, rev(dly$d75)), border=FALSE, col="grey50") lines(median ~ yday, dly) abline(h=0)
data(mscstn) data(mscdata) par.orig <- par(no.readonly=TRUE) # structure in R str(mscdata) # first few rows head(mscdata) # here are all the station IDs stnids <- levels(mscdata$id) # show all data rng.p <- range(mscdata$precip, na.rm=TRUE) rng.t <- range(mscdata$t_mean, na.rm=TRUE) par(mfcol=c(2, 3), mgp=c(2, 1, 0), mar=c(3, 3, 3, 1), bty="l") for (n in levels(mscdata$id)) { dat <- mscdata[mscdata$id == n,] plot(t_mean ~ date, dat, "l", col="red", ylim=rng.t) abline(h=0) plot(precip ~ date, dat, "l", col="blue", ylim=rng.p, main=n) } par(par.orig) # show stations and station names available in this data frame data.frame(stnids, name=getstnname(stnids)) dat <- mksub(mscdata, id=1108447) dat$month <- mkseas(dat, "mon") plot(t_mean ~ date, dat, "l") plot(t_mean ~ date, dat, subset=(month == "Dec")) seas.temp.plot(dat) year.plot(dat) # plot high-resolution statistics dly.tmp <- tapply(dat$t_mean, dat$yday, quantile, c(5, 25, 50, 75, 95) / 100, na.rm=TRUE) dly <- data.frame(yday=1:366, t(matrix(unlist(dly.tmp), nrow=5))) names(dly) <- c("yday", "d5", "d25", "median", "d75", "d95") plot(median ~ yday, dly, "n", ylim=c(-5, 25), ylab="mean temperature", xlab="day of year") polygon(c(1:366, 366:1), c(dly$d5, rev(dly$d95)), border=FALSE, col="grey80") polygon(c(1:366, 366:1), c(dly$d25, rev(dly$d75)), border=FALSE, col="grey50") lines(median ~ yday, dly) abline(h=0)
Meteorological Service of Canada weather station data, including national ID, station ID, Province, latitude and longitude.
A data.frame
with 4493 climate stations with the
following 6 columns:
name |
Full station name |
nid |
National ID, alphanumeric key |
sid |
Station ID, also used for airport codes |
prov |
Canadian Province |
lat |
Decimal degrees latitude; NAD83 |
long |
Decimal degrees longitude; NAD83 |
This data object is used as a look-up table to convert a unique
station identifier (nid
) or ID into a station name, using
getstnname
.
Currently, this data only includes weather stations from Alberta, British Columbia and the Yukon.
Mike Toews
Provided by the Meteorological Service of Canada, with permission.
str(seas::mscstn) table(mscstn$prov) plot(lat ~ long, seas::mscstn, pch=".")
str(seas::mscstn) table(mscstn$prov) plot(lat ~ long, seas::mscstn, pch=".")
Plots interarrivals for precipitation using boxplots, giving the typical number of continuous wet days and dry days (or spells) throughout the season. The mean value is also drawn as a single line.
## S3 method for class 'interarrival' plot(x, width = 11, start = 1, rep = 0, start.day = 1, ylog = FALSE, maxy, main, ...)
## S3 method for class 'interarrival' plot(x, width = 11, start = 1, rep = 0, start.day = 1, ylog = FALSE, maxy, main, ...)
x |
an |
width |
size of bin; see |
start |
starting bin number; e.g., if |
rep |
repetition of the bins in the boxplot |
start.day |
when |
ylog |
|
maxy |
maximum number of days for the y-axis; it can either be
passed as |
main |
main title for plot, otherwise other title will be automatically generated |
... |
ignored |
Mike Toews
data(mscdata) dat.int <- interarrival(mksub(mscdata, id=1108447)) plot(dat.int, width="mon") plot(dat.int, ylog=FALSE, maxy=35, rep=10)
data(mscdata) dat.int <- interarrival(mksub(mscdata, id=1108447)) plot(dat.int, width="mon") plot(dat.int, ylog=FALSE, maxy=35, rep=10)
Plots a “normal” of a seasonal variable, including a precipitation normal (which shows rain and snow fractions, where available). Significant missing data values are also indicated.
## S3 method for class 'seas.norm' plot(x, start = 1, rep = 0, ylim, varwidth = FALSE, normwidth = FALSE, leg, add.alt = FALSE, main, ylab, ...)
## S3 method for class 'seas.norm' plot(x, start = 1, rep = 0, ylim, varwidth = FALSE, normwidth = FALSE, leg, add.alt = FALSE, main, ylab, ...)
x |
a |
start |
starting bin |
rep |
repeat bins |
ylim |
range of y-axis; either as a single value,
|
varwidth |
|
normwidth |
normalizes the width of the bars to a fixed
|
leg |
if |
add.alt |
|
main |
title for plot; if it is missing, then it will automatically be generated |
ylab |
y-axis label; if it is missing, then it will automatically be generated |
... |
ignored |
The varwidth
variable is useful for separating different
precipitation patterns throughout the season. It changes the width of
the bar proportional to the frequency of precipitation events within
the bin. Ideally, the bars will be tall and narrow with intense storms
that occur infrequently, such as convective storms. Conversely the
bars will be broader with less-intense rainfall events occurring more
frequently.
Mike Toews
seas.norm
, precip.norm
,
seas.sum
data(mscdata) dat <- mksub(mscdata, id=1108447) d.ss <- seas.sum(dat) plot(seas.norm(d.ss)) plot(precip.norm(d.ss, fun=median)) plot(precip.norm(d.ss, fun=mean)) plot(precip.norm(d.ss, fun=mean, norm="active")) plot(precip.norm(d.ss, fun=median, norm="active")) plot(precip.norm(d.ss), start=15, rep=12) mar <- par("mar") plot(precip.norm(d.ss), add.alt=TRUE) par(mar=mar) d2.ss <- seas.sum(dat, start.day=as.Date("2000-08-01")) plot(precip.norm(d2.ss, fun="mean"))
data(mscdata) dat <- mksub(mscdata, id=1108447) d.ss <- seas.sum(dat) plot(seas.norm(d.ss)) plot(precip.norm(d.ss, fun=median)) plot(precip.norm(d.ss, fun=mean)) plot(precip.norm(d.ss, fun=mean, norm="active")) plot(precip.norm(d.ss, fun=median, norm="active")) plot(precip.norm(d.ss), start=15, rep=12) mar <- par("mar") plot(precip.norm(d.ss), add.alt=TRUE) par(mar=mar) d2.ss <- seas.sum(dat, start.day=as.Date("2000-08-01")) plot(precip.norm(d2.ss, fun="mean"))
Plots normalized seasonal sums using boxplots.
## S3 method for class 'seas.sum' plot(x, var, norm = "days", year.filter, ylim, start = 1, rep = 0, col = "lightgrey", main, ylab, ...)
## S3 method for class 'seas.sum' plot(x, var, norm = "days", year.filter, ylim, start = 1, rep = 0, col = "lightgrey", main, ylab, ...)
x |
a |
var |
name of seasonal variable in |
norm |
a variable to normalize by, either |
year.filter |
use only these years for analysis |
ylim |
either a single value for |
start |
starting bin at left-hand side of plot |
rep |
repeat bins on right-hand side of plot |
col |
colour for boxplot, default is |
main |
title for plot; if it is missing, then it will automatically be generated |
ylab |
y-axis label; if it is missing, then it will automatically be generated |
... |
ignored |
This function is a boxplot interpretation of a seas.sum
object. This is not the same as treating var
as a continuous
variable and using seas.var.plot
, since a seas.sum
object has been smoothed. Daily extreme values are not well
represented here as a result.
The appearance of the boxplots are sensitive to the width
parameter specified in the seas.sum
function on strongly
discontinuous variables. Small bin widths capture the discontinuities
better than wider bins, and changes the skew of the distribution.
For instance, the median will appear to decrease as width
decreases.
Mike Toews
seas.sum
, image.seas.sum
, seas.norm
data(mscdata) par.orig <- par(no.readonly=TRUE) on.exit(par.orig) dat <- mksub(mscdata, id=1108447) dat.ss <- seas.sum(dat) # Normalized by the number of days in each bin plot(dat.ss) # Normalized by the number of active days in each bin plot(dat.ss, norm="active") # Snow, using a different start day, and a better y-axis: dat2.ss <- seas.sum(dat, var="snow", width="mon", start.day=as.Date("2000-08-01")) par(yaxs="i") plot(dat2.ss, var="snow") plot(dat2.ss, var="snow", norm="active")
data(mscdata) par.orig <- par(no.readonly=TRUE) on.exit(par.orig) dat <- mksub(mscdata, id=1108447) dat.ss <- seas.sum(dat) # Normalized by the number of days in each bin plot(dat.ss) # Normalized by the number of active days in each bin plot(dat.ss, norm="active") # Snow, using a different start day, and a better y-axis: dat2.ss <- seas.sum(dat, var="snow", width="mon", start.day=as.Date("2000-08-01")) par(yaxs="i") plot(dat2.ss, var="snow") plot(dat2.ss, var="snow", norm="active")
Calculate the cumulative precipitation departure (CPD) for a station with a given precipitation normal.
precip.dep(x, norm, var = "precip")
precip.dep(x, norm, var = "precip")
x |
a seasonal |
norm |
a |
var |
a common seasonal variable found in |
This function is useful for looking at the behaviour of a precipitation time-series in relation to its precipitation normal over an extended period of time. This is especially useful for identifying changes in precipitation, and is useful for relating to groundwater recharge patterns.
Returns a data.frame
similar to x
, but contains the
departures in the dep
column.
The selection of fun
in precip.norm
, such as
using mean
or median
, will affect
the result of this function; width
has only a minor effect.
Periods with missing (NA
) values in var
of x
will
have a flat departure, neither increasing nor decreasing.
Mike Toews
data(mscstn) data(mscdata) dat <- mksub(mscdata, id=1108447) dat.ss <- seas.sum(dat) dat.dep <- precip.dep(dat,precip.norm(dat.ss, fun="mean")) plot(dep ~ date, dat.dep, type="l", main="CPD from mean normals") dat.dep <- precip.dep(dat, precip.norm(dat.ss, fun="median")) plot(dep ~ date, dat.dep, type="l", main="CPD from median normals")
data(mscstn) data(mscdata) dat <- mksub(mscdata, id=1108447) dat.ss <- seas.sum(dat) dat.dep <- precip.dep(dat,precip.norm(dat.ss, fun="mean")) plot(dep ~ date, dat.dep, type="l", main="CPD from mean normals") dat.dep <- precip.dep(dat, precip.norm(dat.ss, fun="median")) plot(dep ~ date, dat.dep, type="l", main="CPD from median normals")
Reads a Meteorological Service of Canada (MSC) digital archive files (HLY and DLY formats) into a data.frame.
read.msc(file, flags = FALSE, add.elem, format, verbose = TRUE)
read.msc(file, flags = FALSE, add.elem, format, verbose = TRUE)
file |
file name (with path, if not in |
flags |
|
add.elem |
either a |
format |
parameter ignored and will be removed in a future release |
verbose |
|
This function currently reads in HLY (hourly) and DLY (daily) archive formats. This is automatically detected. The other formats, FIF (fifteen-minute) and MLY (monthly), are not currently supported.
The input file can include multiple stations and multiple elements
(measured variables). The multiple stations are deciphered through
the id
column, and the multiple variables appear as columns to
the output data frame.
This function currently only reads a limited number of elements, however additional elements can be used by editing two lines in the R source for this function.
Returns a data.frame
object with the following minimum
fields:
id
:factor
used to distinguish multiple
stations within a single data frame
year
:integer
year
yday
:integer
day of year; 1–365 or 1–366
date
:Date
, useful for plotting a continuous
time-series
datetime
:POSIXct
, includes date and time
info, only included if file
is in HLY archive format
element
:numeric
, with
attributes
set for units
and
long.name
; these can be changed using attr
on
dat$varname
flag
:factor
; included if flags=TRUE
The are as many element
columns for each element found in the
archive file, such as:
alias | name | long.name | units |
1 | t_max |
daily maximum temperature | °C |
2 | t_min |
daily minimum temperature | °C |
3 | t_mean |
daily mean temperature | °C |
10 | rain |
total rainfall | mm |
11 | snow |
total snowfall | mm |
12 | precip |
total precipitation | mm |
13 | snow_d |
snow on the ground | cm |
... | ... | other elements | optional |
Additional elements (or variables) can be added by specifying the
element
variable, and their units can be set using, for
example, attr(dat$var, "units") <- "cm"
.
Units are in common metric units: ‘mm’ for precipitation-related
measurements, ‘cm’ for snow depth, and
‘?C’ for temperature. The flag
columns are
a single character factor
, described in the MSC
Archive documentation. Units are added to each column using, for example
attr(dat$precip, "units") <- "mm"
.
Mike Toews
Climate data can be requested from MSC, or can be obtained
directly from the Canadian Daily Climate Data (CDCD)
CD-ROMs, which are available for a free download (procedure described
in A1128551.DLY
).
https://web.archive.org/web/20130625230337/http://climate.weatheroffice.gc.ca/prods_servs/documentation_index_e.html (archived) Technical Documentation - Documentation for the Digital Archive of Canadian Climatological Data (Surface) Identified By Element
http://climate.weatheroffice.gc.ca/prods_servs/index_e.html#cdcd
(dead link) CDCD CD-ROM download location
mscstn
, mksub
, mkseas
,
A1128551.DLY
fname <- system.file("extdata", "A1128551.DLY", package="seas") print(fname) dat <- read.msc(fname) print(head(dat)) seas.temp.plot(dat) year.plot(dat) # Show how to convert from daily to monthly data dat$yearmonth <- factor(paste(format(dat$date, "%Y-%m"), 15, sep="-")) mlydat <- data.frame(date=as.Date(levels(dat$yearmonth))) mlydat$year <- factor(format(mlydat$date, "%Y")) mlydat$month <- mkseas(mlydat, "mon") # means for temperature data mlydat$t_max <- as.numeric( tapply(dat$t_max, dat$yearmonth, mean, na.rm=TRUE)) mlydat$t_min <- as.numeric( tapply(dat$t_min, dat$yearmonth, mean, na.rm=TRUE)) mlydat$t_mean <- as.numeric( tapply(dat$t_mean, dat$yearmonth, mean, na.rm=TRUE)) # sums for precipitation-related data mlydat$rain <- as.numeric( tapply(dat$rain, dat$yearmonth, sum, na.rm=TRUE)) mlydat$snow <- as.numeric( tapply(dat$snow, dat$yearmonth, sum, na.rm=TRUE)) mlydat$precip <- as.numeric( tapply(dat$precip, dat$yearmonth, sum, na.rm=TRUE)) print(head(mlydat), 12) # Show how to convert from a HLY file into daily summaries ## Not run: hlydat <- read.msc(bzfile("HLY11_L1127800.bz2"), flags=TRUE) hlydat$date <- factor(hlydat$date) # sum the solar radiation for each day to find the 'total daily' sumdat <- tapply(hlydat$solar, hlydat$date, sum, na.rm=TRUE) dlydat <- data.frame(date=as.Date(names(sumdat)), solar=as.numeric(sumdat)) # sum the number of hours without measurements sumdat <- tapply(hlydat$solar, hlydat$date, function(v)(24 - sum(!is.na(v)))) dlydat$na <- as.integer(sumdat) # quality control to remove days with less than 4 hours missing Summerland <- dlydat[dlydat$na < 4,] attr(Summerland$solar, "units") <- "W/(m^2*day)" attr(Summerland$solar, "long.name") <- "Daily total global solar radiation" seas.var.plot(Summerland, var="solar", col="yellow", width=5) ## End(Not run)
fname <- system.file("extdata", "A1128551.DLY", package="seas") print(fname) dat <- read.msc(fname) print(head(dat)) seas.temp.plot(dat) year.plot(dat) # Show how to convert from daily to monthly data dat$yearmonth <- factor(paste(format(dat$date, "%Y-%m"), 15, sep="-")) mlydat <- data.frame(date=as.Date(levels(dat$yearmonth))) mlydat$year <- factor(format(mlydat$date, "%Y")) mlydat$month <- mkseas(mlydat, "mon") # means for temperature data mlydat$t_max <- as.numeric( tapply(dat$t_max, dat$yearmonth, mean, na.rm=TRUE)) mlydat$t_min <- as.numeric( tapply(dat$t_min, dat$yearmonth, mean, na.rm=TRUE)) mlydat$t_mean <- as.numeric( tapply(dat$t_mean, dat$yearmonth, mean, na.rm=TRUE)) # sums for precipitation-related data mlydat$rain <- as.numeric( tapply(dat$rain, dat$yearmonth, sum, na.rm=TRUE)) mlydat$snow <- as.numeric( tapply(dat$snow, dat$yearmonth, sum, na.rm=TRUE)) mlydat$precip <- as.numeric( tapply(dat$precip, dat$yearmonth, sum, na.rm=TRUE)) print(head(mlydat), 12) # Show how to convert from a HLY file into daily summaries ## Not run: hlydat <- read.msc(bzfile("HLY11_L1127800.bz2"), flags=TRUE) hlydat$date <- factor(hlydat$date) # sum the solar radiation for each day to find the 'total daily' sumdat <- tapply(hlydat$solar, hlydat$date, sum, na.rm=TRUE) dlydat <- data.frame(date=as.Date(names(sumdat)), solar=as.numeric(sumdat)) # sum the number of hours without measurements sumdat <- tapply(hlydat$solar, hlydat$date, function(v)(24 - sum(!is.na(v)))) dlydat$na <- as.integer(sumdat) # quality control to remove days with less than 4 hours missing Summerland <- dlydat[dlydat$na < 4,] attr(Summerland$solar, "units") <- "W/(m^2*day)" attr(Summerland$solar, "long.name") <- "Daily total global solar radiation" seas.var.plot(Summerland, var="solar", col="yellow", width=5) ## End(Not run)
Reads and writes the data format used in SDSM's ‘DAT’ and ‘OUT’ extensions.
# reading read.sdsm(file, start = 1961, end = 2000, calendar) # writing write.sdsm(dat, var, start, end, file = "")
# reading read.sdsm(file, start = 1961, end = 2000, calendar) # writing write.sdsm(dat, var, start, end, file = "")
file |
name of ‘DAT’ or ‘OUT’ file |
dat |
|
start |
starting year |
end |
ending year |
var |
name of variable to be written from |
calendar |
calender used for data; if unspecified, this is
assumed to be proleptic Gregorian (normal); however, for CCCma
models this should be "365_day", and for Hadley models this should
be "360_day"; see |
This function readings and writes climate data with the Statistical Downscaling Model, or SDSM. The model uses ‘DAT’ extensions for input data, such as daily observations of mean temperature, and ‘OUT’ extensions for modeled output.
read.sdsm
returns a data.frame
of the measured
variables. The variables are named V1
...Vn
,
for n ensembles.
If a calendar
is specified, this is stored as an attribute in
the date
data frame column.
Mike Toews
Wilby, R.L., Dawson, C.W. and Barrow, E.M. 2002. SDSM — a decision support tool for the assessment of regional climate change impacts, Environmental Modelling Software, 17 (2), 145–157, doi:10.1016/S1364-8152(01)00060-3
SDSM can be downloaded free-of-charge for Windows platforms from
https://www.sdsm.org.uk/
CGCM1 and HADCM3 model data for SDSM can be downloaded from the
Canadian Climate Impacts and Scenarios website:
https://web.archive.org/web/20120218192015/http://www.cics.uvic.ca/scenarios/sdsm/select.cgi (archived)
## Not run: # reading fname <- system.file("extdata", "GF_2050s_precip.OUT", package="seas") gf50 <- read.sdsm(fname) gf50.ss <- seas.sum(gf50, var=paste("V", 1:20, sep=""), name="Grand Forks") # analysis image(gf50.ss, var="V1") image(gf50.ss, var="V2") image(gf50.ss, var="V3") # writing data(mscdata) hj <- mksub(mscdata, id=2100630) fname <- paste(tempdir(), "HJ_Obs_prcp.DAT", sep="/") write.sdsm(hj, "precip", 1961, 2000, fname) ## End(Not run)
## Not run: # reading fname <- system.file("extdata", "GF_2050s_precip.OUT", package="seas") gf50 <- read.sdsm(fname) gf50.ss <- seas.sum(gf50, var=paste("V", 1:20, sep=""), name="Grand Forks") # analysis image(gf50.ss, var="V1") image(gf50.ss, var="V2") image(gf50.ss, var="V3") # writing data(mscdata) hj <- mksub(mscdata, id=2100630) fname <- paste(tempdir(), "HJ_Obs_prcp.DAT", sep="/") write.sdsm(hj, "precip", 1961, 2000, fname) ## End(Not run)
Check the suitability of a data.frame
or
seas.sum
object for seas.
seas.df.check(x, orig, var) seas.sum.check(x, orig, var, norm, year.filter, ann.only)
seas.df.check(x, orig, var) seas.sum.check(x, orig, var, norm, year.filter, ann.only)
x |
a data frame with temporal observations |
orig |
the original name of the data frame, for error messages |
var |
one or more variables in |
norm |
something to normalize |
year.filter |
a subset of |
ann.only |
|
This utility function simply checks the suitability of a
data.frame
or seas.sum
objects for use with
seas.
If x
is data.frame
(using seas.df.check
that is
really required, is a ‘date’ column, named x$date
with a
class of either link{POSIXct}
or link{Date}
, and
one or more variables in the var
columns of x
.
There must be at least one finite observation in each of var
,
if supplied.
These function is used within other functions, and is not intended to be called directly.
seas.df.check
returns a few helpful items from x
in a
list
using invisible
:
id
:station ID from one of attr(x,"id")
or
x$id[1]
name
:name of seasonal data, such as a place
year.range
:integers of start, and ending years
calendar
:an attribute from x$date
;
otherwise this will be NULL
for a normal proleptic
Gregorian calendar
main
:main title, from .seastitle
units
:units for var[1]
long.name
:long name for var[1]
ylab
:y-axis label for var[1]
seas.sum.check
returns x
with modifications, depending
on norm
and year.filter
.
Mike Toews
hidden
functions for seas
data(mscdata) dat <- mksub(mscdata, id=1108447) str(seas.df.check(dat)) dat.ss <- seas.sum(dat) str(seas.sum.check(dat.ss, norm="days"))
data(mscdata) dat <- mksub(mscdata, id=1108447) str(seas.df.check(dat)) dat.ss <- seas.sum(dat) str(seas.sum.check(dat.ss, norm="days"))
Calculates annual and seasonal ‘normal’ statistics on a
seas.sum
object, including precipitation normals for
rain, snow and total precipitation.
seas.norm(x, var, fun = "median", norm = "days", year.filter, ann.only = FALSE, precip.norm = FALSE) precip.norm(x, fun = "median", norm = "days", year.filter)
seas.norm(x, var, fun = "median", norm = "days", year.filter, ann.only = FALSE, precip.norm = FALSE) precip.norm(x, fun = "median", norm = "days", year.filter)
x |
|
var |
variable name for the ‘normal’; if omitted will
use |
norm |
variable for normalization of the sum, usually the number of "days" in each bin, but it can also be "active" to estimate the precipitation normal for days of active precipitation |
year.filter |
filter specific years for analysis |
fun |
|
ann.only |
only annual statistics returned (saves time from other calculations) |
precip.norm |
|
This function calculates the statistics of precipitation data on an
annual and seasonal scope from a seas.sum
object.
The seasonal input data are normalized by the number of days in each
bin, to produce a precipitation rate in ‘mm/day’. This is
because the number of days in each bin is not equal. The function
fun
is then applied to the normalized precipitation, and
operates along each bin, across multiple years of data. The supplied
function is usually "median"
or "mean"
,
but it can also be a built in R function, such as "var"
for variance, or a composite such as:
function(i, na.rm)(quantile(i, 0.2, na.rm=na.rm, names=F)) |
the 20% quantile |
function(i, na.rm)(mean(i, na.rm=na.rm)/(sd(i, na.rm=na.rm)^3)) |
skewness |
If fun = "mean"
, then the statistics are
straightforward (using apply
), however if fun =
"median"
and there are more than 2 years of data, a different
approach is taken. The median is a special case of the
quantile function, where the probability is 50% of the
population. The median
and quantile
functions are more resistant to outliers than mean
, and
can have advantages on precipitation data. Precipitation occurring
at a given time of year does not have a normal distribution since it
is a value that is not always occurring. It often has a left-skewed
distribution, consisting of many zero measurements, and few extreme
precipitation events.
In this function, if fun = "median"
(default) the
median
function is only used to calculate the median
annual precipitation. The quantile
function is used to
calculate the seasonal statistics, since the sum of medians applied in
each bin are less than the median annual precipitation. This is
because there are usually many measurements of no rain, which skew the
distribution to the left. The percentile for the quantile function is
found using a secant method (Cheny and Kincaid, 1999) such that the
sum of the quantiles from each bin are equal to the median of the
annual precipitation.
Snow and rain (which are the two components of precipitation) are
calculated similarly (if fun = "median"
). The annual total
rain and snow amounts are determined by finding the percentile of a
quantile function where the sum is equal to the median of the annual
precipitation. The seasonal snow and rain amounts are independently
found using the same method to find the seasonal precipitation. The
fraction of the snow in each bin,
is multiplied by the seasonal
precipitation to determine the seasonal rain and snow amounts. This
is because the sum of rain and snow in each bin does not equal the
seasonal precipitation. This way, a figure with
precip.only = TRUE
and = FALSE
will have identical daily
precipitation rates in each bin.
The pitfalls of calculating precipitation ‘normals’ is that it assumes that precipitation occurs every day at a constant rate within each bin. This is not realistic, as the precipitation rates are much higher when it is actually occurring.
Returns a precip.norm
object, which is a list
with the following elements:
seas |
An |
ann |
Annual precipitation statistics. |
width |
from |
bins |
from |
bin.lengths |
maximum number of days in each bin |
year.range |
from |
start.day |
from |
var |
same as input parameter |
units |
units for |
long.name |
long name for |
ann.only |
ann.only same as input parameter |
precip.only |
from same as input parameter |
a.cut |
from |
fun |
|
id |
from |
name |
from |
Seasonal data are explicitly normalized to a rate per day (i.e., mm/day), and not per month (i.e., mm/month). This is because a time-derivative per month has unequal intervals of time, ranging between 28 to 31 days. This directly creates up to 10% error in the analysis between months.
Units for annual normals, however, remain per year, since a year is a suitable time derivative.
Mike Toews
Cheny, E. W. and Kincaid, D. 1999, Numerical Mathematics and Computing, Pacific Grove: Brooks/Cole Pub., 671 p.
Guttman, N.B. 1989, ‘Statistical descriptors of climate’, American Meteorological Society, 70, 602–607.
plot.seas.norm
, seas.var.plot
,
precip.dep
data(mscdata) # calculate precipitation normal dat <- mksub(mscdata, id=1108447) dat.ss <- seas.sum(dat) dat.nm <- precip.norm(dat.ss, fun="mean") # plot precipitation normal plot(dat.nm) # this is the same as plot.precip.norm(dat.nm) # use precipitation normal dat.dep <- precip.dep(dat, dat.nm) plot(dep ~ date, dat.dep, type="l", main="CPD from mean normals")
data(mscdata) # calculate precipitation normal dat <- mksub(mscdata, id=1108447) dat.ss <- seas.sum(dat) dat.nm <- precip.norm(dat.ss, fun="mean") # plot precipitation normal plot(dat.nm) # this is the same as plot.precip.norm(dat.nm) # use precipitation normal dat.dep <- precip.dep(dat, dat.nm) plot(dep ~ date, dat.dep, type="l", main="CPD from mean normals")
Create a seasonal sum object used for analysis of precipitation data (among other things, such as recharge rates); this object has sums in each ‘bin’ of a season, as well as for each annum (or year).
seas.sum(x, var, width = 11, start.day = 1, prime, a.cut = 0.3, na.cut = 0.2)
seas.sum(x, var, width = 11, start.day = 1, prime, a.cut = 0.3, na.cut = 0.2)
x |
a |
var |
the names of one or more variables in |
width |
a number specifying the width of the bin (factor) in
days, or |
start.day |
the first day of the season, specified as either a
|
prime |
a single variable from |
a.cut |
cut-off value for the day to be considered an
active or ‘wet day’ (based on the |
na.cut |
cut-off fraction of missing values; can be single value
or a vector for |
This function is used to discretize and sum time-varying data in a
data.frame
for analysis in seasonal and
annual parts. This is particularly useful for calculating
normals of rates, such as precipitation and recharge. This function
simply sums up each variable in each bin for each annum (or year), and
provides the results in several arrays.
Sums are not normalized, and represent a sum for the number of
days in the bin (seasonal data) or annum (for annual data). Seasonal
data can be normalized by the number of days (for a rate per day) or
by the number of active days where prime > a.cut
.
For annual sums, annums with many missing values are ignored
(receiving a value of NA
) since it has insufficient data for a
complete sum. The amount of allowable NA
values per annum is
controlled by na.cut[1]
, which is a fraction of NA
values for the whole annum (default is 0.2).
The seasonal sums are calculated independently from the annual
sums. Individual bins from each year with many missing values
are ignored, where the amount of allowable NA
values is
controlled by na.cut[2]
(or na.cut[1]
, if the
length
of na.cut
is 1). The default fraction of
NA
s in each bin of each annum is 0.2.
Returns a seas.sum
object, which is a list
with
the following elements:
ann
:A data.frame
of annual data; the columns are:
year
:year, or annum
active
:the number of ‘active’ days in the year
where the prime variable is above a.cut
(if used)
days
:number of days in each year
na
:number of missing days in the year
annual sum of one or more variable; if the original units were mm/day, they are now mm/year
seas
:An array:
of seasonal data; the dimensions are:
[[1]]
:year, or annum
[[2]]
:bins, or seasonal factors generated by
mkseas
[[3]]
:sums of variables for each bin of each year; if
the original unit was mm/day, it is now mm per number of
days, which is held in the days
item
active
:the number of ‘active’ days in the bin
where the prime variable is above a.cut
(if used)
days
:an array of the number of days in each bin; this
array is useful for normalizing the numbers in seas
to
comparable units of mm/day
na
:number of missing days in each bin
start.day
:same as input
years
:years (same as ann[[1]]
and
seas[[1]]
); if start.day
is not 1, this represents the
starting and ending years (i.e., 1991_1992
) of each annum;
see mkann
var
:variable(s) which the sums represent (part of
ann[[2]]
and seas[[3]]
)
units
:a list
of units for each
var
, such as “mm/day”; these are obtained from the
units
attribute (using attr
) found in
x$var
long.name
:a list
of long names for each var
;
these are obtained from long.name
in x$var
; set to
be var
if NULL
prime
:a prime
variable, such as "precip"
width
:width
argument passed to mkseas
bins
:names of bins returned by mkseas
(same as
seas[[2]]
)
bin.lengths
:the maximum length in days for each bin
year.range
:range of years from x
precip.only
:value used in argument (modified if
insufficient data found in x
)
na.cut
:value used in argument
a.cut
:value used in argument; if it is zero or
NA
, this will be FALSE
id
:from attr(x,"id")
(NULL
if not set)
name
:from attr(x,"name")
(NULL
if not set)
Mike Toews
To view the result try image.seas.sum
, or
alternatively, plot.seas.sum
To calculate and view a “normal”, use seas.norm
and plot.seas.norm
, or for precipitation use
precip.norm
and plot.precip.norm
data(mscdata) dat <- mksub(mscdata, id=1108447) dat.ss <- seas.sum(dat, width="mon") # Structure in R str(dat.ss) # Annual data dat.ss$ann # Demonstrate how to slice through a cubic array dat.ss$seas["1990",,] dat.ss$seas[,2,] # or "Feb", if using English locale dat.ss$seas[,,"precip"] # Simple calculation on an array (monthly.mean <- apply(dat.ss$seas[,,"precip"], 2, mean,na.rm=TRUE)) barplot(monthly.mean, ylab="Mean monthly total (mm/month)", main="Un-normalized mean precipitation in Vancouver, BC") text(6.5, 150, paste("Un-normalized rates given 'per month' should be", "avoided since ~3-9% error is introduced", "to the analysis between months", sep="\n")) # Normalized precip norm.monthly <- dat.ss$seas[,,"precip"] / dat.ss$days norm.monthly.mean <- apply(norm.monthly, 2, mean,na.rm=TRUE) print(round(norm.monthly, 2)) print(round(norm.monthly.mean, 2)) barplot(norm.monthly.mean, ylab="Normalized mean monthly total (mm/day)", main="Normalized mean precipitation in Vancouver, BC") # Better graphics of data dat.ss <- seas.sum(dat, width=11) image(dat.ss)
data(mscdata) dat <- mksub(mscdata, id=1108447) dat.ss <- seas.sum(dat, width="mon") # Structure in R str(dat.ss) # Annual data dat.ss$ann # Demonstrate how to slice through a cubic array dat.ss$seas["1990",,] dat.ss$seas[,2,] # or "Feb", if using English locale dat.ss$seas[,,"precip"] # Simple calculation on an array (monthly.mean <- apply(dat.ss$seas[,,"precip"], 2, mean,na.rm=TRUE)) barplot(monthly.mean, ylab="Mean monthly total (mm/month)", main="Un-normalized mean precipitation in Vancouver, BC") text(6.5, 150, paste("Un-normalized rates given 'per month' should be", "avoided since ~3-9% error is introduced", "to the analysis between months", sep="\n")) # Normalized precip norm.monthly <- dat.ss$seas[,,"precip"] / dat.ss$days norm.monthly.mean <- apply(norm.monthly, 2, mean,na.rm=TRUE) print(round(norm.monthly, 2)) print(round(norm.monthly.mean, 2)) barplot(norm.monthly.mean, ylab="Normalized mean monthly total (mm/day)", main="Normalized mean precipitation in Vancouver, BC") # Better graphics of data dat.ss <- seas.sum(dat, width=11) image(dat.ss)
Plot seasonal temperature normals using boxplots, and also plot seasonal diurnal variability between minimum and maximum temperature.
seas.temp.plot(x, width = 11, start = 1, rep = 0, start.day = 1, var = c("t_min", "t_max", "t_mean"), add.alt = FALSE, ylim, main, ylab, ...)
seas.temp.plot(x, width = 11, start = 1, rep = 0, start.day = 1, var = c("t_min", "t_max", "t_mean"), add.alt = FALSE, ylim, main, ylab, ...)
x |
a |
width |
size of bin; see |
start |
starting bin number; e.g., if |
rep |
repetition of the bins in the boxplots |
start.day |
if |
var |
array specifying the names of the columns in |
add.alt |
|
ylim |
|
main |
title for plot; if it is missing, then it will automatically be generated |
ylab |
y-axis label; if it is missing, then it will automatically be generated |
... |
ignored |
Plots boxplots for seasonal temperature normals from mean daily temperature, and diurnal variability with the mean difference of daily minimum and maximum temperatures (red vertical lines). If the mean is not supplied, it is calculated from the mean of daily maximum and minimum temperatures.
Returns values from boxplot
statistics on mean temperature.
This function was formerly named plot.seas.temp
, but required
renaming as it is not an S3 method.
Mike Toews
seas.var.plot
, plot.seas.norm
,
year.plot
Use mksub
to make a subset of x
.
data(mscdata) dat <- mksub(mscdata, id=1108447) seas.temp.plot(dat) seas.temp.plot(dat, width="mon", add.alt=TRUE) # starting and ending elsewhere seas.temp.plot(dat, start=18, rep=3)
data(mscdata) dat <- mksub(mscdata, id=1108447) seas.temp.plot(dat) seas.temp.plot(dat, width="mon", add.alt=TRUE) # starting and ending elsewhere seas.temp.plot(dat, start=18, rep=3)
Plot seasonal normals of a variable using boxplots.
seas.var.plot(x, var, width = 11, start = 1, rep = 0, start.day = 1, col, ylim, add.alt, alt.ylab, main, ylab, ylog, ...)
seas.var.plot(x, var, width = 11, start = 1, rep = 0, start.day = 1, col, ylim, add.alt, alt.ylab, main, ylab, ylog, ...)
x |
a |
var |
a variable; a column name in |
width |
size of bin; see |
start |
starting bin number; e.g., if |
rep |
repetition of the bins in the boxplot |
start.day |
when |
col |
colour for the boxplots; the default is |
ylim |
|
add.alt |
this adds an alternative axis, and is specified by
|
alt.ylab |
label for the alternate y-axis (the primary y-axis
label is set through attributes for |
main |
title for plot; if it is missing, then it will automatically be generated |
ylab |
y-axis label; if it is missing, then it will automatically be generated |
ylog |
used to |
... |
ignored |
Shows normals of a seasonal variable using boxplots.
Returns values from boxplot
statistics on the variable.
This function was formerly named plot.seas.var
, but required
renaming as it is not an S3 method.
Mike Toews
seas.var.plot
, plot.seas.norm
,
year.plot
.
Use mksub
to make a subset of x
.
opar <- par(no.readonly=FALSE) on.exit(par(opar)) data(mscdata) dat <- mksub(mscdata, id=1108447) seas.var.plot(dat, var="t_max", col="tomato", add.alt=c(5/9, 32), alt.ylab="F") abline(h=0) par(opar) # reset graphics parameters seas.var.plot(dat, var="t_min", start=18, rep=16) pdat <- dat[dat$precip > 0,] attr(pdat$precip, "long.name") <- "precipitation intensity" attr(pdat$precip, "units") <- "mm/day" par(ylog=TRUE) seas.var.plot(pdat, var="precip", col="azure") title(sub="These boxplots are simply plotted on a log-y scale") par(opar) seas.var.plot(pdat, var="precip", col="azure", ylog=TRUE) title(sub="These boxplots are based on log-transformed values") seas.var.plot(pdat, var="precip", col="azure", ylog=TRUE, add.alt=TRUE) title(sub="The actual axis for graph is on the right-side")
opar <- par(no.readonly=FALSE) on.exit(par(opar)) data(mscdata) dat <- mksub(mscdata, id=1108447) seas.var.plot(dat, var="t_max", col="tomato", add.alt=c(5/9, 32), alt.ylab="F") abline(h=0) par(opar) # reset graphics parameters seas.var.plot(dat, var="t_min", start=18, rep=16) pdat <- dat[dat$precip > 0,] attr(pdat$precip, "long.name") <- "precipitation intensity" attr(pdat$precip, "units") <- "mm/day" par(ylog=TRUE) seas.var.plot(pdat, var="precip", col="azure") title(sub="These boxplots are simply plotted on a log-y scale") par(opar) seas.var.plot(pdat, var="precip", col="azure", ylog=TRUE) title(sub="These boxplots are based on log-transformed values") seas.var.plot(pdat, var="precip", col="azure", ylog=TRUE, add.alt=TRUE) title(sub="The actual axis for graph is on the right-side")
Set default options for seas.
setSeasOpts()
setSeasOpts()
setSeasOpts
sets all the default values for options in
seas, and at some point it may support arguments for styles,
such as ‘black and white’. However, after the initial setting of
options, users may change the options to modify the look of graphics
produced in seas.
Other details of the graphics can be modified using
par
. This includes the font sizes, back-ground colour,
font family, and many others. For example, setting par(cex=0.75)
will reduce the font size in the active device by 75% of the
original size; while par(font.main=2)
will change only the font
for the main titles.
setSeasOpts()
only sets the options
in the current
environment, and returns nothing.
This is automatically done when seas is loaded (using
.onLoad
).
Here are all the supported options for seas, with the default
values shown for each option. Options are stored in
list
s, which make them easy to ‘get’, but
difficult to ‘set’, and is shown in the
Examples section at the bottom.
seas.main
:formating style for main title:
fmt
:format for name
and id
(if
available) as the first "%s"
, followed by a range of
years as the second "%s"
; these are formated by
sprintf
; "%s\n%s"
rngsep
:separation between ranges of years; "-"
,
other alternatives could be " to "
show.id
:show id (if available) in main title;
TRUE
show.fun
:show function (where applicable) in
main title; TRUE
seas.label
:label formating for variables:
fmt
:label for name and units (if available);
"%s (%s)"
, other alternatives could be
"%s, %s"
monthday
:format for month and day (see
strftime
for format codes); this can be either
"%b %-d"
(for most Unix-like systems),
"%b %#d"
(for Windows systems), or "%b %d"
(for other systems); this should produce a string, such as
‘Aug 1’ for August 1st
month
similar as previous, but when starting
exactly on month-breaks; "%B"
ann
a label for image.seas.sum
;
default is ‘annual’
seas.month.grid
:setting for the display of the
month grid (see .seasmonthgrid
), which is common to
many plots that use a numeric
width
in
mkseas
:
abb
:abbreviate month names for grid; TRUE
len
:trim month name lengths to a number, for
instance to get J|F|M|A|M|J|J|A|S|O|N|D, use 1
; NULL
force
:force the display of each month label using
mtext
, otherwise labels can be automatically placed
and adjusted for device using axis
; TRUE
label
:show a month label on the grid; TRUE
col
:colour for month grid; "lightgrey"
lwd
:width for month grid lines, multiplied by
par("lwd")
; 1
lty
:style for month grid lines; 1
seas.bxp
:attributes which affect the display of boxplots, used by various functions:
boxcol
:default box-fill colour; "lightgrey"
outcex
:outlier symbol size, multiplied by
par("cex")
; 1
seas.temp
:attributes which affect the display of
seas.temp.plot
(among other functions):
col
:colours for boxplot fill and diurnal variability
lines; c("lightgrey","red")
lwd
:width of diurnal variability lines in
seas.temp.plot
, multiplied by par("lwd")
;
3
seas.precip
:attributes which affect the display of precipitation:
col
:colour; "grey"
density
:pattern density; NULL
angle
:pattern angel; 45
lwd
:thickness of box line, multiplied by
par("lwd")
; 1
seas.rain
:attributes which affect the display of rain:
col
:colour; "lightblue"
density
:pattern density; NULL
angle
:pattern angel; 45
lwd
:thickness of box line, multiplied by
par("lwd")
; 1
seas.snow
:attributes which affect the display of snow:
col
:colour; "lightgrey"
density
:pattern density; NULL
angle
:pattern angel; -45
lwd
:thickness of box line, multiplied by
par("lwd")
; 1
seas.interarrival
:attributes which affect the display
of wet- and dry-spells in plot.interarrival
;
organized as c(wet,dry)
:
col
:colour; c("lightblue","orange")
seas.median
:attributes which affect the display of
the median
lines in image.seas.sum
:
col
:colour; "red"
lwd
:width of line, multiplied by
par("lwd")
; 1
lty
:style of line; 1
seas.mean
:attributes which affect the display of the
mean
lines in image.seas.sum
:
col
:colour; "red"
lwd
:width of line, multiplied by
par("lwd")
; 1
lty
:style of line; 1
seas.na
:attributes which affect the display of
NA
or missing values in various plots:
col
:colour; "red"
pch
:character symbol; "x"
Mike Toews
if(is.null(getOption("seas.main"))) setSeasOpts() # Modify an option getOption("seas.main")$show.id cp <- orig <- getOption("seas.main") cp$show.id <- FALSE options(seas.main=cp) getOption("seas.main")$show.id options(seas.main=orig)
if(is.null(getOption("seas.main"))) setSeasOpts() # Modify an option getOption("seas.main")$show.id cp <- orig <- getOption("seas.main") cp$show.id <- FALSE options(seas.main=cp) getOption("seas.main")$show.id options(seas.main=orig)
Example LARS-WG data file of synthetic data from Summerland, BC.
Both files are ASCII-based, and can be viewed in any text editor
‘summerland.sr’ is the ‘site file’, which contains the meta-data
‘summerland.dat’ is the data file
Details of these file formats can be found in the LARS-WG manual and help documentation.
The sample file name was generated in LARS-WG from calibration of data from Summerland (MSC ID: 1127800). Thirty-years were generated, each synthetic year has 365-days.
Mike Toews
read.lars
, which contains an example using
these files
Write climate data in the format used by the Hydrological Evaluation of Landfill Performance (HELP) model. This exports the data using two slightly different variants of HELP: the DOS versions (3.07 to 3.80D) and for Visual HELP.
write.help(file, dat, var = "", name = "", region, lat, visual.help = FALSE, metric = TRUE)
write.help(file, dat, var = "", name = "", region, lat, visual.help = FALSE, metric = TRUE)
file |
name of output file; [DOS] HELP uses extensions ‘*.D4’, ‘*.D7’, and ‘*.D13’ for daily precipitation, temperature and solar radiation, respectively; Visual HELP uses the file names ‘_weather1.dat’, ‘_weather2.dat’ and ‘_weather3.dat’ for the same series of variables |
dat |
|
var |
variable to be exported; must be one of |
name |
|
region |
|
lat |
|
visual.help |
logical formats output for Visual HELP; else formated for the DOS HELP versions (default) |
metric |
logical if using metric units (this only sets a
flag, please ensure the data are in either °C,
mm/day and |
This utility function is experimental and has not been extensively tested; please report any errors to me.
HELP requires continuous data; no missing values are allowed.
Data imported from SDSM use a 365-day calendar, and can be
approximated using conv365toGregorian
.
Mike Toews
HELP 3.07 - Original version for the US EPA; free download
https://www.epa.gov/land-research/hydrologic-evaluation-landfill-performance-help-model
HELP-D - Developed by Dr. Klaus Berger, University
of Hamburg
https://www.geo.uni-hamburg.de/en/bodenkunde/service/help-model.html
Visual HELP - Uses a similar underlying code as HELP 3.07, but
features a Windows GUI https://www.waterloohydrogeologic.com/visual-help/
(dead link)
read.msc
, read.sdsm
,
read.lars
, conv365toGregorian
Determines the number of days per year using a given calendar.
year.length(x, calendar)
year.length(x, calendar)
x |
year or a |
calendar |
calendar, see details |
The number of days per year depends on the choice of
calendar. Calendar names used in the function are the same defined
for the CF conventions, used for netCDF files. If a calendar is not
specified (or NULL
), then it is assumed to
be a proleptic Gregorian calendar (which extends before
1582-10-15). Other accepted calendars are:
"360"
: always 360-days per year
"365_day"
or "noleap"
: always 365-days per year
"366"
or "all_leap"
: always 366-days per year
"julian"
: 366 days on years divisible by 4, otherwise
365 days
Returns a vector the same length as x
with the numbers of days
corresponding to each year.
Mike Toews
http://cfconventions.org/Data/cf-conventions/cf-conventions-1.7/cf-conventions.html#calendar
cal <- data.frame(year=c(1899, 1900, 1904, 2000, 2080, 2100)) cal[["Gregorian"]] <- year.length(cal$year) cal[["Julian"]] <- year.length(cal$year, "julian") cal[["360_day"]] <- year.length(cal$year, "360_day") cal[["365_day"]] <- year.length(cal$year, "365_day") cal[["366_day"]] <- year.length(cal$year, "366_day") cal
cal <- data.frame(year=c(1899, 1900, 1904, 2000, 2080, 2100)) cal[["Gregorian"]] <- year.length(cal$year) cal[["Julian"]] <- year.length(cal$year, "julian") cal[["360_day"]] <- year.length(cal$year, "360_day") cal[["365_day"]] <- year.length(cal$year, "365_day") cal[["366_day"]] <- year.length(cal$year, "366_day") cal
Plots a continuous set of annual temperature and precipitation statistics for a single climate station.
year.plot(x, start.day = 1, precip.only = FALSE, precip.ylim, temp.ylim, na.cut = 10, ...)
year.plot(x, start.day = 1, precip.only = FALSE, precip.ylim, temp.ylim, na.cut = 10, ...)
x |
a |
start.day |
starting day of annum; either a |
precip.only |
only precipitation data is used; rain and snow ignored |
precip.ylim |
range for precipitation graph |
temp.ylim |
range for temperature graph |
na.cut |
minimum number of missing data points in a year to make it void; temperature and precipitation are treated independently |
... |
ignored |
This simply shows temperature using (boxplot
s) and
annual precipitation totals. The red bars are directly proportional to
the fraction of missing (or NA
) values for the year; statistics
not shown if there are more than na.cut
NA
values in a
given year.
This function was formerly named plot.year
, but required
renaming as it is not an S3 method.
Mike Toews
mscdata
, seas.temp.plot
,
plot.seas.norm
(can be used for precipitation normals),
calculate statistics with tapply
data(mscdata) year.plot(mksub(mscdata, id=1108447)) year.plot(mksub(mscdata, id=1108447, start=as.Date("1975-08-01"), end=as.Date("2004-07-31")), start.day=as.Date("2000-08-01"))
data(mscdata) year.plot(mksub(mscdata, id=1108447)) year.plot(mksub(mscdata, id=1108447, start=as.Date("1975-08-01"), end=as.Date("2004-07-31")), start.day=as.Date("2000-08-01"))