[R] conditioned xyplot, many y variables

Jacob Wegelin jacobwegelin at fastmail.fm
Sun Feb 7 18:32:30 CET 2010


The example below creates parallel time-series plots of three different y variables conditioned by a dichotomous factor. In the graphical layout,

 	•       Each y variable inhabits its own row and is plotted on its own distinct scale.

 	•       Each level of the factor has its own column, but within each row the scale is held constant across columns.

 	•       The panels fit tightly (as they do in lattice) without superfluous whitespace or ticks.

Currently I know of no lattice solution to this problem, only a traditional graphics solution. Can one solve this problem elegantly using lattice?

The difficulty is to lock the levels of the factor (the columns) into the same scale for each y variable (for each row), while allowing the scales to differ between the y variables (between the rows).

Details:

#	Toy data:

N<-15
TIME <- (1:N)/N
ppp <- TIME^2
QQQ <- exp(TIME)
z <- ppp / QQQ
JUNK<-data.frame( ppp=ppp, QQQ=QQQ, z=z, TIME=TIME)
JUNK$ID<-1
jank<-JUNK
jank$ID<-2
jank$ppp<-jank$ppp / 2
jank$QQQ<-jank$QQQ / 2
jank$z<-jank$ppp/jank$QQQ
JUNK<-rbind(JUNK, jank)
jank<-JUNK
jank$ppp<-(jank$ppp) ^(1/4)
jank$QQQ<-(jank$QQQ) / 100000
jank$z <- jank$ppp / jank$QQQ
JUNK$Species<-"Dog"
jank$Species<-"feline"
JUNK<-rbind(JUNK, jank)
JUNK$Species<-factor(JUNK$Species)
JUNK$ID<-factor(JUNK$ID)
summary(JUNK)

#	Traditional graphics solution:

par(mfrow=c(3,2),mar=c(0,0,0,0)+0.0,oma=c(4,4,4,1),xpd=FALSE, las=0)

varNamesAndLabels<-data.frame(
 	name=c("z", "QQQ", "ppp")
 	, label=c("z (mIU/mL)", "QQQ (pg/L)", "ppp (mg/L)")
)
rownames( varNamesAndLabels)<- varNamesAndLabels$name

count_y_variables<-0
for(this_y_name in rownames( varNamesAndLabels) ) {
count_y_variables <- count_y_variables + 1

 	countSpecies<-0
 	for(thisSpecies in levels(JUNK$Species)) {
 		countSpecies<-countSpecies + 1
 		TEMPORARY<-JUNK[JUNK$Species==thisSpecies,]
 		if(countSpecies==1) {
 			plot(JUNK$TIME, JUNK[[this_y_name]], xlab="", ylab="", type="n",xaxt='n', log="y")
 			mtext( varNamesAndLabels[this_y_name,"label"], side=2, line=2.5)
 			}
 		else
 			plot(JUNK$TIME, JUNK[[this_y_name]] , xlab="", ylab="", type="n",xaxt='n', log="y", yaxt="n")
 		for( thisID in levels(TEMPORARY$ID)) {
 			lines(TEMPORARY$TIME[TEMPORARY$ID==thisID], TEMPORARY[[this_y_name]][TEMPORARY$ID==thisID], type="o")
 			}
 		if(count_y_variables == nrow(varNamesAndLabels)) mtext( thisSpecies, side=1, line=2.5)
 	}
}

library("lattice")

#	The three lattice partial solutions below differ only in the value of scales$y$relation.

#	scales$y$relation="same" 
#	forces ppp, QQQ, and z to the same scale, which obscures signal,
#	especially for ppp. But at least it enables us to see that the range of QQQ
#	differs immensely between Dog and feline.
xyplot ( ppp + QQQ + z ~ TIME | Species
  	, group=ID
  	, data=JUNK
  	, ylab=c("ppp (mg/L)", "QQQ (pg/L)", "z (mIU/mL)")
  	, xlab=c("Dog", "feline")
  	, type="o"
  	, strip= FALSE
  	, outer=TRUE
  	, layout=c(2,3)
  	, scales=list(
  		ppp=list( alternating=3)
  		, y=list(
  			relation="same"
  			, alternating=3
  			, rot=0
  			, log=T
  			)
  		)
  	)


#	scales$y$relation="free" 
#	displays ppp, QQQ, and z on different scales, but it also allows
#	the scales for each variable to differ between Dog and feline.
#	This prevents us from visually comparing the species.
xyplot ( ppp + QQQ + z ~ TIME | Species
  	, group=ID
  	, data=JUNK
  	, ylab=c("ppp (mg/L)", "QQQ (pg/L)", "z (mIU/mL)")
  	, xlab=c("Dog", "feline")
  	, type="o"
  	, strip= FALSE
  	, outer=TRUE
  	, layout=c(2,3)
  	, scales=list(
  		ppp=list( alternating=3)
  		, y=list(
  			relation="free"
  			, alternating=3
  			, rot=0
  			, log=T
  			)
  		)
  	)


#	scales$y$relation="sliced" 
#	shows us that the difference max(z)-min(z) differs greatly between
#	Dog and feline.  But it obscures the fact that
#	QQQ differs wildly between Dog and feline, as we saw when
#	relation="same".
xyplot ( ppp + QQQ + z ~ TIME | Species
  	, group=ID
  	, data=JUNK
  	, ylab=c("ppp (mg/L)", "QQQ (pg/L)", "z (mIU/mL)")
  	, xlab=c("Dog", "feline")
  	, type="o"
  	, strip= FALSE
  	, outer=TRUE
  	, layout=c(2,3)
  	, scales=list(
  		ppp=list( alternating=3)
  		, y=list(
  			relation="sliced"
  			, alternating=3
  			, rot=0
  			, log=T
  			)
  		)
  	)

Comments:

The traditional graphics solution requires many lines of custom code.  Also, in traditional graphics I was unable to get the "ylab" labels to read parallel to the axis at the same time that the tick labels read perpendicular to the axis. The lattice package achieves this with "rot=0". In traditional graphics, "las" apparently governs the mtext (outer label) as well as the axis tick labels.

Thanks for any insights

Jacob A. Wegelin
Assistant Professor
Department of Biostatistics
Virginia Commonwealth University
730 East Broad Street Room 3006
P. O. Box 980032
Richmond VA 23298-0032
U.S.A.


More information about the R-help mailing list