4

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.

PascalVKooten
  • 20,643
  • 17
  • 103
  • 160
  • I am not really understanding what you want to achieve. It sounds like you would like to facet a plot? If so, you could [use ggplot2](http://wiki.stdout.org/rcookbook/Graphs/Facets%20%28ggplot2%29/). – Roland Jan 25 '13 at 13:18
  • @Roland Not all functions/packages use **ggplot2** for their plotting and faceting is not the same as what `mfrow` does to the plot device. – Gavin Simpson Jan 25 '13 at 13:30
  • 1
    None of the answers below seem to address the question of using a click to proceed to the next plot when the plot number is >16. – Marc in the box Jan 25 '13 at 13:40
  • @GavinSimpson I am well aware of that and often use base graphics myself. But as I said, I don't even understand the question. The first sentence could mean a lot of things. – Roland Jan 25 '13 at 13:51
  • @Marcinthebox You can't easily do that. `locator(1)` in a loop called if loop index > 16, 32 etc will force user to click plot. `devAskNewPage()` can be used for a prompt in the console. – Gavin Simpson Jan 25 '13 at 13:58
  • @Marcinthebox I've updated my answer along the lines I mentioned above. Easier than I thought... – Gavin Simpson Jan 25 '13 at 14:55
  • @GavinSimpson - looks great Gavin. Didn't realize that `locator`could be used. I knoew there must be something out there along the lines of `devAskNewPage` but couldn't find it. Thanks! – Marc in the box Jan 25 '13 at 15:44
  • Why did the answer get five upvotes and the question just one? – PascalVKooten Jan 25 '13 at 20:52

1 Answers1

11

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)
Gavin Simpson
  • 170,508
  • 25
  • 396
  • 453
  • It might even be that not using `rev()` should be preferred. I'll have to think about it. – PascalVKooten Jan 25 '13 at 13:33
  • if you want regions with unequal size `layout()` function provides an alternative.. – agstudy Jan 25 '13 at 13:36
  • I got the devAskNewPage working. In my case I had to subtract the cases of the for loop integer `i - the amount of ordinal variables %% 16 == 0`. – PascalVKooten Jan 25 '13 at 15:04
  • @Dualinity with `devAskNewPage()` you only need to call it once as it only affects a new page of the device not a plot window. See my updated Answer - you only need to turn it on after plot 1 is done. If you set it before the loop, then you get asked before the first plot is drawn which is not what we want. – Gavin Simpson Jan 25 '13 at 15:08
  • @GavinSimpson Gotcha. Changed to: `if ((i - ord) == 16) {devAskNewPage(ask = TRUE)}` (within the loop) – PascalVKooten Jan 25 '13 at 15:16
  • I used this now for some time, but I am not satisfied. I would like it to continue running the code, so I would like it to process everything and not wait. Only the plot window should wait. Do you know if that's possible? – PascalVKooten Feb 01 '13 at 10:33
  • @Dualinity No, that isn't possible to the best of my knowledge as R doesn't return control until you've clicked etc. You could use the plot history mechanism, draw all plots and then page back through them. But that is another Question. – Gavin Simpson Feb 01 '13 at 11:30