Keith Chamberlain
2006-Mar-09 22:29 UTC
[R] Trellis - setting xlim or ylim by data range in whole column or row
Dear List-mates, I have been trying to set up a 4x8 trellis plot (that is, 4 columns, 8 rows), and would like to have the axis limits set based on the data range of rows (for ylim) and columns (for xlim). I've been using the call: foo<-xyplot(y~x|Epoch+Subject, type=c("l","r"), par.strip.text=list(cex=0.5), ...) and updating to see different effects of scale adjustments, & etc. foo<-update(foo, scale=list(relation="sliced")) #etc. I can have each panel with its own limits using relation="free", limits wide enough to accommodate the whole data range with "same" or the limits of the widest panel for all panels with "split". I have not, however, figured out a way to have the limits for x & y grouped by their column or row. Documentation points to 3 alternate ways of trying to set stuff in panels. (1) a prepanel function, (2) using scales, or (3) focusing in on each panel individually & changing some setting. I've played around with accessing different panels individually with foo[column, row], and using a list to determine which get displayed (instead of using skip because I can't get skip to work). Would I be able to set the xlim values in a similar way? foo[1,]$ylim<-newvalues to set a whole columns ylims (e.g by data range of y in conditioning variable 2 (subject in my case)) and foo[,1]$xlim<-newvalues to get a whole rows xlims by the data range of x in each level of conditioning variable 1 (Epoch in my formula))? If so, what attribute should I access, and if not what would you recommend? I've been reading posts, working examples in Venables & Ripley 4th Ed., and experimenting with different things for the last 4 days. I'm still not used to the lattice terminology, so I could have easily miss interpreted what something was meant for (example- prepanel makes no sense to me yet). Conversely, I got a lot farther, a lot faster, using Lattice than I did using plot or ts.plot. In addition to a much shorter list of attributes that don't make sense to me yet than otherwise, I have been really tickled with the Lattice package. Thanks in advance for your feedback. KeithC.
Deepayan Sarkar
2006-Mar-10 04:55 UTC
[R] Trellis - setting xlim or ylim by data range in whole column or row
On 3/9/06, Keith Chamberlain <Keith.Chamberlain at colorado.edu> wrote:> Dear List-mates, > > I have been trying to set up a 4x8 trellis plot (that is, 4 columns, 8 > rows), and would like to have the axis limits set based on the data range of > rows (for ylim) and columns (for xlim). I've been using the call: > > foo<-xyplot(y~x|Epoch+Subject, > type=c("l","r"), > par.strip.text=list(cex=0.5), > ...) > > and updating to see different effects of scale adjustments, & etc. > foo<-update(foo, scale=list(relation="sliced")) #etc. > > I can have each panel with its own limits using relation="free", limits wide > enough to accommodate the whole data range with "same" or the limits of the > widest panel for all panels with "split". I have not, however, figured out a > way to have the limits for x & y grouped by their column or row. > > Documentation points to 3 alternate ways of trying to set stuff in panels. > (1) a prepanel function, (2) using scales, or (3) focusing in on each panel > individually & changing some setting. > > I've played around with accessing different panels individually with > foo[column, row], and using a list to determine which get displayed (instead > of using skip because I can't get skip to work). Would I be able to set the > xlim values in a similar way? > > foo[1,]$ylim<-newvalues to set a whole columns ylims (e.g by data range of > y in conditioning variable 2 (subject in my case)) and > > foo[,1]$xlim<-newvalues > > to get a whole rows xlims by the data range of x in each level of > conditioning variable 1 (Epoch in my formula))? If so, what attribute should > I access, and if not what would you recommend?What you want is not impossible, but not simple either. There's a good reason for that---this behavior makes sense only in a very special situation: when you have exactly two conditioning variables (a and b, say) and your layout has exactly nlevels(a) columns and nlevels(b) rows. To fix ideas, consider the following example: library(lattice) d <- expand.grid(a = gl(4, 1, 20), b = gl(8, 1, 40)) d$x <- with(d, rnorm(nrow(d), mean = as.numeric(a) + as.numeric(b))) d$y <- with(d, rnorm(nrow(d), mean = as.numeric(a) + as.numeric(b))) foo is as in your example, foo <- xyplot(y ~ x | a + b, d) At this point, foo has no layout defined (foo$layout is NULL). The layout will be determined when it is plotted. Since there are exactly two conditioning variables, the default here is layout = dim(foo) c(4, 8). So plotting foo is the same as update(foo, layout = dim(foo)) However, if you instead do update(foo, layout = c(0, prod(dim(foo)))) (which is essentially what happens when there is one conditioning variable) you will get a different layout, probably 6x6 (unless you have resized the device). In this case, choosing limits by row or column no longer makes sense. You might say, why not do this whatever the layout, whether it makes sense or not. The problem is, the axis limits for each panel needs to be determined _before_ the layout, because the layout may depend on the aspect ratio and the aspect ratio may depend on the axis limits (e.g. when aspect = "xy"). Workarounds: It is possible to explicitly specify a limit for each panel as a list. For example, you could have (update doesn't work well for this): xyplot(y ~ x | a + b, d, scales list(x list(relation = "free", limits = rep(list(c(0, 11), c(1, 12), c(2, 13), c(4, 14)), 8))), par.strip.text = list(cex = 0.5)) If you are happy with this, that's great, but you will most likely want to omit all but one set of labels and use the freed up space. To control the labelling, you can specify the tick mark locations as a list just like the limits. An undocumented trick to simplify this is to have TRUE for the defaults, and NULL to omit them, so you could do: xyplot(y ~ x | a + b, d, scales list(x list(relation = "free", limits = rep(list(c(0, 11), c(1, 12), c(2, 13), c(4, 14)), 8), at = rep(list(TRUE, NULL), c(4, 28)))), par.strip.text = list(cex = 0.5)) Finally, to make use of the space: xyplot(y ~ x | a + b, d, scales list(x list(relation = "free", limits = rep(list(c(0, 11), c(1, 12), c(2, 13), c(4, 14)), 8), at = rep(list(TRUE, NULL), c(4, 28)))), par.settings list(layout.heights = list(axis.panel = rep(c(1, 0), c(1, 7)))), par.strip.text = list(cex = 0.5))> I've been reading posts, working examples in Venables & Ripley 4th Ed., and > experimenting with different things for the last 4 days. I'm still not used > to the lattice terminology, so I could have easily miss interpreted what > something was meant for (example- prepanel makes no sense to me yet).It's a function that determines the limits for a panel given the data in it (these limits are then combined according to the value of scales$relation). For example, to get rid of uninteresting outliers, you might want to use only the range of the middle 98% of the data: xyplot(y ~ x | b, d, prepanel = function(x, y, ...) list(xlim = quantile(x, c(0.01, 0.99)), ylim = quantile(y, c(0.01, 0.99)))) xyplot(y ~ x | b, d, scales = "free", prepanel = function(x, y, ...) list(xlim = quantile(x, c(0.01, 0.99)), ylim = quantile(y, c(0.01, 0.99))))> Conversely, I got a lot farther, a lot faster, using Lattice than I did > using plot or ts.plot. In addition to a much shorter list of attributes that > don't make sense to me yet than otherwise, I have been really tickled with > the Lattice package. > > > Thanks in advance for your feedback. > KeithC.Deepayan -- http://www.stat.wisc.edu/~deepayan/