Nothing
# Quantile-comparison plots (J. Fox)
# last modified 30 September 2009 by J. Fox
# November 2009 by S. Weisberg -- changed to use showLabels for point identification
# 14 April 2010: set id.n = 0. J. Fox
# 1 June 2010: set reps=100 in qqPlot.lm. J. Fox
# 28 June 2010: fixed labeling bug S. Weisberg
# 11 March 2011: moved up ... argument. J. Fox
# 23 May 2012: line="none" now honored in qqPlot.default. J. Fox
# 2 May 2013: qqPlot.lm() now works with "aov" objects (fixing problem reported by Thomas Burk). J. Fox
# 2015-12-12: allow vectorized col, pch, and cex arguments (suggestion of Emmanuel Curis)
# 2017-02-12: consolidated id argument. J. Fox
# 2017-02-16: replace rlm() with MASS::rlm(). J. Fox
# 2017-03-25: fixed handling of indexes so that unsorted indexes are reported. J. Fox
# 2017-06-27: added formula method and plotting by groups. J. Fox
# 2017-10-26: fix qqPlot.lm() so that it doesn't return names identifical to indices. J. Fox
# 2017-11-30: substitute carPalette() for palette(). J. Fox
# 2018-03-23: properly return point IDs when method="identify"
# 2018-11-04: fixed handling of NAs when plotting by groups in qqPlot.default(). J. Fox
# 2019-04-09: respect order of factor levels when plotting by groups (problem and fix by Vilmantas Gegzna). J. Fox
# 2020-10-19: added filled confidence envelopes. J. Fox
qqp <- function(...) qqPlot(...)
qqPlot<-function(x, ...) {
UseMethod("qqPlot")
}
qqPlot.default <- function(x, distribution="norm", groups, layout,
ylim=range(x, na.rm=TRUE), ylab=deparse(substitute(x)),
xlab=paste(distribution, "quantiles"), glab=deparse(substitute(groups)),
main=NULL, las=par("las"),
envelope=TRUE,
col=carPalette()[1], col.lines=carPalette()[2], lwd=2, pch=1, cex=par("cex"),
line=c("quartiles", "robust", "none"), id=TRUE, grid=TRUE, ...){
if (!missing(groups)){
if (isTRUE(id)) id <- list(n=2)
if (is.null(id$labels)) id$labels <- seq(along=x)
grps <- levels(as.factor(groups))
if (missing(layout)) layout <- mfrow(length(grps), max.plots=12)
if (prod(layout) < length(grps)) stop("layout cannot accomodate ", length(grps), " plots")
oldpar <- par(mfrow=layout)
on.exit(par(oldpar))
for (group in grps){
id.gr <- id
if (!isFALSE(id)) id.gr$labels <- id$labels[groups == group]
qqPlot.default(x[groups == group], distribution=distribution, ylim=ylim, ylab=ylab,
xlab=xlab, main=paste(glab, "=", group), las=las, envelope=envelope, col=col,
col.lines=col.lines, pch=pch, cex=cex, line=line, id=id.gr, grid=grid, ...)
}
return(invisible(NULL))
}
if (!is.list(envelope) && length(envelope == 1) && is.numeric(envelope)){
envelope <- list(level=envelope)
}
if (!isFALSE(envelope)){
envelope <- applyDefaults(envelope,
defaults=list(level=0.95, style="filled", col=col.lines, alpha=0.15, border=TRUE))
style <- match.arg(envelope$style, c("filled", "lines", "none"))
col.envelope <- envelope$col
conf <- envelope$level
alpha <- envelope$alpha
border <- envelope$border
if (style == "none") envelope <- FALSE
}
id <- applyDefaults(id, defaults=list(method="y", n=2, cex=1, col=carPalette()[1], location="lr"), type="id")
if (isFALSE(id)){
id.n <- 0
id.method <- "none"
labels <- id.cex <- id.col <- id.location <- NULL
}
else{
labels <- id$labels
if (is.null(labels)) labels <- if(!is.null(names(x))) names(x) else seq(along=x)
id.method <- id$method
id.n <- if ("identify" %in% id.method) Inf else id$n
id.cex <- id$cex
id.col <- id$col
id.location <- id$location
}
line <- match.arg(line)
index <- seq(along=x)
good <- !is.na(x)
ord <- order(x[good])
if (length(col) == length(x)) col <- col[good][ord]
if (length(pch) == length(x)) pch <- pch[good][ord]
if (length(cex) == length(x)) cex <- cex[good][ord]
ord.x <- x[good][ord]
ord.lab <- labels[good][ord]
q.function <- eval(parse(text=paste("q", distribution, sep="")))
d.function <- eval(parse(text=paste("d", distribution, sep="")))
n <- length(ord.x)
P <- ppoints(n)
z <- q.function(P, ...)
plot(z, ord.x, type="n", xlab=xlab, ylab=ylab, main=main, las=las, ylim=ylim)
if(grid){
grid(lty=1, equilogs=FALSE)
box()}
points(z, ord.x, col=col, pch=pch, cex=cex)
if (line == "quartiles" || line == "none"){
Q.x <- quantile(ord.x, c(.25,.75))
Q.z <- q.function(c(.25,.75), ...)
b <- (Q.x[2] - Q.x[1])/(Q.z[2] - Q.z[1])
a <- Q.x[1] - b*Q.z[1]
if (line == "quartiles") abline(a, b, col=col.lines, lwd=lwd)
}
if (line=="robust") {
coef <- coef(MASS::rlm(ord.x ~ z))
a <- coef[1]
b <- coef[2]
abline(a, b, col=col.lines, lwd=lwd)
}
if (!isFALSE(envelope)) {
zz <- qnorm(1 - (1 - conf)/2)
SE <- (b/d.function(z, ...))*sqrt(P*(1 - P)/n)
fit.value <- a + b*z
upper <- fit.value + zz*SE
lower <- fit.value - zz*SE
if (style == "filled"){
envelope(z, z, lower, upper, col=col.envelope, alpha=alpha, border=border)
} else {
lines(z, upper, lty=2, lwd=lwd, col=col.lines)
lines(z, lower, lty=2, lwd=lwd, col=col.lines)
}
}
extreme <- showLabels(z, ord.x, labels=ord.lab,
method = id.method, n = id.n, cex=id.cex, col=id.col, location=id.location)
if (is.numeric(extreme)){
nms <- names(extreme)
extreme <- index[good][ord][extreme]
if (!all(as.character(extreme) == nms)) names(extreme) <- nms
}
if (length(extreme) > 0) extreme else invisible(NULL)
}
qqPlot.formula <- function (formula, data, subset, id=TRUE, ylab, glab, ...) {
m <- match.call(expand.dots = FALSE)
if (is.matrix(eval(m$data, sys.frame(sys.parent()))))
m$data <- as.data.frame(data)
m$formula <- m$... <- m$id <- m$ylab <- NULL
m[[1]] <- as.name("model.frame")
if (missing(ylab)) ylab <- as.character(formula[[2]])
if (length(formula) == 2){
groups <- FALSE
}
else if (length(formula) == 3){
groups <- TRUE
if(missing(glab)) glab <- as.character(formula[[3]])
}
m$formula <-formula
if (missing(data)){
x <- na.omit(eval(m, parent.frame()))
}
else{
x <- eval(m, parent.frame())
}
if (!isFALSE(id)){
if (isTRUE(id)){
id <- list(n=2)
}
if (is.null(id$labels)){
id$labels <- rownames(x)
}
}
if (!groups && ncol(x) > 1) stop("more than one variable specified")
if (groups && ncol(x) != 2) stop("formula must be of the form variable ~ groups")
if (!groups) qqPlot(x[, 1], id=id, ylab=ylab, ...)
else qqPlot(x[, 1], groups=x[, 2], id=id, ylab=ylab, glab=glab, ...)
}
qqPlot.lm <- function(x, xlab=paste(distribution, "Quantiles"),
ylab=paste("Studentized Residuals(", deparse(substitute(x)), ")", sep=""), main=NULL,
distribution=c("t", "norm"), line=c("robust", "quartiles", "none"), las=par("las"),
simulate=TRUE, envelope=TRUE, reps=100,
col=carPalette()[1], col.lines=carPalette()[2], lwd=2, pch=1, cex=par("cex"),
id=TRUE, grid=TRUE, ...){
distribution <- match.arg(distribution)
force(xlab)
force(ylab)
x <- update(x, na.action="na.exclude")
if (!is.list(envelope) && length(envelope == 1) && is.numeric(envelope)){
envelope <- list(level=envelope)
}
if (!isFALSE(envelope)){
envelope <- applyDefaults(envelope,
defaults=list(level=0.95, style="filled", col=col.lines, alpha=0.15, border=TRUE))
style <- match.arg(envelope$style, c("filled", "lines", "none"))
col.envelope <- envelope$col
conf <- envelope$level
alpha <- envelope$alpha
border <- envelope$border
if (style == "none") envelope <- FALSE
}
id <- applyDefaults(id, defaults=list(method="y", n=2, cex=1, col=carPalette()[1], location="lr"), type="id")
if (isFALSE(id)){
id.n <- 0
id.method <- "none"
labels <- id.cex <- id.col <- id.location <- NULL
}
else{
labels <- id$labels
if (is.null(labels)) labels <- names(residuals(x))
if (length(labels) != length(residuals(x)))
stop("the number of labels, ", length(labels), ", differs from the number of cases, ", length(residuals(x)))
id.method <- id$method
id.n <- if ("identify" %in% id.method) Inf else id$n
id.cex <- id$cex
id.col <- id$col
id.location <- id$location
}
result <- NULL
line <- match.arg(line)
rstudent <- rstudent(x)
index <- seq(along=rstudent)
sumry <- summary.lm(x)
res.df <- sumry$df[2]
if(!simulate){
result <- qqPlot(rstudent, distribution=if (distribution == "t") "t" else "norm", df=res.df-1, line=line,
main=main, xlab=xlab, ylab=ylab, las=las, envelope=envelope,
col=col, col.lines=col.lines, lwd=lwd, pch=pch, cex=cex,
id=list(method=id.method, n=id.n, cex=id.cex,
col=id.col, location="lr", labels=labels), ...)
}
else {
good <- !is.na(rstudent)
rstudent <- rstudent[good]
labels <- labels[good]
n <- length(rstudent)
ord <- order(rstudent)
ord.x <- rstudent[ord]
ord.lab <- labels[ord]
P <- ppoints(n)
z <- if (distribution == 't') qt(P, df=res.df-1) else qnorm(P)
plot(z, ord.x, type="n", xlab=xlab, ylab=ylab, main=main, las=las)
if(grid) grid(lty=1, equilogs=FALSE)
points(z, ord.x, pch=pch, col=col, cex=cex)
yhat <- na.omit(fitted.values(x))
S <- sumry$sigma
Y <- matrix(yhat, n, reps) + matrix(rnorm(n*reps, sd=S), n, reps)
X <- model.matrix(x)
rstud <- apply(rstudent(lm(Y ~ X - 1)), 2, sort)
if (!isFALSE(envelope)) {
lower <- apply(rstud, 1, quantile, prob=(1 - conf)/2)
upper <- apply(rstud, 1, quantile, prob=(1 + conf)/2)
if (style == "filled"){
envelope(z, z, lower, upper, col=col.envelope, alpha=alpha, border=border)
} else {
lines(z, upper, lty=2, lwd=lwd, col=col.lines)
lines(z, lower, lty=2, lwd=lwd, col=col.lines)
}
}
if (line == "quartiles"){
Q.x <- quantile(rstudent, c(.25,.75))
Q.z <- if (distribution == 't') qt(c(.25,.75), df=res.df - 1) else qnorm(c(.25,.75))
b <- (Q.x[2] - Q.x[1])/(Q.z[2] - Q.z[1])
a <- Q.x[1] - b*Q.z[1]
abline(a, b, col=col.lines, lwd=lwd)
}
if (line=="robust"){
coef <- coefficients(MASS::rlm(ord.x~z))
a <- coef[1]
b <- coef[2]
abline(a, b, col=col.lines, lwd=lwd)
}
result <- showLabels(z, ord.x,labels=ord.lab,
method = id.method, n = id.n, cex=id.cex, col=id.col, location=id.location)
nms <- names(result)
result <- index[good][ord][result]
names(result) <- nms
result
}
if (all(as.character(result) == names(result))) names(result) <- NULL
if (length(result) == 0) invisible(result) else if (is.numeric(result)) sort(result) else result
}
qqPlot.glm <- function(x, ...){
stop("QQ plot for studentized residuals not available for glm")
}
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.