# Using ggplot2 and qplot

========================================================

Prepared by Shane Mueller

# Method Overview

The ggplot2 library is a follow-up of the ggplot library, and stands for the ‘grammar of graphics’. It produces attractive, professional-looking graphics that are good, especially for presentations. This comes at a cost of some of the flexibility that standard R graphics give, but it is often worthwhile. The ggplot2 library was developed by Hadley Wickham, who also developed reshape2 and dplyr. Because of its peculiarities, you may end up using these other libraries to make full use of its power.

There is a lot of basic introductory tutorials for ggplot out there. See links in the resources below.

Finally, ggplot has pretty nice control over the graphics formats you save. It has functions that will create several different formats directly, with specified dimensions and dpi, so you are not at the whim of the RStudio window for creating your figure resolutions.

There is a more modern graphics library being developed by the developers of ggplot2 called ggvis, which intends to make interactive web graphics. If you understand ggplot2, ggvis should be easy to pick up and let you do some exciting things.

# Overview of Functions

There are two main ways to use ggplot2. The ‘traditional’ way (using the ggplot() function) can be difficult but offers a lot of power. The simple way (using qplot) is more straight-forwrad, but can be a bit more limiting.

## The easy way: qplot

qplot stands for quickplot, and either function name can be used. It wraps up all major plotting methods into one function. If we look at the function definitions, some of the arguments are similar to what appear in the normal plot() functions: you specify x and y values, labels, limits, etc. The geom argument specifies what type of plot you want to create.

qplot(x, y = NULL, ..., data, facets = NULL, margins = FALSE,
geom = "auto", stat = list(NULL), position = list(NULL), xlim = c(NA,
NA), ylim = c(NA, NA), log = "", main = NULL,
xlab = deparse(substitute(x)), ylab = deparse(substitute(y)), asp = NA)

Let’s look at the crabs data set in the MASS library. This data set has 200 observations of crabs (100 male and 100 female) on 5 different measures, with two species (Blue or orange). FL=frontal lobe size; RW rear width; CL=carapace length, CW = carapace width, BD = body depth.

library(MASS)
library(ggplot2)
head(crabs)
  sp sex index   FL  RW   CL   CW  BD
1  B   M     1  8.1 6.7 16.1 19.0 7.0
2  B   M     2  8.8 7.7 18.1 20.8 7.4
3  B   M     3  9.2 7.8 19.0 22.4 7.7
4  B   M     4  9.6 7.9 20.1 23.1 8.2
5  B   M     5  9.8 8.0 20.3 23.0 8.2
6  B   M     6 10.8 9.0 23.0 26.5 9.8

Let’s look at the frontal lobe width. Doing qplot with one continuous variable will just plot a histogram.

qplot(crabs$FL) I’m not enamored with how this looks. Let’s spruce it up a bit: qplot(FL,data=crabs,xlab="Frontal lobe size (mm)",main="Crab frontal lobe size", binwidth=1) What if we wanted a separate histogram for each species? We can use the facet argument to make separate plots for each level of another variable. qplot(FL,data=crabs, xlab="Frontal lobe size (mm)", main="Crab frontal lobe size", binwidth=1,facets=.~sex) Or, we can make facets in a grid along two IVs: qplot(FL,data=crabs, xlab="Frontal lobe size (mm)", main="Crab frontal lobe size", binwidth=1,facets= sp~sex) The rows and columns aren’t entirely easy to read, but you could change the names of these with dplyr. ## boxplots These histograms can be encapsulated into a boxplot, but now you need to specify this with the geom argument qplot(y=FL,x=sp,data=crabs, geom="boxplot", xlab="Frontal lobe size (mm)", main="Crab frontal lobe size") You could add the points on top of these by specifying a list in the goem qplot(y=FL,x=sp,data=crabs, geom=c("boxplot","point"), xlab="Frontal lobe size (mm)", main="Crab frontal lobe size") And of course, this could be faceted too: qplot(y=FL,x=sp,data=crabs, geom=c("boxplot","point"), facets = .~sex, xlab="Frontal lobe size (mm)", main="Crab frontal lobe size") ## Making scatter plots with qplot If you want to plot points against one another, you specify an x and y value (again, faceted by sex). But we will color each one by its species. qplot(y=FL,x=RW,data=crabs, geom=c("point"), facets = .~sex, colour=sp, ylab="Frontal lobe size (mm)", xlab="Rear width", main="Crab size") Let’s see how frontal size changes as carapace width changes. To do this, let’s start by creating quantiles of CW crabs$CW2 <- floor((order(crabs$CW)-1)/100*5) agg <- aggregate(crabs$FL,list(crabs$CW2),mean) qplot(x=Group.1,y=x,data=agg, geom=c("point","line"), ylab="Frontal lobe size (mm)", xlab="Carapace Width Quantile", main="Crab size") ## Making barplots with qplot (deprecated) Bar plots will often want you to create a statistic on the data. Although in the past, qplot could do this from the raw data, qplot can no longer do this (and users are directed to the more complex ggplot()). ##Deprecated in ggplot2 2.0: ##qplot(x=CW2, y=FL,data=crabs, geom="bar")  qplot(x=Group.1,y=x,data=agg, geom=c("point","line"), ylab="Frontal lobe size (mm)", xlab="Carapace Width Quantile", main="Crab size") ###How to make a ‘matplot’ in ggplot2 In standard R, the matplot function is handy because it allows you to take a matrix of values and plot several series against eachother. library(dplyr) agg <- aggregate(dplyr::select(crabs,FL,RW,CL,CW,BD,CW),list(species=crabs$sp,sex=crabs$sex),mean) matplot(dplyr::select(agg,FL,RW,CL,CW,BD),type="b",xaxt="n",ylab="Size (mm)") axis(1,1:4,labels=paste(agg$species,agg$sex)) Let’s say we want to do something like this, but with qplot/ggplot. We quickly find out that it is not easy. It doesn’t work because ggplot expects a single variable, and you are to tell it how it needs to be plotted. We can do one series, but not multiple: newagg <- dplyr::select(agg,species,sex,FL,RW,CL,CW,BD) newagg$aggname <- paste(agg$sex,agg$species)
qplot(x=aggname,y=FL,data=newagg,ylab="Size (mm)")

