views:

159

answers:

5

Hi all,

I wish to recreate this graph: alt text

(from here)

Using R base graphics.

I have no clue how to do that. Any advice ?

(My motivation is that I wish to create a plot where the line width (and/or color) will reflect another dimension. Until now - ggplot2 is the only place I found in R for how to do this. I would be happy to be able to do this also in base R)

+2  A: 

See help(polygon) and example(polygon) (esp the Brownian motion example) -- the varying width is pretty common in some fields to show variability through time.

The same example is also in demo(graphics):

## An example showing how to fill between curves.

par(bg="white")
n <- 100
x <- c(0,cumsum(rnorm(n)))
y <- c(0,cumsum(rnorm(n)))
xx <- c(0:n, n:0)
yy <- c(x, rev(y))
plot(xx, yy, type="n", xlab="Time", ylab="Distance")
polygon(xx, yy, col="gray")
title("Distance Between Brownian Motions")
Dirk Eddelbuettel
Thank you dirk. Is there a way to change the polygon opacity?
Tal Galili
I'd think so. Isn't alpha, where supported, the fourth argument to the generic colour specification?
Dirk Eddelbuettel
After second testing: 1) Is there a way to create a curve polygon? 2) (in the risk of sounding ignorant) what do I type to get to the "generic colour specification"? Thanks Dirk!
Tal Galili
@Tal Galili: I guess you just use lots of points to get a curve. As for the color just do something like: `col=rgb(0.5, 1, 0.5, 0.5)`
nico
Hint: a curve is just a lot of short lines joined together. And look at `rgb`.
hadley
Thank you Nico and Hadley.
Tal Galili
+1  A: 

And to get the smooth curve, look at loess and predict.loess

hadley
Thanks Hadley..
Tal Galili
+2  A: 

I don't know if exactly replicating the graph is possible in base graphics. In grid graphics it is possible. Nevertheless, the following code gets you an example that's something like what you want. Adapt it to the data set.

n <- 20
x <- rnorm(n)
y <- rnorm(n)
o <- order(x)
x <- x[o]
y <- y[o]
m <- loess(y~x, span = 1) #ggplot seems to smooth more than default
f <- predict(m, se = TRUE)
ci <- f$se * qt(0.975, f$df)
cih <- f$fit + ci
cil <- f$fit - ci
plot(x,y, ylim = c(min(cil,y), max(cih,y)))
lines(x, f$fit, lwd = 2)
xx <- c(x, rev(x))
yy <- c(cil, rev(cih))
polygon(xx, yy, col="#A9A9A930", border = NA)
John
Thank you for the code john. BTW, how easy would it be to do it in grid ?
Tal Galili
No idea... if you want the whole thing, the background and everything, grid might be easier. I wonder if grid is how Hadley gets the curves so smooth. The standard lines function doesn't make them as smooth as ggplot. I'm just guessing that doing it in grid fixes this because that's what ggplot is built on. But I really have no idea.
John
For this application, there's no difference between base and grid. If you want a smoother curve, use more pieces.
hadley
It's funny, I was just experimenting.. I never clarified that even with a lot of pieces it wasn't as good as yours. Therefore, I thought you used some kind of different drawing mechanism. It turns out that it was just that my definition of "a lot" apparently wasn't high enough. Between 1000 and 2000 seems to be a good match. I can get it almost the same as ggplot then.
John
Thanks again Hadley for helping out here.
Tal Galili
+1  A: 

OK, I spent a little too much time messing with this... note the last line is the ggplot version so you can compare the two.

#loess and error curves almost just like ggplot2
op <- par(las=1, mar = c(3,3,1,1))
n <- 30
x <- sort(rnorm(n)) #(varying density in predictor)
x <- x + abs(min(x))
x <- x/max(x)*2*pi 
y <- sin(x)+rnorm(n) #(curvy)
m <- loess(y~x)
xx <- seq(min(x), max(x), (max(x)-min(x))/1000) #increase density of values to predict over to increase quality of curve
f <- predict(m, xx, se = TRUE)
ci <- f$se * qt(0.975, f$df)
cih <- f$fit + ci
cil <- f$fit - ci
plot(x,y, ylim = c(min(cil,y), max(cih,y)), cex.axis = 0.85, xlab = '', ylab = '', type = 'n')
title(xlab = 'x', ylab = 'y',line = 2)
grid(col = 'gray')
points(x,y, pch = 19, cex = 0.65)
lines(xx, f$fit, col = 'blue', lwd = 1.2)
xx <- c(xx, rev(xx))
yy <- c(cil, rev(cih))
polygon(xx, yy, col=rgb(0.1,0.1,0.1,0.25), border = NA)
par(op)

#qplot(x,y, geom = 'point') + stat_smooth()
John
Impressive - you just taken the "winning answer mark" from your other answer. I hope you at least enjoyed it :) (I so identify with your first sentence about oh so many things I do with R...)
Tal Galili
A: 

Would geom_ribbon in GGPlot be what you need? This creates a variable-width line.

Jesse
Thanks Jesse, but notice I am trying to do the above with base R. See the reply I accepted.
Tal Galili