R for reproducible scientific analysis

Creating publication quality graphics

Learning Objectives

  • To be able to use ggplot2 to generate publication quality graphics
  • To understand the basics of the grammar of graphics:
  • The aesthetics layer
  • The geometry layer
  • Adding statistics
  • Transforming scales
  • Coloring or paneling by groups.

Plotting our data is one of the best ways to quickly explore it and the various relationships between variables.

There are three main plotting systems in R, the base plotting system, the lattice package, and the ggplot2 package.

Today we’ll be learning about the ggplot2 package, because it is the most effective for creating publication quality graphics.

ggplot2 is built on the grammar of graphics, the idea that any plot can be expressed from the same set of components: a data set, a coordinate system, and a set of geoms–the visual representation of data points.

The key to understanding ggplot2 is thinking about a figure in layers: just like you might do in an image editing program like Photoshop, Illustrator, or Inkscape.

Let’s start off with an example:

library("ggplot2")
ggplot(data = healthData, aes(x = selfRatedHealth, y = health)) +
  geom_point()

plot of chunk lifeExp-vs-gdpPercap-scatter

So the first thing we do is call the ggplot function. This function lets R know that we’re creating a new plot, and any of the arguments we give the ggplot function are the global options for the plot: they apply to all layers on the plot.

We’ve passed in two arguments to ggplot. First, we tell ggplot what data we want to show on our figure, in this example the health data we read in earlier. For the second argument we passed in the aes function, which tells ggplot how variables in the data map to aesthetic properties of the figure, in this case the x and y locations. Here we told ggplot we want to plot the “education” column of the gapminder data frame on the x-axis, and the “health” column on the y-axis. Notice that we didn’t need to explicitly pass aes these columns (e.g. x = healthData[, "education"]), this is because ggplot is smart enough to know to look in the data for that column!

By itself, the call to ggplot isn’t enough to draw a figure:

ggplot(healthData,aes(x=selfRatedHealth,y=health))

plot of chunk unnamed-chunk-2

We need to tell ggplot how we want to visually represent the data, which we do by adding a new geom layer. In our example, we used geom_point, which tells ggplot we want to visually represent the relationship between x and y as a scatterplot of points:

ggplot(healthData,aes(x=selfRatedHealth,y=health)) +
  geom_point()

plot of chunk education-vs-health-scatter2

Challenge 1

Modify the following example so that the figure visualises how illnessReversed varies with health:

ggplot(healthData,aes(x=selfRatedHealth,y=health)) +
  geom_point()

Challenge 2

In the previous examples and challenge we’ve used the aes function to tell the scatterplot geom about the x and y locations of each point. Another aesthetic property we can modify is the point color. Modify the code from the previous challenge to color the points by the “education” column.

HINT: transform the education column to a factor using the as.factor() function.

Layers

We could also make a line plot. Instead, let’s tell ggplot to visualise the data as a line plot:

ggplot(healthData,aes(x=health,y=illnessReversed,color=as.factor(education),by=sex)) + geom_line()

plot of chunk health-line

Instead of adding a geom_point layer, we’ve added a geom_line layer. We’ve added the by aesthetic, which tells ggplot to draw a line for each sex.

But what if we want to visualise both lines and points on the plot? We can simply add another layer to the plot:

ggplot(healthData,aes(x=health,y=illnessReversed,color=as.factor(education),by=sex)) + geom_point() + geom_line()

plot of chunk health-line-point

It’s important to note that each layer is drawn on top of the previous layer. In this example, the points have been drawn on top of the lines. Here’s a demonstration:

ggplot(healthData,aes(x=health,y=illnessReversed,by=sex)) + geom_line(aes(color=as.factor(education))) + geom_point()

plot of chunk health-layer-example-1

In this example, the aesthetic mapping of color has been moved from the global plot options in ggplot to the geom_line layer so it no longer applies to the points. Now we can clearly see that the points are drawn on top of the lines.

Challenge 3

Switch the order of the point and line layers from the previous example. What happened?

Transformations and statistics

Ggplot also makes it easy to overlay statistical models over the data. To demonstrate we’ll go back to our first example:

