Skip to content

Commit 6cf1370

Browse files
FAQ vignettes for ggplot2 (tidyverse#4404)
1 parent 397c1c7 commit 6cf1370

13 files changed

+2051
-0
lines changed

.Rbuildignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@ visual_test
2626
^vignettes/profiling.Rmd$
2727
^cran-comments\.md$
2828
^LICENSE\.md$
29+
^vignettes/articles$

DESCRIPTION

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,3 +269,7 @@ VignetteBuilder: knitr
269269
RoxygenNote: 7.1.1
270270
Roxygen: list(markdown = TRUE)
271271
Encoding: UTF-8
272+
Config/Needs/Website:
273+
ggtext,
274+
tidyr,
275+
forcats

_pkgdown.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,31 @@ reference:
243243
- fortify
244244
- map_data
245245

246+
247+
articles:
248+
- title: Building plots
249+
navbar: ~
250+
contents:
251+
- ggplot2-specs
252+
253+
- title: Developer
254+
navbar: Developer
255+
contents:
256+
- extending-ggplot2
257+
- ggplot2-in-packages
258+
- profiling
259+
260+
- title: FAQ
261+
navbar: FAQ
262+
contents:
263+
- articles/faq-axes
264+
- articles/faq-faceting
265+
- articles/faq-customising
266+
- articles/faq-annotation
267+
- articles/faq-reordering
268+
- articles/faq-bars
269+
270+
246271
news:
247272
releases:
248273
- text: "Version 3.3.0"

vignettes/articles/faq-annotation.Rmd

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
---
2+
title: "FAQ: Annotation"
3+
---
4+
5+
```{=html}
6+
<style>
7+
.content h3 {
8+
margin-top: -30px !important;
9+
}
10+
11+
details {
12+
margin-bottom: 40px;
13+
}
14+
</style>
15+
```
16+
```{r, include = FALSE}
17+
library(ggplot2)
18+
library(dplyr)
19+
knitr::opts_chunk$set(
20+
fig.dpi = 300,
21+
collapse = TRUE,
22+
comment = "#>",
23+
fig.asp = 0.618,
24+
fig.width = 6,
25+
out.width = "80%"
26+
)
27+
```
28+
29+
30+
31+
### Why is annotation created with `geom_text()` pixellated? How can I make it more crisp?
32+
33+
You should use `annotate(geom = "text")` instead of `geom_text()` for annotation.
34+
35+
<details>
36+
37+
<summary>See example</summary>
38+
39+
In the following visualisation we have annotated a histogram with a red line and red text to mark the mean. Note that both the line and the text appears pixellated/fuzzy.
40+
41+
```{r}
42+
mean_hwy <- round(mean(mpg$hwy), 2)
43+
44+
ggplot(mpg, aes(x = hwy)) +
45+
geom_histogram(binwidth = 2) +
46+
geom_segment(
47+
x = mean_hwy, xend = mean_hwy,
48+
y = 0, yend = 35,
49+
color = "red"
50+
) +
51+
geom_text(
52+
x = mean_hwy, y = 40,
53+
label = paste("mean\n", mean_hwy),
54+
color = "red"
55+
)
56+
```
57+
58+
This is because `geom_text()` draws the geom once per each row of the data frame, and plotting these on top of each other. For annotation (as opposed to plotting the data using text as geometric objects to represent each observation) use `annotate()` instead.
59+
60+
61+
```{r}
62+
ggplot(mpg, aes(x = hwy)) +
63+
geom_histogram(binwidth = 2) +
64+
annotate("segment",
65+
x = mean_hwy, xend = mean_hwy, y = 0, yend = 35,
66+
color = "red"
67+
) +
68+
annotate("text",
69+
x = mean_hwy, y = 40,
70+
label = paste("mean =", mean_hwy),
71+
color = "red"
72+
)
73+
```
74+
75+
</details>
76+
77+
### How can I make sure all annotation created with `geom_text()` fits in the bounds of the plot?
78+
79+
Set `vjust = "inward"` and `hjust = "inward"` in `geom_text()`.
80+
81+
<details>
82+
83+
<summary>See example</summary>
84+
85+
Suppose you have the following data frame and visualization. The labels at the edges of the plot are cut off slightly.
86+
87+
```{r}
88+
df <- tibble::tribble(
89+
~x, ~y, ~name,
90+
2, 2, "two",
91+
3, 3, "three",
92+
4, 4, "four"
93+
)
94+
95+
ggplot(df, aes(x = x, y = y, label = name)) +
96+
geom_text(size = 10)
97+
```
98+
99+
You could manually extend axis limits to avoid this, but a more straightforward approach is to set `vjust = "inward"` and `hjust = "inward"` in `geom_text()`.
100+
101+
```{r}
102+
ggplot(df, aes(x = x, y = y, label = name)) +
103+
geom_text(size = 10, vjust = "inward", hjust = "inward")
104+
```
105+
106+
</details>
107+
108+
### How can I annotate my bar plot to display counts for each bar?
109+
110+
Either calculate the counts ahead of time and place them on bars using `geom_text()` or let `ggplot()` calculate them for you and then add them to the plot using `stat_coun()` with `geom = "text"`.
111+
112+
<details>
113+
114+
<summary>See example</summary>
115+
116+
Suppose you have the following bar plot and you want to add the number of cars that fall into each `drv` level on their respective bars.
117+
118+
```{r}
119+
ggplot(mpg, aes(x = drv)) +
120+
geom_bar()
121+
```
122+
123+
One option is to calculate the counts with `dplyr::count()` and then pass them to the `label` mapping in `geom_text()`.
124+
Note that we expanded the y axis limit to get the numbers to fit on the plot.
125+
126+
```{r}
127+
mpg %>%
128+
dplyr::count(drv) %>%
129+
ggplot(aes(x = drv, y = n)) +
130+
geom_col() +
131+
geom_text(aes(label = n), vjust = -0.5) +
132+
coord_cartesian(ylim = c(0, 110))
133+
```
134+
135+
Another option is to let `ggplot()` do the counting for you, and access these counts with `..count..` that is mapped to the labels to be placed on the plot with `stat_count()`.
136+
137+
```{r}
138+
ggplot(mpg, aes(x = drv)) +
139+
geom_bar() +
140+
stat_count(geom = "text", aes(label = ..count..), vjust = -0.5) +
141+
coord_cartesian(ylim = c(0, 110))
142+
```
143+
144+
</details>
145+
146+
### How can I annotate my stacked bar plot to display counts for each segment?
147+
148+
First calculate the counts for each segment (e.g. with `dplyr::count()`) and then place them on the bars with `geom_text()` using `position_stack(vjust = 0.5)` in the `position` argument to place the values in the middle of the segments.
149+
150+
<details>
151+
152+
<summary>See example</summary>
153+
154+
Suppose you have the following stacked bar plot.
155+
156+
```{r}
157+
ggplot(mpg, aes(x = class, fill = drv)) +
158+
geom_bar()
159+
```
160+
161+
You can first calculate the counts for each segment with `dplyr::count()`, which will place these values in a column called `n`.
162+
163+
```{r}
164+
mpg %>%
165+
count(class, drv)
166+
```
167+
168+
You can then pass this result directly to `ggplot()`, draw the segments with appropriate heights with `y = n` in the `aes`thetic mapping and `geom_col()` to draw the bars, and finally place the counts on the plot with `geom_text()`.
169+
170+
```{r}
171+
mpg %>%
172+
count(class, drv) %>%
173+
ggplot(aes(x = class, fill = drv, y = n)) +
174+
geom_col() +
175+
geom_text(aes(label = n), size = 3, position = position_stack(vjust = 0.5))
176+
```
177+
178+
</details>
179+
180+
### How can I display proportions (relative frequencies) instead of counts on a bar plot?
181+
182+
Either calculate the prpportions ahead of time and place them on bars using `geom_text()` or let `ggplot()` calculate them for you and then add them to the plot using `stat_coun()` with `geom = "text"`.
183+
184+
<details>
185+
186+
<summary>See example</summary>
187+
188+
Suppose you have the following bar plot but you want to display the proportion of cars that fall into each `drv` level, instead of the count.
189+
190+
```{r}
191+
ggplot(mpg, aes(x = drv)) +
192+
geom_bar()
193+
```
194+
195+
One option is to calculate the proportions with `dplyr::count()` and then use `geom_col()` to draw the bars
196+
197+
```{r}
198+
mpg %>%
199+
dplyr::count(drv) %>%
200+
mutate(prop = n / sum(n)) %>%
201+
ggplot(aes(x = drv, y = prop)) +
202+
geom_col()
203+
```
204+
205+
Another option is to let `ggplot()` do the calculation of proportions for you, and access these counts with `..prop..`.
206+
Note that we also need to the `group = 1` mapping for this option.
207+
208+
```{r}
209+
ggplot(mpg, aes(x = drv, y = ..prop.., group = 1)) +
210+
geom_bar()
211+
```
212+
213+
</details>
214+

0 commit comments

Comments
 (0)