[R] lattice 3x3 plot: force common y-limits accross rows and align x-axes

Duncan Mackay mackay at northnet.com.au
Tue Feb 19 04:29:23 CET 2013


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: mackay at 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.berton at gene.com>
>
>Cc: "mackay at northnet.com.au" 
><mackay at northnet.com.au>; "r-help at r-project.org" <r-help at 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 at 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 at 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.



More information about the R-help mailing list