Problems with common legend in R - r

I am trying to combine legends of a series of 22 plots but I simply can't make it work.
My legend represents months and each plot is different, some have info in just some of the months.
So the final legend is showing only the legend of my first plot (that only has data in 2 months), and I have no other plot with data in all the months to be used for the legend to be complete.
Any way to fix this?
Trying this:
ggarrange(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12,
p13, p14, p15, p16, p17, p18, p19, p20, p21, p22,
ncol=6, nrow=4, common.legend = TRUE, legend="bottom")
https://oregonstate.box.com/s/gxgo93mpva9wdx9lcfem26cer8ixpcs8

for a better understanding of the obstacles, it is interesting that you provide some reproducible example, but by your text I think it is possible to understand the basics of your problem.
Recently I saw something similar, and managed to solve in a not so elegant way.
Perform the organization of all your plots without legend.
From p1 top22 with show.legend = FALSE for each 'row' (nrow) of your plot set. Then transform into grob.
library(cowplot)
obj1 <- cowplot::plot_grid(p1, ..., p6, align = "hv", nrow = 1)
obj2 <- cowplot::plot_grid(p7, ..., p12, align = "hv", nrow = 1)
obj3 <- cowplot::plot_grid(p13, ..., p18, align = "hv", nrow = 1)
obj4 <- cowplot::plot_grid(p19, ..., p22, NULL, NULL, align = "hv", nrow = 1)
g1grob <- ggplot2::ggplotGrob(obj1)
g2grob <- ggplot2::ggplotGrob(obj2)
g3grob <- ggplot2::ggplotGrob(obj3)
g4grob <- ggplot2::ggplotGrob(obj4)
You can continue to use ggarrange, but not necessarily mind you need to share the legend. I suggest observing the plot_grid function of the cowplot package, using the align = "hv" argument (link).
You need to create an object (objx) so that it has the most complex caption possible, addressing all your points of interest. For from this object you should get its caption using the cowplot package with the get_legend (link) function.
objx <- ggplot2::ggplot(df) +
... +
theme(legend.position = "bottom")
legend <- cowplot::get_legend(objx)
Once this is done, it is only necessary to unite the objects of interest, the plot (obj) and the legend (legend).
lay <- rbind(c(1, 1, 1, 1, 1, 1),
c(2, 2, 2, 2, 2, 2),
c(3, 3, 3, 3, 3, 3),
c(4, 4, 4, 4, 4, 4))
plot_leila <- gridExtra::grid.arrange(g1grob, g2grob, g3grob, g4grob,
layout_matrix = lay)
lay <- rbind(c(rep(1,12)),
c(2))
plot_leila <- gridExtra::grid.arrange(plot_leila, legend,
layout_matrix = lay)
plot_leila
Eventual misalignments can occur, but with patience and testing the packages you will surely get a good result.

Related

R - How to remove 'seperation' line and backround borcers in single plot / multi-plot grids

This is driving me nuts. Have two ggplot objects p and q and use the elegant cowplot::plot_grid function to combine both plots in said grid. However I do get a kind of separation line between the two arranged plots. I use the code below.
library(ggplot2)
library(cowplot)
comb <- plot_grid(p, q, labels = c('A', 'B'),
nrow = 2, ncol = 1,
align = "h",
label_fontfamily = "serif",
greedy = TRUE,
label_size = 12)
comb <- comb + panel_border(remove = TRUE)
save_plot("plot_combined.pdf", comb)
My questions are the following:
How can I remove the separation line?
How can I increase the 'spacing' between the two plots to avoid having the label interfere with the y axis title?
The trick was to adjust my theme as following:
p + theme(plot.background = element_blank()) # This did the trick for me!
You might look at the ggarrange function in the "ggpubr" package. I find it more user friendly than cowplot.
library(ggpubr)
ggarrange(p, q, ncol = 1, nrow = 2, labels = "AUTO")

Ploting 3 maps in 2 rows using R tmap package

I'm trying to save a plot using 3 maps made by the tmap package, with the larger one at the top, and the other 2 at the bottom like the example above:
But using tmap_arrange() provided by the package for this kind of procedure, it gives me the followig:
data(World)
p1 <- tm_shape(World)+tm_polygons()
p2 <- tm_shape(World[World$continent=='South America',])+tm_polygons()
p3 <- tm_shape(World[World$name=='Brazil',])+tm_polygons()
tmap_arrange(p1,p2,p3,nrow=2)
I've tried to use many options, like export the maps as images and then import again to R to compose a full image using par() and/or split.screen(), but also doesn't work properly.
There is any way to work around this and get the wanted result?
Thanks in advance!
One hackish way would be to use the grid package functionality. Grab the output of each plot/map and store it as a gTree object and then try to arrange the new objects in a grid.
library(tmap)
library(cowplot) # for plot_grid() function - good to arrange multiple plots into a grid
library(grid)
library(gridGraphics)
data(World)
tm_shape(World) + tm_polygons()
g1 <- grid.grab()
tm_shape(World[World$continent == 'South America', ]) + tm_polygons()
g2 <- grid.grab()
tm_shape(World[World$name == 'Brazil', ]) + tm_polygons()
g3 <- grid.grab()
# Try to arrange the plots into a grid using cowplot::plot_grid().
# First bind the p2 and p3 as one plot;
# adjust distance between them by forcing a NULL plot in between.
p23 <- plot_grid(g2, NULL, g3, rel_widths = c(1, -0.7, 1), nrow = 1)
plot_grid(g1, p23, nrow = 2, scale = c(0.8, 1))
I could not figure it out how to make it respond to the align argument though :/ But maybe this puts you in some exploring direction or others can edit/improve this answer.
# Save the plot
ggsave(filename = "tmap-arrange-grid-1.png",
width = 10, height = 6, units = "cm", dpi = 150)
Note that, initially I thought that I could explore with adding a NULL object to tmap_arrange like tmap_arrange(p1, NULL, p2, p3, nrow = 2), but unfortunately, it does not accept it.
Another approach, inspired from this related question could be something along these lines:
library(grid)
grid.newpage()
pushViewport(viewport(layout = grid.layout(nrow = 2, ncol = 2)))
print(p1, vp = viewport(layout.pos.row = 1, layout.pos.col = 1:2))
print(p2, vp = viewport(layout.pos.row = 2, layout.pos.col = 1))
print(p3, vp = viewport(layout.pos.row = 2, layout.pos.col = 2))
Again, here, I didn't have the time to explore with aligning the plots perfectly, but others might improve this answer.

