forked from rdpeng/exdata
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathggplot2.Rmd
More file actions
521 lines (302 loc) · 29.9 KB
/
Copy pathggplot2.Rmd
File metadata and controls
521 lines (302 loc) · 29.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
# The ggplot2 Plotting System: Part 1
```{r setup, echo = FALSE}
knitr::opts_chunk$set(message = F, error = F, warning = F, comment = NA,
tidy = F, fig.path = "images/ggplot2-", fig.height = 4)
```
The `ggplot2` package in R is an implementation of _The Grammar of Graphics_ as described by Leland Wilkinson in his book. The package was originally written by Hadley Wickham while he was a graduate student at Iowa State University (he still actively maintains the packgae). The package implements what might be considered a third graphics system for R (along with `base` graphics and `lattice`). The package is available from [CRAN](http://cran.r-project.org/package=ggplot2) via `install.packages()`; the latest version of the source can be found on the package's [GitHub Repository](https://github.com/hadley/ggplot2). Documentation of the package can be found at [http://docs.ggplot2.org/current/]()
The grammar of graphics represents an abstraction of graphics ideas and objects. You can think of this as developing the verbs, nouns, and adjectives for data graphics. Developing such a grammar allows for a "theory" of graphics on which to build new graphics and graphics objects. To quote from Hadley Wickham's book on `ggplot2`, we want to "shorten the distance from mind to page". In summary,
> "...the grammar tells us that a statistical graphic is a __mapping__ from data to __aesthetic__ attributes (colour, shape, size) of __geometric__ objects (points, lines, bars). The plot may also contain statistical transformations of the data and is drawn on a specific coordinate system" -- from _ggplot2_ book
You might ask yourself "Why do we need a grammar of graphics?" Well, for much the same reasons that having a grammar is useful for spoken languages. The grammer allows for a more compact summary of the base components of a language, and it allows us to extend the language and to handle situations that we have not before seen.
If you think about making a plot with the base graphics system, the plot is constructed by calling a series of functions that either create or annotate a plot. There's no convenient agreed-upon way to describe the plot, except to just recite the series of R functions that were called to create the thing in the first place. In a previous chapter, we described the base plotting system as a kind of "artist's palette" model, where you start with blank "canvas" and build up from there.
For example, consider the following plot made using base graphics.
```{r,fig.height=5,fig.cap="Scatterplot of Temperature and Ozone in New York (base graphics)"}
with(airquality, {
plot(Temp, Ozone)
lines(loess.smooth(Temp, Ozone))
})
```
How would one describe the creation of this plot? Well, we could say that we called the `plot()` function and then added a loess smoother by calling the `lines()` function on the output of `loess.smooth()`.
The base plotting system is convenient and it often mirrors how we think of building plots and analyzing data. But a key drawback is that you can’t go back once plot has started (e.g. to adjust margins), so there is in fact a need to plan in advance. Furthermore, it is difficult to "translate" a plot to others because there's no formal graphical language; each plot is just a series of R commands.
Here's the same plot made using `ggplot2`.
```{r,fig.cap="Scatterplot of Temperature and Ozone in New York (ggplot2)"}
library(ggplot2)
ggplot(airquality, aes(Temp, Ozone)) +
geom_point() +
geom_smooth(method = "loess", se = FALSE)
```
Note that the output is roughly equivalent, and the amount of code is similar, but `ggplot2` allows for a more elegant way of expressing the components of the plot. In this case, the plot is a *dataset* (`airquality`) with *aesthetic mappings* derived from the `Temp` and `Ozone` variables, a set of *points*, and a *smoother*. In a sense, the `ggplot2` system takes many of the cues from the base plotting system and formalizes them a bit.
The `ggplot2` system also takes some cues from `lattice`. With the `lattice` system, plots are created with a single function call (`xyplot`, `bwplot`, etc.). Things like margins and spacing are set automatically because the entire plot is specified at once. The `lattice` system is most useful for conditioning types of plots and is good for putting many many plots on a screen. That said, it is sometimes awkward to specify an entire plot in a single function call because many different options have to be specified at once. Furthermore, annotation in plots is not intuitive and the use of panel functions and subscripts is difficult to wield and requires intense preparation.
The `ggplot2` system essentially takes the good parts of both the base graphics and lattice graphics system. It automatically handles things like margins and spacing, and also has the concept of "themes" which provide a default set of plotting symbols and colors. While `ggplot2` bears a superficial similarity to `lattice`, `ggplot2` is generally easier and more intuitive to use. The default thems makes many choices for you, but you can customize the presentation if you want.
## The Basics: `qplot()`
The `qplot()` function in `ggplot2` is meant to get you going *q*uickly. It works much like the `plot()` function in base graphics system. It looks for variables to plot within a data frame, similar to lattice, or in the parent environment. In general, it's good to get used to putting your data in a data frame and then passing it to `qplot()`.
Plots are made up of _aesthetics_ (size, shape, color) and _geoms_ (points, lines). Factors play an important role for indicating subsets of the data (if they are to have different properties) so they should be __labeled__ properly.
The `qplot()` hides much of what goes on underneath, which is okay for most operations, `ggplot()` is the core function and is very flexible for doing things `qplot()` cannot do.
## Before You Start: Label Your Data
One thing that is always true, but is particularly useful when using `ggplot2`, is that you should always use informative and descriptive labels on your data. More generally, your data should have appropriate *metadata* so that you can quickly look at a dataset and know
* what the variables are
* what the values of each variable mean
This means that each column of a data frame should have a meaningful (but concise) variable name that accurately reflects the data stored in that column. Also, non-numeric or categorical variables should be coded as factor variables and have meaningful labels for each level of the factor. For example, it's common to code a binary variable as a "0" or a "1", but the problem is that from quickly looking at the data, it's impossible to know whether which level of that variable is represented by a "0" or a "1". Much better to simply label each observation as what they are. If a variable represents temperature categories, it might be better to use "cold", "mild", and "hot" rather than "1", "2", and "3".
While it's sometimes a pain to make sure all of your data are properly labelled, this investment in time can pay dividends down the road when you're trying to figure out what you were plotting. In other words, including the proper metadata can make your exploratory plots essentially self-documenting.
## ggplot2 “Hello, world!”
This example dataset comes with the `ggplot2` package and contains data on the fuel economy of 38 popular models of car from 1999 to 2008.
```{r}
library(ggplot2)
str(mpg)
```
You can see from the `str()` output that all of the factor variables are appropriately coded with meaningful labels. This will come in handy when `qplot()` has to label different aspects of a plot. Also note that all of the columns/variables have meaningful (if sometimes abbreviated) names, rather than names like "X1", and "X2", etc.
We can make a quick scatterplot of the engine displacement (`displ`) and the highway miles per gallon (`hwy`).
```{r,fig.cap="Plot of engine displacement and highway mileage"}
qplot(displ, hwy, data = mpg)
```
Note that in the call to `qplot()` you must specify the `data` argument so that `qplot()` knows where to look up the variables.
## Modifying aesthetics
We can introduce a third variable into the plot by modifying the color of the points based on the value of that third variable. Color is an aesthetic and the color of each point can be mapped to a variable. Note that the x-coordinates and y-coordinates are aesthetics too, and they got mapped to the `displ` and `hwy` variables, respectively. In this case we will map the color to the `drv` variable which indicates whether a car is front wheel drive, rear wheel drive, or 4-wheel drive.
```{r,fig.cap="Engine displacement and highway mileage by drive class"}
qplot(displ, hwy, data = mpg, color = drv)
```
Now we can see that the front wheel drive cars tend to have lower displacement relative to the 4-wheel or rear wheel drive cars. Also, it's clear that the 4-wheel drive cars have the lowest highway gas mileage.
## Adding a geom
Sometimes it's nice to add a smoother to a scatterplot ot highlight any trends. Trends can be difficult to see if the data are very noisy or there are many data points obscuring the view. A smooth is a "geom" that you can add along with your data points.
```{r,fig.cap="Engine displacement and highway mileage w/smoother"}
qplot(displ, hwy, data = mpg, geom = c("point", "smooth"))
```
Note that previously, we didn't have to specify `geom = "point"` because that was done automatically. But if you want the smoother overlayed with the points, then you need to specify both explicitly.
Here it seems that engine displacement and highway mileage have a nonlinear U-shaped relationship, but from the previous plot we know that this is largely due to confounding by the drive class of the car.
## Histograms
The `qplot()` function can be used to be used to plot 1-dimensional data too. By specifying a single variable, `qplot()` will by default make a histogram. Here we make a histogram if the highway mileage data and stratify on the drive class. So technically this is three histograms overlayed on top of each other.
```{r,fig.cap="Histogram of highway mileage by drive class"}
qplot(hwy, data = mpg, fill = drv, binwidth = 2)
```
Having the different colors for each drive class is nice, but the three histograms can be a bit difficult to separate out. Side-by-side boxplots is one solution to this problem.
```{r,fig.cap="Boxplots of highway mileage by drive class"}
qplot(drv, hwy, data = mpg, geom = "boxplot")
```
Another solution is to plot the histograms in separate panels using facets.
## Facets
Facets are a way to create multiple panels of plots based on the levels of categorical variable. Here, we want to see a histogram of the highway mileages and the categorical variable is the drive class variable. We can do that using the `facets` argument to `qplot()`.
The `facets` argument expects a formula type of input, with a `~` separating the left hand side variable and the right hand side variable. The left hand side variable indicates how the rows of the panels should be divided and the right hand side variable indicates how the columns of the panels should be divided. Here, we just want three rows of histograms (and just one column), one for each drive class, so we specify `drv` on the left hand side and `.` on the right hand side indicating that there's no variable there (it's empty).
```{r,fig.width=5,fig.cap="Histogram of highway mileage by drive class"}
qplot(hwy, data = mpg, facets = drv ~ ., binwidth = 2)
```
We could also look at more data using facets, so instead of histograms we could look at scatterplots of engine displacement and highway mileage by drive class. Here we put the `drv` variable on the right hand side to indicate that we want a column for each drive class (as opposed to splitting by rows like we did above).
```{r, fig.width=6,fig.cap="Engine displacement and highway mileage by drive class"}
qplot(displ, hwy, data = mpg, facets = . ~ drv)
```
What if you wanted to add a smoother to each one of those panels? Simple, you literally just add the smoother as another geom.
```{r, fig.width=6,fig.cap="Engine displacement and highway mileage by drive class w/smoother"}
qplot(displ, hwy, data = mpg, facets = . ~ drv) + geom_smooth()
```
You could have also used the "geom" argument to `qplot()`, as in
```{r,eval=FALSE}
qplot(displ, hwy, data = mpg, facets = . ~ drv, geom = c("point", "smooth"))
```
There's more than one way to do it.
## Case Study: MAACS Cohort
This case study will use data based on the Mouse Allergen and Asthma Cohort Study (MAACS). This study was aimed at characterizing the indoor (home) environment and its relationship with asthma morbidity amonst children aged 5--17 living in Baltimore, MD. The children all had persistent asthma, defined as having had an exacerbation in the past year. A representative publication of results from this study can be found in this paper by [Lu, et al.](http://goo.gl/WqE9j8)
NOTE: Because the individual-level data for this study are protected by various U.S. privacy laws, we cannot make those data available. For the purposes of this chapter, we have simulated data that share many of the same features of the original data, but do not contain any of the actual measurements or values contained in the original dataset.
```{r,echo=FALSE}
maacs <- read.csv("data/maacs_sim.csv")
str(maacs)
```
The key variables are:
* `mopos`: an indicator of whether the subject is allergic to mouse allergen (yes/no)
* `pm25`: average level of PM2.5 over the course of 7 days (micrograms per cubic meter)
* `eno`: exhaled nitric oxide
The outcome of interest for this analysis will be exhaled nitric oxide (eNO), which is a measure of pulmonary inflamation. We can get a sense of how eNO is distributed in this population by making a quick histogram of the variable. Here, we take the log of eNO because some right-skew in the data.
```{r,fig.cap="Histogram of log eNO"}
qplot(log(eno), data = maacs)
```
A quick glance suggests that the histogram is a bit "fat", suggesting that there might be multiple groups of people being lumped together. We can stratify the histogram by whether they are allergic to mouse.
```{r,fig.cap="Histogram of log eNO by mouse allergic status"}
qplot(log(eno), data = maacs, fill = mopos)
```
We can see from this plot that the non-allergic subjects are shifted slightly to the left, indicating a lower eNO and less pulmonary inflammation. That said, there is significant overlap between the two groups.
An alternative to histograms is a density smoother, which sometimes can be easier to visualize when there are multiple groups. Here is a density smooth of the entire study population.
```{r, fig.cap="Density smooth of log eNO"}
qplot(log(eno), data = maacs, geom = "density")
```
And here are the densities straitified by allergic status. We can map the color aesthetic to the `mopos` variable.
```{r,fig.cap="Density smooth of log eNO by mouse allergic status"}
qplot(log(eno), data = maacs, geom = "density", color = mopos)
```
These tell the same story as the stratified histograms, which sould come as no surprise.
Now we can examine the indoor environment and its relationship to eNO. Here, we use the level of indoor PM2.5 as a measure of indoor environment air quality. We can make a simple scatterplot of PM2.5 and eNO.
```{r,fig.cap="eNO and PM2.5"}
qplot(log(pm25), log(eno), data = maacs, geom = c("point", "smooth"))
```
The relationship appears modest at best, as there is substantial noise in the data. However, one question that we might be interested in is whether allergic individuals are prehaps more sensitive to PM2.5 inhalation than non-allergic individuals. To examine that question we can stratify the data into two groups.
This first plot uses different plot symbols for the two groups and overlays them on a single canvas. We can do this by mapping the `mopos` variable to the `shape` aesthetic.
```{r,fig.cap="eNO and PM2.5 by mouse allergic status"}
qplot(log(pm25), log(eno), data = maacs, shape = mopos)
```
Because there is substantial overlap in the data it is a bit challenging to discern the circles from the triangles. Part of the reason might be that all of the symbols are the same color (black).
We can plot each group a different color to see if that helps.
```{r,fig.cap="eNO and PM2.5 by mouse allergic status"}
qplot(log(pm25), log(eno), data = maacs, color = mopos)
```
This is slightly better but the substantial overlap makes it difficult to discern any trends in the data. For this we need to add a smoother of some sort. Here we add a linear regression line (a type of smoother) to each group to see if there's any difference.
```{r}
qplot(log(pm25), log(eno), data = maacs, color = mopos) + geom_smooth(method = "lm")
```
Here we see quite clearly that the red group and the green group exhibit rather different relationships between PM2.5 and eNO. For the non-allergic individuals, there appears to be a slightly negative relationship between PM2.5 and eNO and for the allergic individuals, there is a positive relationship. This suggests a strong interaction between PM2.5 and allergic status, an hypothesis perhaps worth following up on in greater detail than this brief exploratory analysis.
Another, and perhaps more clear, way to visualize this interaction is to use separate panels for the non-allergic and allergic individuals using the `facets` argument to `qplot()`.
```{r, fig.width=9}
qplot(log(pm25), log(eno), data = maacs, facets = . ~ mopos) + geom_smooth(method = "lm")
```
## Summary of qplot()
The `qplot()` function in `ggplot2` is the analog of `plot()` in base graphics but with many built-in features that the traditionaly `plot()` does not provide. The syntax is somewhere in between the base and lattice graphics system. The `qplot()` function is useful for quickly putting data on the page/screen, but for ultimate customization, it may make more sense to use some of the lower level functions that we discuss later in the next chapter.
# The ggplot2 Plotting System: Part 2
In this chapter we'll get into a little more of the nitty gritty of how `ggplot2` builds plots and how you can customize various aspects of any plot. In the previous chapter we used the `qplot()` function to quickly put points on a page. The `qplot()` function's syntax is very similar to that of the `plot()` function in base graphics so for those switching over, it makes for an easy transition. But it's worth knowing the underlying details of how `ggplot2` works so that you can really exploit its power.
## Basic Components of a ggplot2 Plot
A `ggplot2` plot consists of a number of key components. Here are a few of the more commonly used ones.
- A _data frame_: stores all of the data that will be displayed on the plot
- _aesthetic mappings_: describe how data are mapped to color, size, shape, location
- _geoms_: geometric objects like points, lines, shapes.
- _facets_: describes how conditional/panel plots should be constructed
- _stats_: statistical transformations like binning, quantiles, smoothing.
- _scales_: what scale an aesthetic map uses (example: male = red, female = blue).
- _coordinate system_: describes the system in which the locations of the geoms will be drawn
It's essential that you properly organize your data into a data frame before you start with `ggplot2`. In particular, it's important that you provide all of the appropriate metadata so that your data frame is self-describing and your plots will be self-documenting.
When building plots in ggplot2 (rather than using `qplot()`) the "artist's palette"" model may be the closest analogy. Essentially, you start with some raw data, and then you gradually add bits and pieces to it to create a plot. Plots are built up in layers, with the typically ordering being
1. Plot the data
2. Overlay a summary
3. Add metadata and annotation
For quick exploratory plots you may not get past step 1.
## Example: BMI, PM2.5, Asthma
To demonstrate the various pieces of `ggplot2` we will use a running example from the Mouse Allergen and Asthma Cohort Study (MAACS), which was described in the previous chapter. Here, the question we are interested in is
> "Are overweight individuals, as measured by body mass index (BMI), more susceptible than normal weight individuals to the harmful effects of PM2.5 on asthma symptoms?"
There is a suggestion that overweight individuals may be more susceptible to the negative effects of inhaling PM2.5. This would suggest that increases in PM2.5 exposure in the home of an overweight child would be more deleterious to his/her asthma symptoms than they would be in the home of a normal weight child. We want to see if we can see that difference in the data from MAACS.
NOTE: Because the individual-level data for this study are protected by various U.S. privacy laws, we cannot make those data available. For the purposes of this chapter, we have simulated data that share many of the same features of the original data, but do not contain any of the actual measurements or values contained in the original dataset.
We can look at the data quickly with `str()`.
```{r,echo=TRUE}
maacs <- read.csv("data/bmi_pm25_no2_sim.csv")
str(maacs)
```
The outcome we will look at here, `NocturnalSymp`, is the number of days in the past 2 weeks where the child experienced asthma symptoms (e.g. coughing, wheezing) while sleeping.
## Building Up in Layers
First we can create a `ggplot` object that stores the dataset and the basic aesthetics for mapping the x- and y-coordinates for the plot. Here we will eventually be plotting the log of PM2.5 and `NocturnalSymp` variable.
```{r}
head(maacs)
g <- ggplot(maacs, aes(logpm25, NocturnalSympt))
summary(g)
class(g)
```
You can see above that the object `g` contains the dataset `maacs` and the mappings.
Now, normally if you were to `print()` a `ggplot` object a plot would appear on the plot device, however, our object `g` actually doesn't contain enough information to make a plot yet.
```{r, error=TRUE}
g <- ggplot(maacs, aes(logpm25, NocturnalSympt))
print(g)
```
## First Plot with Point Layer
To make a scatterplot we need add at least one *geom*, such as points. Here we add the `geom_point()` function to create a traditional scatterplot.
```{r,Scatterplot of PM2.5 and days with nocturnal symptoms}
g <- ggplot(maacs, aes(logpm25, NocturnalSympt))
g + geom_point()
```
## Adding More Layers: Smooth
Because the data appear rather noisy, it might be better if we added a smoother on top of the points to see if there is a trend in the data with PM2.5.
```{r, fig.cap="Scatterplot with smoother"}
g + geom_point() + geom_smooth()
```
The default smoother is a loess smoother, which is flexible and nonparametric but might be too flexible for our purposes. Perhaps we'd prefer a simple linear regression line to highlight any first order trends. We can do this by specifying `method = "lm"` to `geom_smooth()`.
```{r,fig.cap="Scatterplot with linear regression line"}
g + geom_point() + geom_smooth(method = "lm")
```
Here, we can see there appears to be a slight increasing trend, suggesting that higher levels of PM2.5 are assocuated with increased days with nocturnal symptoms.
## Adding More Layers: Facets
Because our primary question involves comparing overweight individuals to normal weight individuals, we can stratify the scatterplot of PM2.5 and nocturnal symptoms by the BMI category (`bmicat`) variable, which indicates whether an individual is overweight or now. To visualize this we can add a `facet_grid()`, which takes a formula argument. Here we want one row and two columns, one column for each weight category. So we specify `bmicat` on the right hand side of the forumla passed to `facet_grid()`.
```{r, fig.width=9,fig.cap="Scatterplot of PM2.5 and nocturnal symptoms by BMI category"}
g + geom_point() +
geom_smooth(method = "lm") +
facet_grid(. ~ bmicat)
```
Now it seems clear that the relationship between PM2.5 and nocturnal symptoms is relatively flat amongst normal weight individuals, while the relationship is increasing amongst overweight individuals. This plot suggests that overweight individuals may be more susceptible to the effects of PM2.5.
There are a variety of annotations you can add to a plot, including different kinds of labels. You can use `xlab()` for x-axis labels, `ylab()` for y-axis labels, and `ggtitle()` for specifying plot titles. The `labs()` function is generic and can be used to modify multiple types of labels at once.
For things that only make sense globally, use `theme()`, i.e. `theme(legend.position = "none")`. Two standard appearance themes are included
* `theme_gray()`: The default theme (gray background)
* `theme_bw()`: More stark/plain
## Modifying Geom Properties
You can modify properties of geoms by specifying options to their respective `geom_*` functions. For example, here we modify the points in the scatterplot to make the color "steelblue", the size larger , and the alpha transparency greater.
```{r,fig.cap="Modifying point color with a constant"}
g + geom_point(color = "steelblue", size = 4, alpha = 1/2)
```
In addition to setting specific geom attributes to constants, we can map aesthetics to variables. So, here, we map the color aesthetic `color` to the variable `bmicat`, so the points will be colored according to the levels of `bmicat`. We use the `aes()` function to indicate this difference from the plot above.
```{r,fig.cap="Mapping color to a variable"}
g + geom_point(aes(color = bmicat), size = 4, alpha = 1/2)
```
## Modifying Labels
Here is an example of modifying the title and the x and y labels to make the plot a bit more informative.
```{r,fig.cap="Modifying plot labels"}
g + geom_point(aes(color = bmicat)) +
labs(title = "MAACS Cohort") +
labs(x = expression("log " * PM[2.5]), y = "Nocturnal Symptoms")
```
## Customizing the Smooth
We can also customize aspects of the smoother that we overlay on the points with `geom_smooth()`. Here we change the line type and increase the size from the default. We also remove the shaded standard error from the line.
```{r, fig.cap="Customizing a smoother"}
g + geom_point(aes(color = bmicat), size = 2, alpha = 1/2) +
geom_smooth(size = 4, linetype = 3, method = "lm", se = FALSE)
```
## Changing the Theme
The default theme for `ggplot2` uses the gray background with white grid lines. If you don't find this suitable, you can use the black and white theme by using the `theme_bw()` function. The `theme_bw()` function also allows you to set the typeface for the plot, in case you don't want the default Helvetica. Here we change the typeface to Times.
```{r, fig.cap="Modifying the theme for a plot"}
g + geom_point(aes(color = bmicat)) + theme_bw(base_family = "Times")
```
## More Complex Example
Now you get the sense that plots in the `ggplot2` system are constructed by successively adding components to the plot, starting with the base dataset and maybe a scatterplot. In this section we will show a slightly more complicated example with an additional variable. Now, we will ask the question
> How does the relationship between PM2.5 and nocturnal symptoms vary by BMI category and nitrogen dioxide (NO2)?
Unlike our previous BMI variable, NO2 is continuous, and so we need to make NO2 categorical so we can condition on it in the plotting. We can use the `cut()` function for this purpose. We will divide the NO2 variable into tertiles.
First we need to calculate the tertiles with the `quantile()` function.
```{r}
cutpoints <- quantile(maacs$logno2_new, seq(0, 1, length = 4), na.rm = TRUE)
```
Then we need to divide the original `logno2_new` variable into the ranges defined by the cut points computed above.
```{r}
maacs$no2tert <- cut(maacs$logno2_new, cutpoints)
```
The `not2tert` variable is now a categorical factor variable containing 3 levels, indicating the ranges of NO2 (on the log scale).
```{r}
## See the levels of the newly created factor variable
levels(maacs$no2tert)
```
The final plot shows the relationship between PM2.5 and nocturnal symptoms by BMI category and NO2 tertile.
```{r,fig.cap="PM2.5 and nocturnal symptoms by BMI category and NO2 tertile",fig.width=9, fig.height=5}
## Setup ggplot with data frame
g <- ggplot(maacs, aes(logpm25, NocturnalSympt))
## Add layers
g + geom_point(alpha = 1/3) +
facet_wrap(bmicat ~ no2tert, nrow = 2, ncol = 4) +
geom_smooth(method="lm", se=FALSE, col="steelblue") +
theme_bw(base_family = "Avenir", base_size = 10) +
labs(x = expression("log " * PM[2.5])) +
labs(y = "Nocturnal Symptoms") +
labs(title = "MAACS Cohort")
```
## A Quick Aside about Axis Limits
One quick quirk about `ggplot2` that caught me up when I first started using the package can be displayed in the following example. I make a lot of time series plots and I often want to restrict the range of the y-axis while still plotting all the data. In the base graphics system you can do that as follows.
```{r, fig.cap="Time series plot with base graphics"}
testdat <- data.frame(x = 1:100, y = rnorm(100))
testdat[50,2] <- 100 ## Outlier!
plot(testdat$x, testdat$y, type = "l", ylim = c(-3,3))
```
Here I've restricted the y-axis range to be between -3 and 3, even though there is a clear outlier in the data.
With `ggplot2` the default settings will give you this.
```{r,fig.cap="Time series plot with default settings"}
g <- ggplot(testdat, aes(x = x, y = y))
g + geom_line()
```
Modifying the `ylim()` attribute would seem to give you the same thing as the base plot, but it doesn't.
```{r,fig.cap="Time series plot with modified ylim"}
g + geom_line() + ylim(-3, 3)
```
Effectively, what this does is subset the data so that only observations between -3 and 3 are included, then plot the data.
To plot the data without subsetting it first and still get the restricted range, you have to do the following.
```{r,fig.cap="Time series plot with restricted y-axis range"}
g + geom_line() + coord_cartesian(ylim = c(-3, 3))
```
And now you know!
## Resources
- The _ggplot2_ book by Hadley Wickham
- The _R Graphics Cookbook_ by Winston Chang (examples in base plots and in ggplot2)
- ggplot2 web site (http://ggplot2.org)
- ggplot2 mailing list (http://goo.gl/OdW3uB), primarily for developers