Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R smartly deciding about par-mfrow in a function

Tags:

r

par

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.

like image 394
PascalVKooten Avatar asked Dec 21 '22 10:12

PascalVKooten


1 Answers

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)
like image 155
Gavin Simpson Avatar answered Jan 22 '23 15:01

Gavin Simpson