Duncan and Bert, Thank you very much for your help with my question. It's very much appreciated.
I used your suggestions to get the plot I needed: * 3x3 lattice of dotplots, * x-limits are the same for all panels, * y-limits and y-ticks in each row are the same, * y-limits and y-ticks are different between rows, * within each row subjects are ordered by sum(count) in the row. My code is below just in case somebody in the r-help list finds it useful. Regards, Boris. # raw data df <- data.frame(        subject=c('A','A','A',                  'BB','BB',                  'CCC','CCC','CCC',                  'DD','DD',                  'A','A','A',                  'FFFF','FFFF',                  'A','A',                  'B','B'),        risk=c('high','high','high',               'high','high',               'high','high','high',               'med','med',               'med','med','med',               'med','med',               'low','low',               'low','low'),        treatment=c('none','optX','optZ',                    'none','optZ',                    'none','optX','optZ',                    'none','optZ',                    'none','optX','optZ',                    'none','optZ',                    'none','optX',                    'none','optZ'),        count=c(5,10,2,                3,5,                8,1,2,                3,7,                10,2,5,                15,2,                7,7,                10,8)) # re-level factors df$risk <- factor(df$risk,levels=c('low','med','high')) df$treatment <- factor(df$treatment,levels=c('none','optX','optZ')) # create unique subjects ordered by sum(count) and risk df$sbj.byrisk <- paste(df$risk,df$subject,sep="_") df$sbj <- reorder(reorder(df$sbj.byrisk,df$count,sum),as.numeric(df$risk)) df$sbj.ix <- as.numeric(df$sbj) # for each row (i.e. risk), find limits, ticks, labels, and # maximum number of points per panel df.byrisk <- split(df,df['risk']) ylim <- lapply(df.byrisk,function(idf) return(range(idf$sbj.ix))) ytck <- lapply(df.byrisk,function(idf) return(sort(unique(idf$sbj.ix)))) ylbl <- lapply(df.byrisk,function(idf) {                          ytck <- sort(unique(idf$sbj.ix))                          jdnx <- pmatch(ytck,idf$sbj.ix)                          ylbl <- sub(".*_","",idf$sbj[jdnx])                          return(ylbl)                        }) yhei <- unlist(lapply(ytck,length)) # set up lists for limits, ticks, labels, panel heights ylims <- rep(ylim,c(3,3,3)) ytcks <- rep(list(NULL,NULL,NULL),c(3,3,3)) ytcks[seq(1,7,by=3)] <- ytck ylbls <- rep(list(NULL,NULL,NULL),c(3,3,3)) ylbls[seq(1,7,by=3)] <- ylbl # set up plot layout laywid <- list(axis.panel=c(1,0.1,0.1)) layhei <- list(panel=yhei/sum(yhei)) # plot oltc <- dotplot(sbj~count|treatment+risk,data=df,                type=c("p","h"),origin=0,                scales=list(x=list(limits=c(-1,16),                                   alternating=FALSE),                            y=list(relation="free",                                   alternating=FALSE,                                   limits=ylims,                                   at=ytcks,                                   labels=ylbls)),                par.settings=list(layout.widths=laywid,                                  layout.heights=layhei),                between=list(y=0.2)) useOuterStrips(oltc) ________________________________ From: Duncan Mackay <mac...@northnet.com.au> oject.org> Sent: Monday, February 18, 2013 10:29:23 PM Subject: Re: [R] lattice 3x3 plot: force common y-limits accross rows and align x-axes Hi Boris Just a different take on it, quick glimpse of it library(lattice) library(latticeExtra) z= unique(df$subject) df$nsub <- sapply(df$subject, pmatch, z) useOuterStrips(xyplot(count ~ nsub|treatment*risk, df, type = "h", lwd = 2, scales = list(x = list(at = 1:6, labels = z)))) The order can be changed by changing the order in z by making subject a factor in the correct order see http://finzi.psych.upenn.edu/R/Rhelp02/archive/43626.html on how to change the yaxis limits. An example of mine (cut and paste) for an 8x3 panel xyplot (it could be streamlined - i needed to change things as I went along to get everything in)      par.settings = layout.heights = list(panel = c(1,1,0.6,0.6,0.6,0.6,1,0.5)/sum(c(1,1,0.6,0.6,1,0.6,1,0.5)) )              ),      scales = list(x = list(alternating = FALSE,                   relation  = "same",                   rot    = 0),              y = list(alternating = FALSE,                   relation  = "free",                   limits = list(c(-1500,30000),c(-1500,30000),c(-1500,30000), # BZ                          c(-1500,30000),c(-1500,30000),c(-1500,30000), # LV                          c(-2000,20000),c(-2000,20000),c(-2000,20000), # L2                          c( -500, 4000),c( -500, 4000),c( -500, 4000), # CL                          c(-2000,20000),c(-2000,20000),c(-2000,20000), # OP                          c(-2000,20000),c(-2000,20000),c(-2000,20000), # AB                          c(-1500,30000),c(-1500,30000),c(-1500,30000), # MO                          c(-500, 4000),c(-500, 4000),c(-500, 4000)), # MX                   at = rep(list(seq(0,30000,10000), NULL,                          seq(0,30000,10000), NULL,                          seq(0,20000,10000), NULL,                          seq(0, 4000, 2000), NULL,                          seq(0,20000,10000), NULL,                          seq(0,20000,10000), NULL,                          seq(0,30000,10000), NULL,                          seq(0, 4000, 2000), NULL ),                          c(1,2, 1,2, 1,2, 1,2, 1,2, 1,2, 1,2, 1,2) ),                   labels = rep(list(as.character(seq(0,30,10)), NULL,                            as.character(seq(0,30,10)), NULL,                            as.character(seq(0,20,10)), NULL,                            as.character(seq(0, 4, 2)), NULL,                            as.character(seq(0,20,10)), NULL,                            as.character(seq(0,20,10)), NULL,                            as.character(seq(0,30,10)), NULL,                            as.character(seq(0, 4, 2)), NULL ),                            c(1,2, 1,2, 1,2, 1,2, 1,2, 1,2, 1,2, 1,2) ),                   rot    = 0)            ), I had different panel heights for each row so if they were all the same it would be panel = rep(1,n)/n the trick is to get the rep of the lists to match what would normally happen for each of the all the panels ie whether an axis/label is required str(plot object) can help if problems HTH Duncan Duncan Mackay Department of Agronomy and Soil Science University of New England Armidale NSW 2351 Email: home: mac...@northnet.com.au At 12:22 19/02/2013, you wrote: > Content-Type: text/plain > Content-Disposition: inline > Content-length: 14523 > > Bert, > > Thank you very much for your reply.àYour suggestions to set manually > y-limits of panels in lattice plot certainly puts me on the right track. > > It works really well with xyplot(): > > hf <- data.frame( > à àx=seq(1,20,by=1), > à ày=seq(0.1,2,by=0.1), > à àrisk=gl(2,10,labels=c("low","high")), > à àtreatment=rep(gl(2,5,labels=c("oXX","oYY")),2))à à à à à à à > à à à à à à > à > xyplot(y~x|treatment+risk,data=hf,type="b", > à à à à à àscales=list(y=list(limits=list(c(-0.1,1.1),c(-0.1,1.1), > à à à à à à à à à à à à à à à à à à à à à à à à à à > à à à à à à à à à à àc(1.0,2.1),c(1.0,2.1)), > à à à à à à à à à à à à à à à à à à> at=list(seq(0,1,0.2),NULL, > à à à à à à à à à à à à à à à à à à à à à à à à à > àseq(1,2,0.2),NULL), > à à à à à à à à à à à à à à à à à àrelation="free"))) > > With the xyplot() above, I get 2x2 lattice where panels in the same row have > the same y-limits: > > Panel 1,2 (row 1): -0.1, 1.1 > Panel 3,4 (row 2): 1.0, 2.1 > > Unfortunately, it does not work so well with dot plots: > > > kf <- data.frame(subject=c("A","BB","A","C","DDD","DDD"), > à à à à à à à à à à à à à à à à> risk=c("low","low","low","high","high","high"), > à à à à à à à à à à à à à à à à> treatment=c("oXX","oXX","oYY","oXX","oXX","oYY"), > à à à à à à à à à à à à à à à àcount=c(5,7,10,4,13,8)) > kf$risk <- factor(kf$risk,levels=c("low","high")) > kf$treatment <- factor(kf$treatment,levels=c("oXX","oYY")) > > lims.low <- factor(c("A","BB")) > lims.high <- factor(c("C","DDD")) > dotplot(subject~count|treatment+risk,data=kf,type=c("p","h"), > à à à à à à àscales=c(y=list(limits=list(lims.low,lims.low, > à à à à à à à à à à à à à à à à à à à à à à à à à à > à à à àlims.high,lims.high), > à à à à à à à à à à à à à à à à à à à à à à à> relation="free"))) > > > With the dotplot() above I get 2x2 lattice plot where all panels haveàthe > same y-limits; y-ticks on all panels are 'A','BB','C','DDD'. > > > This behaviour is probably fixed by design.àAccording to documentation > for prepanel functions: "... to make this information consistent between > panels, the ââ¬Ëxlimââ¬â¢ or ââ¬Ëylimââ¬â¢ values should > represent all the levels of the corresponding factor, even if some are not > used within that particular panel." > > A way to trick lattice would be to use xyplot() with a custom panel > function.àI'll give a try today or tomorrow. > > Regards, > Boris. > > > > > ________________________________ > From: Bert Gunter <gunter.ber...@gene.com> > > Cc: "mac...@northnet.com.au" <mac...@northnet.com.au>; "r-help@r-project.org" > <r-help@r-project.org> > Sent: Monday, February 18, 2013 1:09:10 PM > Subject: Re: [R] lattice 3x3 plot: force common y-limits accross rows and > align x-axes > > Boris: > > If I understand you correctly, you wish to set panel limits by row. I > know of no "slick" way of doing this (others may), as what is in a row > can change depending on layout and how you determine the scale for the > rows' contents may depend on the application context. > > So I would do it manually: First, outside of trellis, compute your > xlim and ylim values for each row as you desire. Then issue the > trellis call, with the relation="free" component in the scales = list, > Then just use the list form of the xlim and ylim argument to xyplot > with your precomputed limits. > > -- Bert > > > > Hi Duncan, > > > > Thank you for quick reply. > > > > I am not sure that your solution solves the problem.àIf I use > > useOuterStrips(dotplot(count ~ subject|risk*treatment,df)) > > the order of subjects and panel y-limits in each panel are > > > > A, B, BB, CCC, DD, FFFF. > > > > However, the order of subjects and y-limits which I would > > like to get are > > > > Panels 1,2,3 (row 1): A, B > > > > Panels 4,5,6 (row 2): DD, A, FFFF > > > > Panels 7,8,9 (row 3): BB, CCC, A. > > > > I can re-index subjects so that they have correct order in each row. > > However, I am not sure how to specify per-panel y-limits in lattice > > so that all panels in the same row have the same y-limits irrespective > > of what data is in these panels. > > > > With relation "same", the limits are the same for all plots; with > > relation "free" the limits depend on the data in the panel.àI thought > > that relation "free" and specification of y-limits via prepanel > > function (my previous trys) or as a list would do the trick: > > scales=list(y=list(limits=list(panel-1-limits, panel-2-limits, ...)) > > but I cannot get it to work. > > > > I guess I am missing something basic ... any ideas or advice to give > > up are greatly appreciated. > > > > Regards, > > Boris. > > > > > > > > Hi Boris > > > > Not sure what you mean exactly > > try > > > > library(latticeExtra) > > useOuterStrips(dotplot(count ~ subject|risk*treatment,df)) > > > > if you want to change the order of the subjects in each panel and an > > index column and plot the index column instead of subject and change > > the scales to suit. > > > > HTH > > > > Duncan > > > > Duncan Mackay > > Department of Agronomy and Soil Science > > University of New England > > Armidale NSW 2351 > > Email: home: mackay at northnet.com.au At 07:54 16/02/2013, you wrote: > >>Good afternoon, >>I would like to ask for help in controlling y-axis limits > >>and labels in >lattice doplots.àUnfortunately, the problem is somewhat > >>convoluted, >please bear with the long explanation. >>I would like to > >>create a 3x3 lattice of dotplots, say subject ~ count. >The plot is > >>conditioned on variables treatment and risk: subject ~ count >|treatment + > >>risk.àIn the experiment,ànot all subjects were exposed >to all > >>combinations of treatment and risk.àFor each risk, I would like >to > >>show subject ~ count | treatment and order the subjects by the total > >>>count.àAt the same time, I would like the x-axes to be the same in all > >>>panels and aligned by columns. >>Here is a sample data set: >># raw data > >>>df <- data.frame(subject=c('A','A','A','BB','BB','CCC','CCC','CCC', > >>>'DD','DD','A','A','A','FFFF','FFFF', >'A','A', 'B','B'), > >>>>risk=c('high','high','high','high',' high','high','high','high', >'med','med','med','med','med','med','med', > >à>'low','low','low','low'), >>treatment=c('none > >','optX','optZ','none','optZ','none','optX','optZ', > >>>'none','optZ','none','optX','optZ','none','optZ', > >>'none','optX','none','optZ'), >count=c(5,10,2, 3,5,8,1,2, >3,7,10,2,5,15,2, > >>7,7,10,8)) ># re-level factors >df$risk <- > >factor(df$risk,levels=c('low','med','high')) >df $treatment <- > >factor(df$treatment,levels=c('none','optX','optZ')) >>>## > df >##à> >àsubject risk treatment count >## 1ààààA highàà> >ànoneàà5 >## 2ààààA highàààoptXà> >à10 >## 3ààààA highàààoptZàà2 >## > >4àààBB highààànoneàà3 >## 5ààà> >BB highàààoptZàà5 >## 6àààCCC highàà> >ànoneàà8 >## 7àààCCC highàààoptXà> >à1 >## 8àààCCC highàààoptZàà2 >## 9à> > ààDDàmedààànoneàà3 >## 10àààDDàmedàààoptZàà7 >## 11àààAàmedààànoneàà10 >## 12àààAàmedàààoptXàà > 2 >## 13àààAàmedàààoptZàà5 >## 14à> àFFFFàmedààànoneàà15 >## 15ààFFFFà>medàààoptZ > >à2 >## 16àààAàlowààànoneàà7 >## > >17àààAàlowàààoptXàà7 >## 18àà> >àBàlowààànoneàà10 >## 19àààBà> >lowàààoptZàà8 >>One way to plot the data is to break-up > >the data into sub-frames, one >frame for each risk, order subjects by total > >counts, create dotplots, >and merge with trellis.c().àThis almost works > >but in the merged plot I >cannot decrease column spacing to be small > >enough.àAlso, the output of >trellis.c() would not work with > >useOuterStrips() which I really like. >My code is in TRY ONE below. > >>>Another way to create the plot is specify y-limits for each panel with > >>custom prepanel and panel functions.àFor each panel, the data-frame for > >>the panel row is isolated, subjects in the data-frame for the current >row > >are ordered by counts, panel y-limits are set to the re-ordered >levels, > >y-data for each panel is releveled, and data plotted with >standard panel.dotplot().àThis > somewhat works but lattice does not >honour > >àthe user-defined y-limits and labels are not correct.àI suspect > >>that it is not correct to useày-relation="same" in this case but "free" > >>and "sliced" do not give correct results too. My code in in TRY TWO >below. > >>>If anybody can offer any assistance with this problem, it would be much > >>appreciated, >Sincerely, >Boris. >>>#### BEGIN TRY ONE - MERGE LATTICE > >PLOTS #### >library(lattice) >library(latticeExtra) >l ibrary(grid) >>for > >(irisk in levels(df$risk)) { ># subset data frame >df.irisk <- > >subset(df,risk==irisk) >># order subjects by total count; store levels of > >subjectx variables ># for later re-use in panel labels >df.irisk$subjectx <- > >df.irisk$subject[,drop=TRUE] >df.irisk$subjectx <- > >reorder(df.irisk$subjectx,df.irisk$count,sum) >a > >ssign(paste('sbjx.',irisk,sep=''),levels(df.irisk$subjectx)) >># create > >dotplot and store it in oltc.{irisk} variable >oltc.irisk <- > >dotplot(subjectx~count|treatment,data=df.irisk, >layout=c(3,1),type=c('p','h'), > >à>xlim=c(-1,16),origin=0, >xlab="",ylab="") >as > >sign(paste('oltc.',irisk,sep=''),oltc.irisk) >} >># combine everthing in > >one plot >oltc <- c(low=oltc.low,med=oltc.med,high=oltc.high) >pri nt(oltc) > >>># get rid of variable labels in middle and right column; decrease ># > >distance between columns.àBut can't make inter-column spaces ># small > >enought and get rid of the panels in all but top rows. >laywid <- > >trellis.par.get('layout.widths') >laywid$between <- -5 >laywid$axis.panel > ><- 0.7 >yscales <- list(labels=list(sbjx.low,NULL,NULL, >sbjx.med,N > >ULL,NULL, >sbjx.high,NULL,NULL)) >oltd <- > >update(oltc,scales=list(y=yscales), >par.setting > >s=list(layout.widths=laywid)) >print(oltd) >>### # END TRY ONE - MERGE > >LATTICE PLOTS #### >>#### BEGIN TRY TWO - CUSTOM PREPANEL AND PANEL > >FUNCTIONS #### >>prepanel.dotplot.x <- > >function(x,y,type,subscripts,...,data=NULL) { ># find data-frame that > >corresponds to the entire row of the plot >irisk <- > >à levels(data$risk[subscripts,drop=TRUE]) >idata <- > >subset(data,risk==irisk) >># in the sub-frame, order subjects by total > >counts >idata$subjectx <- > >reorder(idata$subject[,drop=TRUE],idata$count,sum) >># set y-limits >ylim > ><- levels(idata$subjectx) >># increment packet counter and print new panel > >limits >pcknum = lattice.options()$packet.counter >lattice.option > >s(packet.counter=pcknum+1) >cat(paste(pcknum,":" ,paste(ylim,collapse=", > >")),sep="\n") >return(list(ylim=ylim)) >} >>pane l.dotplot.x <- > >function(x,y,type,subscripts,...,data=NULL) { ># get the sub-frame for the > >row >irisk <- levels(data$risk[subscripts,drop=TRUE]) >idata <- > >subset(data,risk==irisk) >># in the sub-frame, order subjects by total > >counts >idata$subjectx <- > >reorder(idata$subject[,drop=TRUE],idata$count,sum) >># re-order > >y-variable to "correct levels" >y <- > >factor(as.character(y),levels(idata$subjectx)) > ># print levels of the > >releveled subjects - should be the same ># as the output of > >àprepanel.dotplot.x >pnlnum <- panel.number() > >>cat(paste(pnlnum,':',paste(level s(y),collapse=", ")),sep="\n") >># call > >standard dotplot >panel.dotplot(x,y,...) >} >># the data is plotted > >correctly but the labels and limits are not >correct > >>lattice.options(packet.counter=1) >oltc <- > >dotplot(subject~count|treatment+risk,data=df, >l > >ayout=c(3,3),subscripts=TRUE, >prepanel=function (...) > >>{prepanel.dotplot.x(...,data=df)}, >panel > >=function(...){panel.dotplot.x(...,data=df)}, >s > >cales=list(y=list(relation='same')), >drop.unuse d.levels=FALSE, > >>xlim=c(0,16)) >print(oltc) >>## ## END TRY TWO - CUSTOM PANEL AND PREPANEL > >FUNCTIONS #### >>_________________________________________ _____ >R-help at > >r-project.org mailing list >https://stat.ethz.ch/mailman/listinfo/r-he lp > >>PLEASE do read the posting guide > >http://www.R-project.org/posting-guide.html >and provide commented, > >minimal, self-contained, reproducible code. > >àààà[[alternative HTML version deleted]] > > > > ______________________________________________ > > 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. > > > > -- > > Bert Gunter > Genentech Nonclinical Biostatistics > > Internal Contact Info: > Phone: 467-7374 > Website: > http://pharmadevelopment.roche.com/index/pdb/pdb-functional-groups/pdb-biostatistics/pdb-ncb-home.htm >    [[alternative HTML version deleted]] > > > ______________________________________________ > 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. [[alternative HTML version deleted]]
______________________________________________ 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.