#
#
# Residual plots:
# resid4plot four panels with matching coordinates
# resid1plot one or more unrelated individual plots
# resid1panel one panel of resid1plot
#
# $Revision: 1.39 $ $Date: 2020/12/19 05:25:06 $
#
#
resid4plot <- local({
Contour <- function(...,
pch, chars, cols, etch, size,
maxsize, meansize, markscale, symap, zap,
legend, leg.side, leg.args) {
## avoid passing arguments of plot.ppp to contour.default
contour(...)
}
do.clean <- function(fun, ...,
pch, chars, cols, etch, size,
maxsize, meansize, markscale, symap, zap,
legend, leg.side, leg.args,
nlevels, levels, labels, drawlabels, labcex) {
## avoid passing arguments of plot.ppp, contour.default to other functions
fun(...)
}
do.lines <- function(x, y, defaulty=1, ...) {
force(x)
force(y)
dont.complain.about(x,y)
do.call(lines,
resolve.defaults(list(quote(x), quote(y)),
list(...),
list(lty=defaulty)))
}
resid4plot <-
function(RES,
plot.neg=c("image", "discrete", "contour", "imagecontour"),
plot.smooth=c("imagecontour", "image", "contour", "persp"),
spacing=0.1, outer=3, srange=NULL, monochrome=FALSE, main=NULL,
xlab="x coordinate", ylab="y coordinate", rlab,
col.neg=NULL, col.smooth=NULL,
...)
{
plot.neg <- match.arg(plot.neg)
if(missing(rlab)) rlab <- NULL
rlablines <- if(is.null(rlab)) 1 else sum(nzchar(rlab))
clip <- RES$clip
Yclip <- RES$Yclip
Z <- RES$smooth$Z
W <- RES$W
Wclip <- Yclip$window
type <- RES$type
typename <- RES$typename
Ydens <- RES$Ydens[Wclip, drop=FALSE]
Ymass <- RES$Ymass[Wclip]
# set up 2 x 2 plot with space
wide <- diff(W$xrange)
high <- diff(W$yrange)
space <- spacing * max(wide,high)
width <- wide + space + wide
height <- high + space + high
outerspace <- outer * space
outerRspace <- (outer - 1 + rlablines) * space
plot(c(0, width) + c(-outerRspace, outerspace),
c(0, height) + c(-outerspace, outerRspace),
type="n", asp=1.0, axes=FALSE, xlab="", ylab="")
# determine colour map for background
nullvalue <- if(type == "eem") 1 else 0
if(is.null(srange)) {
Yrange <- if(!is.null(Ydens)) summary(Ydens)$range else NULL
Zrange <- if(!is.null(Z)) summary(Z)$range else NULL
srange <- range(c(Yrange, Zrange, nullvalue), na.rm=TRUE)
} else check.range(srange)
backcols <- beachcolours(srange, nullvalue, monochrome)
if(is.null(col.neg)) col.neg <- backcols
if(is.null(col.smooth)) col.smooth <- backcols
# ------ plot residuals/marks (in top left panel) ------------
Xlowleft <- c(W$xrange[1],W$yrange[1])
vec <- c(0, high) + c(0, space) - Xlowleft
# shift the original window
Ws <- shift(W, vec)
# shift the residuals
Ys <- shift(Yclip,vec)
# determine whether pre-plotting the window(s) is redundant
redundant <-
(plot.neg == "image") && (type != "eem") && (Yclip$window$type == "mask")
# pre-plot the window(s)
if(!redundant) {
YsWin <- Ys$window
if(!clip)
do.clean(plot, YsWin, add=TRUE, ...)
else
do.clean(ploterodewin, Ws, YsWin, add=TRUE, ...)
}
## adjust position of legend associated with eroded window
sep <- if(clip) Wclip$yrange[1] - W$yrange[1] else NULL
## decide whether mark scale should be shown
showscale <- (type != "raw")
switch(plot.neg,
discrete={
neg <- (Ys$marks < 0)
## plot negative masses of discretised measure as squares
if(any(c("maxsize","meansize","markscale") %in% names(list(...)))) {
plot(Ys[neg], add=TRUE, legend=FALSE, ...)
} else {
hackmax <- 0.5 * sqrt(area(Wclip)/Yclip$n)
plot(Ys[neg], add=TRUE, legend=FALSE, maxsize=hackmax, ...)
}
## plot positive masses at atoms
plot(Ys[!neg], add=TRUE,
leg.side="left", leg.args=list(sep=sep),
show.all=TRUE, main="",
...)
},
contour = {
Yds <- shift(Ydens, vec)
Yms <- shift(Ymass, vec)
Contour(Yds, add=TRUE, ...)
dont.complain.about(Yms)
do.call(plot,
resolve.defaults(list(x=quote(Yms), add=TRUE),
list(...),
list(use.marks=showscale,
leg.side="left", show.all=TRUE,
main="", leg.args=list(sep=sep))))
},
imagecontour=,
image={
Yds <- shift(Ydens, vec)
Yms <- shift(Ymass, vec)
if(redundant)
do.clean(ploterodeimage,
Ws, Yds, rangeZ=srange, colsZ=col.neg,
...)
else if(type != "eem")
do.clean(image,
Yds, add=TRUE, ribbon=FALSE,
col=col.neg, zlim=srange,
...)
if(plot.neg == "imagecontour")
Contour(Yds, add=TRUE, ...)
## plot positive masses at atoms
dont.complain.about(Yms)
do.call(plot,
resolve.defaults(list(x=quote(Yms), add=TRUE),
list(...),
list(use.marks=showscale,
leg.side="left", show.all=TRUE,
main="", leg.args=list(sep=sep))))
}
)
# --------- plot smoothed surface (in bottom right panel) ------------
vec <- c(wide, 0) + c(space, 0) - Xlowleft
Zs <- shift.im(Z, vec)
switch(plot.smooth,
image={
do.clean(image,
Zs, add=TRUE, col=col.smooth,
zlim=srange, ribbon=FALSE,
...)
},
contour={
Contour(Zs, add=TRUE, ...)
},
persp={ warning("persp not available in 4-panel plot") },
imagecontour={
do.clean(image,
Zs, add=TRUE, col=col.smooth, zlim=srange, ribbon=FALSE,
...)
Contour(Zs, add=TRUE, ...)
}
)
lines(Zs$xrange[c(1,2,2,1,1)], Zs$yrange[c(1,1,2,2,1)])
# -------------- lurking variable plots -----------------------
# --------- lurking variable plot for x coordinate ------------------
# (cumulative or marginal)
# in bottom left panel
if(!is.null(RES$xmargin)) {
a <- RES$xmargin
observedV <- a$xZ
observedX <- a$x
theoreticalV <- a$ExZ
theoreticalX <- a$x
theoreticalSD <- theoreticalHI <- theoreticalLO <- NULL
if(is.null(rlab)) rlab <- paste("marginal of", typename)
} else if(!is.null(RES$xcumul)) {
a <- RES$xcumul
observedX <- a$empirical$covariate
observedV <- a$empirical$value
theoreticalX <- a$theoretical$covariate
theoreticalV <- a$theoretical$mean
theoreticalSD <- a$theoretical$sd
theoreticalHI <- a$theoretical$upper
theoreticalLO <- a$theoretical$lower
if(is.null(rlab)) rlab <- paste("cumulative sum of", typename)
}
# pretty axis marks
pX <- pretty(theoreticalX)
rV <- range(0, observedV, theoreticalV, theoreticalHI, theoreticalLO)
if(!is.null(theoreticalSD))
rV <- range(rV,
theoreticalV+2*theoreticalSD,
theoreticalV-2*theoreticalSD)
pV <- pretty(rV)
# rescale smoothed values
rr <- range(c(0, observedV, theoreticalV, pV))
yscale <- function(y) { high * (y - rr[1])/diff(rr) }
xscale <- function(x) { x - W$xrange[1] }
if(!is.null(theoreticalHI)) {
## shaded confidence bands
xp <- xscale( c(theoreticalX, rev(theoreticalX)) )
yp <- yscale( c(theoreticalHI, rev(theoreticalLO)) )
dont.complain.about(xp, yp)
do.call.matched(polygon,
resolve.defaults(
list(x=quote(xp),
y=quote(yp)),
list(...),
list(col="grey", border=NA)))
}
do.clean(do.lines, xscale(observedX), yscale(observedV), 1, ...)
do.clean(do.lines, xscale(theoreticalX), yscale(theoreticalV), 2, ...)
if(!is.null(theoreticalSD)) {
do.clean(do.lines,
xscale(theoreticalX),
yscale(theoreticalV + 2 * theoreticalSD),
3, ...)
do.clean(do.lines,
xscale(theoreticalX),
yscale(theoreticalV - 2 * theoreticalSD),
3, ...)
}
axis(side=1, pos=0, at=xscale(pX), labels=pX)
text(xscale(mean(theoreticalX)), - outerspace, xlab)
axis(side=2, pos=0, at=yscale(pV), labels=pV)
text(-outerRspace, yscale(mean(pV)), rlab, srt=90)
# --------- lurking variable plot for y coordinate ------------------
# (cumulative or marginal)
# in top right panel
if(!is.null(RES$ymargin)) {
a <- RES$ymargin
observedV <- a$yZ
observedY <- a$y
theoreticalV <- a$EyZ
theoreticalY <- a$y
theoreticalSD <- NULL
if(is.null(rlab)) rlab <- paste("marginal of", typename)
} else if(!is.null(RES$ycumul)) {
a <- RES$ycumul
observedV <- a$empirical$value
observedY <- a$empirical$covariate
theoreticalY <- a$theoretical$covariate
theoreticalV <- a$theoretical$mean
theoreticalSD <- a$theoretical$sd
theoreticalHI <- a$theoretical$upper
theoreticalLO <- a$theoretical$lower
if(is.null(rlab)) rlab <- paste("cumulative sum of", typename)
}
# pretty axis marks
pY <- pretty(theoreticalY)
rV <- range(0, observedV, theoreticalV, theoreticalHI, theoreticalLO)
if(!is.null(theoreticalSD))
rV <- range(rV,
theoreticalV+2*theoreticalSD,
theoreticalV-2*theoreticalSD)
pV <- pretty(rV)
# rescale smoothed values
rr <- range(c(0, observedV, theoreticalV, pV))
yscale <- function(y) { y - W$yrange[1] + high + space}
xscale <- function(x) { wide + space + wide * (rr[2] - x)/diff(rr) }
if(!is.null(theoreticalHI))
do.call.matched(polygon,
resolve.defaults(
list(x=xscale(c(theoreticalHI, rev(theoreticalLO))),
y=yscale(c(theoreticalY, rev(theoreticalY)))),
list(...),
list(col="grey", border=NA)))
do.clean(do.lines, xscale(observedV), yscale(observedY), 1, ...)
do.clean(do.lines, xscale(theoreticalV), yscale(theoreticalY), 2, ...)
if(!is.null(theoreticalSD)) {
do.clean(do.lines,
xscale(theoreticalV+2*theoreticalSD),
yscale(theoreticalY),
3, ...)
do.clean(do.lines,
xscale(theoreticalV-2*theoreticalSD),
yscale(theoreticalY),
3, ...)
}
axis(side=4, pos=width, at=yscale(pY), labels=pY)
text(width + outerspace, yscale(mean(theoreticalY)), ylab, srt=90)
axis(side=3, pos=height, at=xscale(pV), labels=pV)
text(xscale(mean(pV)), height + outerRspace, rlab)
#
if(!is.null(main))
title(main=main)
invisible(NULL)
}
resid4plot
})
#
#
# Residual plot: single panel(s)
#
#
resid1plot <- local({
Contour <- function(...,
pch, chars, cols, etch, size,
maxsize, meansize, markscale, symap, zap,
legend, leg.side, leg.args) {
## avoid passing arguments of plot.ppp to contour.default
contour(...)
}
do.clean <- function(fun, ...,
pch, chars, cols, etch, size,
maxsize, meansize, markscale, symap, zap,
legend, leg.side, leg.args,
nlevels, levels, labels, drawlabels, labcex) {
## avoid passing arguments of plot.ppp, contour.default to other functions
fun(...)
}
resid1plot <-
function(RES, opt,
plot.neg=c("image", "discrete", "contour", "imagecontour"),
plot.smooth=c("imagecontour", "image", "contour", "persp"),
srange=NULL, monochrome=FALSE, main=NULL,
add=FALSE, show.all=!add, do.plot=TRUE,
col.neg=NULL, col.smooth=NULL,
...) {
if(!any(unlist(opt[c("all", "marks", "smooth",
"xmargin", "ymargin", "xcumul", "ycumul")])))
return(invisible(NULL))
if(!add && do.plot) {
## determine size of plot area by calling again with do.plot=FALSE
cl <- match.call()
cl$do.plot <- FALSE
b <- eval(cl, parent.frame())
bb <- as.owin(b, fatal=FALSE)
if(is.owin(bb)) {
## initialise plot area
plot(bb, type="n", main="")
force(show.all)
add <- TRUE
}
}
## extract info
clip <- RES$clip
Y <- RES$Y
Yclip <- RES$Yclip
Z <- RES$smooth$Z
W <- RES$W
Wclip <- Yclip$window
type <- RES$type
Ydens <- RES$Ydens[Wclip, drop=FALSE]
Ymass <- RES$Ymass[Wclip]
## determine colour map
if(opt$all || opt$marks || opt$smooth) {
nullvalue <- if(type == "eem") 1 else 0
if(is.null(srange)) {
Yrange <- if(!is.null(Ydens)) summary(Ydens)$range else NULL
Zrange <- if(!is.null(Z)) summary(Z)$range else NULL
srange <- range(c(Yrange, Zrange, nullvalue), na.rm=TRUE)
} else check.range(srange)
backcols <- beachcolours(srange, nullvalue, monochrome)
if(is.null(col.neg)) col.neg <- backcols
if(is.null(col.smooth)) col.smooth <- backcols
}
## determine main heading
if(is.null(main)) {
prefix <- if(opt$marks) NULL else
if(opt$smooth) "Smoothed" else
if(opt$xcumul) "Lurking variable plot for x coordinate\n" else
if(opt$ycumul) "Lurking variable plot for y coordinate\n" else
if(opt$xmargin) "Lurking variable plot for x coordinate\n" else
if(opt$ymargin) "Lurking variable plot for y coordinate\n" else NULL
main <- paste(prefix, RES$typename)
}
## ------------- residuals ---------------------------------
if(opt$marks) {
## determine whether pre-plotting the window(s) is redundant
redundant <- (plot.neg == "image") &&
(type != "eem") && (Yclip$window$type == "mask")
## pre-plot the window(s)
if(redundant && !add) {
z <- do.clean(plot,
as.rectangle(W), box=FALSE, main="",
do.plot=do.plot, ...)
} else {
if(!clip)
z <- do.clean(plot,
W, main="",
add=add, show.all=show.all, do.plot=do.plot, ...)
else
z <- do.clean(ploterodewin,
W, Wclip, main="",
add=add, show.all=show.all, do.plot=do.plot, ...)
}
bb <- as.owin(z)
switch(plot.neg,
discrete={
neg <- (Y$marks < 0)
## plot negative masses of discretised measure as squares
if(any(c("maxsize", "markscale") %in% names(list(...)))) {
z <- plot(Y[neg], add=TRUE,
show.all=show.all, do.plot=do.plot, ...)
} else {
hackmax <- 0.5 * sqrt(area(Wclip)/Yclip$n)
z <- plot(Y[neg], add=TRUE, maxsize=hackmax,
show.all=show.all, do.plot=do.plot, ...)
}
## plot positive masses at atoms
zp <- plot(Y[!neg], add=TRUE,
show.all=show.all, do.plot=do.plot, ...)
bb <- boundingbox(bb, z, zp)
},
contour = {
z <- Contour(Ydens, add=TRUE, do.plot=do.plot, ...)
bb <- boundingbox(bb, z)
},
imagecontour=,
image={
if(redundant) {
z <- do.clean(ploterodeimage,
W, Ydens, rangeZ=srange, colsZ=col.neg,
add=add, show.all=show.all, main="",
do.plot=do.plot, ...)
} else if(type != "eem") {
z <- do.clean(image,
Ydens, col=col.neg, zlim=srange, ribbon=FALSE,
add=TRUE, show.all=show.all, do.plot=do.plot,
main="", ...)
}
bb <- boundingbox(bb, z)
if(plot.neg == "imagecontour") {
z <- Contour(Ydens, add=TRUE,
show.all=show.all, do.plot=do.plot, ...)
bb <- boundingbox(bb, z)
}
## decide whether mark scale should be shown
showscale <- (type != "raw")
## plot positive masses at atoms
dont.complain.about(Ymass)
z <- do.call(plot,
resolve.defaults(list(x=quote(Ymass), add=TRUE),
list(...),
list(use.marks=showscale,
do.plot=do.plot)))
bb <- boundingbox(bb, z)
}
)
if(do.plot && show.all) title(main=main)
}
# ------------- smooth -------------------------------------
if(opt$smooth) {
if(!clip) {
switch(plot.smooth,
image={
z <- do.clean(image,
Z, main="", axes=FALSE, xlab="", ylab="",
col=col.smooth, zlim=srange, ribbon=FALSE,
do.plot=do.plot, add=add, show.all=show.all, ...)
bb <- as.owin(z)
},
contour={
z <- Contour(Z, main="", axes=FALSE, xlab="", ylab="",
do.plot=do.plot, add=add, show.all=show.all, ...)
bb <- as.owin(z)
},
persp={
if(do.plot)
do.clean(persp,
Z, main="", axes=FALSE, xlab="", ylab="", ...)
bb <- NULL
},
imagecontour={
z <- do.clean(image,
Z, main="", axes=FALSE, xlab="", ylab="",
col=col.smooth, zlim=srange, ribbon=FALSE,
do.plot=do.plot, add=add, show.all=show.all, ...)
Contour(Z, add=TRUE, do.plot=do.plot, ...)
bb <- as.owin(z)
}
)
if(do.plot && show.all) title(main=main)
} else {
switch(plot.smooth,
image={
do.clean(plot,
as.rectangle(W), box=FALSE, main=main,
do.plot=do.plot, add=add, ...)
z <- do.clean(ploterodeimage,
W, Z, colsZ=col.smooth, rangeZ=srange,
do.plot=do.plot, ...)
bb <- boundingbox(as.rectangle(W), z)
},
contour={
do.clean(plot,
W, main=main,
do.plot=do.plot, add=add, show.all=show.all, ...)
z <- Contour(Z, add=TRUE,
show.all=show.all, do.plot=do.plot, ...)
bb <- as.owin(z)
},
persp={
if(do.plot)
do.clean(persp,
Z, main=main, axes=FALSE, xlab="", ylab="", ...)
bb <- NULL
},
imagecontour={
do.clean(plot,
as.rectangle(W), box=FALSE, main=main,
do.plot=do.plot, add=add, ...)
z <- do.clean(ploterodeimage,
W, Z, colsZ=col.smooth, rangeZ=srange,
do.plot=do.plot, ...)
Contour(Z, add=TRUE, do.plot=do.plot, ...)
bb <- as.owin(z)
}
)
}
}
# ------------ cumulative x -----------------------------------------
if(opt$xcumul) {
a <- RES$xcumul
obs <- a$empirical
theo <- a$theoretical
do.clean(resid1panel,
obs$covariate, obs$value,
theo$covariate, theo$mean, theo$sd,
"x coordinate", "cumulative mark", main=main,
...,
do.plot=do.plot)
bb <- NULL
}
# ------------ cumulative y -----------------------------------------
if(opt$ycumul) {
a <- RES$ycumul
obs <- a$empirical
theo <- a$theoretical
do.clean(resid1panel,
obs$covariate, obs$value,
theo$covariate, theo$mean, theo$sd,
"y coordinate", "cumulative mark", main=main,
...,
do.plot=do.plot)
bb <- NULL
}
## ------------ x margin -----------------------------------------
if(opt$xmargin) {
a <- RES$xmargin
do.clean(resid1panel,
a$x, a$xZ, a$x, a$ExZ, NULL,
"x coordinate", "marginal of residuals", main=main,
...,
do.plot=do.plot)
bb <- NULL
}
# ------------ y margin -----------------------------------------
if(opt$ymargin) {
a <- RES$ymargin
do.clean(resid1panel,
a$y, a$yZ, a$y, a$EyZ, NULL,
"y coordinate", "marginal of residuals", main=main,
...,
do.plot=do.plot)
bb <- NULL
}
attr(bb, "bbox") <- bb
return(invisible(bb))
}
resid1plot
})
resid1panel <- local({
do.lines <- function(x, y, defaulty=1, ...) {
do.call(lines,
resolve.defaults(list(x, y),
list(...),
list(lty=defaulty)))
}
resid1panel <- function(observedX, observedV,
theoreticalX, theoreticalV, theoreticalSD, xlab, ylab,
..., do.plot=TRUE)
{
if(!do.plot) return(NULL)
## work out plot range
rX <- range(observedX, theoreticalX)
rV <- range(c(0, observedV, theoreticalV))
if(!is.null(theoreticalSD))
rV <- range(c(rV, theoreticalV + 2*theoreticalSD,
theoreticalV - 2*theoreticalSD))
## argument handling
## start plot
plot(rX, rV, type="n", xlab=xlab, ylab=ylab, ...)
do.lines(observedX, observedV, 1, ...)
do.lines(theoreticalX, theoreticalV, 2, ...)
if(!is.null(theoreticalSD)) {
do.lines(theoreticalX, theoreticalV + 2 * theoreticalSD, 3, ...)
do.lines(theoreticalX, theoreticalV - 2 * theoreticalSD, 3, ...)
}
}
resid1panel
})
#
#
ploterodewin <- function(W1, W2, col.edge=grey(0.75), col.inside=rgb(1,0,0),
do.plot=TRUE, ...) {
## internal use only
## W2 is assumed to be an erosion of W1
switch(W1$type,
rectangle={
z <- plot(W1, ..., do.plot=do.plot)
plot(W2, add=TRUE, lty=2, do.plot=do.plot)
},
polygonal={
z <- plot(W1, ..., do.plot=do.plot)
plot(W2, add=TRUE, lty=2, do.plot=do.plot)
},
mask={
Z <- as.im(W1)
x <- as.vector(rasterx.mask(W1))
y <- as.vector(rastery.mask(W1))
ok <- inside.owin(x, y, W2)
Z$v[ok] <- 2
z <- plot(Z, ..., col=c(col.edge, col.inside),
add=TRUE, ribbon=FALSE, do.plot=do.plot,
show.all=TRUE)
}
)
return(z)
}
ploterodeimage <- function(W, Z, ..., Wcol=grey(0.75), rangeZ, colsZ,
do.plot=TRUE) {
# Internal use only
# Image Z is assumed to live on a subset of mask W
# colsZ are the colours for the values in the range 'rangeZ'
if(!is.mask(W)) {
if(do.plot)
plot(W, add=TRUE)
W <- as.mask(W)
}
# Extend the colour map to include an extra colour for pixels in W
# (1) Add the desired colour of W to the colour map
pseudocols <- c(Wcol, colsZ)
# (2) Breakpoints
bks <- seq(from=rangeZ[1], to=rangeZ[2], length=length(colsZ)+1)
dZ <- diff(bks)[1]
pseudobreaks <- c(rangeZ[1] - dZ, bks)
# (3) Determine a fake value for pixels in W
Wvalue <- rangeZ[1] - dZ/2
# Create composite image on W grid
# (with W-pixels initialised to Wvalue)
X <- as.im(Wvalue, W)
# Look up Z-values of W-pixels
xx <- as.vector(rasterx.mask(W))
yy <- as.vector(rastery.mask(W))
Zvalues <- lookup.im(Z, xx, yy, naok = TRUE, strict=FALSE)
# Overwrite pixels in Z
inZ <- !is.na(Zvalues)
X$v[inZ] <- Zvalues[inZ]
z <- image(X, ..., add=TRUE, ribbon=FALSE,
col=pseudocols, breaks=pseudobreaks,
do.plot=do.plot)
out <- list(X, pseudocols, pseudobreaks)
attr(out, "bbox") <- as.owin(z)
return(out)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.