R smartly deciding about par-mfrow in a function

par, r

Solution

Getting the number of rows and columns for the device

The `n2mfrow()` was designed for this purpose, although it tends to vary rows faster than columns so is opposite of what you want. For example:

> n2mfrow(2)
[1] 2 1

indicates 2 rows by 1 column. Of course, `rev()` makes it easy to get the output you want:

> rev(n2mfrow(3))
[1] 1 3

Here is output from `n2mfrow()` for 2 to 16 total plots with columns varying faster:

t(sapply(2:16, function(x) rev(n2mfrow(x))))

> t(sapply(2:16, function(x) rev(n2mfrow(x))))
      [,1] [,2]
 [1,]    1    2
 [2,]    1    3
 [3,]    2    2
 [4,]    2    3
 [5,]    2    3
 [6,]    3    3
 [7,]    3    3
 [8,]    3    3
 [9,]    3    4
[10,]    3    4
[11,]    3    4
[12,]    4    4
[13,]    4    4
[14,]    4    4
[15,]    4    4

Making this interactive

For the "click after 16" bit. If doing your plotting in a `for(i in numplots)` loop, when `i` > 16 call `devAskNewPage(ask = TRUE)` and that will prompt for user to active next plot.

For example:

np <- 18 ## number of plots
rc <- ifelse(np > 16, 16, np)
op <- par(mfrow = rev(n2mfrow(rc)))
for(i in seq_len(np)) {
  if(i == 2) {
    devAskNewPage(ask = TRUE)
  }
  plot(1:10)
}
par(op)
devAskNewPage(ask = FALSE)

A similar thing could be done using `locator(1)` to force a click to move on post 16 plots, but it needs a bit more work:

np <- 18 ## number of plots
rc <- ifelse(np > 16, 16, np)
op <- par(mfrow = rev(n2mfrow(rc)))
for(i in seq_len(np)) {
  if((i %% 16) + 1 == 2 && i > 1) {
    message("Page filled. Click on device to continue...")
    locator(1)
  }
  plot(1:10)
}
par(op)

Problem

I want to print output, according to the amount of variables that have more than 10 unique values in a data-frame. This could be any number of variables. I am looking for a way to implement this as to set the plot window to be perfect for the amount of variables. It kind of should be like: - 2 vars -> 1 by 2 - 3 vars -> 1 by 3 - 4 vars -> 2 by 2 - 5 vars -> 2 by 3 - 6 vars -> 2 by 3 - ..... - ..... - 16 vars -> 4 by 4 - 16+ vars -> 4 by 4 Is there a logical formula for this; How to make this into a succesful `par(mfrow=(c(x,y)))`? Also, how to make sure when the par limit has been reached, to `click` for the next window, I can't click when I have more than 16, but instead just overwrites the previous graphs.

Original source