rlattice

How can I scale symbol size by a data attribute in R lattice?


I would like to scale symbol size by a data attribute using Lattice. In the example, I am conditioning on Month. There are two groups ('Ellipse'), each has three x-y observations made at Hours 1,2, and 3. It's a point & line graph, and I want to make the symbols for each Ellipse increment in size according to Hour, to indicate the direction in which time is incrementing. In the xyplot code below, I have added 'cex=d$Hour', but this just assigns different symbol sizes to the two Ellipses.

d <- data.table(expand.grid(Hour=1:3, Month=1:3, Ellipse=1:2))
d[, x := c(rnorm(9, mean=1, sd=1),rnorm(9, mean=2, sd=1.5))]
d[, y := c(rnorm(9, mean=1, sd=1),rnorm(9, mean=2, sd=2))]

xyplot(y ~ x|Month, d, type=c('l','p'), group = Ellipse,
    cex = d$Hour,
    auto.key=list(title="Ellipse", corner=c(0.8,0.8)))

Example showing symbol size scaled by Ellipse instead of Hour


Solution

  • The default panel function for xyplot is panel.xyplot, which calls panel.superpose when argument groups is non-NULL.

    So we read help("panel.superpose"):

    panel.superpose divides up the x (and optionally y) variable(s) by the unique values of groups[subscripts], and plots each subset with different graphical parameters. The graphical parameters (col.symbol, pch, etc.) are usually supplied as suitable atomic vectors, but can also be lists. When panel.groups is called for the i-th level of groups, the corresponding element of each graphical parameter is passed to it. In the list form, the individual components can themselves be vectors.

    So we try the "list form" of graphical parameter cex:

    library(lattice)
    set.seed(0L)
    
    d <- expand.grid(Hour = 1:3, Month = 1:3, Ellipse = 1:2)
    d[["x"]] <- c(rnorm(9, mean = 1, sd = 1), rnorm(9, mean = 2, sd = 1.5))
    d[["y"]] <- c(rnorm(9, mean = 1, sd = 1), rnorm(9, mean = 2, sd = 2  ))
    
    xyplot(y ~ x | Month,
           data = d,
           auto.key = list(title = "Ellipse", corner = c(0.8, 0.8)),
           groups = Ellipse,
           type = c("l", "p"), 
           cex = list(sort(unique(d[["Hour"]]))))
    

    And that seems to do the trick ...

    same image but with points increasing in size within groups

    Well, in general, Hour need not be 1:3 in every level of Month:Ellipse. In the general case, you may need to use other features of lattice to get what you want, e.g., you may need to define your own panel function wrapping panel.xyplot. But that seems to be beyond the scope of the question ...