R Customizing graphics
Customizing graphics
In this chapter (it tends to be overly comprehensive: consider it as a reference and feel free to skip it), we consider all the configurable details in graphics: symbols, colours, annotations (with text and mathematical symbols), grid graphics, but also LaTeX and GUI building with Tk. This chapter's object of interest is the graphic -- the previous chapter, still about graphics, was data-centric.
Things can be quite complicated because there are two sets of graphical functions: the classical ones and those, more complex but much more powerful, from the lattice and grid packages. We shall detail them in turn and finally explain how graphics can leave R: isolated PDF or PNG files, for inclusion of PDF (e.g., LaTeX) or HTML documents, use of interactive programs to look at the data, etc.
Graphics
Basic commands
Here are the main functions that turn data into graphs. We do not detail them here, we shall come back on them when we have some data to provide them with.
The "plot" function draw a set of points; it may link the points by a broken line.
The syntax "y ~ x" might look strange: it should be read "y as a function of x". We shall also use this syntax to describe the regression models. The can be more complex, for instance, "y ~ x1 + x2" means "y as a function of x1 and x2" and "y ~ x | z" means "y as a function of x for each value of z" (more about this later, when we tackle lattice plots and mixed models).
library(MASS)
data(beav1)
plot(beav1$temp ~ beav1$time)
x <- beav1$time
y <- beav1$temp
o <- order(x)
x <- x[o]
y <- y[o]
plot(y ~ x,
type = "l",
xlab = "Time",
ylab = "Temperature",
main = "The \"plot\" function, with type=\"l\"")
plot(y ~ x,
type = "b",
lwd = 3,
xlim = c(0, 400),
xlab = "Time",
ylab = "Temperature",
main = "The \"plot\" function, with type=\"b\"")
Actually, it is a generic function: it will behave in a different way depending on its argument type. If the argument belongs to the "toto" class, it will look for a "plot.toto" function; if it does not exist, it will fall back to the "plot.default" function. Among others, the "plot", "print", "summary", "predict" behave that way.
# What we would expect
> plot
function (x, y, ...)
UseMethod("plot") # What we used to have
> plot
function (x, y, ...)
{
if (is.null(attr(x, "class")) && is.function(x)) {
if ("ylab" %in% names(list(...)))
plot.function(x, ...)
else plot.function(x, ylab = paste(deparse(substitute(x)),
"(x)"), ...)
}
else UseMethod("plot")
} # What we currently have (R-2.1.0)
> plot
function (x, y, ...)
{
if (is.null(attr(x, "class")) && is.function(x)) {
nms <- names(list(...))
if (missing(y))
y <- {
if (!"from" %in% nms)
0
else if (!"to" %in% nms)
1
else if (!"xlim" %in% nms)
NULL
}
if ("ylab" %in% nms)
plot.function(x, y, ...)
else plot.function(x, y, ylab = paste(deparse(substitute(x)),
"(x)"), ...)
}
else UseMethod("plot")
}
<environment: namespace:graphics> > apropos("^plot\.")
[1] "plot.data.frame" "plot.default" "plot.density" "plot.factor"
[5] "plot.formula" "plot.function" "plot.histogram" "plot.lm"
[9] "plot.mlm" "plot.mts" "plot.new" "plot.POSIXct"
[13] "plot.POSIXlt" "plot.table" "plot.ts" "plot.TukeyHSD"
[17] "plot.window" "plot.xy" > methods(plot)
[1] plot.acf* plot.boot* plot.correspondence*
[4] plot.data.frame* plot.Date* plot.decomposed.ts*
[7] plot.default plot.dendrogram* plot.density
[10] plot.ecdf plot.EDAM* plot.factor*
[13] plot.formula* plot.hclust* plot.histogram*
[16] plot.HoltWinters* plot.isoreg* plot.lda*
[19] plot.lm plot.mca* plot.medpolish*
[22] plot.mlm plot.NaiveBayes* plot.POSIXct*
[25] plot.POSIXlt* plot.ppr* plot.prcomp*
[28] plot.princomp* plot.profile* plot.profile.nls*
[31] plot.rda* plot.ridgelm* plot.shingle*
[34] plot.spec plot.spec.coherency plot.spec.phase
[37] plot.stepclass* plot.stepfun plot.stl*
[40] plot.table* plot.ts plot.tskernel*
[43] plot.TukeyHSD Non-visible functions are asterisked
To get the non-visible functions, you can use the "getAnywhere" function.
> plot.Date
Error: Object "plot.Date" not found > getAnywhere("plot.Date")
A single object matching 'plot.Date' was found
It was found in the following places
registered S3 method for plot from namespace graphics
namespace:graphics
with value function (x, y, xlab = "", axes = TRUE, frame.plot = axes, xaxt = par("xaxt"),
...)
{
axisInt <- function(x, main, sub, xlab, ylab, col, lty, lwd,
xlim, ylim, bg, pch, log, asp, ...) axis.Date(1, x, ...)
plot.default(x, y, xaxt = "n", xlab = xlab, axes = axes,
frame.plot = frame.plot, ...)
if (axes && xaxt != "n")
axisInt(x, ...)
}
<environment: namespace:graphics> > str( getAnywhere("plot.Date") )
List of 5
$ name : chr "plot.Date"
$ objs :List of 2
..$ :function (x, y, xlab = "", axes = TRUE,
frame.plot = axes, xaxt = par("xaxt"),
...)
..$ :function (x, y, xlab = "", axes = TRUE,
frame.plot = axes, xaxt = par("xaxt"),
...)
$ where : chr [1:2] "registered S3 method for plot from namespace graphics"
"namespace:graphics"
$ visible: logi [1:2] FALSE FALSE
$ dups : logi [1:2] FALSE TRUE
- attr(*, "class")= chr "getAnywhere" > str( getAnywhere("plot.Date")$objs[[1]] )
function (x, y, xlab = "", axes = TRUE,
frame.plot = axes, xaxt = par("xaxt"),
...) > getAnywhere("plot.Date")$objs[[1]]
function (x, y, xlab = "", axes = TRUE,
frame.plot = axes, xaxt = par("xaxt"),
...)
{
axisInt <- function(x, main, sub, xlab, ylab, col, lty, lwd,
xlim, ylim, bg, pch, log, asp, ...) axis.Date(1, x, ...)
plot.default(x, y, xaxt = "n", xlab = xlab, axes = axes,
frame.plot = frame.plot, ...)
if (axes && xaxt != "n")
axisInt(x, ...)
}
<environment: namespace:graphics>
TODO: the following examples should be as simple as possible, just the function, with NO optional arguments. A second example can be graphically more appealling, but the first should be provides by readable code.
The "matplot" can plot several curves at the same time.
x <- as.matrix( EuStockMarkets[1:50,] )
matplot(x, # By default: not lines,
main = "matplot", # but unconnected coloured numbers
xlab = "",
ylab = "")
matplot(x,
type = "l", # Lines -- but I am not happy
lty = 1, # with the axes
xlab = "",
ylab = "",
main = "matplot")
x <- as.matrix( EuStockMarkets )
matplot(time(EuStockMarkets),
x,
log = "y",
type = 'l',
lty = 1,
ylab = "Closing price",
xlab = "Date",
main = "matplot",
axes = FALSE)
axis(1)
axis(2)
box()
The "pairs" command plots a "matrix of scatterplots" (aka "splom", for ScatterPLOt Matrix).
pairs(longley)
pairs(longley,
gap=0,
diag.panel = function (x, ...) {
par(new = TRUE)
hist(x,
col = "light blue",
probability = TRUE,
axes = FALSE,
main = "")
lines(density(x),
col = "red",
lwd = 3)
rug(x)
})
The "stripchart" plots a 1-dimensional cloud of points.
stripchart(longley$Unemployed)
The "hist" command plots a histogram.
hist(longley$Unemployed)
hist(longley$Unemployed,
probability = TRUE, # Change the vertical units,
# to overlay a density estimation
col = "light blue")
lines(density(longley$Unemployed),
col = "red",
lwd = 3)
The "boxplot" command displays one or several box-and-whiskers diagram(s).
boxplot(longley$Unemployed)
boxplot(longley$Unemployed,
horizontal = TRUE,
col = "pink",
main = "Box-and-whiskers plot (boxplot)")
data(InsectSprays)
boxplot(count ~ spray,
data = InsectSprays,
col = "pink",
xlab = "Spray",
ylab = "Count",
main = "Insect sprays")
boxplot(count ~ spray,
data = InsectSprays,
col = "pink",
horizontal = TRUE,
las = 1, # Horizontal labels
xlab = "Count",
ylab = "Spray",
main = "Insect sprays")
The "contour" function displays a contour plot (I sometimes use it to look at a likelihood function or a bidimensioinal density, estimated with the "kde2d" function).
N <- 50
x <- seq(-1, 1, length=N)
y <- seq(-1, 1, length=N)
xx <- matrix(x, nr=N, nc=N)
yy <- matrix(y, nr=N, nc=N, byrow=TRUE)
z <- 1 / (1 + xx^2 + (yy + .2 * sin(10*yy))^2)
contour(x, y, z,
main = "Contour plot")
The image function plots the same information, with colours.
image(z)
image(x, y, z,
xlab = "",
ylab = "")
contour(x, y, z, lwd=3, add=TRUE)
The "persp" function draw a 3D surface.
persp(z)
op <- par(mar=c(0,0,3,0)+.1)
persp(x, y, z,
theta = 45, phi = 30,
shade = .5,
col = rainbow(N),
border = "green",
main = "perspective plot, theta=45, phi=30")
par(op)
# From the manual: the sinc function
x <- seq(-10, 10, length= 30)
y <- x
f <- function(x,y) { r <- sqrt(x^2+y^2); 10 * sin(r)/r }
z <- outer(x, y, f)
z[is.na(z)] <- 1
op <- par(bg = "white", mar=c(0,2,3,0)+.1)
persp(x, y, z,
theta = 30, phi = 30,
expand = 0.5,
col = "lightblue",
ltheta = 120,
shade = 0.75,
ticktype = "detailed",
xlab = "X", ylab = "Y", zlab = "Sinc(r)",
main = "The sinc function"
)
par(op)
Text
Here are a few ways of configuring those graphics.
You can add a title, change the name of the axes.
n <- 100
x <- rnorm(n)
y <- 1 - x^2 + .3*rnorm(n)
plot(y ~ x,
xlab = 'X axis',
ylab = "Y axis",
main = "Title")
You can also add the title and the axes names afterwards, with the "title" function.
plot(y ~ x,
xlab = "",
ylab = "",
main = "")
title(main = "Title",
xlab = "X axis",
ylab = "Y axis")
The "text" function allows you to add text in the plot.
set.seed(1)
plot.new()
plot.window(xlim=c(0,1), ylim=c(0,1))
box()
N <- 50
text(
runif(N), runif(N),
sample( # Random words...
scan("/usr/share/dict/cracklib-small", character(0)),
N
)
)
TODO: the "adj" and "pos" arguments...
The "mtext" function allows you to add text in the margin of the plot -- for instance, if your plot has a title and a subtitle, or if you need two different y axes, one on each side of the plot.
N <- 200
x <- runif(N, -4, 4)
y <- sin(x) + .5 * rnorm(N)
plot(x, y,
xlab = "", ylab = "",
main = paste("The \"mtext\" function",
paste(rep(" ", 60), collapse="")))
mtext("Line 0", 3, line=0)
mtext("Line 1", 3, line=1)
mtext("Line 2", 3, line=2)
mtext("Line 3", 3, line=3)
N <- 200
x <- runif(N, -4, 4)
y <- sin(x) + .5 * rnorm(N)
plot(x, y, xlab="", ylab="", main="")
mtext("Subtitle", 3, line=.8)
mtext("Title", 3, line=2, cex=1.5)
mtext("X axis", 1, line=2.5, cex=1.5)
mtext("X axis subtitle", 1, line=3.7)
N <- 200
x <- seq(-4,4, length=N)
y1 <- sin(x)
y2 <- cos(x)
op <- par(mar=c(5,4,4,4)) # Add some space in the right margin
# The default is c(5,4,4,2) + .1
xlim <- range(x)
ylim <- c(-1.1, 1.1)
plot(x, y1, col="blue", type="l",
xlim=xlim, ylim=ylim,
axes=F, xlab="", ylab="", main="Title")
axis(1)
axis(2, col="blue")
par(new=TRUE)
plot(x, y2, col="red", type="l",
xlim=xlim, ylim=ylim,
axes=F, xlab="", ylab="", main="")
axis(4, col="red")
mtext("First Y axis", 2, line=2, col="blue", cex=1.2)
mtext("Second Y axis", 4, line=2, col="red", cex=1.2)
Mathematical symbols
The text may contain mathematical symbols.
x <- seq(-5,5,length=200)
y <- sqrt(1+x^2)
plot(y~x, type='l',
ylab=expression( sqrt(1+x^2) ))
title(main=expression(
"graph of the function f"(x) == sqrt(1+x^2)
))
You can also start with such a formula and dynamically change a part of it -- typically, to insert the numeric value of a variable.
x <- seq(-5,5,length=200)
op <- par(mfrow=c(2,2))
for (i in 1:4) {
y <- sqrt(i+x^2)
plot(y ~ x,
type = 'l',
ylim = c(0,6),
ylab = substitute(
expression( sqrt(i+x^2) ),
list(i=i)
))
title(main = substitute(
"graph of the function f"(x) == sqrt(i+x^2),
list(i=i)))
}
par(op)
Here are a few examples from the manual.
# From the manual
plot(1:10, 1:10, main = "text(...) examples\n~~~~~~~~~~~~~~",
sub = "R is GNU ©, but not ® ...")
mtext("«ISO-accents»: ± éè øØ å<Å æ<Æ", side=3)
points(c(6,2), c(2,1), pch = 3, cex = 4, col = "red")
text(6, 2, "the text is CENTERED around (x,y) = (6,2) by default",
cex = .8)
text(2, 1, "or Left/Bottom - JUSTIFIED at (2,1) by `adj = c(0,0)'",
adj = c(0,0))
text(4, 9, expression(hat(beta) == (X^t * X)^{-1} * X^t * y))
text(4, 8.4, "expression(hat(beta) == (X^t * X)^{-1} * X^t * y)", cex = .75)
text(4, 7, expression(bar(x) == sum(frac(x[i], n), i==1, n)))
You can even write in Japanese.
?Japanese # From the manual
plot(1:9, type="n", axes=FALSE, frame=TRUE, ylab="",
main= "example(Japanese)", xlab= "using Hershey fonts")
par(cex=3)
Vf <- c("serif", "plain")
text(4, 2, "\\#J2438\\#J2421\\#J2451\\#J2473", vfont = Vf)
text(4, 4, "\\#J2538\\#J2521\\#J2551\\#J2573", vfont = Vf)
text(4, 6, "\\#J467c\\#J4b5c", vfont = Vf)
text(4, 8, "Japan", vfont = Vf)
par(cex=1)
text(8, 2, "Hiragana")
text(8, 4, "Katakana")
text(8, 6, "Kanji")
text(8, 8, "English")
# Other example from the manual
# (it also contains katakana and kanji tables)
make.table <- function(nr, nc) {
opar <- par(mar=rep(0, 4), pty="s")
plot(c(0, nc*(10%/%nc) + 1), c(0, -(nr + 1)),
type="n", xlab="", ylab="", axes=FALSE)
invisible(opar)
} get.r <- function(i, nr) i %% nr + 1
get.c <- function(i, nr) i %/% nr + 1
Esc2 <- function(str) paste("\\", str, sep="") draw.title <- function(title, nc)
text((nc*(10%/%nc) + 1)/2, 0, title, font=2) draw.vf.cell <- function(typeface, fontindex, string, i, nr, raw.string=NULL) {
r <- get.r(i, nr)
c <- get.c(i, nr)
x0 <- 2*(c - 1)
if (is.null(raw.string)) raw.string <- Esc2(string)
text(x0 + 1.1, -r, raw.string, col="grey")
text(x0 + 2, -r, string, vfont=c(typeface, fontindex))
rect(x0 + .5, -(r - .5), x0 + 2.5, -(r + .5), border="grey")
} draw.vf.cell2 <- function(string, alt, i, nr) {
r <- get.r(i, nr)
c <- get.c(i, nr)
x0 <- 3*(c - 1)
text(x0 + 1.1, -r, Esc2(string <- Esc2(string)), col="grey")
text(x0 + 2.2, -r, Esc2(Esc2(alt)), col="grey", cex=.6)
text(x0 + 3, -r, string, vfont=c("serif", "plain"))
rect(x0 + .5, -(r - .5), x0 + 3.5, -(r + .5), border="grey")
} tf <- "serif"
fi <- "plain"
nr <- 25
nc <- 4
oldpar <- make.table(nr, nc)
index <- 0
digits <- c(0:9,"a","b","c","d","e","f")
draw.title("Hiragana : \\\\#J24nn", nc)
for (i in 2:7) {
for (j in 1:16) {
if (!((i == 2 && j == 1) || (i == 7 && j > 4))) {
draw.vf.cell(tf, fi, paste("\\#J24", i, digits[j], sep=""),
index, nr)
index <- index + 1
}
}
}
Lines
You can choose the line colour,
plot(runif(5), ylim=c(0,1), type='l')
for (i in c('red', 'blue', 'green')) {
lines( runif(5), col=i )
}
title(main="Lines in various colours")
their width,
plot(runif(5), ylim=c(0,1), type='n')
for (i in 5:1) {
lines( runif(5), col=i, lwd=i )
}
title(main = "Varying the line thickness")
their type,
op <- par(mfrow=c(3,2))
plot(runif(5), type = 'p',
main = "plot type 'p' (points)")
plot(runif(5), type = 'l',
main = "plot type 'l' (lines)")
plot(runif(5), type = 'b',
main = "plot type 'b' (both points and lines)")
plot(runif(5), type = 's',
main = "plot type 's' (stair steps)")
plot(runif(5), type = 'h',
main = "plot type 'h' (histogram)")
plot(runif(5), type = 'n',
main = "plot type 'n' (no plot)")
par(op)
the line type (lty),
op <- par(mfrow=c(3,2), mar=c(3,1,5,1))
plot(runif(5), lty = 1,
axes = FALSE, type = "l", lwd = 3,
main = "lty = 1 (default, solid)")
plot(runif(5), lty = 2,
axes = FALSE, type = "l", lwd = 3,
main = "lty = 2 (dashed)")
plot(runif(5), lty = 3,
axes = FALSE, type = "l", lwd = 3,
main = "lty = 3 (dotted)")
plot(runif(5), lty = "dotdash",
axes = FALSE, type = "l", lwd = 3,
main = "lty = 4 (dot, dash)")
plot(runif(5), lty = "longdash",
axes = FALSE, type = "l", lwd = 3,
main = "lty = 5 (longdash)")
plot(runif(5), lty = "twodash",
axes = FALSE, type = "l", lwd = 3,
main = "lty = 6 (twodash)")
par(op)
# You can also cook up your own line type
# by providing the length of each segment and
# each space
op <- par(mfrow=c(2,2), mar=c(3,1,5,1))
for (lty in c("42", "14", "8222", "82624222")) {
plot(runif(5), lty = lty,
axes = FALSE, type = "l", lwd = 3,
main = paste("lty =", lty))
}
par(op)
the symbols used (pch) or their size (cex),
op <- par(mar=c(1,1,4,1)+.1)
plot(0,0,
xlim = c(1,5), ylim = c(-.5,4),
axes = F,
xlab = '', ylab = '',
main = "Available symbols")
for (i in 0:4) {
for (j in 1:5) {
n <- 5*i+j
points(j, i,
pch = n,
cex = 3)
text(j,i-.25, as.character(n))
}
}
par(op)
The "density" and "angle" options add shading lines.
hist(longley$Unemployed, density=3, angle=45)
Splitting the screen
You can also put several graphics in a simgle picture. It might then be necessary to modify the margins to leave some room for the title. The easiest way is through the "mfrow" or "mfcol" argument of the "par" function. (With "mfrow", the plots are first placed in the first row, then the second, etc.; with "mfcol", the plots are first placed in the first column, the the second, etc.)
op <- par(mfrow = c(2, 2))
for (i in 1:4)
plot(runif(20), runif(20),
main=paste("random plot (",i,")",sep=''))
par(op)
mtext("Four plots, without enough room for this title",
side=3, font=2, cex=2, col='red')
op <- par(mfrow = c(2, 2),
oma = c(0,0,3,0) # Outer margins
)
for (i in 1:4)
plot(runif(20), runif(20),
main=paste("random plot (",i,")",sep=''))
par(op)
mtext("Four plots, with some room for this title",
side=3, line=1.5, font=2, cex=2, col='red')
op <- par(mfrow = c(2, 2),
oma = c(0,0,3,0),
mar = c(3,3,4,1) + .1 # Margins
)
for (i in 1:4)
plot(runif(20), runif(20),
xlab = "", ylab = "",
main=paste("random plot (",i,")",sep=''))
par(op)
mtext("Title",
side=3, line=1.5, font=2, cex=2, col='red')
par(op)
You can also superimpose several graphics, by playing with the "fig" graphical parameter.
n <- 20
x <- rnorm(n)
y <- x^2 - 1 + .3*rnorm(n)
plot(y ~ x,
main = "The \"fig\" graphic parameter")
op <- par()
for (i in 2:10) {
done <- FALSE
while(!done) {
a <- c( sort(runif(2,0,1)),
sort(runif(2,0,1)) )
par(fig=a, new=T)
r <- try(plot(runif(5), type='l', col=i))
done <- !inherits(r, "try-error")
}
}
par(op)
n <- 1000
x <- rt(n, df=10)
hist( x,
col = "light blue",
probability = "TRUE",
ylim = c(0, 1.2*max(density(x)$y)))
lines(density(x),
col = "red",
lwd = 3)
op <- par(fig = c(.02,.4,.5,.98),
new = TRUE)
qqnorm(x,
xlab = "", ylab = "", main = "",
axes = FALSE)
qqline(x, col = "red", lwd = 2)
box(lwd=2)
par(op)
For slightly more complicated layouts, you can use the "layout" function.
op <- par(oma = c(0,0,3,0))
layout(matrix(c(1, 1, 1,
2, 3, 4,
2, 3, 4), nr = 3, byrow = TRUE))
hist( rnorm(n), col = "light blue" )
hist( rnorm(n), col = "light blue" )
hist( rnorm(n), col = "light blue" )
hist( rnorm(n), col = "light blue" )
mtext("The \"layout\" function",
side = 3, outer = TRUE,
font = 2, size = 1.2)
par(op)
There is also a "split.screen" function -- completely incompatible with the above.
random.plot <- function () {
N <- 200
f <- sample(list(rnorm,
function (x) { rt(x, df=2) },
rlnorm,
runif),
1) [[1]]
x <- f(N)
hist(x, col="light blue", main="", xlab="", ylab="", axes=F)
axis(1)
}
op <- par(bg="white", mar=c(2.5,2,1,2))
split.screen(c(2,1))
split.screen(c(1,3), screen = 2)
screen(1); random.plot()
#screen(2); random.plot() # Screen 2 was split into three screens: 3, 4, 5
screen(3); random.plot()
screen(4); random.plot()
screen(5); random.plot()
close.screen(all=TRUE)
par(op)
Overlaying graphical elements
You can add several graphical elements: either with certain commands, that do not start a new graphic ("points", "lines", "segments", "text"); or by adding "add=T" to commands that normally start a new picture; or with "par(new=TRUE)" which asks NOT to start a new picture.
plot(runif(5), runif(5),
xlim = c(0,1), ylim = c(0,1))
points(runif(5), runif(5),
col = 'orange', pch = 16, cex = 3)
lines(runif(5), runif(5),
col = 'red')
segments(runif(5), runif(5), runif(5), runif(5),
col = 'blue')
title(main = "Overlaying points, segments, lines...")
You can paint parts of the drawing area with the "polygon" command.
my.col <- function (f, g, xmin, xmax, col, N=200,
xlab="", ylab="", main="") {
x <- seq(xmin, xmax, length = N)
fx <- f(x)
gx <- g(x)
plot(0, 0, type = 'n',
xlim = c(xmin,xmax),
ylim = c( min(fx,gx), max(fx,gx) ),
xlab = xlab, ylab = ylab, main = main)
polygon( c(x,rev(x)), c(fx,rev(gx)),
col = 'red', border = 0 )
lines(x, fx, lwd = 3)
lines(x, gx, lwd = 3)
}
op <- par(mar=c(3,3,4,1)+.1)
my.col( function(x) x^2, function(x) x^2+10*sin(x),
-6, 6,
main = "The \"polygon\" function")
par(op)
TODO: Example with two colours.
You can define colors with a number, a character string giving its English name (such as "light blue" -- the complete list in in the "rgb.txt" file) or with a character string containing its RGB (or RGBA) code (such as "#CC00FF").
The "rainbow", "heat.color", etc. commands provide colour lists.
# From the manual
ch.col <- c("rainbow(n, start=.7, end=.1)",
"heat.colors(n)",
"terrain.colors(n)",
"topo.colors(n)",
"cm.colors(n)")
n <- 16
nt <- length(ch.col)
i <- 1:n
j <- n/nt
d <- j/6
dy <- 2*d
plot(i, i+d,
type="n",
yaxt="n",
ylab="",
main=paste("color palettes; n=",n))
for (k in 1:nt) {
rect(i-.5, (k-1)*j+ dy, i+.4, k*j,
col = eval(parse(text=ch.col[k])))
text(2*j, k * j +dy/4, ch.col[k])
}
The "legend" command adds a legend to the graphic.
TODO:
Explain the "xjust" and "yjust" arguments.
In ALL the graphics of this document, use both arguments.
After that, proofread the HTML/PNG result to check the legend did
not disappear. x <- seq(-6,6,length=200)
y <- sin(x)
z <- cos(x)
plot(y~x, type='l', lwd=3,
ylab='', xlab='angle', main="Trigonometric functions")
abline(h=0,lty=3)
abline(v=0,lty=3)
lines(z~x, type='l', lwd=3, col='red')
legend(-6,-1, yjust=0,
c("Sine", "Cosine"),
lwd=3, lty=1, col=c(par('fg'), 'red'),
)
To precisely set its position, you may use the picture limits.
xmin <- par('usr')[1]
xmax <- par('usr')[2]
ymin <- par('usr')[3]
ymax <- par('usr')[4] TODO: Example using those
One can also use keywords to identify a corner.
plot(y~x, type='l', lwd=3,
ylab='', xlab='angle', main="Trigonometric functions")
abline(h=0,lty=3)
abline(v=0,lty=3)
lines(z~x, type='l', lwd=3, col='red')
legend("bottomleft",
c("Sine", "Cosine"),
lwd=3, lty=1, col=c(par('fg'), 'red'),
)
The "inset" argument allows you to move the legend away from the plot.
plot(y~x, type='l', lwd=3,
ylab='', xlab='angle', main="Trigonometric functions")
abline(h=0,lty=3)
abline(v=0,lty=3)
lines(z~x, type='l', lwd=3, col='red')
legend("bottomleft",
c("Sine", "Cosine"),
inset = c(.03, .03),
lwd=3, lty=1, col=c(par('fg'), 'red'),
)
You can also put the legend outside the plot.
op <- par(no.readonly=TRUE)
plot(y~x, type='l', lwd=3,
ylab='', xlab='angle', main="Trigonometric functions")
abline(h=0,lty=3)
abline(v=0,lty=3)
lines(z~x, type='l', lwd=3, col='red')
par(xpd=TRUE) # Do not clip to the drawing area
lambda <- .025
legend(par("usr")[1],
(1 + lambda) * par("usr")[4] - lambda * par("usr")[3],
c("Sine", "Cosine"),
xjust = 0, yjust = 0,
lwd=3, lty=1, col=c(par('fg'), 'red'),
)
par(op)
labcurve in Hmisc : to put the name of the curve on the
curve (and not in a remote legend)
You can also add a grid behind a picture to ease its interpretation.
?grid
You can also draw the graphic on a background (a gradient a a pastel image): just save the graphic as a PNG file (using the "png" function), with a transparent background, and composite it with the picture you have chosen with the "composite" command (from ImageMagick) -- you are supposed to type this in a shell (if you are under Windoze, you are on your own: it is too complicated for me).
composite faithful_hist_orig.png faithful600_light.jpg faithful_hist.png
par
TODO
User interaction
The "locator" command gives the coordinates of the position of the mouse when the user clicked.
The "identify" gives the name of the plotted point nearest to the position of the mouse when the user clicked.
For more interactivity, you can use Tk (a simple library to build GUI) or an external program (we shall soon speak about ggobi).
Grid
The graphical functions we have just seen present a few problems. First, if you choose to devide the screen to display several plots, you cannot go back to an already produced plot to add to it -- nor even to alter it. Second, you cannot nest those screen divisions.
Grid is a low-level graphics library that completely replaces the "standard" commands we have just seen and address those problems. It is used, for instance, by the "lattice" library.
TODO: rewrite this section...
library(help=grid)
library(grid)
?Grid
The idea is to divide the drawing area into rectangular areas (which may overlap): the Viewports.
The commands to draw segments, points, etc. are no longer the same: they are called grid.lines, grid.points, etc.
> apropos("^grid\.")
[1] "grid.Call" "grid.Call.graphics" "grid.circle"
[4] "grid.collection" "grid.copy" "grid.display.list"
[7] "grid.draw" "grid.edit" "grid.frame"
[10] "grid.get" "grid.grill" "grid.grob"
[13] "grid.layout" "grid.legend" "grid.lines"
[16] "grid.line.to" "grid.move.to" "grid.multipanel"
[19] "grid.newpage" "grid.pack" "grid.panel"
[22] "grid.place" "grid.plot.and.legend" "grid.points"
[25] "grid.polygon" "grid.pretty" "grid.prop.list"
[28] "grid.rect" "grid.segments" "grid.set"
[31] "grid.show.layout" "grid.show.viewport" "grid.strip"
[34] "grid.text" "grid.top.level.vp" "grid.xaxis"
[37] "grid.yaxis"
You no longer set/get graphical parameters with the "par" command but with "gpar". To modify one of these parameters, you just add the "gpar" command as an argument of the graphic function you want to customize.
grid.rect(gp=gpar(fill="grey"))
The following lines start a new picture, paint it in grey, create a new viewport and enter it.
grid.newpage()
grid.rect(gp=gpar(fill="grey"))
push.viewport(...)
...
pop.viewport()
You can define a viewport with its width and height (with respect to the containing viewport). You can also endow it with units (when drawing inside this new viewport, you will either use the default units (width=height=1) or those user-defined units).
viewport(w = 0.9, h = 0.9, # width and height
xscale=c(xmin,xmax),
yscale=c(ymin,ymax),
)
Often, one adds some space inside the frame:
viewport(w = 0.9, h = 0.9,
xscale=c(xmin,xmax)+.05*c(-1,1),
yscale=c(ymin,ymax)+.05*c(-1,1),
)
Here is an example from the manual.
library(grid)
grid.show.viewport(viewport(x=0.6, y=0.6,
w=unit(1, "inches"), h=unit(1, "inches")))
You can also define a viewport containing a table (or a matrix) or viewports.
viewport(layout=grid.layout(2, 2)))
Here is an example from the manual. The following command defines 8 viewports, represented by the blue rectangles (the white part will remain white).
grid.show.layout(grid.layout(4,2,
heights=unit(rep(1, 4),
c("lines", "lines", "lines", "null")),
widths=unit(c(1, 1), "inches")))
The following lines start a new picture, define a new viewport, divide it into four and put something inside those four parts.
dessine <- function () {
push.viewport(viewport(w = 0.9, h = 0.9,
xscale=c(-.1,1.1), yscale=c(-.1,1.1)))
grid.rect(gp=gpar(fill=rgb(.5,.5,0)))
grid.points( runif(50), runif(50) )
pop.viewport()
}
grid.newpage()
grid.rect(gp=gpar(fill=rgb(.3,.3,.3)))
push.viewport(viewport(layout=grid.layout(2, 2)))
for (i in 1:2) {
for (j in 1:2) {
push.viewport(viewport(layout.pos.col=i,
layout.pos.row=j))
dessine()
pop.viewport()
}
}
pop.viewport()
Among the examples from the manual, you will find:
grid.multipanel(vp=viewport(0.5, 0.5, 0.8, 0.8))
But this function is NOT documented.
TODO: check that it is still the case in R 2.1.0
Yet, its code is worth insightful.
> grid.multipanel
function (x = runif(90), y = runif(90), z = runif(90), nrow = 2,
ncol = 5, nplots = 9, newpage = TRUE, vp = NULL)
{
# If requested, start a new picture
if (newpage)
grid.newpage()
# It the user said, in the arguments, that we were to
# go to a given viewport, we do so -- otherwise, we
# stay in the current viewport, i.e., the whole page.
# (In the example above, we had given this argument
# in order to create a margin around the picture.)
if (!is.null(vp))
push.viewport(vp)
# We create a viewport, we divide it into a table of viewports.
# Here, we can see that the "grid.multipanel" has been written to
# serve as an illustration, for the user has to specify the number
# of rows and columns: we trust him, the pictures will be readable
# and the table will have a sufficient number of entries...
temp.vp <- viewport(layout = grid.layout(nrow, ncol))
push.viewport(temp.vp)
# User-land units:
# the x- and y-limits, plus 2.5% on each side
xscale <- range(x) + c(-1, 1) * 0.05 * diff(range(x))
yscale <- range(y) + c(-1, 1) * 0.05 * diff(range(y))
breaks <- seq(min(z), max(z), length = nplots + 1)
for (i in 1:nplots) {
col <- (i - 1)%%ncol + 1
row <- (i - 1)%/%ncol + 1
# We go to each entry of the table
panel.vp <- viewport(layout.pos.row = row, layout.pos.col = col)
# In each of those entries , we only plot a small part of the data:
# here, we select the points we want
panelx <- x[z >= breaks[i] & z <= breaks[i + 1]]
panely <- y[z >= breaks[i] & z <= breaks[i + 1]]
# We give all that to the grid.panel function, that does the
# actual job
grid.panel(panelx, panely, range(z),
c(breaks[i], breaks[i + 1]),
xscale, yscale,
axis.left = (col == 1),
axis.left.label = is.odd(row),
axis.right = (col == ncol || i == nplots),
axis.right.label = is.even(row),
axis.bottom = (row == nrow),
axis.bottom.label = is.odd(col),
axis.top = (row == 1),
axis.top.label = is.even(col),
vp = panel.vp)
}
# We use the grid.text command to name the axes.
grid.text("Compression Ratio",
unit(0.5, "npc"), unit(-4, "lines"),
gp = gpar(fontsize = 20),
just = "center", rot = 0)
grid.text("NOx (micrograms/J)",
unit(-4, "lines"), unit(0.5, "npc"),
gp = gpar(fontsize = 20),
just = "centre", rot = 90)
pop.viewport()
if (!is.null(vp))
pop.viewport()
}
Let us now browse through the code of the "grid.panel" function.
> grid.panel
function (x = runif(10), y = runif(10),
zrange = c(0, 1), zbin = runif(2),
xscale = range(x) + c(-1, 1) * 0.05 * diff(range(x)),
yscale = range(y) + c(-1, 1) * 0.05 * diff(range(y)),
axis.left = TRUE, axis.left.label = TRUE,
axis.right = FALSE, axis.right.label = TRUE,
axis.bottom = TRUE, axis.bottom.label = TRUE,
axis.top = FALSE, axis.top.label = TRUE,
vp = NULL)
{
if (!is.null(vp))
push.viewport(vp)
# We divide the Viewport: one row on the top (for the level names)
# and the rest beneath.
temp.vp <- viewport(layout =
grid.layout(2, 1, heights = unit(c(1, 1), c("lines", "null"))))
push.viewport(temp.vp)
strip.vp <- viewport(layout.pos.row = 1, layout.pos.col = 1,
xscale = xscale)
push.viewport(strip.vp)
# The grid.strip command draws a bright orange rectangle,
# representing all the data, on top of which we add dark
# orange rectangle, representing the data plotted in this viewport.
grid.strip(range.full = zrange, range.thumb = zbin)
# A black frame
grid.rect()
if (axis.top)
grid.xaxis(main = FALSE, label = axis.top.label)
pop.viewport() # On to the actual plot.
plot.vp <- viewport(layout.pos.row = 2, layout.pos.col = 1,
xscale = xscale, yscale = yscale)
push.viewport(plot.vp)
# Draw a grid
grid.grill()
# Plot the points
grid.points(x, y, gp = gpar(col = "blue"))
# A frame around the picture
grid.rect()
# The axes, if required
if (axis.left)
grid.yaxis(label = axis.left.label)
if (axis.right)
grid.yaxis(main = FALSE, label = axis.right.label)
if (axis.bottom)
grid.xaxis(label = axis.bottom.label)
pop.viewport(2)
if (!is.null(vp))
pop.viewport()
invisible(list(strip.vp = strip.vp, plot.vp = plot.vp))
}
here is another example:
do.it <- function (x=runif(100), y=runif(100),
a=.9, b=.1,
col1=rgb(0,.3,0), col2=rgb(1,1,0)) {
xscale <- range(x) + c(-1,1)*.05
yscale <- range(y) + c(-1,1)*.05
grid.newpage()
grid.rect(gp=gpar(fill=col1, col=col1))
w1 <- a - b/2
w2 <- 1 - a - b/2
c1 <- b/3 + w1/2
c2 <- a + b/6 + w2/2
vp1 <- viewport(x=c1, y=c1, width=w1, height=w1,
xscale=xscale, yscale=yscale)
push.viewport(vp1)
grid.rect(gp=gpar(fill=col2, col=col2))
grid.points(x,y)
pop.viewport()
vp2 <- viewport(x=c1, y=c2, width=w1, height=w2,
xscale=xscale, yscale=c(0,1))
push.viewport(vp2)
grid.rect(gp=gpar(fill=col2, col=col2))
grid.points(x,rep(.5,length(x)))
pop.viewport()
vp3 <- viewport(x=c2, y=c1, width=w2, height=w1,
xscale=c(0,1), yscale=yscale)
push.viewport(vp3)
grid.rect(gp=gpar(fill=col2, col=col2))
grid.points(rep(.5,length(y)),y)
pop.viewport()
}
do.it()
Exercise: replace the scatterplots by box-and-whiskers plots.
LaTeX
LaTeX is a word processor extensively used in mathematics, computer science and theoretical physics. Its typographic quality still surpasses that of mainstream word processors.
It looks like (and indeed is) a programming language: you describe the structure of you document in a text file ("this is a chapter title", "this is a section title", "this is a quotation", "insert the table of contents here", etc.); optionnally, you give some typographic instructions (how the chapter heads should look like, etc.); and you compile the file to get a neat PDF file.
If you want to use LaTeX but are too accustomed to WYSIWYG word processors, have a look at Lyx -- which, strictly speaking, is not WYSIWYG but WYSIWYM (What You See Is What You Mean).
http://www.mail-archive.com/r-help%40stat.math.ethz.ch/msg46946.html
http://www.ci.tuwien.ac.at/~leisch/Sweave/LyX
http://www.troubleshooters.com/lpm/200210/200210.htm
If you want to learn LaTeX, have a look at
http://www.ctan.org/tex-archive/info/lshort/english/lshort.pdf
If you just want to be impressed or to impress your friends/colleagues, have a look at the ConTeXt web page (ConTeXt can be seen as a variant or a competitor to LaTeX, but they are both based on the underlying TeX typesetting system, so any argument in favour of one is also in favour of the other).
http://www.pragma-ade.com/
xtable
The xtable package turns tables produced by R (in particular, the tables displaying the anova results) into LaTeX tables, to be included in an article.
> xtable(anova(lm.D9 <- lm(weight ~ group)))
% latex table generated in R 1.6.2 by xtable 1.0-11 package
% Fri Feb 28 18:47:58 2003
\begin{table}
\begin{center}
\begin{tabular}{lrrrrr}
\hline
& Df & Sum Sq & Mean Sq & F value & Pr($>$F) \\
\hline
group & 1 & 0.69 & 0.69 & 1.42 & 0.2490 \\
Residuals & 18 & 8.73 & 0.48 & & \\
\hline
\end{tabular}
\end{center}
\end{table}
> xtable(summary(lm(weight~group)))
% latex table generated in R 1.6.2 by xtable 1.0-11 package
% Fri Feb 28 18:57:00 2003
\begin{table}
\begin{center}
\begin{tabular}{rrrrr}
\hline
& Estimate & Std. Error & t value & Pr($>$$|$t$|$) \\
\hline
(Intercept) & 5.0320 & 0.2202 & 22.85 & 0.0000 \\
groupTrt & $-$0.3710 & 0.3114 & $-$1.19 & 0.2490 \\
\hline
\end{tabular}
\end{center}
\end{table}
See also the "latex" command in the "Hmisc" library (this is what I currently use).
http://biostat.mc.vanderbilt.edu/twiki/pub/Main/StatReport/latexFineControl.pdf
TODO: give more details.
Sweave
Sweave allows you to include R code in LaTeX documents; at each new LaTeX compilation, R will redo the computations and the drawings. It is very useful when you write R documentation: you are certain that the code presented to the reader is correct and that it actually produces the pictures. More generally, it is useful when you write statistical reports.
library(tools)
?Sweave http://www.ci.tuwien.ac.at/~leisch/Sweave
Here is an example:
\documentclass[a4paper,12pt]{article}
\usepackage[T1]{fontenc}
\usepackage[latin1]{inputenc}
\usepackage[frenchb]{babel}
\parindent=0pt
\begin{document} Computations whose code and results will not be printed:
<<results=hide,echo=FALSE>>=
y <- 1+1
y
@
(nothing appears in the PDF document, it is normal). Computations whose results is not printed (but whose code is).
<<results=hide,echo=TRUE>>=
library("MASS")
ajoute <- function (a,b) {
a+b
}
x <- ajoute(1,2)
x
@ Computations with results:
<<results=verbatim>>=
n <- 100
x <- runif(n)
y <- 1 - x - x^2 + rnorm(n)
r <- lm(y~poly(x,5))
summary(r)
@ Computations whose results are "invisible" (a function that returns
nothing or an invisible object) but that prints (with the "cat"
command) LaTeX commands. (The "latex" or "xtable" commands
mentionned above use "cat" that way.)
<<results=tex>>=
cat("\\centerline{\\LaTeX}")
@ A graphic with its code:
<<fig=TRUE>>=
n <- 100
a <- rnorm(n)
b <- 1 - 2*a + rnorm(n)
plot(b~a)
abline(lm(b~a), col='red', lwd=3)
@ A graphic without its code (usually in a "figure" environment):
<<results=hide,echo=FALSE>>=
a <- function (x) {
round(x, digits=2)
}
@
It is also possible to use the result of some computations in the
text: ``the coefficient of the first regression are
\Sexpr{a(r$coef[1])}, \Sexpr{a(r$coef[2])} and \Sexpr{a(r$coef[3])}''. \end{document}
It can be compiled as:
Sweave("tmp.Rnw")
system("pdflatex tmp.tex")
system("xpdf tmp.pdf")
here is the result:
SweaveExample.pdf
The options that appear in the code are detailled here:
?RweaveLatex
The most common problem is that functions from the "lattice" library do not seem to produce any plot in Sweave. This is due to the fact that the plot is not produced by the functions themselves but by the corresponding "print" method.
TODO: graphics and loops.
When I use Sweave, I start with the following file:
sweave_template.Rnw
Lattice (Treillis) plots
Lattice (slicing)
http://cm.bell-labs.com/cm/ms/departments/sia/project/trellis/
The idea behind Lattice (or Treillis -- but the word "treillis" has been registered, so we cannot use it any longer) plots is to plot a 3- (or more) dimensional point cloud, by cutting the cloud into slices, and projecting those slices on a 2-dimensionnal space. You get one plot for each slice.
You can also interpret those plots as plots in which you have partitionned the observations into groups (the slices) and drawn a plot for each group.
library(help=lattice)
library(lattice)
?Lattice
?xyplot
xyplot
The following example (three quantitative variables) displays earthquake epicenters.
data(quakes)
library(lattice)
Depth <- equal.count(quakes$depth, number=8, overlap=.1)
xyplot(lat ~ long | Depth, data = quakes)
This is much more readable than the projection on one of the coordinate planes (because we do not forget one of the variable, we just slice along it), on the three of them or even on a "carefully chosen" plane (this is called Principal Component Analysis, we shall come back on it later).
plot(lat ~ long, data=quakes)
op <- par(mfrow=c(2,2))
plot(lat ~ long, data=quakes)
plot(lat ~ -depth, data=quakes)
plot(-depth ~ long, data=quakes)
par(op)
library(mva)
biplot(princomp(quakes[1:3]))
pairs( princomp(quakes[1:3])$scores )
library(scatterplot3d)
scatterplot3d(quakes[,1:3],
highlight.3d = TRUE,
pch = 20)
barchart
An example with a quantitative variable and 3 qualitative variables in which, if we fix the qualitative variables, we have a single observation (this is sometimes called a "factorial design").
data(barley)
barchart(yield ~ variety | year * site, data=barley)
The "scales" argument allows you to change the axes and their ticks (here, we avoid label overlap).
barchart(yield ~ variety | year * site, data = barley,
ylab = "Barley Yield (bushels/acre)",
scales = list(x = list(0, abbreviate = TRUE,
minlength = 5)))
dotplot(yield ~ variety | year * site, data = barley)
dotplot(variety ~ yield | year * site, data = barley)
dotplot
We display the values of one of the qualitative variables by different colours or symbols (for one of the farms, the yield increased: actually, the data for the two years have been interchanged) with the "groups" argument.
%%G 400 1000
data(barley)
## BUG in print_dotplot...
dotplot(variety ~ yield | site, groups = year,
data = barley,
layout = c(1, 6), aspect = .5, pch = 16,
col.line = c("grey", "transparent"),
panel = "panel.superpose",
panel.groups = "panel.dotplot")
%--
bwplot, histogram, densityplot and stripplot
An example with a quantitative variable, qualitative variables, but for which we have several observations in each class.
library(nlme)
data(bdf)
d <- data.frame( iq=bdf$IQ.perf, sex=bdf$sex, den=bdf$denomina )
d <- d[1:100,]
bwplot( ~ d$iq | d$sex + d$den )
histogram( ~ d$iq | d$sex + d$den )
densityplot( ~ d$iq | d$sex + d$den )
stripplot( ~ d$iq | d$sex + d$den )
Other example: a quantitative variable as a fcuntion of another quantitative variable and a qualitative variable (we turn the quantitative variable into a "single" with the "equal.count" function).
d <- data.frame( x=bdf$aritPOST, y=bdf$sex, z=equal.count(bdf$langPRET) )
bwplot( ~ x | y + z, data=d )
histogram( ~ x | y + z, data=d )
densityplot( ~ x | y + z, data=d )
An example with only qualitative variables (we first compute the contingency table, with the "table" function).
d <- data.frame( x= (bdf$IQ.perf>11), y=bdf$sex, z=bdf$denomina )
d <- as.data.frame(table(d))
barchart( Freq ~ x | y * z, data=d )
Formulas
The formulas used by the "lattice" library may look a bit complex, at first sight.
x ~ y Plot x as a function of y (on a single plot)
x ~ y | z Plots x as a function of y after cutting the data
into slices for different values of z
x ~ y | z1 * z2 Idem, we cut with according the values of (z1,z2)
x~y|z, groups=t Idem, but we use a different symbol (or a
different colour) according to the values of t
But it also works with univariate data.
~ y
~ y | z
~ y | z1 * z2
~ y | z1 * z2, groups=t
If the variable used to cut the data into slices is qualitative, we ghget a slice for each value. but if it is quantitative, it is better to consider intervals: this can be done with the "equal.count" function, that will choose the intervals so that each contains the same number of observations.
Position
At a lower level, the "lattice" package allows you to precisely specify the location of several plots.
n <- 200
x <- rnorm(n)
y <- x^3+rnorm(n)
plot1 <- xyplot(y~x)
plot2 <- bwplot(x)
# Beware, the order is xmin, ymin, xmax, ymax
print(plot1, position=c(0, .2, 1, 1), more=T)
print(plot2, position=c(0, 0, 1, .2), more=F)
But, actually, we could already do this with the the classical plotting functions and "par(fig=...)".
n <- 200
x <- rnorm(n)
y <- x^4+rnorm(n)
k <- .7
op <- par(mar=c(0,0,0,0))
# Attention : l'ordre est xmin, xmax, ymin, ymax
par(fig=c(0,k,0,k))
plot(y~x)
par(fig=c(0,k,k,1), new=T)
boxplot(x, horizontal=T)
par(fig=c(k,1,0,k), new=T)
boxplot(y, horizontal=F)
par(op)
TODO: Put this example above, when I was speaking of the "par" function?
Configuration
Actually, the "xyplot", "dotplot", "histogram", "densityplot", "stripplot" simply cut the data into slices and delagate the actual plotting to other functions ("panel.xyplot", etc.), so that you can customize the plots. If you write such a function, you must not use the standard plotting functions ("points", "lines", "segments", "abline", "polygon") but those of the "grid" package ("panel.points", "panel.lines", "panel.segments", "panel.abline", etc.)
%%G 600 1000
# From the manual
# BUG in print_dotplot...
dotplot(variety ~ yield | site,
data = barley,
groups = year,
panel = function(x, y, subscripts, ...) {
dot.line <- trellis.par.get("dot.line")
panel.abline(h = y,
col = dot.line$col,
lty = dot.line$lty)
panel.superpose(x, y, subscripts, ...)
},
key = list(
space = "right",
transparent = TRUE,
points = list(
pch = trellis.par.get("superpose.symbol")$pch[1:2],
col = trellis.par.get("superpose.symbol")$col[1:2]
),
text = list(c("1932", "1931"))
),
xlab = "Barley Yield (bushels/acre) ",
aspect = 0.5,
layout = c(1,6),
ylab = NULL
)
%--
The "treillis.par.get" is equivalent to the "par" function for standard plots: it gives you the current values of the various graphical parameters. You can modify them with the "treillis.par.set" function.
> str(trellis.par.get())
List of 23
$ background :List of 1
..$ col: chr "#909090"
$ add.line :List of 3
..$ col: chr "#000000"
..$ lty: num 1
..$ lwd: num 1
$ add.text :List of 3
..$ cex : num 1
..$ col : chr "#000000"
..$ font: num 1
$ bar.fill :List of 1
..$ col: chr "#00ffff"
$ box.dot :List of 4
..$ col : chr "#000000"
..$ cex : num 1
..$ font: num 1
..$ pch : num 16
$ box.rectangle :List of 3
..$ col: chr "#00ffff"
..$ lty: num 1
..$ lwd: num 1
$ box.umbrella :List of 3
..$ col: chr "#00ffff"
..$ lty: num 2
..$ lwd: num 1
$ dot.line :List of 3
..$ col: chr "#aaaaaa"
..$ lty: num 1
..$ lwd: num 1
$ dot.symbol :List of 4
..$ cex : num 0.8
..$ col : chr "#00ffff"
..$ font: num 1
..$ pch : num 16
$ plot.line :List of 3
..$ col: chr "#00ffff"
..$ lty: num 1
..$ lwd: num 1
$ plot.symbol :List of 4
..$ cex : num 0.8
..$ col : chr "#00ffff"
..$ font: num 1
..$ pch : num 1
$ reference.line :List of 3
..$ col: chr "#aaaaaa"
..$ lty: num 1
..$ lwd: num 1
$ strip.background:List of 1
..$ col: chr [1:7] "#ffd18f" "#c8ffc8" "#c6ffff" "#a9e2ff" ...
$ strip.shingle :List of 1
..$ col: chr [1:7] "#ff7f00" "#00ff00" "#00ffff" "#007eff" ...
$ superpose.line :List of 3
..$ col: chr [1:7] "#00ffff" "#ff00ff" "#00ff00" "#ff7f00" ...
..$ lty: num [1:7] 1 1 1 1 1 1 1
..$ lwd: num [1:7] 1 1 1 1 1 1 1
$ regions :List of 1
..$ col: chr [1:100] "#FF80FF" "#FF82FF" "#FF85FF" "#FF87FF" ...
$ superpose.symbol:List of 4
..$ cex : num [1:7] 0.8 0.8 0.8 0.8 0.8 0.8 0.8
..$ col : chr [1:7] "#00ffff" "#ff00ff" "#00ff00" "#ff7f00" ...
..$ font: num [1:7] 1 1 1 1 1 1 1
..$ pch : chr [1:7] "o" "o" "o" "o" ...
$ axis.line :List of 4
..$ line: num 0
..$ col : chr "#000000"
..$ lty : num 1
..$ lwd : num 1
$ box.3d :List of 3
..$ col: chr "#000000"
..$ lty: num 1
..$ lwd: num 1
$ par.xlab.text :List of 3
..$ cex : num 1
..$ col : chr "#000000"
..$ font: num 1
$ par.ylab.text :List of 3
..$ cex : num 1
..$ col : chr "#000000"
..$ font: num 1
$ par.main.text :List of 3
..$ cex : num 1.2
..$ col : chr "#000000"
..$ font: num 2
$ par.sub.text :List of 3
..$ cex : num 1
..$ col : chr "#000000"
..$ font: num 2
The "show.setings" explains the meaning of all that.
show.settings()
The "panel.abline" plots lines (here, we use the "h" argument, so that the lines are horizontal, but you can also get vertical lines with the "v" argument, lines given by their intercept and slope (in this order) or even regression line (give an "lm" object)).
The "panel.superpose" uses different colours of different symbols depending on the value of the variable.
The "key" argument specifies the legend.
Here is another example: we overlay histogram, density estimation and gaussian density.
y <- cars$dist
x <- cars$speed
vitesse <- shingle(x, co.intervals(x, number=6))
histogram(~ x | vitesse, type = "density",
panel = function(x, ...) {
ps <- trellis.par.get('plot.symbol')
nps <- ps
nps$cex <- 1
trellis.par.set('plot.symbol', nps)
panel.histogram(x, ...)
panel.densityplot(x, col = 'brown', lwd=3)
panel.xyplot(x = jitter(x), y = rep(0, length(x)), col='brown' )
panel.mathdensity(dmath = dnorm,
args = list(mean=mean(x),sd=sd(x)),
lwd=3, lty=2, col='white')
trellis.par.set('plot.symbol', ps)
})
Here is a list of the (high-level) functions you may want to use.
> apropos("^panel\..*")
[1] "panel.3dscatter" "panel.3dscatter.new" "panel.3dwire"
[4] "panel.abline" "panel.barchart" "panel.bwplot"
[7] "panel.cloud" "panel.densityplot" "panel.dotplot"
[10] "panel.fill" "panel.grid" "panel.histogram"
[13] "panel.levelplot" "panel.linejoin" "panel.lmline"
[16] "panel.loess" "panel.mathdensity" "panel.pairs"
[19] "panel.parallel" "panel.qq" "panel.qqmath"
[22] "panel.qqmathline" "panel.splom" "panel.stripplot"
[25] "panel.superpose" "panel.superpose.2" "panel.tmd"
[28] "panel.wireframe" "panel.xyplot" "panel.smooth" > apropos("^prepanel\..*")
[1] "prepanel.default.bwplot" "prepanel.default.cloud"
[3] "prepanel.default.densityplot" "prepanel.default.histogram"
[5] "prepanel.default.levelplot" "prepanel.default.parallel"
[7] "prepanel.default.qq" "prepanel.default.qqmath"
[9] "prepanel.default.splom" "prepanel.default.tmd"
[11] "prepanel.default.xyplot" "prepanel.lmline"
[13] "prepanel.loess" "prepanel.qqmathline"
Apart from the "panel.superpose" function (a replacement for the "panel.xyplot" function when there is a "groups" argument), and perhaps "panel.smooth" (plots the points, as with "xyplot", and adds a regression curve), the names should be self-explanatory.
Banking
Whe you plot curves, you can more easily estimate and compare the slope of the tangents when this slope is around 45 degrees. "Banking" refers to a choice of units on the axes so that the slope is often around 45 degrees.
This is articularily useful for time series: in the second plot, it is obvious that the downwards movement is slower. You may also see it in the first plot, if you have good eyes, and if you know what you are looking for.
data(sunspot.year)
sunspot <- sunspot.year[20 + 1:37]
xyplot(sunspot ~ 1:37 ,type = "l",
scales = list(y = list(log = TRUE)),
sub = "log scales")
xyplot(sunspot ~ 1:37 ,type = "l", aspect="xy",
scales = list(y = list(log = TRUE)),
sub = "log scales")
R Customizing graphics的更多相关文章
- R2—《R in Nutshell》 读书笔记(连载)
R in Nutshell 前言 例子(nutshell包) 本书中的例子包括在nutshell的R包中,使用数据,需加载nutshell包 install.packages("nutshe ...
- 用python调用R做数据分析-准备工作
0.R的介绍 R是自由软件,不带不论什么担保.在某些条件下你能够将其自由散布,用'license()'或'licence()'来看散布的具体条件. R是个合作计划.有很多人为之做出了贡献,用'cont ...
- 《R语言实战》读书笔记--第一章 R语言介绍
1.典型的数据分析过程可以总结为一下图形: 注意,在模型建立和验证的过程中,可能需要重新进行数据清理和模型建立. 2.R语言一般用 <- 作为赋值运算符,一般不用 = ,原因待考证.用-> ...
- z-fighting在unity中的解决方式
如果在画面中,发现有画面闪烁的问题.那么大多数情况下是z-fighting引起的, 解决方案: 1, 在每个场景中,找到那个MainCamera,然后在Inspector上,找到MainCamera的 ...
- 如何让DevExpress TreeList的每个结点高亮显示?
概述:如何让DevExpress TreeList的每个节点高亮显示? 如何让DXperience TreeList的每个节点高亮显示? 效果如下: private void treeList1_Cu ...
- WIN 8.1 x64 环境下 COM Surrogate 停止工作解决方案
我的笔记本电脑是THINKPAD T420 4180AT8,NVIDIA NVS 4200M,Intel(R) HD Graphics 3000,WIN 8.1 x64操作系统.在安装完NVIDIA独 ...
- [转载]Android开发常用调试技术记录
ANDROID 调试技术: 1)Ps 指令 ls –l /proc/27/ cat /proc/27/cmdline #cmdline文件表示了这个进程所在的命令行. cat /proc/ ...
- ViewGroup源码部分解析
ViewGroup的官方解析是: A <code>ViewGroup</code> is a special view that can contain other views ...
- TreeList
1.获取当前被选中的节点数据 string tmp = treeL.FocusedNode.GetDisplayText(this.treeListColumnIndex); 2.是否允许编辑 tre ...
随机推荐
- 前言和第一章.NET的体系结构
前言 COM:组件对象模型(Component Object Model COM)源自对象链接和嵌入(Object Linking and Embedding )OLE. DCOM:(Distribu ...
- [译]GLUT教程 - 移动镜头3
Lighthouse3d.com >> GLUT Tutorial >> Input >> Moving the Camera III 上一节的示例中我们用键盘更改 ...
- 检测session用户信息跳转首页界面
方案一:采用jsp方式检测用户信息跳转 <%@ page language="java" pageEncoding="UTF-8"%> <%@ ...
- Http协议 详解(转载)
http://blog.csdn.net/gueter/archive/2007/03/08/1524447.aspx 引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分 ...
- db2 error
DB2 SQL Error: SQLCODE=-668, SQLSTATE=57016, SQLERRMC=7;MCD_BJ.MTL_CHANNEL_DEF, DRIVER=4.18.60 你的表处于 ...
- vim visual模式 复制
按ESC再按“V”,进入visual模式 用键盘向左向右箭头选中要复制的文字,按两下"Y"键 再到要粘贴的地方,按“P”键即可. 转自: http://jingyan.baidu. ...
- mysql 与mongodb的特点与优劣
首先我们来分析下mysql 与mongodb的特点与优劣.下面是我以前做的ppt的部分截图. 再来分析下应用场景,a.如果需要将mongodb作为后端db来代替mysql使用,即这里mysql与mon ...
- SVN分支与主干
我的理解:在svn版本库中创建两个目录,一个主干如truck,一个分支目录如branch(注:分支可以创建多个),分别在客户端中检出代码,在分支中进行bug的修复以及新模块的开发,开发完后再merge ...
- 自己定义Application的未捕获异常处理
近期由于工作原因.进行Android应用开发时发现应用在出现类似空指针等异常时,抛出未被捕获的异常.Android系统有默认的未捕获异常处理器,默认行为是结束对应的线程,但并不会直接退出程序,并且在应 ...
- FineUIPro中如何支持多语言(全局资源文件和本地资源文件)
一个客户在邮件中问到了FineUIPro的多语言实现问题,其实 FineUIPro 并没有对此做特殊处理,因此直接使用 ASP.NET 原生支持的资源文件就能实现. 下面我们就以FineUIPro的空 ...