R ggarrange how to include upper scripts in the plot titles? - r

I am trying to add plot labels as titles in plots merged by ggarrange. My label contains parantheses and substricpts. I have found that using expression('My volume [m'^3*'/ha]') I can handle both, which works perfectly if placed as x or y label (ylab(expression('My volume [m'^3*'/ha]'))).
However, when using the same approach using ggarrange to combine different plots, and wishing to name them a) and b), the naming prints quotes as well:
How can I correctly write the expression, or using paste('..', '..') approach that quotes are not visible?
Dummy example to create several plots and plot them using ggarrange:
p1 <- ggplot(cars, aes(x=speed, y=dist)) + geom_point() + geom_smooth()
p2 <- p1
ggarrange(p1, p2,
nrow = 2, ncol = 1,
common.legend = TRUE,
legend="bottom",
labels=list(paste("a) ", 'My rate [%]'),
paste('b)', expression('My volume [m'^3*'/ha]'))), # How to change this???
align = c("hv"),
font.label = list(size = 10,
face = "plain",
color ="black"))
Wrong labeled output b:

Finally, I have found my answer based on this post. This works when replacing titles, but I bet it would work for ggarrange as well. Important it that it works with paranteses and a superscript.
p1 + ggtitle(expression(paste("a) ", "volume [m"^3, "/ha", "]")))

Related

Problems with positioning of ggplot labels with ggarrange

I'm trying to create a panel of plots using ggarrange. I'm using the "labels" argument to create a title for each one, but the positioning is coming out differently for each plot depending on how long the title is. It seems that the longer the title, the further to the right the label gets printed.
How can I make all labels left-justified? I've tried using hjust or label.x, but this doesn't change things.
This is my code and the plot:
ggarrange(plot1,plot2,plot3,
common.legend=TRUE,
labels = c("asdf", "asdfasdf", "asdfasdfasdfsadfasdf"),
hjust=-0.8,
ncol = 2, nrow = 2)
I am not sure whether this is the short-cut to your question but trying this may help :
plot1 <- plot1 + theme(legend.position="left")+
labs(title="asdf")
plot2<- plot2 + theme(legend.position="left")+
labs(title="asdfasf")
plot3 <- plot3 + theme(legend.position="left")+
labs(title="asdfasdfasfdsas")
ggarrange(plot1,plot2,plot3,
common.legend=TRUE,
hjust=-0.8,
ncol = 2, nrow = 2)
You can check: https://www.royfrancis.com/customising-ggplot2/
In my opinion, you may use geom_text() to set the label first for every plot, then use ggarrange() to put all subfigures together.
hjust works for horizontal shift and vjust for vertical. In my case, I kept hjust=-7 to keep the labels in the middle, and it worked. You have to try it based on your data.

ggsave cuts of part of the common legend created with ggarrange

I am trying to generate multiple plots from my data by using lapply and then arranging the resulting list with ggarrange. When I try to save the final figure with ggsave part of the legend text is cut off in the png.
First I define what I want to plot along with Plot titles and colors
main.overview <- list(
c("AA", "AA", "black"),
c("X5.HETE", "5-HETE", "red"),)
I then define a function to generate the plots.
plot.overview = function(data, mediator) {
analyte <- mediator[[1]]
name <- mediator[[2]]
color <- mediator[[3]]
ggplot(data = data, aes_string(x="Compound",y=analyte)) +
geom_boxplot(aes(fill=Compound)) +
labs(title=name) +
scale_fill_brewer(palette="Reds") +
theme_classic() +
theme(plot.title = element_text(hjust = 0.5, color = color),axis.title.x = element_blank(),axis.title.y = element_blank())}
Finally I call the function and arrange the plots into a figure
myplots <- lapply(main.overview, plot.overview, data=lm)
arrange <- ggarrange(plotlist = myplots, common.legend = TRUE, nrow=1, legend = "right")
figure <- annotate_figure(arrange, left = text_grob(expression(10^6~cells), rot=90))
ggsave("overview.png", dpi="print", device="png",plot=figure, height=10, width=30, units="cm")
In the final png however the common legend i put on the right is cut off.
EDIT:
I have figured out part of the problem, the problem only occurs on my desktop-pc and not on my laptop, so it might be a problem with additional packages or versions of the R libraries

Adjust spacing between subplots of panel figure (ggplot) in case of different axis.title/text properties

