4

I'm trying to make a 2 panel figure in RStudio. Simple enough usually:

par(mfrow=c(1,2)) #1*2 plotting window

However, when I make the plot using the scatterplot() function from the car package it seems to override this division of the plotting window.

Reproducible example: The format I'm looking for can be produced with:

par(mfrow=c(1,2))
plot(iris$Sepal.Length,iris$Sepal.Width)
plot(iris$Petal.Width,iris$Sepal.Width)

But I'd like to use scatterplot() for a few reasons. But when I try the same formatting trick again, it doesn't work. Try this block:

library(car)
par(mfrow=c(1,2))
scatterplot(Sepal.Length~Sepal.Width|Species,data=iris,grid="FALSE", boxplots="", reg.line="FALSE",pch=c(0,1,2))
scatterplot(Petal.Width~Sepal.Width|Species,data=iris,grid="FALSE", boxplots="", reg.line="FALSE",pch=c(0,1,2))

Is anyone aware of a workaround for this?

I also tried an alternative structuring with:

m<-rbind(c(1,2))
layout(m)

No luck.

UPDATE This question is largely a duplicate of this one, except I'm looking for a workaround for it rather than the responses left on that page which basically just acknowledge that scatterplot() does in fact override par(mfrow)

Community
  • 1
  • 1
Jesse001
  • 924
  • 1
  • 13
  • 37
  • Possible duplicate of [Side by side plots using scatterplot from car package](http://stackoverflow.com/questions/23725871/side-by-side-plots-using-scatterplot-from-car-package) – Ian Fiske Nov 23 '16 at 19:44
  • Correct and thank you for pointing me in that direction. However, that feed did not receive an answer beyond 'yup, that happens.' The link to the creators response is the same. Is there a workaround for this? I mean, the ghetto way of pasting everything into powerpoint and grouping it together after the fact works but it's annoyingly cumbersome and not as pretty as R could make it – Jesse001 Nov 23 '16 at 19:53
  • Depends on what you want in the end. Just for viewing, maybe sth like `pdf(tf <- tempfile(fileext = ".pdf"));sp(Sepal.Length~Sepal.Width|Species,data=iris);sp(Petal.Width~Sepal.Width|Species,data=iris);dev.off();shell.exec(tf)`. – lukeA Nov 23 '16 at 19:56
  • @lukeA If I'm reading that right it produces all of the plots and exports them into a single pdf file where each plot gets its own page. correct? What I'd like is for the two plots to be on the same page. – Jesse001 Nov 23 '16 at 20:08
  • Yea, if you set up your pdf reader to show pages side by side, you got what you want - from a visual point of view. As the car package author has written, it's not possible to plot it on a single page; that's not what the function is supposed to do. It's for analyses, not for publication. – lukeA Nov 23 '16 at 20:17
  • I spent hours trying to find other functions that would produce the same plot as I don't want any of the fancy stuff that comes with scatterplot (most of my code is turning that off) and to get around this problem. Do you, or anyone else, have a suggestion for another package that would produce a good scatterplot? – Jesse001 Nov 23 '16 at 20:34
  • Plenty of options, if you would not have insisted on `car::sp` ("But I'd like to use scatterplot() for a few reasons" + title of the post). :) – lukeA Nov 24 '16 at 11:09
  • @lukeA I am open to other options, SP is the only one I've seen though that makes the plots correctly (allows in line calculation of SEM, invokes the standard R graphics language, etc. etc.) and that I know how to manipulate (axis titles, omit plotting factors, include others, etc.). – Jesse001 Nov 25 '16 at 15:33

1 Answers1

1

You can output side-by-side figures in an rmarkdown document using the chunk argument fig.show='hold'. Another option is to use ggplot2 to create the plot, instead of the cars scatterplot function. I show both approaches below.

Side-by-Side cars::scatterplot plots in a rmarkdown document

Below is an example with PDF output. out.width='3in' sets the actual size of each plot in the output document, regardless of fig.height and fig.width. But you can still adjust fig.height and fig.width to adjust the aspect ratio and the text size relative to the plot area.

---
title: "Untitled"
author: "eipi10"
date: "November 23, 2016"
output: pdf_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

```{r fig.show='hold', out.width='3in', fig.height=5, fig.width=5}
library(car)

scatterplot(Sepal.Length~Sepal.Width|Species,data=iris,grid="FALSE",
            boxplots="", reg.line="FALSE", pch=c(0,1,2))
scatterplot(Petal.Width~Sepal.Width|Species,data=iris,grid="FALSE", 
            boxplots="", reg.line="FALSE", pch=c(0,1,2))
```

