|
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
|