s-news
[Top] [All Lists]

Summary: Text for individual panels in a trellis plot

To: <s-news@lists.biostat.wustl.edu>
Subject: Summary: Text for individual panels in a trellis plot
From: "John Payne" <jcpayne@u.washington.edu>
Date: Thu, 29 May 2003 00:14:32 -0700
Many thanks for the swift, thoughtful and extremely helpful replies I received from the members of this community.  In brief, I asked how to label individual panels in a trellis plot of the form
xyplot(y~x|factorA*factorB, groups = factorC) when some of the factor combinations are missing.  Bert Gunter and Henrik Aalborg Nielsen suggested inserting an 'if' statement into the panel function, such as this:

.... panel=function(x,y,...){
if(length(y) == 0){ ## or whatever test you want
text(..., label= 'Insufficient Data',cex=2)
}
else panel.xyplot(x,y,...) ## or whatever plotting code you like

However, in my case the problem is that the panel function is not invoked if there are no data.  Jim Pratt pointed out that you can determine which panel you are working on by
    pnl<-get('n',frame=sys.parent())
and in the same vein, Bill Dunlap showed me how to label each panel with its
row, column and number:

a <- data.frame(g1 = rep(letters[1:2], each = 18), g2 = rep(LETTERS[6:8],each = 12),
    y = sort(rnorm(36)),x = sort(runif(36)))
xyplot(y ~ x | g2 * g1, data = "">          panel = function(...){
                panel.xyplot(...);
                mtext(side=1,line=-2,text=paste(n=eval(Quote(paste("n=", n,"p=",p,"q=",q)),local=sys.parent())))
          })
However, he warns that n, p and q "are variables in the function render.trellis(), which is the function
that actually calls the panel function.  It is a messy way of doing things and I would rather have things depend what is given to panel, like length(x) or the subscripts argument (it tells you which rows in the data frame are
being passed to the panel function), but sometimes the panel number is what you need.  If the function render.trellis ever got rewritten you wouldn't be able to depend on n, p, and q still being used."

Finally Nick Ellis suggested a very clever solution, which I give in full.  He wrote:

I can't see a simple way of doing it because the panel function doesn't get
invoked if there's no data:

df <- expand.grid(a=letters[1:3],b=LETTERS[1:3],x=1:10)
df$z <- df$x+rnorm(df$x)
sub <- df$a=="b" & df$b=="B"
xyplot(z~x|a*b,df[!sub,],panel=function(...){
panel.xyplot(...)
text(mean(par("usr")[1:2]),mean(par("usr")[3:4]),"hello")
})

Here is a fairly kludgy way to do it by putting dummy data into every factor
combination, then only plotting the real data or a text message:

dummy <-cbind(expand.grid(a=levels(df$a),b=levels(df$b)),x=mean(df$x),z=mean(df$z))
xyplot(z~x|a*b,rbind(dummy,df[!sub,]),panel=function(x,y,...){
if(length(x)==1)
text(mean(par("usr")[1:2]),mean(par("usr")[3:4]),"No data")
else panel.xyplot(x[-1],y[-1],...)
})

If I understand it correctly, the point of making the dummy values the means of x and y is to ensure that the dummy values don't influence the calculation of the x and y plotting limits.  
 
Thanks so much to everyone for your help!

John Payne
Box 351800
Dept. of Zoology
University of Washington
Seattle, WA 98195

<Prev in Thread] Current Thread [Next in Thread>
  • Summary: Text for individual panels in a trellis plot, John Payne <=