enter image description here

Side-by-Side scatterplots using ggplot2

If you're willing to go with ggplot2 then you can get the two-plot layout relatively easily:

library(ggplot2)
library(gridExtra)
theme_set(theme_bw())

grid.arrange(
  ggplot(iris, aes(Sepal.Width, Sepal.Length, colour=Species)) +
    geom_point() +
    geom_smooth(alpha=0.2) +
    theme(legend.position="top"),
  ggplot(iris, aes(Sepal.Width, Petal.Width, colour=Species)) +
    geom_point() +
    geom_smooth(alpha=0.2) +
    theme(legend.position="top"),
  ncol=2)

enter image description here

Customize ggplot2 plots to look more like cars::scatterplot output

You can customize the code above in other ways. If you don't want the confidence bands, add se=FALSE to geom_smooth. If you want different shapes for each species, add aes(shape=Species) to geom_point. If you want the specific shapes used in base graphics, add + scale_shape_manual(values=0:2), etc. You can also get a single legend with a little extra work.

In the code below, I've added these and other customizations to reproduce something closer to your original base graphics plot.

# Components we'll reuse for both plots
my_theme = list(geom_point(aes(shape=Species)),
                geom_smooth(se=FALSE, show.legend=FALSE, lwd=0.8),
                scale_shape_manual(values=0:2),
                scale_colour_manual(values=c("black", "red","green")),
                theme_bw(),
                theme(panel.grid.major=element_blank(),
                      panel.grid.minor=element_blank(),
                      legend.position="top"))

p1 = ggplot(iris, aes(Sepal.Width, Sepal.Length, colour=Species)) +
  my_theme +
  labs(x="Sepal Width", y="Sepal Length") +
  scale_y_continuous(limits=c(3,8)) +
  scale_x_continuous(limits=c(1,5)) 

p2 = ggplot(iris, aes(Sepal.Width, Petal.Width, colour=Species)) +
  my_theme +
  labs(x="Sepal Width", y="Petal Width")

# Function to extract legend
# https://github.com/hadley/ggplot2/wiki/Share-a-legend-between-two-ggplot2-graphs
g_legend<-function(a.gplot){
  tmp <- ggplot_gtable(ggplot_build(a.gplot))
  leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
  legend <- tmp$grobs[[leg]]
  return(legend)}

leg = g_legend(p1)

grid.arrange(leg,
  arrangeGrob(grobs=lapply(list(p1,p2), function(p) p + guides(colour=FALSE, shape=FALSE)), ncol=2), 
  ncol=1, heights=c(1,10))

enter image description here

eipi10
  • 91,525
  • 24
  • 209
  • 285
  • wow talk about a thorough answer! Thanks @eipi10 ! I'm not too familiar with ggplot, so I'm trying to adapt your answer to my data now. The issues I'm running into at the moment are 1) getting rid of the grid 2) setting the scale limits and 3) relabeling axes. none of those are working the way usual plotting functions do, and the documentation for that function is severely lacking – Jesse001 Nov 23 '16 at 21:09
  • 1
    I've updated my last example to include new axis labels and explicit axis scale ranges. That example also already gets rid of the grid lines. – eipi10 Nov 23 '16 at 21:12
  • 1
    In terms of "usual" plotting functions: `ggplot2` does not work the same way as base graphics. First, it uses the `grid` graphics engine, rather than base graphics to draw all the plot components. Second, it has it's own "grammar" for constructing a plot (in fact, the "gg" stands for "grammar of graphics"). – eipi10 Nov 23 '16 at 21:17
  • I think this may end up working out if I can make it prettier. Thank you. Do you have a preferred source of information for the grammar? I'm going to need to try to expand this now to a 2*3 matrix of plots (3 pairs) and would prefer to suppress redundant axes. I'm also going to need to put in error bars (I removed the line of best fit). – Jesse001 Nov 23 '16 at 21:34
  • 1
    You could look at the relatively new book [`R for Data Science`](http://r4ds.had.co.nz/data-visualisation.html), which was co-authored by Hadley Wickham, the creator of `ggplot2`. The book is published by O'Reilly, but the web version is open access. The link goes directly to the chapter on using ggplot2 for visualization. – eipi10 Nov 23 '16 at 22:01