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.
______________________________________________
R-help@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-help
PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
and provide commented, minimal, self-contained, reproducible code.