Multiple plots are not rendered as described by layout.show - r

Using the raster package and its plot function, I want to arrange six plots of Raster* objects in 2 rows and 3 columns, by columns. Therefore I set up my layout like this:
layout(mat=matrix(1:6, nrow=2, ncol=3), heights=c(1,1), widths=c(2,1,1))
Calling layout.show(6) results in this preview, which is exactly what I want:
However, after the first plot being placed where the 1 is (as expected), the second plot is placed where the 3 is (not as expected). Why's that?
When I then call layout.show(6) again, I get this, which is NOT what I want:
Interestingly, using par(mfcol=c(2,3)) instead of layout also placed the plots by row (i.e. behaved like mfrow).
(I'm aware I could just rearrange the order of plot calls, but I want to know why this doesn't work as I expect it to.)

You cannot do this with plot(Raster*) as that sets the layout itself; thus overwriting your settings. Instead of plot(x) you could use image(x), but then you do not get a legend.
Perhaps the best approach is to use the terra package instead (terra is the replacement for raster)
f <- system.file("ex/elev.tif", package="terra")
r <- rast(f)
layout(mat=matrix(1:6, nrow=2, ncol=3), heights=c(1,1), widths=c(2,1,1))
plot(r)
plot(r*2)
plot(r*3)
plot(r*4)
plot(r*5)
plot(r*6)

Related

Drawing fixed number of graphs using par(mfrow())

I have the question following :
How can we divide our plots using par(mfrow()) with fixed number of subplots in one image ? e.g. I want for example to plot 10 graphs using par(mfrow=c(2,3)) but I want to have 5 in the first image and 5 in the second one, but the par(mfrow()) will divide them into 6:4.
How can we plot 5:5 instead od 6:4 ?
You could call plot.new. Its documentation even says:
This is [...] also useful for skipping plots when a multi-figure
region is in use.
par(mfrow=c(2,3))
for (i in 1:5) plot(i)
plot.new()
for (i in 6:10) plot(i)

How can I stop sapply dropping my barplot titles?

I'm wanting to make a barplot for the factor variables in my data set. To do this I've been running sapply(data[sapply(data, class)=='factor'],function(x) barplot(table(x))). To my annoyance, the plots remember their factor labels, but none of them have retained a title. How can I fix this without titling each graph by hand?
Currently, I'm getting humorously vague untitled graphs like this:
How about
## extract names
fvars <- names(data)[which(sapply(data,inherits,"factor"))]
## apply barplot() with main=
lapply(fvars, function(x) barplot(table(data[[x]]), main=x))
?
Example data:
data <- mtcars
for (i in c("vs","am","gear","carb")) data[[i]] <- factor(data[[i]])
Note that this creates all the plots at once. If you're working in a GUI with a plot history (RStudio or RGui) you can page back through the graphs. Otherwise, you might want to use par(mfrow=c(nr,nc)) (fill in number of rows and columns) to set up subplots before you start.
The numbers that are returned are the bar midpoints (see ?barplot): you could wrap the barplot() call in invisible() if you don't want to see them.

grid.arrange with QICharts

I am trying to arrange multiple charts from qicharts. With some work I got it so grid.arrange would do anything, but it just shows the last item as opposed to both.
library(qicharts)
library(grid)
library(gridExtra)
y <- rnorm(24, 12, 3)
a <- qic(y,chart="i")
b <- qic(y,chart="mr")
grid.arrange(grob(plot(a)),grob(plot(b)))
qicharts:::plot.qic suggests that it relies on base graphics, so the drawing happens immediately on the device and the plot itself is not stored. You could use base functions such as par(mfrow) to arrange multiple plots side by side, or convert those base graphics objects to grob e.g. with the gridGraphics package.
Alternatively, the trellis-based function tcc might produce similar output, and can be used with grid.arrange,
grid.arrange(tcc(rnorm(24)), tcc(rnorm(24)))

positioning plots and table

I would like to plot two histograms and add a table to a pdf file. With the layout function I managed to plot the histograms (plotted them using hist function) where I want them to be but when I used grid.table function from the gridExtra package to add the table the table is laid out on the histograms and I am not able to position them properly. I have tried addtable2plot function but I dont find it visually appealing.
Any thoughts on How do I get around this?
I want my pdf to look like this
histogram1 histogram2
t a b l e
Essentially, one row with two columns and another row with just one column. This is what I did.
require(gridExtra)
layout(matrix(c(1,2,3,3),2,2,byrow=T),heights=c(1,1))
count_table=table(cut(tab$Longest_OHR,breaks=c(0,0.05,0.10,0.15,0.20,0.25,0.30,0.35,0.40,0.45,0.50,0.55,0.60,0.65,0.70,0.75,0.80,0.85,0.90,0.95,1.00)))
ysize=max(count_table)+1000
hist(tab$Longest_OHR,xlab="OHR longest",ylim=c(0,ysize))
count_table=table(cut(tab$Sum_of_OHR.s,breaks=c(0,0.05,0.10,0.15,0.20,0.25,0.30,0.35,0.40,0.45,0.50,0.55,0.60,0.65,0.70,0.75,0.80,0.85,0.90,0.95,1.00)))
ysize=max(count_table)+1000
hist(tab$Sum_of_OHR.s,xlab="OHR Sum",ylim=c(0,ysize))
tmp <- table(cut(tab$Length_of_Gene.Protein, breaks = c(0,100,200,500,1000,2000,5000,10000,1000000000)), cut(tab$Sum_of_OHR.s, breaks = (0:10)/10))
grid.table(tmp)
dev.off()
Any help will be appreciated.
Ram
Here's an example of how to combine two base plots and a grid.table in the same figure.
library(gridExtra)
layout(matrix(c(1,0,2,0), 2))
hist(iris$Sepal.Length, col="lightblue")
hist(iris$Sepal.Width, col="lightblue")
pushViewport(viewport(y=.25,height=.5))
grid.table(head(iris), h.even.alpha=1, h.odd.alpha=1,
v.even.alpha=0.5, v.odd.alpha=1)
The coordinates sent to viewport are the center of the panel. Too see exactly where its boundaries are you can call grid.rect().

Producing statistics over levels

I've generated a set of levels from my dataset, and now I want to find a way to sum the rest of the data columns in order to plot it while plotting my first column. Something like:
levelSet <- cut(frame$x1, "cutting")
boxplot(frame$x1~levelSet)
for (l in levelSet)
{
x2Sum<-sum(frame$x2[levelSet==l])
}
or maybe the inside of the loop should look like:
lines(sum(frame$x2[levelSet==l]))
Any thoughts? I am new to R, but I can't seem to get a hang of the indexing and ~ notation thus far.
I know r doesn't work this way, but I'd like functionality that 'looks' like
hist(frame$x2~levelSet)
## Or
hist(frame$x2, breaks = levelSet)
To plot a histograph, boxplot, etc. over a level set:
Try the lattice package:
library(lattice)
histogram(~x2|equal.count(x1),data=frame)
Substitute shingle for equal.count to set your own break points.
ggplot2 would also work nicely for this.
To put a histogram over a boxplot:
par(mfrow=c(2,1))
hist(x2)
boxplot(x2)
You can also use the layout() command to fine-tune the arrangement.

Resources