1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
|
### Copyright (C) 2001-2020 Deepayan Sarkar <Deepayan.Sarkar@R-project.org>
###
### This file is part of the lattice package for R.
### It is made available under the terms of the GNU General Public
### License, version 2, or at your option, any later version,
### incorporated herein by reference.
###
### This program is distributed in the hope that it will be
### useful, but WITHOUT ANY WARRANTY; without even the implied
### warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
### PURPOSE. See the GNU General Public License for more
### details.
###
### You should have received a copy of the GNU General Public
### License along with this program; if not, write to the Free
### Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
### MA 02110-1301, USA
## overplot groups, but use default plot.* style rather than superpose.* style
panel.superpose.plain <-
function(..., col = NA, col.line = plot.line$col, col.symbol = plot.symbol$col,
pch = plot.symbol$pch, cex = plot.symbol$cex, fill = plot.symbol$fill,
font = plot.symbol$font, fontface = plot.symbol$fontface,
fontfamily = plot.symbol$fontfamily, lty = plot.line$lty,
lwd = plot.line$lwd, alpha = plot.symbol$alpha)
{
plot.line <- trellis.par.get("plot.line")
plot.symbol <- trellis.par.get("plot.symbol")
if (!missing(col)) {
if (missing(col.line))
col.line <- col
if (missing(col.symbol))
col.symbol <- col
}
panel.superpose(..., col.line = col.line, col.symbol = col.symbol,
pch = pch, cex = cex, fill = fill, font = font,
fontfamily = fontfamily, lty = lty, lwd = lwd, alpha = alpha)
}
xyplot.ts <-
function(x, data = NULL,
screens = if (superpose) 1 else colnames(x),
...,
superpose = FALSE, ## not used directly
cut = FALSE,
type = "l",
col = NULL,
lty = NULL,
lwd = NULL,
pch = NULL,
cex = NULL,
fill = NULL,
auto.key = superpose,
panel = if (superpose) "panel.superpose"
else "panel.superpose.plain",
par.settings = list(),
layout = NULL, as.table = TRUE,
xlab = "Time", ylab = NULL,
default.scales = list(y = list(relation =
if (missing(cut)) "free" else "same")))
{
ocall <- sys.call(); ocall[[1]] <- quote(xyplot)
## fix up some default settings;
## these are too obscure to put in as default arguments
if (NCOL(x) == 1) {
## only one series, so use the more standard "panel.superpose"
if (missing(superpose)) superpose <- TRUE
if (missing(auto.key)) auto.key <- FALSE
}
stopifnot(is.null(data))
timex <- time(x)
x <- as.matrix(x)
if (is.null(colnames(x)))
colnames(x) <- paste("V", seq_len(NCOL(x)), sep = "")
cn <- colnames(x)
## set up shingle for cut-and-stack plot
## (may not work well with irregular series)
time <- NULL
if (is.numeric(cut)) cut <- list(number = cut)
if (isTRUE(cut)) {
## calculate optimum aspect ratio using banking (as for aspect = "xy")
timediff <- diff(timex)
asp <- apply(x, 2, function(y)
banking(timediff, diff(y)) * diff(range(y)) / diff(range(timex))
)
asp <- median(asp)
## work out aspect ratio of n panels in vertical layout on a square
nasp <- 1 / (1:6)
## choose number of cuts so that the "xy" aspect matches layout
number <- which.min(abs(1 - (asp * 1:6) / nasp))
cut <- list(number = number)
if (number == 1) cut <- FALSE
}
if (is.list(cut))
{
ecargs <- list(x = timex)
ecargs <- modifyList(ecargs, cut)
time <- do.call(equal.count, ecargs)
default.scales <-
modifyList(list(x = list(relation = "sliced")),
default.scales)
}
## 'screens' defines which panels to draw series in
## if 'screens' was given as a readable value then always show strips
screensgiven <- !missing(screens) && !is.numeric(screens)
screens <- make.par.list(cn, screens, NROW(x), NCOL(x), 1)
screens <- unlist(screens, use.names = FALSE)
screens <- factor(screens, levels = unique(screens))
screens <- rep(screens, length.out = NCOL(x))
fac <- factor(rep(screens, each = NROW(x)))
## formula
tt <- rep(timex, NCOL(x))
fo <- if ((nlevels(fac) > 1) || screensgiven) {
if (!is.null(time))
x ~ tt | time * fac
else
x ~ tt | fac
} else {
if (!is.null(time))
x ~ tt | time
else
x ~ tt
}
if (is.null(layout)) {
npanels <- max(1, nlevels(fac)) * max(1, nlevels(time))
nc <- ceiling(npanels/6)
nr <- ceiling(npanels/nc)
layout <- c(nc, nr)
}
## set lines, not points, as default for key
if (is.logical(auto.key) && auto.key) auto.key <- list()
if (is.list(auto.key))
auto.key <-
modifyList(list(lines = TRUE, points = FALSE), auto.key)
## The original approach (e.g. in 0.18-4) was to update par.settings
## with the col, lty etc for each series, and let this be picked up by
## panel.superpose as well as auto.key.
##
## However, that causes problems: further drawing in the panels
## (e.g. with layer()) can appear to be broken because it uses the same
## par.settings, and this has a constant color for all superposed series
## by default.
##
## So now we avoid updating par.settings unless necessary for auto.key:
needStyles <-
(any(sapply(list(col, lty, lwd, pch, cex, fill), length) > 1))
## If all series are plotted in separate panels AND
## all have the same style, then we don't need 'groups'.
## (this avoids using spurious styles when 'panel' is overridden)
needGroups <-
((length(unique(screens)) < NCOL(x)) ||
(needStyles) ||
(is.list(type) && (length(type) > 1)))
if (needGroups)
groups <- factor(col(x), labels = cn)
else groups <- rep(factor(1), length(x))
if (is.list(type))
type <- make.par.list(cn, type, NROW(x), NCOL(x), "l")
## To make R CMD check happy
force(tt)
force(fo)
force(groups)
tmpcall <-
quote(xyplot(fo, groups = groups,
..., panel = panel,
type = type, distribute.type = is.list(type),
auto.key = auto.key, par.settings = par.settings,
layout = layout, as.table = as.table,
xlab = xlab, ylab = ylab,
default.scales = default.scales))
## Include style arguments (col, lty, etc) in the call only if specified.
## (Originally they were not, and were picked up only from par.settings)
if (length(par.settings) > 0) {
## apply settings here before we look up plot.line etc
opar <- trellis.par.get()
trellis.par.set(par.settings)
on.exit(trellis.par.set(opar))
}
plot.line <- trellis.par.get("plot.line")
plot.symbol <- trellis.par.get("plot.symbol")
unlistIfSimple <- function(z)
if (all(sapply(z, length) == 1)) unlist(z) else z
if (!is.null(col)) {
col <- make.par.list(cn, col, NROW(x), NCOL(x), plot.line$col)
tmpcall$col <- unlistIfSimple(col)
}
if (!is.null(lty)) {
lty <- make.par.list(cn, lty, NROW(x), NCOL(x), plot.line$lty)
tmpcall$lty <- unlistIfSimple(lty)
}
if (!is.null(lwd)) {
lwd <- make.par.list(cn, lwd, NROW(x), NCOL(x), plot.line$lwd)
tmpcall$lwd <- unlistIfSimple(lwd)
}
if (!is.null(pch)) {
pch <- make.par.list(cn, pch, NROW(x), NCOL(x), plot.symbol$pch)
tmpcall$pch <- unlistIfSimple(pch)
}
if (!is.null(cex)) {
cex <- make.par.list(cn, cex, NROW(x), NCOL(x), plot.symbol$cex)
tmpcall$cex <- unlistIfSimple(cex)
}
if (!is.null(fill)) {
fill <- make.par.list(cn, fill, NROW(x), NCOL(x), plot.symbol$fill)
tmpcall$fill <- unlistIfSimple(fill)
}
if (needStyles) {
## set 'superpose' styles to be picked up by auto.key
if (identical(panel, "panel.superpose.plain")) {
## (one alternative would be to define a new simplePlainKey(),
## but that would not work if the user called update(auto.key=))
if (is.null(col)) col <- plot.line$col
if (is.null(lty)) lty <- plot.line$lty
if (is.null(lwd)) lwd <- plot.line$lwd
if (is.null(pch)) pch <- plot.symbol$pch
if (is.null(cex)) cex <- plot.symbol$cex
if (is.null(fill)) fill <- plot.symbol$fill
}
if (!is.null(col)) {
par.settings <-
modifyList(list(superpose.line = list(col = unlist(col)),
superpose.symbol = list(col = unlist(col))),
par.settings)
}
if (!is.null(lty)) {
par.settings <-
modifyList(list(superpose.line = list(lty = unlist(lty))),
par.settings)
}
if (!is.null(lwd)) {
par.settings <-
modifyList(list(superpose.line = list(lwd = unlist(lwd))),
par.settings)
}
if (!is.null(pch)) {
par.settings <-
modifyList(list(superpose.symbol = list(pch = unlist(pch))),
par.settings)
}
if (!is.null(cex)) {
par.settings <-
modifyList(list(superpose.symbol = list(cex = unlist(cex))),
par.settings)
}
if (!is.null(fill)) {
par.settings <-
modifyList(list(superpose.symbol = list(fill = unlist(fill))),
par.settings)
}
}
obj <- eval(tmpcall)
obj$call <- ocall
obj
}
## COPIED FROM ZOO
## http://r-forge.r-project.org/plugins/scmsvn/viewcvs.php/pkg/zoo/R/plot.zoo.R?rev=609&root=zoo&view=markup
make.par.list <- function(nams, x, n, m, def, recycle = sum(unnamed) > 0) {
## if nams are the names of our variables and x is a parameter
## specification such as list(a = c(1,2), c(3,4)) then
## create a new list which uses the named variables from x
## and assigns the unnamed in order. For the remaining variables
## assign them the default value if recycle = FALSE or recycle the
## unnamed variables if recycle = TRUE. The default value for
## recycle is TRUE if there is at least one unnamed variable
## in x and is false if there are only named variables in x.
## n is the length of the series and m is the total number of series
## It only needs to know whether m is 1 or greater than m.
## def is the default value used when recycle = FALSE
## recycle = TRUE means recycle unspecified values
## recycle = FALSE means replace values for unspecified series with def
## Within series recycling is done even if recycle=FALSE.
## Should we allow arbirary names in 1d case?
## if (m > 1) stopifnot(all(names(x) %in% c("", nams)))
if (!is.list(x)) x <- if (m == 1) list(x) else as.list(x)
y <- vector(mode = "list", length = length(nams))
names(y) <- nams
in.x <- nams %in% names(x)
unnamed <- if (is.null(names(x))) rep(TRUE, length(x)) else names(x) == ""
if (!recycle) y[] <- def
y[in.x] <- x[nams[in.x]]
if (recycle) {
stopifnot(sum(unnamed) > 0)
y[!in.x] <- rep(x[unnamed], length.out = sum(!in.x)) ## CHECK, this was: x[unnamed]
} else {
y[which(!in.x)[seq_len(sum(unnamed))]] <- x[unnamed]
}
lapply(y, function(y) if (length(y)==1) y else rep(y, length.out = n))
}
|