Setting ylim in R's plot.lm residual plot - r

Let's say I'm doing a linear model with y ~ x. I get the residuals plot for example with
plot(lm(y ~ x, data.frame(x=c(1,2,3), y=c(4,6,9))), 1)
How can I set the ylim for this plot? (Supplying e.g. ylim=c(-1,1) to this function doesn't work).

ylim is hard-coded into the function stats:::plot.lm (i.e., the s3 plot method for objects of class "lm"). This function is not exported from the stats package. To get around this, you could copy the function and modify it:
plotlm <- stats:::plot.lm
You can edit it using fix("plotlm"). Add a ylim formal argument to the function definition and then find the relevant part of the code. You should change:
if (show[1L]) {
ylim <- range(r, na.rm = TRUE)
if (id.n > 0)
ylim <- extendrange(r = ylim, f = 0.08)
dev.hold()
plot(yh, r, xlab = l.fit, ylab = "Residuals", main = main,
ylim = ylim, type = "n", ...)
# ...
to:
if (show[1L]) {
if(missing(ylim)) {
ylim <- range(r, na.rm = TRUE)
if (id.n > 0)
ylim <- extendrange(r = ylim, f = 0.08)
}
dev.hold()
plot(yh, r, xlab = l.fit, ylab = "Residuals", main = main,
ylim = ylim, type = "n", ...)
# ...
Then you can call this new function:
plotlm(lm(y ~ x, data.frame(x=c(1,2,3), y=c(4,6,9))), 1, ylim = c(-1,1))
And obtain the desired result:

Related

How to edit a Tukey test plot in R

I carried out a post-hoc Tukey test on an ANOVA and then I made a plot of the results. I can't seem to change my x axis title or my y axis title. I get this error:
Error in plot.default(c(xi[, "lwr"], xi[, "upr"]), rep.int(yvals, 2L), :
formal argument "xlab" matched by multiple actual arguments
This is my relevant code:
tuk <- TukeyHSD(final)
plot(tuk,xlab="Differences in mean departure times", ylab="Comparisons")
I also need to change the y axis tick mark labels but I don't know how.
Thanks.
So because of how they wrote the plot() method for TukeyHSD class object you can not change the axis labels by default, this detail is buried in the ?TuketHSD man page.
But you can easily hack together a copy that does allow you to do it. First find the code for the existing method with getAnywhere(plot.TukeyHSD). Then adapt it like so:
tuk_plot <- function (x, xlab, ylab, ylabels = NULL, ...) {
for (i in seq_along(x)) {
xi <- x[[i]][, -4L, drop = FALSE]
yvals <- nrow(xi):1L
dev.hold()
on.exit(dev.flush())
plot(c(xi[, "lwr"], xi[, "upr"]), rep.int(yvals, 2L),
type = "n", axes = FALSE, xlab = "", ylab = "", main = NULL,
...)
axis(1, ...)
# change for custom axis labels
if (is.null(ylabels)) ylabels <- dimnames(xi)[[1L]]
axis(2, at = nrow(xi):1, labels = ylabels,
srt = 0, ...)
abline(h = yvals, lty = 1, lwd = 0.5, col = "lightgray")
abline(v = 0, lty = 2, lwd = 0.5, ...)
segments(xi[, "lwr"], yvals, xi[, "upr"], yvals, ...)
segments(as.vector(xi), rep.int(yvals - 0.1, 3L), as.vector(xi),
rep.int(yvals + 0.1, 3L), ...)
title(main = paste0(format(100 * attr(x, "conf.level"),
digits = 2L), "% family-wise confidence level\n"),
# change for custom axis titles
xlab = xlab, ylab = ylab)
box()
dev.flush()
on.exit()
}
}
Now you can adjust the x and y axis along with custom y-labels:
tuk_plot(tuk, "Hello X Axis", "Hello Y Axis", c("One", "Two", "Three"))
If you don't provide the y-labels the default ones from the model will show up.
Reproducible Example:
fm1 <- aov(breaks ~ wool + tension, data = warpbreaks))
tuk <- TukeyHSD(fm1, "tension")

How to adjust legend position of interaction.plot and lineplot.CI?

I'm a beginner in coding. I was trying to create an interaction plot. Here's my code:
data is clinicaltrials from the data of the book "Learning Statistics with R."
library(sciplot)
library(lsr)
library(gplots)
lineplot.CI(x.factor = clin.trial$drug,
response = clin.trial$mood.gain,
group = clin.trial$therapy,
ci.fun = ciMean,
xlab = "Drug",
ylab = "Mood Gain")
and it produces the graph like this:
As can be seen in the graph, the legend box is not within my screen.
Also I tried creating another plot using the following code:
interaction.plot(x.factor = clin.trial$drug,
trace.factor = clin.trial$therapy,
response = clin.trial$mood.gain,
fun = mean,
type = "l",
lty = 1, # line type
lwd = 2, # line width
legend = T,
xlab = "Drug", ylab = "Mood Gain",
col = c("#00AFBB", "#E7B800"),
xpd = F,
trace.label = "Therapy")
For this code, I got the graph like this:
In this graph, the legend does not have labels.
Could anyone help me with these problems regarding legend?
You probably plan to save the plot via RStudio GUI. When you resize the plot window with your mouse, you need to run the code again to refresh the legend dimensions.
However, it's advantageous to use a more sophisticated method, e.g. to save it as a png with fixed dimensions like so:
library("sciplot")
library("lsr")
library("gplots")
png("Plot_1.png", height=400, width=500)
lineplot.CI(x.factor=clin.trial$drug,
response=clin.trial$mood.gain,
group=clin.trial$therapy,
ci.fun=ciMean,
xlab="Drug",
ylab="Mood Gain"
)
dev.off()
png("Plot_2.png", height=400, width=500)
interaction.plot(x.factor=clin.trial$drug,
trace.factor=clin.trial$therapy,
response=clin.trial$mood.gain,
fun=mean,
type="l",
lty=1, # line type
lwd=2, # line width
legend=T,
xlab="Drug", ylab="Mood Gain",
col=c("#00AFBB", "#E7B800"),
xpd=F,
trace.label="Therapy")
dev.off()
The plots are saved into your working directory, check getwd() .
Edit
You could also adjust the legend position.
In lineplot.CI you may use arguments; either by using characters just for x, e.g. x.leg="topleft" or both coordinates as numeric x.leg=.8, y.leg=2.2.
interaction.plot does not provide yet this functionality. I provide a hacked version below. Arguments are called xleg and yleg, functionality as above.
See ?legend for further explanations.
interaction.plot <- function (x.factor, trace.factor, response, fun = mean,
type = c("l", "p", "b", "o", "c"), legend = TRUE,
trace.label = deparse(substitute(trace.factor)),
fixed = FALSE, xlab = deparse(substitute(x.factor)),
ylab = ylabel, ylim = range(cells, na.rm = TRUE),
lty = nc:1, col = 1, pch = c(1L:9, 0, letters),
xpd = NULL, leg.bg = par("bg"), leg.bty = "n",
xtick = FALSE, xaxt = par("xaxt"), axes = TRUE,
xleg=NULL, yleg=NULL, ...) {
ylabel <- paste(deparse(substitute(fun)), "of ", deparse(substitute(response)))
type <- match.arg(type)
cells <- tapply(response, list(x.factor, trace.factor), fun)
nr <- nrow(cells)
nc <- ncol(cells)
xvals <- 1L:nr
if (is.ordered(x.factor)) {
wn <- getOption("warn")
options(warn = -1)
xnm <- as.numeric(levels(x.factor))
options(warn = wn)
if (!anyNA(xnm))
xvals <- xnm
}
xlabs <- rownames(cells)
ylabs <- colnames(cells)
nch <- max(sapply(ylabs, nchar, type = "width"))
if (is.null(xlabs))
xlabs <- as.character(xvals)
if (is.null(ylabs))
ylabs <- as.character(1L:nc)
xlim <- range(xvals)
if (is.null(xleg)) {
xleg <- xlim[2L] + 0.05 * diff(xlim)
xlim <- xlim + c(-0.2/nr, if (legend) 0.2 + 0.02 * nch else 0.2/nr) *
diff(xlim)
}
dev.hold()
on.exit(dev.flush())
matplot(xvals, cells, ..., type = type, xlim = xlim, ylim = ylim,
xlab = xlab, ylab = ylab, axes = axes, xaxt = "n",
col = col, lty = lty, pch = pch)
if (axes && xaxt != "n") {
axisInt <- function(x, main, sub, lwd, bg, log, asp,
...) axis(1, x, ...)
mgp. <- par("mgp")
if (!xtick)
mgp.[2L] <- 0
axisInt(1, at = xvals, labels = xlabs, tick = xtick,
mgp = mgp., xaxt = xaxt, ...)
}
if (legend) {
yrng <- diff(ylim)
if (is.null(yleg))
yleg <- ylim[2L] - 0.1 * yrng
if (!is.null(xpd) || {
xpd. <- par("xpd")
!is.na(xpd.) && !xpd. && (xpd <- TRUE)
}) {
op <- par(xpd = xpd)
on.exit(par(op), add = TRUE)
}
# text(xleg, ylim[2L] - 0.05 * yrng, paste(" ",
# trace.label), adj = 0)
if (!fixed) {
ord <- sort.list(cells[nr, ], decreasing = TRUE)
ylabs <- ylabs[ord]
lty <- lty[1 + (ord - 1)%%length(lty)]
col <- col[1 + (ord - 1)%%length(col)]
pch <- pch[ord]
}
legend(xleg, yleg, legend = ylabs, col = col,
title = if (trace.label == "") NULL else trace.label,
pch = if (type %in% c("p", "b"))
pch, lty = if (type %in% c("l", "b"))
lty, bty = leg.bty, bg = leg.bg)
}
invisible()
}
Data:
lk <- "https://learningstatisticswithr.com/data.zip"
tmp <- tempfile()
tmp.dir <- tempdir()
download.file(lk, tmp)
unzip(tmp, exdir=tmp.dir)
load("data/clinicaltrial.Rdata")

Modify the limit of the y axis in plot.ACF (package nlme)

I used the function plot.ACF (package nlme) to do a graph of the autocorrelations for model residuals.The problem is that the autocorrelations in the graph are very hard to read. How can I modify the limit of the y axis in the function plot.ACF ?
Here is my graph:
The nlme:::plot.ACF function has a hard-coded ylim assignment, so you have to modify the function slightly (the comment lines below are the only places I made changes).
my_acf_plot <- function (x, alpha = 0, xlab = "Lag", ylab = "Autocorrelation",
grid = FALSE,
ylim = NULL, ## add ylim
...)
{
require("lattice") ## for xyplot, panel.* function
## (unnecessary originally because the package imports
## the required functions)
object <- x
if (is.null(ylim)) ylim <- range(object$ACF) ## set ylim if unset
if (alpha) {
assign("stdv", qnorm(1 - alpha/2)/sqrt(attr(object, "n.used")))
stMax <- max(stdv)
ylim <- c(min(c(-stMax, ylim[1])), max(c(ylim[2], stMax)))
}
assign("alpha", as.logical(alpha))
assign("grid", grid)
xyplot(ACF ~ lag, object, ylim = ylim, panel = function(x,
y, ...) {
x <- as.numeric(x)
y <- as.numeric(y)
if (grid)
panel.grid()
panel.xyplot(x, y, type = "h")
panel.abline(0, 0)
if (alpha) {
llines(x, stdv, lty = 2)
llines(x, -stdv, lty = 2)
}
}, xlab = xlab, ylab = ylab, ...)
}
Example:
library(nlme)
set.seed(101)
d <- data.frame(y=rnorm(50),x=1:50)
my_acf_plot(ACF(gls(y~x,data=d)),ylim=c(-0.3,0.5))

Fix layout / plot options of plot(fevd()) function

I am currently busy with a Vector Autoregressive Analysis in R, using the vars package. I was wondering if the following things are possible:
1) the previous solution for a better fit on the page worked properly, but now with more variables, we have more plots and the layout is screwed again. I already played with some of the win.graph() parameters, but nothing gives me a proper readable solution.
2) The plot(irf(...) function of the vars package gives a one-graph per page output. I was wondering if this is also possible for the plot(fevd() function by adding some extra (unkown to me) parameters options
3) Also, for readability, I would like to color the graphs, plot(fevd() gives an all-kinds-of-gray output, Is it possible to change those colors?
Thank you in advance
Olivier
You will have to modify the plot function for fevd to do what you want. Here's a modified plot.varfevd function that removes all calls to par(). This allows to use layout properly. The lines that have been removed have been commented out (#). I also removed the parameter that asked for confirmation in "single" plots.
plot.varfevd <-function (x, plot.type = c("multiple", "single"), names = NULL,
main = NULL, col = NULL, ylim = NULL, ylab = NULL, xlab = NULL,
legend = NULL, names.arg = NULL, nc, mar = par("mar"), oma = par("oma"),
addbars = 1, ...)
{
K <- length(x)
ynames <- names(x)
plot.type <- match.arg(plot.type)
if (is.null(names)) {
names <- ynames
}
else {
names <- as.character(names)
if (!(all(names %in% ynames))) {
warning("\nInvalid variable name(s) supplied, using first variable.\n")
names <- ynames[1]
}
}
nv <- length(names)
# op <- par(no.readonly = TRUE)
ifelse(is.null(main), main <- paste("FEVD for", names), main <- rep(main,
nv)[1:nv])
ifelse(is.null(col), col <- gray.colors(K), col <- rep(col,
K)[1:K])
ifelse(is.null(ylab), ylab <- rep("Percentage", nv), ylab <- rep(ylab,
nv)[1:nv])
ifelse(is.null(xlab), xlab <- rep("Horizon", nv), xlab <- rep(xlab,
nv)[1:nv])
ifelse(is.null(ylim), ylim <- c(0, 1), ylim <- ylim)
ifelse(is.null(legend), legend <- ynames, legend <- legend)
if (is.null(names.arg))
names.arg <- c(paste(1:nrow(x[[1]])), rep(NA, addbars))
plotfevd <- function(x, main, col, ylab, xlab, names.arg,
ylim, ...) {
addbars <- as.integer(addbars)
if (addbars > 0) {
hmat <- matrix(0, nrow = K, ncol = addbars)
xvalue <- cbind(t(x), hmat)
barplot(xvalue, main = main, col = col, ylab = ylab,
xlab = xlab, names.arg = names.arg, ylim = ylim,
legend.text = legend, ...)
abline(h = 0)
}
else {
xvalue <- t(x)
barplot(xvalue, main = main, col = col, ylab = ylab,
xlab = xlab, names.arg = names.arg, ylim = ylim,
...)
abline(h = 0)
}
}
if (plot.type == "single") {
# par(mar = mar, oma = oma)
# if (nv > 1)
# par(ask = TRUE)
for (i in 1:nv) {
plotfevd(x = x[[names[i]]], main = main[i], col = col,
ylab = ylab[i], xlab = xlab[i], names.arg = names.arg,
ylim = ylim, ...)
}
}
else if (plot.type == "multiple") {
if (missing(nc)) {
nc <- ifelse(nv > 4, 2, 1)
}
nr <- ceiling(nv/nc)
par(mfcol = c(nr, nc), mar = mar, oma = oma)
for (i in 1:nv) {
plotfevd(x = x[[names[i]]], main = main[i], col = col,
ylab = ylab[i], xlab = xlab[i], names.arg = names.arg,
ylim = ylim, ...)
}
}
# on.exit(par(op))
}
Then, you will need short variable names. Pick acronyms if needed.
library(vars)
data(Canada)
colnames(Canada) <-c("name1","name2","name3","name4")
var <- VAR(Canada , p=4 , type = "both")
Using a wide plot window (using win.graph) and using layout (to get the placement of your eight plots), you can get all charts displayed properly. I also changed the colors of the plots as requested. Finally, we are now using single plots as there are no calls to par() which do not sit well with layout().
win.graph(width=15,height=8)
layout(matrix(1:8,ncol=2))
plot.varfevd(fevd(var, n.ahead = 10 ),plot.type = "single", col=1:4)
plot.varfevd(fevd(var, n.ahead = 10 ),plot.type = "single", col=1:4)

Write summary of fit in pdf file or similar

I'm doing a linear fitting on many datasets in a loop and plotting the results in a pdf file. Is it possible to directly save the output of summary(fit) in the same pdf file instead of observing the summaries of about 100 datasets through the console?
LMmodel <- y ~ x
fit <- lm(LMmodel, data = Dataset)
pdf(file = OutputFile, width = 10, height = 6, paper = "a4r")
xLim = range(x)
yLim = range(y)
plot(x, y, type = "p", xlim = xLim, ylim = yLim,
main = plotTitle, xlab = "x [m]", ylab = "y [dB]",
pch = 20, cex = .9)
regLine(fit, col=palette()[2], lwd=2, lty=1)
grid(lwd = 1.5)
plot(density(residuals(fit)), main = "Density Plot of the Residuals"))
dev.off()
graphics.off()
return(summary(fit))
I really recommend Knitr with Rstudio to generate Report.
Here I use you code to generate a pdf in 3 simple steps. I assume you have Rstudio installed.
I create a new R sweave file ( using the menu)
Where I insert 2 chuncks (using the Chunks at right)
<<myplot,echo=FALSE,fig=TRUE>>=
library(car)
x <- rnorm(n=20,mean=30,sd=20)
y <- rnorm(n=20,mean=180,sd=10)
Dataset <- data.frame(x=x,y=y)
LMmodel <- y ~ x
fit <- lm(LMmodel, data = Dataset)
xLim = range(x)
yLim = range(y)
plot(x, y, type = "p", xlim = xLim, ylim = yLim,
main = "plotTitle", xlab = "x [m]", ylab = "y [dB]",
pch = 20, cex = .9)
regLine(fit, col=palette()[2], lwd=2, lty=1)
grid(lwd = 1.5)
plot(density(residuals(fit)), main = "Density Plot of the Residuals")
#
the summary is :
<<mysummary>>=
print(summary(fit))
#
You generate a pdf file using the compile PDF button.
You can insert what you want between the summary and the plots to build complex reports.

Resources