R: plot grid objects using par(mfrow) - r

I would like to plot grid objects and base R objects on the same png. The package I am using (meta) uses the grid graphics system.
I would like to use mfrow for this if possible, as it is what I am using elsewhere.
If I plot:
png("test.png",width=297,height=210,units="mm",res=300)
par(mfrow=c(2,2))
plot(1,1)
plot(1,1)
plot(1,1)
plot(1,1)
dev.off()
Everything works fine.
However if I plot:
library(meta)
m <- metaprop(4:1, c(10, 20, 30, 40))
png("test.png",width=297,height=210,units="mm",res=300)
par(mfrow=c(2,2))
plot(1,1)
forest(m,new=F)
plot(1,1)
forest(m,new=F)
dev.off()
Things aren't right as the forest plots try to take up the whole page rather than being restricted to their corners.
Thanks in advance for your help

I bet it behaves similar to heatmap() plots, see here.
Possible example for a solution from the post (didn't test):
--snip // Citation (Dr Paul Murrell)--
library(gridGraphics)
grid.newpage()
pushViewport(viewport(0, .5, .5, .5, just=c("left", "bottom")))
grid.echo(function() { heatmap(test) }, newpage=FALSE)
popViewport()
pushViewport(viewport(.5, 0, .5, .5, just=c("left", "bottom")))
grid.echo(function() { heatmap(test) }, newpage=FALSE)
popViewport()
--snip--

Modifying this answer, you can combine them into a plot, but I think the margins and settings for forest() needs to be optimized so that the titles etc can be seen properly:
library(gridBase)
library(gridExtra)
layout(matrix(c(1,2),nrow=1),widths=c(1,3))
par(mar=c(2.5,2.5,2.5,2.5))
plot(1,1)
plot.new()
vps <- baseViewports()
pushViewport(vps$figure)
vp1 <-plotViewport()
forest(m,new=FALSE)
popViewport()

Related

Grid Graphics Representation Problem in R-Studio

I am working with that book and R-Studio. I tried to render a grid graphic as described in the book:
library(grid)
pushViewport(plotViewport(c(5, 4, 2, 2)))
pushViewport(dataViewport(pressure$temperature,pressure$pressure,name="plotRegion"))
grid.points(pressure$temperature, pressure$pressure,name="dataSymbols")
grid.rect()
grid.xaxis()
grid.yaxis()
grid.text("temperature", y=unit(-3, "lines"))
grid.text("pressure", x=unit(-3, "lines"), rot=90)
grid.edit("dataSymbols", pch=2)
upViewport(1)
grid.rect(gp=gpar(lty="dashed"))
downViewport("plotRegion")
grid.text("Pressure (mm Hg)\nversus\nTemperature (Celsius)",x=unit(150, "native"), y=unit(600, "native"))
When running that code, it looks like the following:
According to the book, the result should look like this
What do I wrong? Was also running dev.off() without any effect....
I have access to the dataset pressure

Get 2 plots and a vertical legend next to each other

I want to have two plots next to each other and a common legend for both.
Like This:
Plot 1 | Plot 2 | Legend
Unfortunately, the legend is plotted inside of the second plot...
This is my current approach:
par(mfrow=c(1,3))
plot(...)
plot.new()
plot(...)
legend("center", ...)
I thought with par(mfrow=c(1,3)) I would get one row with 3 columns of plots - so exactely the result I wanted to obtain.
Is the legend maybe not treated as a plot but as belonging to plot number 2 and so it is plotted with the same column?
You were close. legend needs a plot.new in front of it, if you want to have it as a "standalone" plot.
par(mfrow=c(1, 3))
plot(1:10)
plot(1:10)
plot.new()
legend("center", pch=1, legend=c("x", "y"))
Result
I hope this works for you as an example. Nevertheless, there are better libraries to be used such as ggplot2 or plotly.
par(mfrow = c(1, 2), oma = c(0, 0, 0, 2))
plot(hp~mpg, data=mtcars, col=cyl,pch=19)
plot(disp~wt, data=mtcars, col=cyl,pch=19)
legend(x=6, y=250, legend=as.numeric(levels(factor(mtcars$cyl))), pch=19, col= as.numeric(levels(factor(mtcars$cyl))) )

Can't get axis labels to show on r plot()

I'm working with the meuse dataset in the sp library in R and I'm just trying to obtain a simple plot of the meuse grid which highlights the different areas of flooding frequency. However, I can't seem to get the axis labels to display. I've tried using a par() statement beforehand but it doesn't appear to be doing anything?
data(meuse.grid) #in sp library
summary(meuse.grid)
str(meuse.grid)
coordinates(meuse.grid) = ~x+y
proj4string(meuse.grid)<-CRS("+init=epsg:28992")
gridded(meuse.grid)=TRUE
class(meuse.grid)
par(mar=c(10,10,4,2)+0.1,mgp=c(5,1,0))
plot(meuse.grid["ffreq"], scale.frac = 0.6,main="Flooding Frequency Class Map",
xlab="Easting",ylab="Northing",axes=TRUE)
Any suggestions?
You could use mtext as a fix, expand slightly outer margins oma in advance. You could also fix the title with this method.
par(mar=c(10,10,4,2) + 0.1, mgp=c(5,1,0), oma=c(2, 2, 2, 2))
plot(meuse.grid["ffreq"], scale.frac = 0.6,main="",
xlab="",ylab="",axes=TRUE)
mtext("Easting", side=1, line=3, font=2)
mtext("Northing", side=2, line=3, font=2)
mtext("Flooding Frequency Class Map", side=3, line=1, font=2, cex=1.2)
Try reducing the plot margins by setting par() before your plot() function. The default values are:
par(mar = c(5, 4, 4, 2) + 0.1)
where each number represents a side of the plot (bottom, left, top, right). setting the outer margins via par(oma) (in a similar way to above) might also help.

Nested layouts in R

I want to make a plot consisting of multiple plots consisting of multiple plots, say a 5x2 grid with three plots in each cell. To be more precise, what I need is not just one figure but finding a way of using my plotting function multiple times in a single plot.
I have written a function that uses layout to stack plots, with a common axis in outer margin. I actually need it for seqIplot and seqdplot functions from the TraMineR package, but as far as I understand the problem is not related to those, so here is a minimal working example with barplot.
stackedplot <- function(data){
layout(matrix(c(1:3), nrow=3))
par(mar=c(0,0,0,0), oma=c(4,1,1,1), mgp=c(3,0.5,0), cex=1)
barplot(data[[1]], axes=F, xlab="", ylab="", horiz=TRUE)
barplot(data[[2]], axes=F, xlab="", ylab="", horiz=TRUE)
barplot(data[[3]], axes=F, xlab="", ylab="", horiz=TRUE)
axis(1, at=c(0:10)/10, outer=TRUE)
mtext("Label", line=2, side=1)
}
stackedplot(list(1:10, 10:1, rep(1,10)))
What I would like to do is to then use something like layout again and use stackedplot for the grids of the layout, i.e. something like this (which, of course, does not work):
layout(matrix(c(1:2), nrow=1))
stackedplot(list(1:10, 10:1, rep(1,10)))
stackedplot(list(rep(1,10), 1:10, 10:1))
I have tried split.screen, with no success:
split.screen(c(1,2))
screen(1)
stackedplot(list(1:10, 10:1, rep(1,10)))
screen(2)
stackedplot(list(rep(1,10), 1:10, 10:1))
close.screen(all = TRUE)
I also tried grid package, but apparently it is not compatible with base graphics.
grid.newpage()
pushViewport(viewport(x=0, y=0, width=0.5, height=1,
default.units="native"))
print(stackedplot(list(1:10, 10:1, rep(1,10))), newpage=FALSE)
pushViewport(viewport(x=0.5, y=0, width=0.5, height=1,
default.units="native"))
print(stackedplot(list(rep(1,10), 1:10, 10:1)), newpage=FALSE)
After more research and some help I am now answering my own question in case it would be useful to someone else.
Nested layouts can be created with the grid package, which can be used for base graphics using the gridBase package. The function for the stacked plots is written as follows.
library(grid)
library(gridBase)
stackedplot <- function(data, main=""){
top.vp <- viewport(layout=grid.layout(nrow=5, ncol=1,
heights=unit(c(3, 1, 1, 1, 5),
c("lines", "null", "null", "null", "lines"))),
width=unit(0.9, "npc"))
title <- viewport(layout.pos.row=1, layout.pos.col=1, name="title")
p1 <- viewport(layout.pos.row=2, layout.pos.col=1, name="plot1")
p2 <- viewport(layout.pos.row=3, layout.pos.col=1, name="plot2")
p3 <- viewport(layout.pos.row=4, layout.pos.col=1, name="plot3")
xaxis <- viewport(layout.pos.row=5, layout.pos.col=1, name="xaxis")
splot <- vpTree(top.vp, vpList(title, p1, p2, p3, xaxis)) # Defining the hierarchy of the viewports
pushViewport(splot) # Creating viewports for plotting with the definitions of splot
upViewport() # Navigating up in the viewport tree
downViewport("plot1") # Navigating down in the viewport tree, searching for viewport "plot1"
grid.rect() # Plotting a rectangle (borders for the viewport)
par(plt=gridPLT(), new=TRUE) # Taking the dimensions of the viewport for a base graphics plot
# Adding plot to an existing plot
barplot(data[[1]], axes=FALSE, xlab="", ylab="", horiz=TRUE)
upViewport()
downViewport("plot2")
grid.rect()
par(plt=gridPLT(), new=TRUE)
barplot(data[[2]], axes=FALSE, xlab="", ylab="", horiz=TRUE)
upViewport()
downViewport("plot3")
grid.rect()
par(plt=gridPLT(), new=TRUE)
barplot(data[[3]], xlab="", ylab="", horiz=TRUE)
upViewport()
downViewport("xaxis")
grid.text("X label", y = unit(2, "lines"))
upViewport()
downViewport("title")
grid.text(main, y = unit(1, "lines"))
upViewport(2)
}
The function first describes a viewport (of 90% of the window's width) that is divided into a 5x1 grid of viewports with differing heights. Each viewport in the grid is given a name that can be later called. The tree of viewports (splot) is described with vpTree which defines the hierarchical structure of the viewports. After describing the viewports those are actually prepared for plotting with pushViewport.
Now each named viewport is first seeked and then opened for plotting with upViewport (which goes up in the viewport tree) and downViewport (which seeks for the requested viewport down in the viewport tree).
For plotting base graphics, gridPLT is needed here (alternatively gridFIG or gridOMI can be used, see the manual of gridBase for further info). After that any base graphics function can be used to plot into the current viewport.
After the requested plots, upViewport(2) is used to navigate back to the root (2 viewports up in the hierarchy).
Now the stackedplot function can be called multiple times in another grid as follows.
opar <- par(no.readonly=TRUE) # Saving graphical parameters
plot.new() # Needed for par(new=TRUE) in stackedplot()
multitop.vp <- viewport(layout=grid.layout(1,2), width = unit(0.95, "npc"))
pl1 <- viewport(layout.pos.col=1, layout.pos.row=1, name="A")
pl2 <- viewport(layout.pos.col=2, layout.pos.row=1, name="B")
vpall <- vpTree(multitop.vp, vpList(pl1,pl2))
pushViewport(vpall)
upViewport()
downViewport("A")
stackedplot(data=list(1:10,10:1,rep(10,10)),main="A")
upViewport()
downViewport("B")
stackedplot(data=list(10:1,rep(10,10),1:10),main="B")
upViewport(2)
par(opar) # Returning the graphical parameters saved earlier

How to remove the ticks from a grid.yaxis

I need to remove the ticks and major line from a generated axis using grid.yaxis.
According to ?grid.yaxis there is an "edits" parameter that will let me configure the "major", "ticks" and "labels".
However, I cant find how to use the edits parameter.
Here's some example code that will draw an axis in the center.
grid_test_axis <- function ()
{
grid.newpage()
vplayout <- function(x,y)
viewport(layout.pos.row=x,layout.pos.col=y)
pushViewport( viewport( layout=grid.layout( nrow=3, ncol=3, widths=c(1,1,1), heights=c(1,1,1)) ) )
pushViewport(viewport(layout.pos.col=1, clip="on"))
grid.rect(gp=gpar(fill="red"))
popViewport()
pushViewport(viewport(layout.pos.col=3, clip="on"))
grid.rect(gp=gpar(fill="brown"))
popViewport()
pushViewport(viewport(layout.pos.row=1,layout.pos.col=2))
grid.rect(gp=gpar(fill="yellow"))
popViewport()
pushViewport(viewport(layout.pos.row=3,layout.pos.col=2))
grid.rect(gp=gpar(fill="blue"))
popViewport()
pushViewport(viewport(layout.pos.row=2,layout.pos.col=2))
pushViewport(viewport(layout=grid.layout(nrow=1, ncol=2)))
pushViewport(viewport(layout.pos.row=1,layout.pos.col=2))
grid.yaxis(main=TRUE, at=seq(.1, .9, length=5))
popViewport(3)
}
I would like to just stay with the numbers, not the ticks or major line.
Thanks.
Try this:
grid.yaxis(name="ya", main=TRUE, at=seq(0.1, 0.9, length=5))
grid.remove(gPath("ya", "ticks"))
grid.remove(gPath("ya", "major"))

Resources