I would like to adjust the spacing between plots that are aligned in a panel using the cowplot package when some plots contain axis titles/labels, and others don't.
Example
Let's create three plots:
library(tidyverse)
library(cowplot)
set.seed(123)
df <- data.frame(x = rnorm(n = 100),
y = rnorm(n = 100))
plot <- ggplot(data = df, aes(x, y)) + geom_point()
plot_grid(plot, plot, plot, nrow = 1, align = "vh")
These plots are aligned perfectly! But often, I have a scenario in which I would like to create a 'cleaner' panel figure. One way to do this is to remove the titles/text of the y-axis of the second and third plots.
Like this:
plot2 <- plot + theme(axis.title.y = element_blank(),
axis.text.y = element_blank())
plot_grid(plot, plot2, plot2, nrow = 1, align = "vh")
Again, perfectly aligned, but the spacing between the first and the second plot (and the second and third plot) is quite large. I would like to reduce the spacing to create a more compact plot, while the axis remain exactly the same size.
Expected output
Is this possible with cowplot? Or is there another way to do this?
Referencing this post on github, plot_grid() doesn't add any space by default and uses the margins of your plot. To remove the space outside your plot area, you can use them(plot.margin=...) to remove.
With that being said... that's not what's going on here! Printing either plot or plot2 will yield a plot with no margins. It appears the issue is with the use of the align= argument in plot_grid(). I'm not sure why, but setting it to anything other than the default values (align="none") results in the extra whitespace around the plots. Very strange... needless to say, removing that argument fixes your problem:
Original code using align="vh"
plot_grid(plot, plot2, plot2, nrow = 1, align="vh")
Using align="none"
plot_grid(plot, plot2, plot2, nrow = 1, align="none")
Any further space would be added according to your graphics device, since the actual plot you get depends on the size and resolution of that device.
Here is a solution using the patchwork package
library(tidyverse)
set.seed(123)
df <- data.frame(x = rnorm(n = 100),
y = rnorm(n = 100))
plot1 <- ggplot(data = df, aes(x, y)) + geom_point()
plot2 <- plot1 + theme(axis.title.y = element_blank(),
axis.text.y = element_blank())
# install.packages("patchwork", dependencies = TRUE)
library(patchwork)
plot1 + plot2 + plot2 +
plot_layout(ncol = 3)
Created on 2020-07-24 by the reprex package (v0.3.0)

add title using grid.arrange for multiple plots made with gridExtra::grid.arrange

