Join Multiple R Rastervis levelplots - r

I have two rasterstacks, each with a common legend, that I want to put on a single plot with a space in between stacks. I want the raster images to be the same size within each block and across blocks. Is there an easy way to do this using Rastervis::levelplot. I believe the best way is too add a legend to grid.arrange object, as in this MWE
library(raster)
library(rasterVis)
s <- stack(
raster( matrix(runif(9),3,3)),
raster( matrix(runif(9),3,3)) )
gridExtra::grid.arrange(
levelplot(s, colorkey=FALSE, at=seq(0,1,length.out=11)),
levelplot(s, at=seq(0,1,length.out=11)),
ncol=2)
An even simpler solution would be to do this from within a single leveplot call

I think you are looking to do something like this:
levObj <- levelplot(s)
comb_levObj <- c(levObj, levObj, layout = c(4, 1), merge.legends = F)
print(comb_levObj)
But, a simpler solution would be:
s <- stack(s,s)
levelplot(s)

Related

Efficient way to plot multiple ggplots from list using gridextra?

I have generated a list containing 25 ggplot elements and I want to plot them all on one page. Since I couldn't find a way to use par() for ggplots, I used the package gridextra and specifically the function grid.arrange().
It comes in less handy than par() for base-R plots....My attempt was the following and I wonder if there is a more efficient way to write it?
Thanks in advance!
plot_collection <- grid.arrange(DBScan_plots[[1]], DBScan_plots[[2]], DBScan_plots[[3]], DBScan_plots[[4]], DBScan_plots[[5]],
DBScan_plots[[6]], DBScan_plots[[7]], DBScan_plots[[8]], DBScan_plots[[9]], DBScan_plots[[10]],
DBScan_plots[[11]], DBScan_plots[[12]], DBScan_plots[[13]], DBScan_plots[[14]], DBScan_plots[[15]],
DBScan_plots[[16]], DBScan_plots[[17]], DBScan_plots[[18]], DBScan_plots[[19]], DBScan_plots[[20]],
DBScan_plots[[21]], DBScan_plots[[22]], DBScan_plots[[23]], DBScan_plots[[24]], DBScan_plots[[25]],
nrow = 5,
ncol = 5)
grid.arrange works with lists of plots. Just specify it with grobs = .
In your case:
plot_collection <- grid.arrange(grobs = DBScan_plots, nrow = 5, ncol = 5)

rasterVis - setting the bottom plots in the middle with levelplot

I am using the awesome rasterVis to create a panel with maps that have the same extent (i.e. same spatial coverage) but that show different features (i.e. each with its own legend).
This is what it looks like so far:
library(raster)
library(rasterVis)
library(RColorBrewer)
library(gridExtra)
# make-up data
r <- raster(system.file("external/test.grd", package="raster"))
s <- stack(r, r*2, r*3, r*4, r*5)
names(s) <- paste0("Field ",seq(1,5))
# pre-allocate list
l <- vector("list", length=nlayers(s))
# define theme for plots
my.theme <- rasterTheme(region=brewer.pal(11,'RdYlGn'))
# loop over stack layers to fill list
for (n in (1:nlayers(s))){
l[[n]] <- levelplot(s[[n]], margin=F, main=names(s[[n]]), par.settings=my.theme)
}
# plot combined maps
grid.arrange(l[[1]], l[[2]], l[[3]], l[[4]], l[[5]], ncol=3)
Note that the default positioning for the maps is:
a b c
d e
However, I would like to have a finer control on the positioning. Specifically, I would like to "center" the bottom two facets in order to distribute the void space more evenly on the sides of the plot.
In other words, the placement I am looking for would look like:
a b c
d e
How can I achieve this? I looked up the documentation for (grid.arrange), but couldn't find any option the would solve my problem.
Thanks in advance for any hints.
Here's an approach with cowplot::plot_grid inspired by this answer
library(cowplot)
top <- plot_grid(l[[1]], l[[2]], l[[3]],
ncol=3)
bottom <- plot_grid(NULL, l[[4]], NULL, l[[5]], NULL,
ncol=6, rel_widths=c(0.12,0.34,0.12,0.34,0.06))
plot_grid(top, bottom,
ncol=1, rel_heights=c(1,1))
You can modify the rel_widths in the bottom plot_grid call to get it just like you like.
You can provide a layout with 6 columns and use NA for the blanks,
library(gridExtra)
p <- ggplot()
grid.arrange(grobs = list(p,p,p,p,p),
layout_matrix = rbind(c(1,1,2,2,3,3), c(NA,4,4,5,5,NA)))

Using a pheatmap in arrangeGrob

