1

I am trying to use the plot_grid function from cowplot R package to put two plots together. However, I was getting the below error:

Error in switch(x[[2]][[1]]$name, C_abline = C_abline(x[[2]]), C_plot_new = C_plot_new(x[[2]]), : EXPR must be a length 1 vector

Therefore, testing both graphics I discovery that the error came from a ggplot which I used grid_text. Thus, in my example here I included only one plot. With the below you can reproduce the problem:

library(cowplot)
library(ggplot2)
library(ggforce)
library(grid)


### Example
circles <- as.data.frame(cbind(c(0.5, 1.5, 2.5), c(1, 2, 1), c(0.2, 0.2, 0.2)))

# Behold the some circles
ggplot() + geom_circle(aes(x0=V1, y0=V2, r=V3, fill=c("red", "blue", "green")), data=circles)+
  theme_bw() + ylab(expression(symbol('\253'))) + xlab(expression(symbol('\253')))+ theme(legend.position="none",
                                                                                          axis.title.x=element_text(size = 50),
                                                                                          axis.text.x=element_blank(),
                                                                                          axis.ticks.x=element_blank(),
                                                                                          axis.title.y=element_text(size = 50),
                                                                                          axis.text.y=element_blank(),
                                                                                          axis.ticks.y=element_blank()) 

grid.text("Distinct", x = unit(0.04, "npc"), y = unit(0.80, "npc"))

exP <- recordPlot()

plot_grid(exP)

I would be glad to receive any idea how to use plot_grid on that kind of object (ggplot + grid_text).

4
  • The other plot is working without any problems. That's why I only include one for simplicity. I will clarify on that. Commented Oct 17, 2017 at 17:08
  • Why not using grid.arrange ? Commented Oct 17, 2017 at 17:40
  • Because it give this error: Error in gList(list(grobs = list(list(x = 0.5, y = 0.5, width = 1, height = 1, : only 'grobs' allowed in "gList" Commented Oct 17, 2017 at 17:42
  • The error is caused by whatever it is that recordPlot() does. I recommend not to use it, in particular when you're only working with grid graphics, as is the case here. See my proposed answer for alternatives. Commented Nov 23, 2017 at 20:52

2 Answers 2

2

Try this:

library(ggplot2)
library(ggforce)
library(grid)
library(gridExtra)


### Example
circles <- as.data.frame(cbind(c(0.5, 1.5, 2.5), c(1, 2, 1), c(0.2, 0.2, 0.2)))

# Behold the some circles
p1 <- ggplot() + 
  geom_circle(aes(x0=V1, y0=V2, r=V3, fill=c("red", "blue", "green")), data=circles)+
  theme_bw() + ylab(expression(symbol('\253'))) + xlab(expression(symbol('\253')))+ 
  theme(legend.position="none",
        axis.title.x=element_text(size = 50),
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank(),
        axis.title.y=element_text(size = 50),
        axis.text.y=element_blank(),
        axis.ticks.y=element_blank()) 

print(p1)
grid.text("Distinct", x = unit(0.04, "npc"), y = unit(0.80, "npc"))
p2 <- grid.grab()

grid.arrange(p1,p2, nrow=1)

enter image description here

Sign up to request clarification or add additional context in comments.

1 Comment

Importantly, this answer works because recordPlot() was replaced by grid.grab(), not because plot_grid() was replaced by grid.arrange(). The problem is in recordPlot(). Once you've captured the text grob with grid.grab(), plot_grid() can handle it just fine.
2

Your example should work, and the fact that it doesn't is a bug that I need to look into.

However, even if it did work, I'd recommend against it. I haven't had good experiences with recorded plots, and in general doing the whole round trip of first drawing the plot and then capturing it seems awkward and error-prone to me. I suggests three alternatives of doing what you want to do. They all give you the same final result.

First, you can use grid graphics to combine a ggplot and any other grob into a combined grob, which you can then hand to plot_grid():

library(cowplot)
library(ggplot2)
library(ggforce)
library(grid)

# Plot of mpg data, to use in plot_grid below
pmpg <- ggplot(mpg, aes(x=cty, y=hwy)) + geom_point()

# Plot with circles
circles <- as.data.frame(cbind(c(0.5, 1.5, 2.5), c(1, 2, 1), c(0.2, 0.2, 0.2)))
pcircles <- ggplot() + 
  geom_circle(aes(x0=V1, y0=V2, r=V3, fill=c("red", "blue", "green")),
              data=circles) +
  theme_bw() + ylab(expression(symbol('\253'))) + 
  xlab(expression(symbol('\253'))) + 
  theme(legend.position="none",
        axis.title.x=element_text(size = 50),
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank(),
        axis.title.y=element_text(size = 50),
        axis.text.y=element_blank(),
        axis.ticks.y=element_blank()) 

# text grob
gtext <- grid::textGrob("Distinct", x = unit(0.04, "npc"), y = unit(0.80, "npc"))

# make combined grob
gcombined <- grid::grobTree(ggplotGrob(pcircles), gtext)

plot_grid(pmpg, gcombined)

The result:

enter image description here

Second, I wrote the ggdraw() function and related functions to make it easy to combine ggplot objects and other grid objects. E.g., you can draw your text grob onto the plot like this:

pcombined <- ggdraw(pcircles) + draw_grob(gtext)
plot_grid(pmpg, gcombined)

The result looks exactly the same as before.

And, if all you want to do is draw some text, you can also use draw_text() instead of draw_grob():

pcombined <- ggdraw(pcircles) + draw_text("Distinct", x = 0.04, y = 0.8)
plot_grid(pmpg, gcombined)

Finally, I'd like to point out that the solution by Marco Sandri, which uses grid.grab(), also works with plot_grid() instead of grid.arrange().

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.