forked from hadley/r4ds
-
Notifications
You must be signed in to change notification settings - Fork 0
/
variation.Rmd
607 lines (418 loc) · 25.8 KB
/
variation.Rmd
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
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
863
595
596
597
598
599
600
601
602
603
604
605
606
607
# Variation
```{r, include = FALSE}
library(ggplot2)
```
If you measure any quantity twice---and precisely enough, you will get two different results. This is true even for quantities that should be constant, like the speed of light (below).
This phenomenon, called _variation_, is the beginning of data science. To understand anything you must decipher patterns of variation. But variation does more than just obscure, it is an incredibly useful tool. Patterns of variation provide evidence of causal relationships.
The best way to study variation is to collect data, particularly rectangular data: data that is made up of variables, observations, and values.
* A _variable_ is a quantity, quality, or property that you can measure.
* A _value_ is the state of a variable when you measure it. The value of a
variable may change from measurement to measurement.
* An _observation_ is a set of measurements you make under similar conditions
(usually all at the same time or on the same object). Observations contain
values that you measure on different variables.
Rectangular data provides a clear record of variation, but that doesn't mean it is easy to understand. The human mind isn't built to process tables of data. This section will show you the best ways to comprehend your own data, which is the most important challenge of data science.
```{r, echo = FALSE}
mat <- as.data.frame(matrix(morley$Speed 299500, ncol = 10))
knitr::kable(mat, caption = "*The speed of light is* the *universal constant, but variation obscures its value, here demonstrated by Albert Michelson in 1879. Michelson measured the speed of light 100 times and observed 30 different values (in km/sec).*", col.names = c("\\s", "\\s", "\\s", "\\s", "\\s", "\\s", "\\s", "\\s", "\\s", "\\s"))
```
***
*Tip*: Throughout this section, we will rely on a distinction between two types of variables:
* A variable is **continuous** if you can arrange its values in order _and_ an infinite number of values can exist between any two values of the variable. For example, numbers and date-times are continuous variables. `ggplot2` will treat your variable as continuous if it is a numeric, integer, or a recognizable date-time class (but not a factor, see `?factor`).
* A variable is **discrete** if it is not continuous. Discrete variables can only contain a finite (or countably infinite) set of unique values. For example, character strings and boolean values are discrete variables. `ggplot2` will treat your variable as discrete if it is not a numeric, integer, or recognizable date-time class.
***
### Visualizing Distributions
The first group of geoms visualizes the _distribution_ of the values in a variable.
Recall that a variable is a quantity, quality, or property whose value can change between measurements. This unique property---that the values of a variable can vary---gives the word "variable" its name. It also motivates all of data science. Scientists attempt to understand what determines the value of a variable. They then use that information to predict or control the value of the variable under a variety of circumstances.
One of the most useful tools in this quest are the values themselves, the values that you have already observed for a variable. These values reveal which states of the variable are common, which are rare, and which are seemingly impossible. The pattern of values that emerges as you collect large amounts of data is known as the variable's _distribution_.
The distribution of a variable reveals information about the probabilities associated with the variable. As you collect more data, the proportion of observations that occur at a value (or in an interval) will match the probability that the variable will take that value (or take a value in that interval) in a future measurement.
In theory, it is easy to visualize the distribution of a variable; simply display how many observations occur at each value of the variable. In practice, how you do this will depend on the type of variable that you wish to visualize.
##### Discrete distributions
Use `geom_bar()` to visualize the distribution of a discrete variable. `geom_bar()` counts the number of observations that are associated with each value of the variable, and it displays the results as a series of bars. The height of each bar reveals the count of observations that are associated with the x value of the bar.
```{r}
ggplot(data = diamonds)
geom_bar(mapping = aes(x = cut))
```
***
*Tip* - Since each of the geoms in this subsection visualizes the values of a single variable, you do not need to provide a $y$ aesthetic.
***
Useful aesthetics for `geom_bar()` are:
* x (required)
* alpha
* color
* fill
* linetype
* size
* weight
Useful position adjustments for `geom_bar()` are
* "stack" (default)
* "dodge"
* "fill"
Useful stats for `geom_bar()` are
* "bin" (default)
* "identity" (to map bar heights to a y variable)
The `width` argument of `geom_bar()` controls the width of each bar. The bars will touch when you set `width = 1`.
```{r}
ggplot(data = diamonds)
geom_bar(mapping = aes(x = cut), width = 1)
```
***
*Tip*: You can compute the counts of a discrete variable quickly with R's `table()` function. These are the numbers that `geom_bar()` visualizes.
```{r}
table(diamonds$cut)
```
***
##### Continuous distributions
The strategy of counting the number of observations at each value breaks down for continuous data. If your data is truly continuous, then no two observations will have the same value---so long as you measure the data precisely enough (e.g. without rounding to the _n_th decimal place).
To get around this, data scientists divide the range of a continuous variable into equally spaced intervals, a process called _binning_.
```{r, echo = FALSE}
# knitr::include_graphics("images/visualization-17.png")
```
They then count how many observations fall into each bin.
```{r, echo = FALSE}
# knitr::include_graphics("images/visualization-18.png")
```
And display the count as a bar, or some other object.
```{r, echo = FALSE}
# knitr::include_graphics("images/visualization-19.png")
```
This method is temperamental because the appearance of the distribution can change dramatically if the bin size changes. As no bin size is "correct," you should explore several bin sizes when examining data.
```{r, echo = FALSE}
# knitr::include_graphics("images/visualization-20.png")
```
Several geoms exist to help you visualize continuous distributions. They almost all use the "bin" stat to implement the above strategy. For each of these geoms, you can set the following arguments for "bin" to use:
* `binwidth` - the width to use for the bins in the same units as the x variable
* `origin` - origin of the first bin interval
* `right` - if `TRUE` bins will be right closed (e.g. points that fall on the border of two bins will be counted with the bin to the left)
* `breaks` - a vector of actual bin breaks to use. If you set the breaks argument, it will overide the binwidth and origin arguments.
Use `geom_histogram()` to make a traditional histogram. The height of each bar reveals how many observations fall within the width of the bar.
```{r}
ggplot(data = diamonds)
geom_histogram(aes(x = carat))
```
By default, `geom_histogram()` will divide the range of the variable into 30 equal length bins. The quickest way to change this behavior is to set the binwidth argument.
```{r}
ggplot(data = diamonds)
geom_histogram(aes(x = carat), binwidth = 1)
```
Notice how different binwidths reveal different information. The plot above shows that the availability of diamonds decreases quickly as carat size increases. The plot below shows that there are more diamonds than you would expect at whole carat sizes (and common fractions of carat sizes). Moreover, for each popular size, there are more diamonds that are slightly larger than the size than there are that are slightly smaller than the size.
```{r}
ggplot(data = diamonds)
geom_histogram(aes(x = carat), binwidth = 0.01)
```
Useful aesthetics for `geom_histogram()` are:
* x (required)
* alpha
* color
* fill
* linetype
* size
* weight
Useful position adjustments for `geom_histogram()` are
* "stack" (default)
* "fill"
`geom_freqpoly()` uses a line to display the same information as `geom_histogram()`. You can think of `geom_freqpoly()` as drawing a line that connects the tops of the bars that would appear in a histogram.
```{r message = FALSE, fig.show='hold', fig.width=4, fig.height=4}
ggplot(data = diamonds)
geom_freqpoly(aes(x = carat))
ggplot(data = diamonds)
geom_histogram(aes(x = carat))
```
It is easier to compare levels of a third variable with `geom_freqpoly()` than with `geom_histogram()`. `geom_freqpoly()` displays the shape of the distribution faithfully for each subgroup because you can plot multiple lines in the same graph without adjusting their position. Notice that `geom_histogram()` must stack each new subgroup on top of the others, which obscures the shape of the distributions.
```{r message = FALSE, fig.show='hold', fig.width=4, fig.height=4}
ggplot(data = diamonds)
geom_freqpoly(aes(x = carat, color = cut))
ggplot(data = diamonds)
geom_histogram(aes(x = carat, fill = cut))
```
Useful aesthetics for `geom_freqpoly()` are:
* x (required)
* y
* alpha
* color
* linetype
* size
Although the name of `geom_freqpoly()` suggests that it draws a polygon, it actually draws a line. You can draw the same information as a true polygon (and thus fill in the area below the line) if you combine `geom_area()` with `stat = "bin"`. You will learn more about `geom_area()` in _Visualizing functions between two variables_.
```{r}
ggplot(data = diamonds)
geom_area(aes(x = carat, fill = cut), stat = "bin", position = "stack")
```
`geom_density()` plots a one dimensional kernel density estimate of a variable's distribution. The result is a smooth version of the information contained in a histogram or a freqpoly.
```{r}
ggplot(data = diamonds)
geom_density(aes(x = carat))
```
`geom_density()` displays $density$---not $count$---on the y axis, which makes it easier to compare the shape of the distributions of multiple subgroups; the area under each curve will be normalized to one, no matter how many total observations occur in the subgroup.
`geom_density()` does not use the binwidth argument. You can control the smoothness of the density with `adjust`, and you can select the kernel to use to estimate the density with `kernel`. Set kernel to one of "gaussian" (default), "epanechikov", "rectangular", "triangular", "biweight", "cosine", "optcosine".
```{r}
ggplot(data = diamonds)
geom_density(aes(x = carat, color = cut), kernel = "gaussian", adjust = 4)
```
Useful aesthetics for `geom_density()` are:
* x (required)
* y
* alpha
* color
* fill
* linetype
* size
Useful position adjustments for `geom_density()` are
* "identity" (default)
* "stack" (when using the fill aesthetic)
* "fill" (when using the fill aesthetic)
`geom_dotplot()` provides a final way to visualize distributions. This unique geom displays a point for each observation, but it stacks points that appear in the same bin on top of each other. The result is similar to a histogram, the height of each stack reveals the number of points in the stack.
```{r}
ggplot(data = mpg)
geom_dotplot(aes(x = displ), binwidth = 0.2)
```
Useful aesthetics for `geom_dotplot()` are:
* x (required)
* y
* alpha
* color
* fill
Useful arguments that apply to `geom_dotplot()`
* `binaxis` - the axis to bin along ("x" or "y")
* `binwidth` - the interval width to use when binning
* `dotsize` - diameter of dots relative to binwidth
* `stackdir` - which direction to stack the dots ("up" (default), "down", "center", "centerwhole")
* `stackgroups` - Has the equivalent of `position = "stack"` when set to true.
* `stackratio` - how close to stack the dots. Values less than 1 cause dots to overlap, which shortens stacks.
In practice, I find that `geom_dotplot()` works best with small data sets and takes a lot of tweaking of the binwidth, dotsize, and stackratio arguments to fit the dots within the graph (the stack heights depend entirely on the organization of the dots, which renders the y axis ambiguous). That said, dotplots can be useful as a learning aid. They provide an intuitive representation of a histogram.
### Compare Distributions
### Visualize Covariation
#### Visualize functions between two variables
Distributions provide useful information about variables, but the information is general. By itself, a distribution cannot tell you how the value of a variable in one set of circumstances will differ from the value of the same variable in a different set of circumstances.
_Covariation_ can provide more specific information. Covariation is a relationship between the values of two or more variables.
To see how covariation works, consider two variables: the $volume$ of an object and its $temperature$. If the $volume$ of the object usually increases when the $temperature$ of the object increases, then you could use the value of $temperature$ to help predict the value of $volume$.
You've probably heard that "correlation (covariation) does not prove causation." This is true, two variables can covary without one causing the other. However, covariation is often the first clue that two variables have a causal relationship.
Visualization is one of the best ways to spot covariation. How you look for covariation will depend on the structural relationship between two variables. The simplest structure occurs when two continuous variables have a functional relationship, where each value of one variable corresponds to a single value of the second variable.
In this scenario, covariation will appear as a pattern in the relationship. If two variables o not covary, their functional relationship will look like a random walk.
The variables `date` and `unemploy` in the `economics` data set have a functional relationship. The `economics` data set comes with `ggplot2` and contains various economic indicators for the United States between 1967 and 2007. The `unemploy` variable measures the number of unemployed individuals in the United States in thousands.
A scatterplot of the data reveals the functional relationship between `date` and `unemploy`.
```{r}
ggplot(data = economics)
geom_point(aes(x = date, y = unemploy))
```
`geom_line()` makes the relationship clear. `geom_line()` creates a line chart, one of the most used---and most efficient---devices for visualizing a function.
```{r}
ggplot(data = economics)
geom_line(aes(x = date, y = unemploy))
```
Useful aesthetics for `geom_line()` are:
* x (required)
* y (required)
* alpha
* color
* linetype
* size
Use `geom_step()` to turn a line chart into a step function. Here, the result will be easier to see with a subset of data.
```{r}
ggplot(data = economics[1:150, ])
geom_step(aes(x = date, y = unemploy))
```
Control the step direction by giving `geom_step()` a direction argument. `direction = "hv"` will make stairs that move horizontally then vertically to connect points. `direction = "vh"` will do the opposite.
Useful aesthetics for `geom_step()` are:
* x (required)
* y (required)
* alpha
* color
* linetype
* size
`geom_area()` creates a line chart with a filled area under the line.
```{r}
ggplot(data = economics)
geom_area(aes(x = date, y = unemploy))
```
Useful aesthetics for `geom_area()` are:
* x (required)
* y (required)
* alpha
* color
* fill
* linetype
* size
##### Visualize correlations between two variables
Many variables do not have a functional relationship. As a result, a single value of one variable can correspond to multiple values of another variable.
Height and weight are two variables that are often related, but do not have a functional relationship. You could examine a classroom of students and notice that three different students, with three different weights all have the same height, 5'4". In this case, there is not a one to one relationship between height and weight.
The easiest way to plot the relationship between two variables is with a scatterplot, i.e. `geom_point()`. If the variables covary, a pattern will appear in the points. If they do not, the points will look like a random cloud of points.
```{r}
ggplot(data = mpg)
geom_point(mapping = aes(x = displ, y = hwy))
```
Useful aesthetics for `geom_point()` are:
* x (required)
* y (required)
* alpha
* color
* fill (for some shapes)
* shape
* size
Useful position adjustments for `geom_point()` are:
* "identity" (default)
* "jitter"
In fact, the jitter adjustment is so useful that `ggplot2` provides the `geom_jitter()`, which is identical to `geom_point()` but comes with `position = "jitter"` by default.
```{r}
ggplot(data = mpg)
geom_jitter(mapping = aes(x = displ, y = hwy))
```
`geom_jitter()` can be a useful way to visualize the distribution between two discrete variables. Can you tell why `geom_point()` would be less useful here?
```{r}
ggplot(data = mpg)
geom_jitter(mapping = aes(x = cyl, y = fl, color = fl))
```
Use `geom_rug()` to visualize the distribution of each variable in the scatterplot. `geom_rug()` adds a tickmark along each axis for each value observed in the data. `geom_rug()` works best as a second layer in the plot (see Section 3 for more info on layers).
```{r}
ggplot(data = mpg)
geom_point(mapping = aes(x = displ, y = hwy))
geom_rug(mapping = aes(x = displ, y = hwy), position = "jitter")
```
Use the `sides` argument to control which axes to place a "rug" on.
* `sides = "bl"` - (default) Places a rug on each axis
* `sides = "b"` - Places a rug on the bottom axis
* `sides = "l"` - Places a rug on the left axis
Useful aesthetics for `geom_rug()` are:
* x (required)
* y (required)
* alpha
* color
* linetype
* size
Useful position adjustments for `geom_rug()` are:
* "identity" (default)
* "jitter"
Use `geom_text()` to display a label, instead of a point, for each observation in a scatterplot. `geom_text()` lets you add information to the scatterplot, but is less effective when you have many data points.
```{r}
ggplot(data = mpg[sample(1:234, 10), ])
geom_text(mapping = aes(x = displ, y = hwy, label = class))
```
Useful aesthetics for `geom_text()` are:
* x (required)
* y (required)
* alpha
* angle
* color
* family
* fontface
* hjust
* label (`geom_text()` displays the values of this variable)
* lineheight
* linetype
* size
* vjust
Control the appearance of the labels with the following arguments. You can also use each of these arguments as an aesthetic. To do so, set them inside the `aes()` call in `geom_text()`'s mapping argument.
* `angle` - angle of text
* `family` - font family of text
* `fontface` - bold, italic, etc.
* `hjust` - horizontal adjustment
* `vjust`- vertical adjustment
Scatterplots do not work well with large data sets because individual points will begin to occlude each other. As a result, you cannot tell where the mass of the data lies. Does a black region contain a single layer of points? Or hundreds of points stacked on top of each other.
You can see this type of plotting in the `diamonds` data set. The data set only contains 53,940 points, but the points overplot each other in a way that we cannot fix with jittering.
```{r}
ggplot(data = diamonds)
geom_point(mapping = aes(x = carat, y = price))
```
For large data, it is more useful to plot summary information that describes the raw data than it is to plot the raw data itself. Several geoms can help you do this.
The simplest way to summarize covariance between two variables is with a model line. The model line displays the trend of the relationship between the variables.
Use `geom_smooth()` to display a model line between any two variables. As with `geom_rug()`, `geom_smooth()` works well as a second layer for a plot (See Section 3 for details).
```{r}
ggplot(data = diamonds)
geom_point(mapping = aes(x = carat, y = price))
geom_smooth(mapping = aes(x = carat, y = price))
```
`geom_smooth()` will add a loess line to your data if the data contains less than 1000 points, otherwise it will fit a general additive model to your data with a cubic regression spline, and plot the resulting model line. In either case, `geom_smooth()` will display a message in the console to tell you what it is doing. This is not a warning message; you do not need to worry when you see it.
`geom_smooth()` will also plot a standard error band around the model line. You can remove the standard error band by setting the `se` argument of `geom_smooth()` to `FALSE`.
Use the `model` argument of `geom_smooth()` to adda specific type of model line to your data. `model` takes the name of an R modeling function. `geom_smooth()` will use the function to calculate the model line. For example, the code below uses R's `lm()` function to fit a linear model line to the data.
```{r}
ggplot(data = diamonds)
geom_point(mapping = aes(x = carat, y = price))
geom_smooth(mapping = aes(x = carat, y = price), method = lm)
```
By default, `geom_smooth()` will use the formula `y ~ x` to model your data. You can modify this formula by setting the `formula` argument to a different formula. If you do this, be sure to refer to the variable on your $x$ axis as `x` and the variable on your $y$ axis as `y`, e.g.
```{r}
ggplot(data = diamonds)
geom_point(mapping = aes(x = carat, y = price))
geom_smooth(mapping = aes(x = carat, y = price),
method = lm, formula = y ~ poly(x, 4))
```
Useful aesthetics for `geom_smooth()` are:
* x (required)
* y (required)
* alpha
* color
* fill
* linetype
* size
* weight
Useful arguments for `geom_smooth()` are:
* `formula` - the formula to use in the smoothing function
* `fullrange` - Should the fit span the full range of the plot, or just the data?
* `level` - Confidence level to use for standard error ribbon
* `method` - Smoothing function to use, a model function in R
* `n` - The number of points to evaluate smoother at (defaults to 80)
* `se` - If TRUE` (the default), `geom_smooth()` will include a standard error ribbon
Be careful, `geom_smooth()` will overlay a trend line on every data set, even if the underlying data is uncorrelated. You can avoid being fooled by also inspecting the raw data or calculating the correlation between your variables, e.g. `cor(diamonds$carat, diamonds$price)`.
`geom_quantile()` fits a different type of model to your data. Use it to display the results of a quantile regression (see `?rq` for details). Like `geom_smooth()`, `geom_quantile()` takes a formula argument that describes the relationship between $x$ and $y$.
```{r}
ggplot(data = diamonds)
geom_point(mapping = aes(x = carat, y = price))
geom_quantile(mapping = aes(x = carat, y = price),
quantiles = c(0.05, 0.5, 0.95),
formula = y ~ poly(x, 2))
```
Useful aesthetics for `geom_quantile()` are:
* x (required)
* y (required)
* alpha
* color
* linetype
* size
* weight
Useful arguments for `geom_quantile()` are:
* `formula` - the formula to use in the smoothing function
* `quantiles` - Conditional quantiles of $y$ to display. Each quantile is displayed with a line.
`geom_smooth()` and `geom_quantile()` summarize the relationship between two variables as a function, but you can also summarize the relationship as a bivariate distribution.
`geom_bin2d()` divides the coordinate plane into a two dimensional grid and then displays the number of observations that fall into each bin in the grid. This technique let's you see where the mass of the data lies; bins with a light fill color contain more data than bins with a dark fill color. Bins with no fill contain no data at all.
```{r}
ggplot(data = diamonds)
geom_bin2d(mapping = aes(x = carat, y = price), binwidth = c(0.1, 500))
```
Useful aesthetics for `geom_bin2d()` are:
* x (required)
* y (required)
* alpha
* color
* fill
* size
* weight
Useful arguments for `geom_bin2d()` are:
* `bins` - A vector like `c(30, 40)` that gives the number of bins to use in the horizontal and vertical directions.
* `binwidth` - A vector like `c(0.1, 500)` that gives the binwidths to use in the horizontal and vertical directions. Overrides `bins` when set.
* `drop` - If `TRUE` (default) `geom_bin2d()` removes the fill from all bins that contain zero observations.
`geom_hex()` works similarly to `geom_bin2d()`, but it divides the coordinate plain into hexagon shaped bins. This can reduce visual artifacts that are introduced by the aligning edges of rectangular bins.
```{r}
ggplot(data = diamonds)
geom_hex(mapping = aes(x = carat, y = price), binwidth = c(0.1, 500))
```
`geom_hex()` requires the `hexbin` package, which you can install with `install.packages("hexbin")`.
`geom_density2d()` uses density contours to display similar information. It is the two dimensional equivalent of `geom_density()`. Interpret a two dimensional density plot the same way you would interpret a contour map. Each line connects an area of equal density, which makes changes of slope easy to see.
As with other summary geoms, `geom_density2d()` makes a useful second layer.
```{r}
ggplot(data = diamonds)
geom_point(mapping = aes(x = carat, y = price))
geom_density2d(mapping = aes(x = carat, y = price))
```
Useful aesthetics for `geom_density2d()` are:
* x (required)
* y (required)
* alpha
* color
* linetype
* size
Useful arguments for `geom_density2d()` are:
* `h` - A vector like `c(0.2, 500)` that gives the bandwiths to use to estimate the density in the horizontal and vertical directions.
* `n` - number of gridpoints to use when estimating the density (defaults to 100).
##### Visualize correlations between three variables
There are two ways to add three (or more) variables to a two dimensional plot. You can map additional variables to aesthics within the plot, or you can use a geom that is designed to visualize three variables.
`ggplot2` provides three geoms that are designed to display three variables: `geom_raster()`, `geom_tile()` and `geom_contour()`. These geoms generalize `geom_bin2d()` and `geom_density()` to display a third variable instead of a count, or a density.
`geom_raster()` and `geom_tile()`