[R] Trellis - setting xlim or ylim by data range in whole column or row

Keith Chamberlain Keith.Chamberlain at colorado.edu
Fri Mar 10 08:07:55 CET 2006


Dear Deepayan,

My deepest thanks! Your example code worked perfectly. I understood the
caveats you detailed about figuring out the axis limits before resolving the
layout, which depend on a bunch of other stuff. I'm glad this is possible.
Yes, this particular layout does only make sense in this special case (e.g.
2 conditioning variables & exactly n and m-levels).

Thank you again for your feedback. I am excited to go put your examples to
work.

Rgds,
KeithC.

-----Original Message-----
From: Deepayan Sarkar [mailto:deepayan.sarkar at gmail.com] 
Sent: Thursday, March 09, 2006 9:55 PM
To: Keith Chamberlain
Cc: r-help at stat.math.ethz.ch
Subject: Re: 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/




More information about the R-help mailing list