Nested mfrow and layout - r

I have a plotting function that just uses base graphics to draw a two-pane plot, using layout. What I would like is to iterate through thousands of objects, and save the plots to a .pdf file, with three of the two-pane plots per page.
Quick dummy example:
examplefunc <- function() {
layout(mat = matrix(1:2, nrow = 1), widths = 3:4, heights = 3)
plot(0)
plot(0)
}
pdf("exmaple.pdf", height = 10, width = 8)
par(mfrow = c(3,1)) # Also tried using layout here.
examplefunc()
examplefunc()
examplefunc()
graphics.off()
The output is a three page .pdf, rather than the desired one page .pdf with three figures. I'd like to keep using layout to get the proportions of the figures correct.

As the help page for layout says, it is incompatible with par(mfrow and other forms of multiple plotting and using layout overrides instead of nests a previous call to layout. So this will be very difficult.
The simplest approach would be to remove the call to layout from the function and set up the grid of 6 panels outside the function. If you wrote the function then that is straight forward, but if using a function from a package then this becomes more difficult. You can either create your own version of the function without layout or some functions have options to only plot one of their plots (and you would just call it multiple times).
Another approach would be to set the pdf file to have 1/3rd the usual height and plot each pair to one page, then use an external tool to combine sets of 3. Tools like Imagemagick or pdftk may help.

Each time you call layout or par you create a new plotting window. Instead, you should only call layout once. For example,
examplefunc <- function() {
plot(0); plot(0)
}
Then
pdf("/tmp/exmaple.pdf", height = 10, width = 8)
layout(mat = matrix(1:6, ncol = 2, byrow=T), widths = 3:4, heights = c(3, 3, 3))
examplefunc()
examplefunc()
examplefunc()
graphics.off()
You can see the layout of the plots via
layout(mat = matrix(1:6, ncol = 2, byrow=T),
widths = 3:4, heights = c(3, 3, 3))
layout.show(6)

Related

Replay recorded plot with new layout in R

I am trying to create and record plots in a 1x1 device:
par(mfrow = c(1, 1) )
plot(rnorm(10) )
p1 <- recordPlot()
plot(rnorm(20) )
p2 <- recordPlot()
and then to put them in a new layout (e.g., a 1x2 device):
par(mfrow = c(1, 2) )
p1
p2
However, this produce the same effect (i.e., plotting each plot in a 1x1 device). It seems replaying plots uses the original layout (graphical parameters) that was in effect when they were recorded.
Is there some method that allows a saved plot to be replayed in a new layout ?
NB: I am aware this would be easier via ggplot2, but my question is about base plots.
I did some digging, and I don't think this is possible. I used the following to look at what attributes are available inside the object. None of them seemed to indicate the layout could be adjusted.
summary(p1)
p1[[1]]
p1[[2]]
If you need the same plot across two different layouts could you use set.seed() to recreated the same plot? See the example below.
par(mfrow = c(1, 1))
set.seed(1234)
plot(rnorm(10))
par(mfrow = c(1, 2))
set.seed(1234)
plot(rnorm(10))
I'd be interested to see if anyone else has a better answer!

R: Print ggplots and matrices to panels in PDF?

I'm creating a multipage PDF, where each page should contain 2 graphs (ggplot2) and 2 matrices. Previously, I was using plot(), where the code and PDF layout for each page was something like this:
pdf("Rplots.pdf", paper = "letter", width = 7.5, height = 10)
layout(matrix(c(1,1,2,4,3,3),3,2, byrow = TRUE), heights = c(7,4,7))
# Plot at the top of each page
plot(dataTop)
# Summary at the bottom of each page
summary <- matrix(dataTop, ncol = 2, nrow = 6)
textplot(summary)
# Plot at the top of each page
plot(dataBottom)
# Summary at the bottom of each page
summary <- matrix(dataBottom, ncol = 2, nrow = 6)
textplot(summary)
dev.off()
I've replaced the plot() with ggplot() and have trouble getting it to print using the same panel layout.
1) Is there any simple way to print a combination of ggplots and matrices using the type of layout I have above?
2) Is there some way to ensure the ggplot is confined/expanded to some certain amount of space on the PDF?
Thank you!

to display two heatmaps in same pdf side by side in R