To do multiple series, we can rely on melt in reshape2

library(reshape2)
head(melt(newagg)) ##this basically does it right!
  species sex aggname variable  value
1       B   F     F B       FL 13.270
2       O   F     F O       FL 17.594
3       B   M     M B       FL 14.842
4       O   M     M O       FL 16.626
5       B   F     F B       RW 12.138
6       O   F     F O       RW 14.836
##alternately:
agg2 <- melt(newagg[,1:6],id.vars=c("species","sex"))
head(agg2)
  species sex variable  value
1       B   F       FL 13.270
2       O   F       FL 17.594
3       B   M       FL 14.842
4       O   M       FL 16.626
5       B   F       RW 12.138
6       O   F       RW 14.836
qplot(x=paste(species,sex),y=value,group=variable,geom="line",data=agg2,ylab="Size (mm)",xlab="Species/Sex")

ggplot is called ‘grammar of graphics’ because it is a true grammar for composing more complex graphics. In the previous example, suppose we wanted to add points to the plot. We can do so with syntax like this:

##Nothing happens here that we can see::
myplot <- qplot(x=paste(species,sex),y=value,group=variable,geom="line",data=agg2,ylab="Size (mm)",xlab="Species-Sex combination")
myplot + geom_point()

##add color/alpha transparency to points
myplot + geom_point(size=4,alpha=.45, color="gold")

myplot + geom_point(size=4,alpha=.45, color="red") +
geom_line(col="darkblue")+
ggtitle("Crab measurements") 

For simple graphs with minimal adornment, this method is fine. But qplot is a shortcut for a more complex set of operations using the ggplot function. If you want to do more complex things, you will need to use ggplot()

## The powerful way: ggplot

The ggplot function provides much more precise control and access over how things are formatted, aggregated, and displayed. ggplot requires you to use a data fram in a ‘melted’ format (qplot seems to be a bit more forgiving). All of the additional adornments work fine, but now you need to think harder about how to organize your data in the ggplot function. If you do this right, it makes organizing things fairly easy.

Now, instead of qplot, we need to use ggplot. It works almost like the qplot, but instead of specifying x,y directly, we need to add logic that tells how the ‘aesthetics’ map onto the data colmumns. This is done via the aes() argument. Now, we need a geom function added to the function to display anything.

myplot <- ggplot(agg2, aes(x=paste(species,sex),y=value,group=variable))
myplot + geom_point(size=6,alpha=.45, color="navy") +
ylab("Size (mm)")+xlab("Species-Sex combination")+
geom_line(col="darkblue")+
ggtitle("Crab measurements") 

## Error bars

Suppose we want to add error bars. We need to first compute standard errors for our data set, which shouldn’t be too hard.

library(reshape2)
agg.se <- aggregate(dplyr::select(crabs,FL,RW,CL,CW,BD,CW),list(species=crabs$sp,sex=crabs$sex),
function(x){sd(x)/sqrt(length(x))})
newagg.se <- dplyr::select(agg.se,species,sex,FL,RW,CL,CW,BD)
agg2.se <- melt(newagg.se,id.vars=c("species","sex"))
agg2.a <- left_join(agg2,agg2.se,by=c("species","sex","variable"))
agg2.a$ymin <- agg2.a$value.x-agg2.a$value.y agg2.a$ymax <- agg2.a$value.x+agg2.a$value.y