I'm attempting to plate two plots in the same .jpg using arrangeGrob().
I've only just started learning about grids and grobs and I think I know what the problem is: pheatmap is a grid object and containing grob objects, not allowing me to put it in arrangeGrob. Is this true?
Would I somehow need to put the qplot in a grid and the pheatmap in a grid and then put those grids in a new grid?
library(grid)
library(gridExtra)
library(pheatmap)
library(ggplot2)
hmdat=rbind(c(1,2,3),
c(3,4,5),
c(5,6,7))
hm=pheatmap(hmdat)
qp=qplot(1,1)
lm=rbind(c(1,2,2),
c(1,2,2))
jpeg("plots.jpg")
arrangeGrob(qp,hm, layout_matrix=lm)
dev.off()
The above code snippet runs just fine when using
arrangeGrob(qp,qp, layout_matrix=lm)
I'm not sure if you wanted to have 6 figures or you wanted to have two figures one with twice as wide as the other one (I tried to do minimum code change):
library("grid")
library("gridExtra")
library("pheatmap")
library("ggplot2")
hmdat=rbind(c(1,2,3),
c(3,4,5),
c(5,6,7))
hm <- pheatmap::pheatmap(hmdat)
qp <- qplot(1,1)
lm <- rbind(c(1,2,2),
c(1,2,2))
grid.arrange(grobs = list(qp,hm[[4]]), layout_matrix = lm)
which will give you:
The same way you can have multiple pheatmaps side-by-side:
library("grid")
library("gridExtra")
library("pheatmap")
hmdat <- rbind(c(1,2,3),
c(3,4,5),
c(5,6,7))
hm <- pheatmap::pheatmap(hmdat)
lm <- rbind(c(1,2),
c(3,3))
grid.arrange(grobs = list(hm[[4]],
hm[[4]],
hm[[4]]),
layout_matrix = lm)
As #hrbrmstr mentioned in the comment, you should use the 4th item in the pheatmap object. Also remember to provide grobs as list to the grid.arrange

contour plot of a custom function in R

I'm working with some custom functions and I need to draw contours for them based on multiple values for the parameters.
Here is an example function:
I need to draw such a contour plot:
Any idea?
Thanks.
First you construct a function, fourvar that takes those four parameters as arguments. In this case you could have done it with 3 variables one of which was lambda_2 over lambda_1. Alpha1 is fixed at 2 so alpha_1/alpha_2 will vary over 0-10.
fourvar <- function(a1,a2,l1,l2){
a1* integrate( function(x) {(1-x)^(a1-1)*(1-x^(l2/l1) )^a2} , 0 , 1)$value }
The trick is to realize that the integrate function returns a list and you only want the 'value' part of that list so it can be Vectorize()-ed.
Second you construct a matrix using that function:
mat <- outer( seq(.01, 10, length=100),
seq(.01, 10, length=100),
Vectorize( function(x,y) fourvar(a1=2, x/2, l1=2, l2=y/2) ) )
Then the task of creating the plot with labels in those positions can only be done easily with lattice::contourplot. After doing a reasonable amount of searching it does appear that the solution to geom_contour labeling is still a work in progress in ggplot2. The only labeling strategy I found is in an external package. However, the 'directlabels' package's function directlabel does not seem to have sufficient control to spread the labels out correctly in this case. In other examples that I have seen, it does spread the labels around the plot area. I suppose I could look at the code, but since it depends on the 'proto'-package, it will probably be weirdly encapsulated so I haven't looked.
require(reshape2)
mmat <- melt(mat)
str(mmat) # to see the names in the melted matrix
g <- ggplot(mmat, aes(x=Var1, y=Var2, z=value) )
g <- g+stat_contour(aes(col = ..level..), breaks=seq(.1, .9, .1) )
g <- g + scale_colour_continuous(low = "#000000", high = "#000000") # make black
install.packages("directlabels", repos="http://r-forge.r-project.org", type="source")
require(directlabels)
direct.label(g)
Note that these are the index positions from the matrix rather than the ratios of parameters, but that should be pretty easy to fix.
This, on the other hand, is how easilyy one can construct it in lattice (and I think it looks "cleaner":
require(lattice)
contourplot(mat, at=seq(.1,.9,.1))
As I think the question is still relevant, there have been some developments in the contour plot labeling in the metR package. Adding to the previous example will give you nice contour labeling also with ggplot2
require(metR)
g + geom_text_contour(rotate = TRUE, nudge_x = 3, nudge_y = 5)

grid.arrange with John Fox's effects plots

I'd like to combine multiple effect plots in one window with the effects package, but don't know if there is an easy way to do so.
Here's an example that doesn't work:
d1 <-data.frame(x1=rnorm(100,0:10),y1=rnorm(100,0:10),x2=rnorm(100,0:10),y2=rnorm(100,0:10))
require(effects)
require(gridExtra)
plot1 <- plot(allEffects(mod=lm(y1~x1,d1)))
plot2 <- plot(allEffects(mod=lm(y2~x2,d1)))
grid.arrange(plot1,plot2,ncol=2)
I think you need to collect the values of allEffects components and then plot them as an 'efflist'. It looked to me that the plotting was base-graphics, but it is in fact 'lattice' if you follow the class-function trail (or if you read: ?plot.efflist )
Try this:
ef1 <-allEffects(mod=lm(y1~x1,d1))[[1]]
ef2 <- allEffects(mod=lm(y2~x2,d1))[[1]]
elist <- list( ef1, ef2 )
class(elist) <- "efflist"
plot(elist, col=2)
Interestingly, the result from plotting an efflist (which is the result from allEffects) is not a lattice graphic; it instead builds up a multipanel graphic of lattice graphics using the print.lattice methods. However, if you plot the individual effects, either by taking the elements from allEffects or by using effect, then you do get lattice graphics.
Either like this
p1 <- plot(allEffects(m1)[[1]])
p2 <- plot(allEffects(m2)[[1]])
or like this.
p1 <- plot(effect("x1", m1))
p2 <- plot(effect("x2", m2))
These can be combined with grid.arrange; the catch is that their class is c("plot.eff", "trellis") which grid.arrange doesn't recognize, so they have to be made into simple trellis objects first.
class(p1) <- class(p2) <- "trellis"
grid.arrange(p1, p2, ncol=2)

Resources