ggplot(data = healthData, aes(x = selfRatedHealth, y = health,color=as.factor(education))) +
  geom_point()

plot of chunk health-vs-gdpPercap-scatter3

We can fit a simple relationship to the data by adding another layer, geom_smooth:

ggplot(data = healthData, aes(x = selfRatedHealth, y = health,color=as.factor(education))) +
  geom_point() + geom_smooth(method="lm")

plot of chunk lm-fit

We can make the line thicker by setting the size aesthetic in the geom_smooth layer:

ggplot(data = healthData, aes(x = selfRatedHealth, y = health,color=as.factor(education))) +
  geom_point() + geom_smooth(method="lm", size = 1.5)

plot of chunk lm-fit2

There are two ways an aesthetic can be specified. Here we set the size aesthetic by passing it as an argument to geom_smooth. Previously in the lesson we’ve used the aes function to define a mapping between data variables and their visual representation.

Challenge 4

Modify the color and size of the points on the point layer in the previous example.

Hint: do not use the aes function.

Multi-panel figures

Earlier we visualised the change in health with selfRatedHealth across education levels in one plot. Alternatively, we can split out different groups in the data into multiple panels by adding a layer of facet panels:

ggplot(data = healthData, aes(x = selfRatedHealth, y = health,color=paste(sex,HIGroup))) + geom_smooth(method="lm") + facet_wrap( ~ alcoholUseInYoungAdulthood)

plot of chunk facet

The facet_wrap layer took a “formula” as its argument, denoted by the tilde (~). This tells R to draw a panel for each unique value in the alcohol column of the healthData dataset.

Modifying text

To clean this figure up for a publication we need to change some of the text elements.

We can do this by adding a couple of different layers. The theme layer controls the axis text, and overall text size, and there are special layers for changing the axis labels. To change the legend title, we need to use the scales layer.

ggplot(data = healthData, aes(x = selfRatedHealth, y = health,color=paste(sex,HIGroup))) + geom_smooth(method="lm") + facet_wrap( ~ alcoholUseInYoungAdulthood) +
  xlab("Self-reported health") + ylab("Health rating from teacher") + ggtitle("Figure 1") +
  scale_colour_discrete(name="Study group and gender", labels= c("Hawaii - Female","Teman - Female","Hawaii - Male","Teman - Male")) +
  theme(axis.text.x=element_blank(), axis.ticks.x=element_blank())

plot of chunk theme

This is just a taste of what you can do with ggplot2. RStudio provides a really useful cheat sheet of the different layers available, and more extensive documentation is available on the ggplot2 website. Finally, if you have no idea how to change something, a quick google search will usually send you to a relevant question and answer on Stack Overflow with reusable code to modify!

Challenge 5

What would you like to visualise from the dataset? Go ahead and try to do it using ggplot!

Lastly, ggplot2 has a very handy function, ggsave() for saving the current plot to a file:

ggsave("fig/Figure1.pdf")
Saving 7 x 7 in image

Challenge solutions

Solution to challenge 1

Modify the example so that the figure visualises how illnessReversed varies with health:

ggplot(healthData, aes(x = health, y = illnessReversed)) + geom_point()

plot of chunk ch1-sol

Solution to challenge 2

In the previous examples and challenge we’ve used the aes function to tell the scatterplot geom about the x and y locations of each point. Another aesthetic property we can modify is the point color. Modify the code from the previous challenge to color the points by the “education” column.

ggplot(healthData, aes(x = health, y = illnessReversed, colour=as.factor(education))) + 
geom_point()

plot of chunk ch2-sol

Solution to challenge 3

Switch the order of the point and line layers from the previous example. What happened?

ggplot(healthData,aes(x=health,y=illnessReversed,by=sex)) + geom_point() + geom_line(aes(color=as.factor(education)))

plot of chunk ch3-sol

The lines now get drawn over the points!

Solution to challenge 4

Modify the color and size of the points on the point layer in the previous example.

Hint: do not use the aes function.

ggplot(data = healthData, aes(x = selfRatedHealth, y = health)) +
  geom_point(size=3,color="red") + geom_smooth(method="lm", size = 1.5)

plot of chunk ch4-sol