head(agg2.a)
  species sex variable value.x   value.y     ymin     ymax
1       B   F       FL  13.270 0.3716291 12.89837 13.64163
2       O   F       FL  17.594 0.4205867 17.17341 18.01459
3       B   M       FL  14.842 0.4529008 14.38910 15.29490
4       O   M       FL  16.626 0.4970920 16.12891 17.12309
5       B   F       RW  12.138 0.3448855 11.79311 12.48289
6       O   F       RW  14.836 0.3321146 14.50389 15.16811

Now, we have a single data frame with value.x which has the mean values, and ymin/ymax which are the top and bottom of the error bars (+/- one s.e.)

myplot <- ggplot(agg2.a,
aes(x=paste(species,sex),
y=value.x,
group=variable,ymin,ymax))+
geom_point(size=5,alpha=.45, color="navy")  +
geom_line(colour="darkblue")  +
ggtitle("Crab measurements") +
ylab("Size (mm)")+xlab("Species-Sex combination")
myplot +   geom_errorbar(aes(ymin=ymin,ymax=ymax))

This is effective but ugly. We can try a few other tweaks:

myplot + geom_errorbar(aes(ymin=ymin,ymax=ymax),colour="navy",width=.1)

The current figure is not much help, because we don’t know what each line means. ggplot will add a legend when it makes sense; sometimes it does not add a legend when you think it also might make sense. In the above figure, although each series was separated with a different line, there was no way of distinguishing the points via a legend. Add this and you will get a legend. Here, we set both colour and shape to depend on a specific value, and the legends will show up

myplot <- ggplot(agg2.a,
aes(x=paste(species,sex),y=value.x,colour=variable,shape=variable,
group=variable,ymin,ymax))+
geom_point(size=5,alpha=.45)  +
geom_line()  +
ggtitle("Crab measurements") +
ylab("Size (mm)")+xlab("Species-Sex combination")
myplot + geom_errorbar(aes(ymin=ymin,ymax=ymax),width=.1)

### Themes

Changing themes should not be done lightly. But if you are producing a figure for publication, black/white or greyscale is usually preferred. Just add a theme_bw() to the end and you can get this:

#standard theme
myplot + geom_errorbar(aes(ymin=ymin,ymax=ymax),width=.1) + theme_grey()

##black and white theme:
myplot + geom_errorbar(aes(ymin=ymin,ymax=ymax),width=.1) + theme_bw()

myplot + geom_errorbar(aes(ymin=ymin,ymax=ymax),width=.1) + theme_bw() +
theme(plot.title = element_text(size = rel(2), colour = "blue"))

### Saving

You can save graphics just like you always do, but the ggsave() functions offers a method for saving the latest graphic you created.

myplot + geom_point(size=4,alpha=.45, color="red") +
geom_line(col="darkblue")+
ggtitle("Crab measurements")  +
geom_errorbar(aes(ymin=ymin,ymax=ymax),width=.1) 

ggsave(filename="demo.png",dpi=600,width=8,height=4)
ggsave(filename="demo.pdf",dpi=600,width=8,height=4)
ggsave(filename="demo.eps",dpi=600,width=8,height=4)

ggsave saves based on the file extension, and currently can save as ps, tex (pictex), pdf, tiff, png, bmp and wmf (windows only).

## Other features

The breadth of things you can do with ggplot is truly amazing. The default themes are nice, but you can change these fairly easily if you dig into examples provided in many places.

# Reporting

The default settings of ggplot2 are best for on-screen graphics. Some journals prefer black-and-white. Alternate themes are available that will still produce attractive black-and-white images.

Most journals will be a bit picky about the graphic format of images. Many will want .tiff format, which is a compressed graphic format that is lossless. .png works this way as well, but you are best off sticking with something they know and understand.

During pdf creation, a journal sometimes compresses image-based graphics and they can be lossy. With standard R graphics, you can save as a .ps format (rename to .eps), and most will be able to handle this as well. However, ggplot renders graphics to a rasterized image, and so overall you images will probably be larger and there could be quality issues if you don’t use a high enough dpi or image size.

## Minimal example with ggvis

library(ggvis)
mtcars %>% ggvis(~wt, ~mpg) %>% layer_points()

# Assumptions and Limitations

ggplot is fairly flexible, and can produce beautiful graphics, but it can be a little frustrating to use when you are used to the layering and drawing of traditional R graphics. Many additional libraries aim to make ggplot more flexible, produce custom plots, or give alternative (easier) syntax to access the plots.

2019-01-16