Nothing
##
## Copyright (c) 2008 Felix Andrews <felix@nfrac.org>
## GPL version 2 or newer
as.layer <- function(x, ...)
UseMethod("as.layer")
as.layer.layer <- function(x, ...)
x
layer <-
function(..., data = NULL,
magicdots = TRUE, exclude = NULL,
packets = NULL,
rows = NULL, columns = NULL,
groups = NULL,
style = NULL, force = FALSE,
theme = if (force) trellis.par.get() else NULL,
under = FALSE, superpose = FALSE)
{
## set layer to quoted expressions in `...`
foo <- eval(substitute(expression(...)))
if (magicdots) {
## The dots `...` are magic:
## pass on only those arguments not named in each call
foo <- as.expression(lapply(foo, magicDots, exclude = exclude))
}
## FIXME: should we have
##
## if (missing(data)) data <- parent.frame()
##
## ? See tests/layer.R for a non-obvious failure. But not sure
## how best to fix.
mostattributes(foo) <-
list(data = data,
under = under,
packets = packets,
rows = rows,
columns = columns,
groups = groups,
superpose = superpose,
style = style,
theme = theme)
lay <- list(foo)
class(lay) <- c("layer", "trellis")
lay
}
## convert a call containing `...` to only pass on arguments
## not named in the call
magicDots <- function(ocall, exclude = NULL, assume.xy = TRUE)
{
if (!is.call(ocall)) stop("arguments to layer() should be calls")
## call recursively with any calls inside this one
for (i in seq_along(ocall)[-1]) {
thisArg <- ocall[[i]]
if (missing(thisArg)) ## eg x[,1]
next
if (is.call(thisArg)) {
## skip function definitions
if (identical(thisArg[[1]], as.symbol("function")))
next
ocall[[i]] <- Recall(thisArg, exclude = exclude, assume.xy = assume.xy)
}
}
Args <- as.list(ocall)[-1]
## nothing to do if there are no dots in the call
idots <- sapply(Args, identical, as.symbol("..."))
if (!any(idots))
return(ocall)
Args <- Args[!idots]
## nothing to do if there are only dots in the call (unless exclude)
if ((length(Args) == 0) && (length(exclude) == 0))
return(ocall)
## assume first argument is 'x' if is un-named, and second 'y'
if (assume.xy && (length(Args) > 0)) {
if (is.null(names(Args)))
names(Args) <- rep("", length = length(Args))
if (identical(names(Args)[1], ""))
names(Args)[1] <- "x"
if (identical(names(Args)[2], ""))
names(Args)[2] <- "y"
}
if (length(exclude) == 0) {
## simple case
mcall <-
substitute(do.call(FUN,
modifyList(list(...), Args)),
list(FUN = ocall[[1]], Args = Args))
} else {
## exclude named arguments from dots
mcall <-
substitute(do.call(FUN,
modifyList(list(...)[!(names(list(...)) %in% exclude)],
Args)),
list(FUN = ocall[[1]], Args = Args, exclude = exclude))
}
mcall
}
layer_ <- function(...)
{
ccall <- match.call()
ccall$under <- TRUE
ccall[[1]] <- quote(layer)
eval.parent(ccall)
}
glayer <- function(...)
{
ccall <- match.call()
ccall$superpose <- TRUE
ccall[[1]] <- quote(layer)
eval.parent(ccall)
}
glayer_ <- function(...)
{
ccall <- match.call()
ccall$superpose <- TRUE
ccall$under <- TRUE
ccall[[1]] <- quote(layer)
eval.parent(ccall)
}
## to avoid print.trellis
print.layer <- function(x, ...) print.default(x, ...)
## to avoid [.trellis and to keep the class attribute
"[.layer" <- function (x, i, ...)
structure(unclass(x)[i], class = class(x))
"+.trellis" <- function(object, lay)
{
ocall <- sys.call(sys.parent()); ocall[[1]] <- quote(`+`)
if (missing(object) || missing(lay)) stop("Only one argument supplied to binary operator + which requires two.")
stopifnot(inherits(object, "trellis"))
lay <- as.layer(lay)
if (inherits(object, "layer")) {
## just concatenate lists
return(structure(c(unclass(object), unclass(lay)),
class = c("layer", "trellis")))
}
panel <- if ("panel" %in% names(object$panel.args.common))
object$panel.args.common$panel
else object$panel
panel <- if (is.function(panel)) panel
else if (is.character(panel)) {
## could be just get(panel), but for flattenPanel:
## do not expand original panel function eg panel.xyplot(...)
tmp <- function(...) NA
body(tmp) <- call(panel, quote(...))
environment(tmp) <- globalenv()
tmp
} else eval(panel)
## a flag to indicate this panel function has layers
## (used by flattenPanel and undoLayer)
.is.a.layer <- TRUE
newpanel <- function(...) {
.UNDER <- unlist(lapply(lay, attr, "under"))
## underlaying items only
drawLayer(lay[.UNDER], list(...))
## original panel function:
panel(...)
## overlaying items only
drawLayer(lay[.UNDER == FALSE], list(...))
}
if ("panel" %in% names(object$panel.args.common))
object$panel.args.common$panel <- newpanel
else object$panel <- newpanel
## need this to allow further calls to update() to insert arguments:
object$call <- call("update", ocall)
object
}
drawLayer <- function(lay, panelArgs = trellis.panelArgs())
{
lay <- as.layer(lay)
.UNDER <- unlist(lapply(lay, attr, "under"))
## underlayers, in reverse order
for (.ITEM in rev(lay[.UNDER]))
drawLayerItem(.ITEM, panelArgs)
## overlayers
for (.ITEM in lay[.UNDER == FALSE])
drawLayerItem(.ITEM, panelArgs)
invisible()
}
drawLayerItem <- function(layer.item, panelArgs)
{
stopifnot(is.expression(layer.item))
## check that any restrictions on packets/rows/columns are met
matchesok <- function(spec, value) {
if (is.null(spec)) return(TRUE)
if (is.numeric(spec) && all(spec <= 0))
## negative indexes exclude items
return(value %in% -spec == FALSE)
else
return(value %in% spec)
}
matchesallok <-
with(list(a = attributes(layer.item)),
matchesok(a$packets, packet.number()) &&
matchesok(a$rows, current.row()) &&
matchesok(a$columns, current.column()))
if (!matchesallok) return()
## set given theme for duration of this function
if (!is.null(attr(layer.item, "theme"))) {
.TRELLISPAR <- trellis.par.get()
trellis.par.set(attr(layer.item, "theme"))
on.exit(trellis.par.set(.TRELLISPAR))
}
## define a layer drawing function, which may be per group
drawLayerItemPerGroup <- function(...)
{
## Note: layer.item is found in this function's environment
dots <- list(...)
## restrict to specified group numbers
groupok <- (matchesok(attr(layer.item, "groups"), dots$group.number) ||
matchesok(attr(layer.item, "groups"), as.character(dots$group.value)))
if (!groupok)
return()
if (!is.null(attr(layer.item, "style"))) {
## extract plot style attributes from given index into superpose.*
.TRELLISPAR <- trellis.par.get()
local({
i <- attr(layer.item, "style")
line <- Rows(trellis.par.get("superpose.line"), i)
symbol <- Rows(trellis.par.get("superpose.symbol"), i)
polygon <- Rows(trellis.par.get("superpose.polygon"), i)
trellis.par.set(plot.line = line,
superpose.line = line,
add.line = line,
add.text = line,
plot.symbol = symbol,
superpose.symbol = symbol,
plot.polygon = polygon,
superpose.polygon = polygon,
axis.text = line,
axis.line = line
)
})
on.exit(trellis.par.set(.TRELLISPAR))
}
with(dots,
eval(layer.item, attr(layer.item, "data"),
environment()))
}
## call panel.superpose for group layers
if (isTRUE(attr(layer.item, "superpose"))) {
do.call("panel.superpose",
modifyList(panelArgs,
list(panel.groups = drawLayerItemPerGroup)))
} else {
do.call("drawLayerItemPerGroup", panelArgs)
}
}
flattenPanel <- function(object)
{
flattenFun <- function(fun)
{
env <- environment(fun)
## check if this panel function is simple or has layers
if (is.null(env) ||
!exists(".is.a.layer", env, inherits = FALSE))
return(as.expression(body(fun)))
## merge: under layers, existing panel, over layers
.UNDER <- sapply(env$lay, attr, "under")
c(do.call("c", rev(env$lay[.UNDER])),
flattenFun(env$panel),
do.call("c", env$lay[.UNDER == FALSE]))
}
flat <- flattenFun(object$panel)
## wrap in braces, as in a function body
as.call(c(quote(`{`), flat))
}
## not exported -- I do not think this is really useful
undoLayer <- function(x)
{
stopifnot(is.function(x$panel))
env <- environment(x$panel)
if (!exists(".is.a.layer", env, inherits=FALSE))
stop("does not look like a layer")
update(x, panel=env$panel)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.