i am trying to display two or more heatmaps side by side in the same png or pdf . The layout or mfcol is not working in the case. Can someone please help me out with this.
Here's one option using the recently introduced gridGraphics package,
library(gridGraphics)
library(grid)
heatmap(as.matrix(mtcars))
library(gridGraphics)
grab_grob <- function(){
grid.echo()
grid.grab()
}
g <- grab_grob()
grid.newpage()
# library(gridExtra)
# grid.arrange(g,g, ncol=2, clip=TRUE)
lay <- grid.layout(nrow = 1, ncol=2)
pushViewport(viewport(layout = lay))
grid.draw(editGrob(g, vp=viewport(layout.pos.row = 1,
layout.pos.col = 1, clip=TRUE)))
grid.draw(editGrob(g, vp=viewport(layout.pos.row = 1,
layout.pos.col = 2, clip=TRUE)))
upViewport(1)
As stated in the help document for heatmap.2,
'heatmap.2()' uses 'layout' and draws the 'image' in the lower
right corner of a 2x2 layout. Consequentially, it can not be
used in a multi column/row layout, i.e., when 'par(mfrow= *)' or
'(mfcol= *)' has been called.
The same is true for heatmap.
Here's a way of doing that. It is very hacky but I think that when a function doesn't do what you want to do the best solution is to make it do it anyway.
Function heatmap.2 contains the following three lines at mid-way through its code:
...
op <- par(no.readonly = TRUE)
on.exit(par(op))
layout(lmat, widths = lwid, heights = lhei, respect = FALSE)
...
It is because of them that you can't use layout and par(mar=...) since it overrides it.
Copy the code of heatmap.2 into a new function (say heatmap.3) and remove those three lines:
heatmap.3 <- function(... #etc etc with the exact same code minus those 3 lines
Then your code to produce your two heatmaps side by side will be, for instance:
layout(rbind(c(4,3,8,7),c(2,1,6,5)),
widths = c(1,2,1,2), heights = c(1,2), respect = FALSE)
heatmap.3(x)
heatmap.3(y)
When preparing your layout remember that the heatmap code plot first the heatmap itself, then the "row" dendrogram, then the "col" dendrogram and finally the histogram, hence the order from top to bottom, left to right is 4, 3, 2, 1 meaning when both heatmap are side by side it becomes 4, 3, 8, 7, 2, 1, 6, 5.
After having exactly the same problem, I came up with the following solution:
1) Use ggplot2 to make your heatmap with dendrogram like here: Reproducing lattice dendrogram graph with ggplot2 and then arrange it with multiplot() function (http://www.cookbook-r.com/Graphs/Multiple_graphs_on_one_page_%28ggplot2%29/)
2) However, this is a lot of work and I wanted to stick with the base heatmap() function. The following is easy (though not plain R) and works on Linux if you have imagemagick installed:
m <- matrix(runif(10^2), ncol=10)
for (i1 in 1:4) {
ifile <- paste0(i1,'_heatmap.pdf')
pdf(ifile)
heatmap(m)
d <- dev.off()
}
system('montage -geometry 100% -tile 2x2 ./*_heatmap.pdf outfile.pdf')

R par(omd) does not contain within mfrow

I would like two plots to show up in two seperate spaces in the plot so I do:
par(mfrow=c(1,2))
plot(1:10,1:10)
Now I would like the second plot to be about 25% shorter than the first plot so I adjust omd:
tmp <- par()$omd
tmp[4] <- 0.75
par(omd=tmp)
plot(1:10,1:10)
The problem is that the second plot shows up ontop of the first plot. How do I avoid this margin issue?
Maybe try using layout instead?
layout(matrix(c(1, 1, 0, 2), ncol = 2L), widths = c(1,1),heights = c(0.5,1))
par(mar = c(3,2,2,2))
plot(1:10,1:10)
par(mar = c(3,2,2,2))
plot(1:10,1:10)
I guess maybe you'd want to set the heights to c(0.2,0.8) to get a 25% reduction?
Edit
But I don't think that omd does what you think it does. It changes the region inside the outer margins, which will always include both plot regions when setting par(mfrow = c(1,2)). What you really want to change, I think is plt, which alters the size of the current plotting region (using quartz, as I'm on a mac):
quartz(width = 5,height = 5)
par(mfrow=c(1,2))
vec <- par("plt")
plot(1:10,1:10)
par(plt = vec * c(1,1,1,0.75))
plot(1:5,1:5)

How to put two 'vcd' grid graphics in a single plot?

I would like to place two (somewhat non-standard) grid graphics in a single plot in R.
Try:
require(vcd)
mosaic(Titanic)
assoc(Titanic)
The trouble is that these aren't lattice graphics, and to my knowledge do not come with a layout argument or similar. And since these are grid graphs, they're impervious to base graph tricks like par(mfrow=c(1,2)).
How can I place the two graphs above in a single plot, with both graphs on the same line?
I already tried the suggestions in How to plot grid plots on a same page?, but they don't seem to work for vcd plots. Ultimately I would like to obtain something similar to:
Neither plot seems to return any object and I cant see how to grab the grobs from looking at grid.ls(). So using the idea from this answer
library(vcd)
library(gridGraphics)
library(gridExtra)
mosaic(Titanic)
m <- grid.grab()
assoc(Titanic)
a <- grid.grab()
grid.newpage()
grid.arrange(m, a, ncol=2)
Im sure there will be a more grid-like approach but ...
Something similar to the solution in How to plot grid plots on a same page? can also be used for vcd displays. The difference is that you need to set newpage = FALSE (to prevent opening a new display) and you need to push and pop the viewport yourself (which can be handy when re-using vcd graphics in more complicated displays such as partykit trees).
The mosaic and association display for the Titanic data can be visualized as:
grid.newpage()
pushViewport(viewport(layout = grid.layout(1, 2)))
pushViewport(viewport(layout.pos.col = 1, layout.pos.row = 1))
mosaic(Titanic, newpage = FALSE)
popViewport()
pushViewport(viewport(layout.pos.row = 1, layout.pos.col = 2))
assoc(Titanic, newpage = FALSE)
popViewport()
yielding
Another option is vcd’s mplot() function (for details, see ?vcd::mplot):
library(vcd)
mplot(
mosaic(Titanic, return_grob = TRUE),
assoc(Titanic, return_grob = TRUE),
keep_aspect_ratio = FALSE
)

Resources