32

I am trying to merge two ggplot2 plots into one based on this table:

   Type    RatingA  RatingB
1  One     3        36
2  Two     5        53
3  One     5        57
4  One     7        74
5  Three   4        38
6  Three   8        83

I want to make two scatter plots with the mean of the ratings in the y axis and type on the x axis.

This is how I create each graph:

p1 <- ggplot(test, aes(x=reorder(Type, RatingA, mean), y=RatingA)) +
        stat_summary(fun.y="mean", geom="point")

p2 <- ggplot(test, aes(x=reorder(Type, RatingB, mean), y=RatingB)) + 
        stat_summary(fun.y="mean", geom="point")

Since p1 and p2 have the same x axis I would like them to be ordered vertically. I looked at facet_align but I couldnt find something that would do the job.

mindless.panda
  • 4,014
  • 4
  • 35
  • 57
Julio Diaz
  • 9,067
  • 19
  • 55
  • 70
  • Similar question: http://stackoverflow.com/questions/1249548/side-by-side-plots-with-ggplot2 – Mikko Nov 10 '15 at 08:45
  • See also [this](https://stackoverflow.com/a/51220506/) for multiple ways to do it (Sep 2018) – Tung Sep 07 '18 at 05:51

4 Answers4

49

You can use grid.arrange() in the gridExtra package like this:

grid.arrange(p1, p2)
Ista
  • 10,139
  • 2
  • 37
  • 38
  • 2
    Could you add some more info? Where is that function from? How to import it? Also, it looks like the function is not plotting into the same canvas but rather concatenates two plots. – Soerendip Jan 18 '19 at 22:11
  • 1
    @Sören `grid.arrange` is in the gridExtra package, as I already stated. You import it just like you would any other package. – Ista Jan 20 '19 at 12:09
15

Julio,

You mention that p1 and p2 have the same x-axis, but the reordering you do based on mean does not make them the same. p1's axis goes "one --> two --> three" while p2's axis goes "two --> one --> three". Is this intentional?

Regardless, ggplot offers a few other solutions to combine these plots into one, namely colour and faceting (which you may have already tried?). The first step to either of these is to melt your data.frame to long format. We will identify the id variable "Type" and melt assumes the rest of the columns are to be melted.

test.m <- melt(test, id.var = "Type")

A quick check of the structure of the new object indicates most everything is in line, except the levels for type are a bit out of whack:

> str(test.m)
'data.frame':   12 obs. of  3 variables:
 $ Type    : Factor w/ 3 levels "One","Three",..: 1 3 1 1 2 2 1 3 1 1 ...
 $ variable: Factor w/ 2 levels "RatingA","RatingB": 1 1 1 1 1 1 2 2 2 2 ...
 $ value   : int  3 5 5 7 4 8 36 53 57 74 ...

So let's rearrage the levels:

test.m$Type <- factor(test.m$Type, c("One", "Three", "Two"), c("One", "Two", "Three"))

Now for the plotting. With colour:

ggplot(test.m, aes(x = Type, y = value, group = variable, colour = variable)) + 
stat_summary(fun.y = "mean", geom = "point") 

or with facets:

ggplot(test.m, aes(x = Type, y = value, group = variable)) + 
stat_summary(fun.y = "mean", geom = "point") +
facet_grid(variable ~ ., scales = "free")

Note I used the scales = "free" argument in the faceting so that each plot has its' own scale. Simply remove that argument if that's not the effect you want.

Chase
  • 67,710
  • 18
  • 144
  • 161
  • 1
    This is a much better solution for this particular problem, but Ista's solution is better in general (e.g. when the two graphs are of different types). – naught101 Jun 04 '14 at 05:22
10

this is an old question, but I recently found multiplot function, with make his job very well.

The multiplot function is from Cookbook for R:

The function it self is:

# Multiple plot function
#
# ggplot objects can be passed in ..., or to plotlist (as a list of ggplot objects)
# - cols:   Number of columns in layout
# - layout: A matrix specifying the layout. If present, 'cols' is ignored.
#
# If the layout is something like matrix(c(1,2,3,3), nrow=2, byrow=TRUE),
# then plot 1 will go in the upper left, 2 will go in the upper right, and
# 3 will go all the way across the bottom.
#
multiplot <- function(..., plotlist=NULL, file, cols=1, layout=NULL) {
  require(grid)

  # Make a list from the ... arguments and plotlist
  plots <- c(list(...), plotlist)

  numPlots = length(plots)

  # If layout is NULL, then use 'cols' to determine layout
  if (is.null(layout)) {
    # Make the panel
    # ncol: Number of columns of plots
    # nrow: Number of rows needed, calculated from # of cols
    layout <- matrix(seq(1, cols * ceiling(numPlots/cols)),
                    ncol = cols, nrow = ceiling(numPlots/cols))
  }

 if (numPlots==1) {
    print(plots[[1]])

  } else {
    # Set up the page
    grid.newpage()
    pushViewport(viewport(layout = grid.layout(nrow(layout), ncol(layout))))

    # Make each plot, in the correct location
    for (i in 1:numPlots) {
      # Get the i,j matrix positions of the regions that contain this subplot
      matchidx <- as.data.frame(which(layout == i, arr.ind = TRUE))

      print(plots[[i]], vp = viewport(layout.pos.row = matchidx$row,
                                      layout.pos.col = matchidx$col))
    }
  }
}

You need just source this function to your script.

AndriusZ
  • 822
  • 1
  • 10
  • 18
  • 1
    I comment here, because I cannot comment on the linked page you provided... Why is there a "file" argument? Apparently, this is not used in the function. – Stingery Nov 25 '15 at 09:54
  • 1
    @Stingery, good question. But I don't know the answer. Sorry. – AndriusZ Nov 25 '15 at 10:11
0

Check out the patchwork package, which allows you to combine multiple plots by adding them together :

library(patchwork)
p1+p2

In order to get them to stack one on top of another, you have two options:

p1+p2+plot_layout(ncol=1)

or:

p1/p2

The documentation for this package is really great also: https://patchwork.data-imaginist.com/index.html

ekatko1
  • 163
  • 8