Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Removing per-panel unused factors in a bar chart with nested factors

Tags:

plot

r

lattice

Some time ago I asked a question on how to remove unused factors in a bar chart, and I got a useful solution for that problem, thanks to @Aaron. Now, I am facing a very similar problem, but the solution that I used in the past does not work for this case.

This is the code to reproduce the data frame that I am using:

set.seed(17)
df <- data.frame(BENCH = sprintf('bench-%s', sort(rep(letters[1:8], 4))),
                 CLASS.CFG = sprintf('class-%s',
                     c(rep('C', 4), rep('A', 4), rep('B', 8),
                       rep('C', 8), rep('A', 4), rep('D', 4))),
                 EXEC.CFG = rep(c('st', 'st', 'dyn', 'dyn'), 8),
                 METRIC = rep(c('ipc', 'pwr'), 16),
                 VALUE = runif(32))

The straightforward command to plot this data frame would be:

library(lattice)
barchart(VALUE ~ BENCH | EXEC.CFG + CLASS.CFG, df, groups = METRIC,
         scales = list(x = list(rot = 45, relation = 'free')),
         auto.key = list(columns = 2))

As you can see, I am plotting VALUE for each BENCH constrained to every possible combination of EXEC.CFG and CLASS.CFG (that is what I mean with nested factors), and using METRIC to create groups.

This is the result that I obtain:

plot_with_gaps

Even if I use 'free' scales for the X axis, in the plot there are some (unnecessary) gaps between some of the bars (e.g., between bench-b and bench-g).

I tried to apply the solution that I got for my previous question in the following way:

pl1 <- barchart(VALUE ~ BENCH | EXEC.CFG + CLASS.CFG,
    subset(df, CLASS.CFG == 'class-A'), groups = METRIC,
    auto.key = list(columns = 2))
pl2 <- barchart(VALUE ~ BENCH | EXEC.CFG + CLASS.CFG,
    subset(df, CLASS.CFG == 'class-B'), groups = METRIC)
pl3 <- barchart(VALUE ~ BENCH | EXEC.CFG + CLASS.CFG,
    subset(df, CLASS.CFG == 'class-C'), groups = METRIC)
pl4 <- barchart(VALUE ~ BENCH | EXEC.CFG + CLASS.CFG,
    subset(df, CLASS.CFG == 'class-D'), groups = METRIC)

pls <- c(pl1, pl2, pl3, pl4)
pls <- update(pls, scales = list(y = 'same'))
pls

And this is the result that I obtain:

wrong_plot

As you will notice, this plot is not correct. It does not respect the nested factors, mixing values from CLASS.CFG and EXEC.CFG in the panel titles.

I have been fighting with this for a while, but with no success. Does anyone know how this can be achieved? (Basically, what I am trying to obtain is a plot like the first one, but without the gaps between the bars).

like image 583
betabandido Avatar asked Jan 22 '13 16:01

betabandido


1 Answers

To do this, you'll need to supply both a modified prepanel function (which sets up the limits of each panel's plotting area) and a modified panel function (which is responsible for plotting the data). In both cases, the key modification is to use x[, drop=TRUE] to drop the unused levels:

library(lattice)

barchart(VALUE ~ BENCH | EXEC.CFG + CLASS.CFG, df, groups = METRIC,
         scales = list(x = list(rot = 45, relation = 'free')),
         prepanel = function(x,y,...) {
             xx <- x[, drop = TRUE]
             list(xlim = levels(xx),
                  xat=sort(unique(as.numeric(xx))))
         },
         panel = function(x,y,...) {
             xx <- x[, drop = TRUE]
             panel.barchart(xx, y, ...)
         },
         auto.key = list(columns = 2))

enter image description here

like image 119
Josh O'Brien Avatar answered Oct 21 '22 19:10

Josh O'Brien