I have to use gridExtra::grid.arrange for plotting several plot besides eachother because of the package I am using to create the fit for the plot.
I have to create a title for the plot using grid.arrange.
Now I want to combine the two, but cannot figure out how. So: I want to plot several figures besides eachother and give them all have a different title.
I have euler1 and euler2 as fits tat represent my data in an euler diagram.
for plotting 2 plots besides eachother this code works for me:
gridExtra::grid.arrange(plot(euler1),plot(euler2))
for giving a single plot a title, this code works for me:
plot1 <- plot(euler1)
grid.arrange(grobs = list(plot1), top = "Title 1")
Now, I would like to combine the two codes.
How can I do it?
I tries for example (but doesn't work):
plot1 <- plot(euler1)
plot2 <- plot(euler2)
gridExtra::grid.arrange(plot1, plot2, grobs = list(plot1, plot2), top = list("Title 1","Title 2"))
Kinds regards,
Judith
Typically you'd add titles to the plot themselves, as in
p1 = ggplot() + ggtitle('plot 1')
p2 = ggplot() + ggtitle('plot 2')
grid.arrange(grobs = list(p1, p2), top = "Global Title", ncol=2)
but if you prefer to use grid.arrange's top argument for the titles, you can nest them,
p = ggplot()
grid.arrange(arrangeGrob(p, top = 'title 1'), arrangeGrob(p, top = 'title 2'), top = "Global Title", ncol=2)
I figured out how to do it, since the use of main in plot was fixed for the eulerr package. Now I can use:
gridExtra::grid.arrange(plot(euler1, main = 'title1'),
plot(euler2, main = 'title2'))
Thanks everyone for the feedback.

directlabels: using different positioning methods for different panels in the same plot

I have a two-panel lattice lineplot. I want to use the directlabels package to automatically label the lines in each plot. But I want to use a different positioning method for each plot. Specifically, I want to use the first.bumpup method for the first panel, and the last.bumpup method for the second panel. Here is a minimal example:
library(directlabels)
library(lattice)
myDF <- data.frame(
y = rep(1:4, 2),
x = rep(rep(1:2, 2), 2),
group = rep(c('a', 'b'), each = 2),
panel = rep(1:2, each = 4))
myPlot <- xyplot(y ~ x | panel, groups = group, data = myDF, type = 'l')
direct.label(
p = myPlot,
method = 'first.bumpup')
This code produces a plot in which labels appear on the left-hand side of each panel:
I want labels on the left-hand side of the left-hand panel (as in this example), but on the right-hand side of the right-hand panel. What is the simplest way to produce that sort of figure?
I've checked the advanced examples in the directlabels documentation, and they make me think that it may be possible to use different methods for different panels by creating a custom positioning method or a custom panel. But I cannot quite see how to do it.
I took a crack at this with ggplot2 (only because I know ggplot2 much better than I know lattice). Let me know what you think. Below are two approaches. The first actually doesn't use directlabels. The placement rule is relatively simple, so I just used geom_text for label placement. The second method does use directlabels, but is more complicated.
Place labels using geom_text
library(dplyr) # For chaining operator (%>%)
library(ggplot2)
library(cowplot) # For cowplot theme
ggplot(myDF, aes(x, y, colour=group)) +
geom_line() +
geom_text(data=myDF %>% group_by(panel) %>%
filter(ifelse(panel==1, x==min(x), x==max(x))),
aes(x + 0.07*(panel-mean(panel)), y, label=group)) +
facet_grid(~panel) +
scale_x_continuous(breaks=seq(1,2,0.2)) +
theme_cowplot() +
guides(colour=FALSE)
In the code above, inside geom_text we keep only the lowest x value for the first panel and the highest x value in the second panel and then place the group labels at the y values that pair with the x values. The x + 0.07*(panel-mean(panel)) is just to move the labels slightly away from the ends of the lines.
Place labels using mapply and directlabels
Here's a more complicated method using directlabels. My approach was to plot each "facet" separately using mapply, so that I could use a different directlabels method for each panel, but then lay the two plots out together as if they were two facets of the same overall plot. If you like the result, maybe you can adapt it to a lattice plot if none of the ggplot2 versions meet your needs.
library(directlabels)
library(ggplot2)
library(gridExtra)
library(cowplot)
pl = mapply(function(pnl, m) {
# Create plot for each level of panel
p = ggplot(myDF[myDF$panel==pnl, ], aes(x, y, colour=group)) +
geom_line() +
facet_grid(~panel) +
scale_x_continuous(breaks=seq(1,2,0.2)) +
theme_cowplot()
# # Tweak margins of panel 1
# if(pnl==1) p = p + theme(plot.margin=unit(rep(0,4),"lines"))
# Remove y-axis title, labels and ticks for panel 2 and tweak margins
if(pnl==2) p = p + theme(axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank())
# Add directlabels with different method for each panel
direct.label(p, method=m)
},
pnl=unique(myDF$panel), m=c("first.bumpup", "last.bumpup"), SIMPLIFY=FALSE)
Because I removed the y-axis title, labels, and ticks in panel 2, that panel is wider than panel 1. plot_grid has an align argument that allows us to align the two plots so that they have the same width, but I don't know of a way to get rid of the space between the plots. grid.arrange will also lay out that plots, but we have to adjust the widths manually (you can adjust the widths manually with plot_grid as well).
# Lay out each panel using plot_grid from cowplot package
plot_grid(plotlist=pl, ncol=2, align="v")
# Lay out each panel using grid.arrange from gridExtra package
grid.arrange(grobs=pl, ncol=2, widths=c(10,9))
Here is an adaptation of eipi10's second solution that creates the desired effect in a lattice plot:
library(directlabels)
library(gridExtra)
library(lattice)
myDF <- data.frame(
y = rep(1:4, 2),
x = rep(rep(1:2, 2), 2),
group = rep(c('a', 'b'), each = 2),
panel = rep(1:2, each = 4))
plotFunction <- function(panelNumber, labelMethod) {
myPlot = xyplot(
y ~ x,
groups = group,
data = myDF[myDF$panel==panelNumber, ],
type = 'l')
direct.label(
p = myPlot,
method = labelMethod)
}
panelList = mapply(
FUN = plotFunction,
panelNumber = unique(myDF$panel),
labelMethod = c('first.bumpup', 'last.bumpup'),
SIMPLIFY = FALSE)
grid.arrange(grobs = panelList, ncol = 2)

Resources