Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

xyplot bottom axis when last row has fewer panels than columns

Tags:

plot

r

lattice

Consider a lattice xyplot that has relation='fixed', alternating=FALSE, and as.table=TRUE.

If the last row of panels is incomplete (i.e. there are fewer panels than columns of the layout), the x-axis is not plotted. For example, panel 4 in the plot below does not have x-axis ticks/labels.

library(lattice)
d <- data.frame(x=runif(100), y=runif(100), grp=gl(5, 20))
xyplot(y~x|grp, d, as.table=TRUE, scales=list(alternating=FALSE, tck=c(1, 0)))

enter image description here

How can I add that axis?

Ideally I want axes only at bottom and left sides, and the incomplete row of panels at bottom (unlike when using as.table=FALSE, which plots the incomplete row at the top). For the example above, I'd like the axis plotted on the bottom border of panel 4, rather than in line with the x-axis of panel 5.

I know that this is easily solved with, e.g., a base graphics approach. I'm specifically interested in a lattice solution.

like image 891
jbaums Avatar asked Sep 15 '25 04:09

jbaums


2 Answers

I am not a lattice expert, but I believe this might work. The idea was originally posted here. First I will regenerate the example:

library(lattice)
set.seed(1)
d <- data.frame(x=runif(100), y=runif(100), grp=gl(5, 20))

Next, lets define a function that will control the panel settings:

trellis.par.set(clip = list(panel = "off"))
myPan <- function(...){
    panel.xyplot(...)
    if(panel.number() == 4) {
        at = seq(0,1,by = 0.2)
        panel.axis("bottom", at = at, outside = T,
                    labels = T, half = F)
    }
    if(panel.number() == 5) {
        at = seq(0,1,by = 0.2)
        panel.axis("bottom",at = at, outside = T,
                   labels = T, half = F)
    }
}

Now to the plot:

xyplot(y~x|grp, d, as.table=TRUE, 
       scales = list(
           x = list(draw = F, relation="same"),
           y = list(tck=c(1,0), alternating=F)),
       layout = c(2,3),
       panel = myPan)

As can be seen, in the xyplot command we asked not to draw the x axis (draw = F) but later panel calls myPan function. There we specifically demand to draw x-axis for panels 4 and 5.

output

enter image description here

Hope it can give you some direction for improvements.

like image 74
Tal J. Levy Avatar answered Sep 16 '25 22:09

Tal J. Levy


Here's another approach based on code provided in a (now deleted) answer by @user20650. It uses grid directly, focussing on panels of the active trellis plot that are missing axes (or at least assumed to be missing axes), and adding them. We also assume that the x-scale is fixed.

The function (which also exists as a gist here):

add_axes <- function() {
  library(grid)
  library(lattice)
  l <- trellis.currentLayout()
  pan <- which(l[nrow(l), ]==0)
  if(length(pan) > 0) {
    g <- grid.ls(print=FALSE)
    # use an existing panel as a template for ticks 
    ticks <- grid.get(g$name[grep("ticks.bottom.panel", g$name)][[1]])
    # use an existing panel as a template for labels
    labels <- grid.get(g$name[grep("ticklabels.bottom.panel", g$name)][[1]])
    ax <- grobTree(ticks, labels)
    invisible(sapply(pan, function(x) {
      trellis.focus("panel", x, nrow(l)-1, clip.off=TRUE)
      grid.draw(ax)
      trellis.unfocus()  
    }))
  }
}

An example:

library(lattice)
d <- data.frame(x=runif(100), y=runif(100), grp=gl(5, 20))
xyplot(y~x|grp, d, as.table=TRUE, scales=list(tck=c(1,0), alternating=FALSE), 
       layout=c(4, 2), xlim=c(-0.1, 1.1))

enter image description here

add_axes()

enter image description here

like image 37
jbaums Avatar answered Sep 16 '25 20:09

jbaums