Dennis Murphy
2010-Aug-21 12:58 UTC
[R] lattice::xyplot() with one factor for points and another for lines
Hi: In lattice, how does one handle separate graphical behavior for two different factors? In the xyplot below, the objective is to use the levels of one factor to distinguish corresponding shapes and colors, and the levels of the other factor to perform level-wise loess smooths. # Illustrative data: d <- data.frame(time = rep(1:8, each = 6), val = rnorm(48), gp1 = factor(rep(1:6, 8)), gp2 = factor(rep(rep(c('A', 'B'), each = 3), 8))) Based on the code from the Lattice book, p. 160, I set up the following: mypch <- 1:6 mycol <- 1:6 with(d, xyplot(val ~ time, panel = function(x, y, ..., groups, subscripts) { pch <- mypch[gp1[subscripts]] col <- mycol[gp1[subscripts]] grp <- gp2 panel.xyplot(x, y, pch = pch, col = col) panel.loess(x, y, groups = grp, lty = 1, col.line = c('blue', 'red')) } ) ) As stated in the book, the with() wrapper allows one to use variable names within the panel function. I was hoping to get away with using both groups and subscripts in the panel function and fake my way through, but no luck. I get 90% of what I want: the points are plotted correctly, but only one loess line shows up instead of two. I put groups before the ellipsis in the argument list, defined groups = gp2 in the function call and a couple of other things, but got the same result. I also tried to put the groups argument at the level of the xyplot() call, but as expected, it plots only the points and skips the loess curves altogether (but does tell you something about how the panel function behaves): # Vain, desperate, naive attempt: with(d, xyplot(val ~ time, groups = gp2, type = c('p', 'smooth'), col.lines = c('red', 'blue'), lty = 1, panel = function(x, y, ..., groups = gp2, subscripts) { pch <- mypch[gp1[subscripts]] col <- mycol[gp1[subscripts]] panel.xyplot(x, y, pch = pch, col = col) } ) ) Adding panel.loess(x, y, groups = groups, ...) leaves the same single line. What's the correct mantra? I'm probably missing something fairly obvious, but it escapes me. [And before Hadley chimes in, I already have a working version in ggplot2, but the person I'm trying to help wants it in lattice, too.] TIA for your assistance, Dennis [[alternative HTML version deleted]]
Deepayan Sarkar
2010-Aug-21 16:53 UTC
[R] lattice::xyplot() with one factor for points and another for lines
On Sat, Aug 21, 2010 at 5:58 AM, Dennis Murphy <djmuser at gmail.com> wrote:> Hi: > > In lattice, how does one handle separate graphical behavior for two > different factors? In the xyplot below, the objective is to use the levels > of one factor to distinguish corresponding shapes and colors, and the levels > of the other factor to perform level-wise loess smooths. > > # Illustrative data: > d <- data.frame(time = rep(1:8, each = 6), val = rnorm(48), > ? ? ? ? ? ? ? ?gp1 = factor(rep(1:6, 8)), > ? ? ? ? ? ? ? ?gp2 = factor(rep(rep(c('A', 'B'), each = 3), 8))) > > Based on the code from the Lattice book, p. 160, I set up the following: > > mypch <- 1:6 > mycol <- 1:6 > > with(d, > xyplot(val ~ time, > ? ? ? panel = function(x, y, ..., groups, subscripts) { > ? ? ? ? ? ? ? ? pch <- mypch[gp1[subscripts]] > ? ? ? ? ? ? ? ? col <- mycol[gp1[subscripts]] > ? ? ? ? ? ? ? ? grp <- gp2 > ? ? ? ? ? ? ? ? panel.xyplot(x, y, pch = pch, col = col) > ? ? ? ? ? ? ? ? panel.loess(x, y, groups = grp, lty = 1, > ? ? ? ? ? ? ? ? ? ? ? ? ? ? col.line = c('blue', 'red')) > ? ? ? ? ?} > ? ? ?) ?) > > As stated in the book, the with() wrapper allows one to use variable names > within the panel function. I was hoping to get away with using both groups > and subscripts in the panel function and fake my way through, but no luck. I > get 90% of what I want: the points are plotted correctly, but only one loess > line shows up instead of two. I put groups before the ellipsis in the > argument list, defined groups = gp2 in the function call and a couple of > other things, but got the same result.You are on the right track, except that panel.loess is not "groups-aware". I would do something like with(d, xyplot(val ~ time, pch = mypch, col = mycol, lty = 1, col.line = c('blue', 'red'), subscripts = TRUE, panel = function(x, y, ..., groups) { panel.superpose(x, y, ..., groups = gp1, panel = panel.points) panel.superpose(x, y, ..., groups = gp2, panel = panel.loess) })) The first call inside the panel function could be simpler, but this makes the intention clearer. -Deepayan