Elegantly combining continuous and factor rasters

When plotting a mixture of continuous and factor rasters with rasterVis::levelplot using print(..., more=TRUE), the height and width of the panels is inconsistent. This seems to be due to differences in the width of the colorkey (legend), and the colorkey's tick labels.
For example:
library(raster)
library(rasterVis)
r1 <- raster(matrix(runif(100), 10))
r2 <- as.factor(raster(matrix(rbinom(100, 1, 0.8), 10)))
levels(r2)[[1]]$name <- c('gray', 'lightblue')
p1 <- levelplot(r1, margin=FALSE, scales=list(draw=FALSE),
at=seq(0, 1, length.out=100))
p2 <- levelplot(r2, scales=list(draw=FALSE),
col.regions=c('gray90', 'lightblue'))
print(p1, split=c(1, 1, 1, 2), more=TRUE)
print(p2, split=c(1, 2, 1, 2))
Is there a way to modify the trellis graphical parameters (e.g., layout widths/heights?) to achieve consistently sized plots, such that it looks more like the layout used when plotting a RasterStack?
Or is there an alternative way of combining these rasters, which would scale to layouts with multiple columns as well as multiple rows? (Other plotting frameworks are fine, but base plot doesn't readily support factor rasters.)
You can use ?c.trellis function from the latticeExtra package.
library(latticeExtra)
c(p1, p2, layout = c(1, 2), merge.legends = TRUE)
However, in your case the legend overlaps slightly. If the order of the plots is not relevant you can instead use
c(p2, p1, layout = c(1, 2), merge.legends = TRUE)
Alternatively you can add some space to your first plot as follows.
p1 <- levelplot(r1, margin=FALSE, scales=list(draw=FALSE),
at=seq(0, 1, length.out=100),
par.settings = rasterTheme(layout.widths = list(key.right = 1.5)))
c(p1, p2, layout = c(1, 2), merge.legends = TRUE)

Plotting figures using 'par(mfrow=c())' in R

I have 3 figures of which I would like to plot in the same place in R. I would like to have 2 columns, which would make the 3rd figure plotted alone in the second row. Using par(mfrow=c(2,2)) functions in R, is there a way to have the bottom figure plotted in the centre of the plot, as opposed to underneath the top figure?
I don't think you can do this using par(mfrow = ...)
However, you can use layout().
Try this:
par(mai=rep(0.5, 4))
layout(matrix(c(1,2,3,3), ncol = 2, byrow = TRUE))
plot(1:10)
plot(1:20)
plot(1:30)
So you can see the idea is to create a matrix where each cell indicates which graph to plot. You can extend the logic as follows:
par(mai=rep(0.5, 4))
layout(matrix(c(1,1, 2,2, 0, 3,3, 0), ncol = 4, byrow = TRUE))
plot(1:10)
plot(1:20)
plot(1:30)

controlling the inner figure margin within grid.layout

I'm trying to plot multiple lattice plots in a grid.
To do so I'm using the following code:
plot <- xyplot(1:10~1:10)
page.layout <- grid.layout(nrow = 2, ncol = 1,
widths = unit(c(1), "null"),
heights = unit(c(1), "null"),
default.units = "null",
respect = FALSE,
just = "centre")
pushViewport(viewport(layout = page.layout))
pushViewport(viewport(layout.pos.row = 1))
par(mar = c(5, 4, 4, 2))
print(plot, newpage = FALSE)
popViewport()
pushViewport(viewport(layout.pos.row = 2))
par(mar = c(5, 4, 4, 2))
print(plot, newpage = FALSE)
popViewport()
I'd like now to reduce the space between the two figure, I read in the vignette for gridBase, that simple graphic controls, such has par(mar=c()) should be working, but it is not the case here.
Maybe I'm missing something obvious, but I can't figure out, why I can't control the margin parameters.
Any suggestions?
lattice provides some options to control the plot margins,
p <- xyplot(1:10~1:10,
par.settings=list(layout.heights=list(top.padding=-3, bottom.padding=-1)))
library(gridExtra)
grid.arrange(p, p, nrow=2)

Resources