This repository has been archived by the owner on Apr 16, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 8
/
tables.Rmd
764 lines (638 loc) · 27.9 KB
/
tables.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
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
---
output: html_document
editor_options:
chunk_output_type: console
---
```{r}
i <- 1
chapter_number <- 5
source("_common.R")
```
# Crafting High-Quality Tables {#tables-chapter}
In his book *Fundamentals of Data Visualization*, Claus Wilke writes that tables are "an important tool for visualizing data." This statement might seem odd. Tables are often considered the opposite of data visualizations such as plots: a place to dump numbers for the few nerds who care to read them. But Wilke sees things differently.
Tables should not be data dumps devoid of design. While bars, lines, and points in graphs are visualizations, so too are numbers in a table, and we should care about their appearance. As an example, take a look at the tables made by reputable news sources; data dumps these are not. Media organizations, whose job it is to communicate effectively, pay a lot of attention to table design. But elsewhere, because of tables’ apparent simplicity, Wilke writes, "they may not always receive the attention they need."
Many people use Microsoft Word to make tables, a strategy that has potential pitfalls. Wilke found that his version of Word included 105 built-in table styles. Of those, around 80 percent, including the default style, violated some key principle of table design. The good news is that R is a great tool for making high-quality tables. It has a number of packages for this purpose, and within these packages, several functions designed to make sure your tables follow important design principles.
Moreover, if you’re writing reports in R Markdown (which you’ll learn about in Chapter \@ref(rmarkdown-chapter)), you can include code that will generate a table when you export your document. By working with a single tool to create tables, text, and other visualizations, you won’t have to copy and paste your data, lowering the risk of human error.
This chapter examines table design principles and shows you how to apply them to your tables using R’s `gt` package, one of the most popular table-making packages (and, as you’ll soon see, one that uses good design principles by default). These principles, and the code in this chapter, are adapted from Tom Mock’s blog post "10+ Guidelines for Better Tables in R." Mock works at Posit, the company that makes RStudio, and has become something of an R table connoisseur. We’ll walk through examples of Mock’s code to show how small tweaks can make a big difference.
## Creating a Data Frame {-}
We’ll begin by creating a data frame that we can use to make tables throughout this chapter. First, let’s load the packages we need. We’ll rely on the `tidyverse` package for general data manipulation functions, `gapminder` for the data we’ll use, `gt` to make the tables, and `gtExtras` to do some formatting on our tables:
```{r echo = TRUE}
library(tidyverse)
library(gapminder)
library(gt)
library(gtExtras)
```
As we saw in Chapter \@ref(data-viz-chapter), the `gapminder` package provides country-level demographic statistics. To make a data frame for our table, let’s use just a few countries (the first four, in alphabetical order: Afghanistan, Albania, Algeria, and Angola) and three years (1952, 1972, and 1992). The `gapminder` data has many years, but we need only a few to demonstrate table-making principles. Here is the code to make the data frame called `gdp`:
```{r echo = TRUE}
gdp <- gapminder %>%
filter(country %in% c("Afghanistan", "Albania", "Algeria", "Angola")) %>%
select(country, year, gdpPercap) %>%
mutate(country = as.character(country)) %>%
pivot_wider(
id_cols = country,
names_from = year,
values_from = gdpPercap
) %>%
select(country, `1952`, `1972`, `1992`) %>%
rename(Country = country)
```
Let’s see what `gdp` looks like:
```{r}
gdp
```
Now that we have some data, let’s use it to make a table.
## Table Design Principles {-}
Unsurprisingly, the principles of good table design are similar to those for data visualization more generally. In this section, we cover six of the most important.
### Principle One: Minimize Clutter {-}
As with data visualization, one of the most important principles of table design is to minimize clutter. One way we can do this is by removing unnecessary elements. A common source of clutter in tables is gridlines. Often, you see tables that look like Figure \@ref(fig:table-with-gridlines).
```{r results='asis', include = TRUE, echo = FALSE}
print_nostarch_file_name(file_type_to_print = "png")
table <- gdp %>%
gt() %>%
tab_style(
style = cell_borders(
side = "all",
color = "black",
weight = px(1),
style = "solid"
),
locations = list(
cells_body(
everything()
),
cells_column_labels(
everything()
)
)
) %>%
opt_table_lines(extent = "none")
```
```{r table-with-gridlines, fig.cap = "A table with gridlines everywhere"}
save_table_for_nostarch(table)
```
Having gridlines around every single cell in our table is unnecessary and creates visual clutter that distracts from the goal of communicating clearly. A table with minimal or even no gridlines (Figure \@ref(fig:table-horizontal-gridlines)) is a much more effective communication tool.
```{r results='asis', include = TRUE, echo = FALSE}
print_nostarch_file_name(file_type_to_print = "png")
table <- gdp %>%
gt()
```
```{r table-horizontal-gridlines, fig.cap = "A table with only horizontal gridlines"}
save_table_for_nostarch(table)
```
I mentioned that `gt` uses good table design principles by default, and this guideline is a great example of it. The second table, with minimal gridlines, requires just two lines of code. We pipe our `gdp` data into the `gt()` function, which creates a table:
```{r echo = TRUE, eval = FALSE}
gdp %>%
gt()
```
To add gridlines to every part of the example, we would have to add additional code. Here, the code that follows the `gt()` function adds gridlines:
```{r echo = TRUE, eval = FALSE}
gdp %>%
gt() %>%
tab_style(
style = cell_borders(
side = "all",
color = "black",
weight = px(1),
style = "solid"
),
locations = list(
cells_body(
everything()
),
cells_column_labels(
everything()
)
)
) %>%
opt_table_lines(extent = "none")
```
Since I don’t recommend taking this approach, I won’t walk through this code. However, if we wanted to remove additional gridlines, we could use the following:
```{r remove-gridlines, echo = TRUE, eval = FALSE}
gdp %>%
gt() %>%
tab_style(
style = cell_borders(color = "transparent"),
locations = cells_body()
)
```
The `tab_style()` function uses a two-step approach. First, it identifies the style we want to modify (in this case, the borders); next, it tells the function where to apply these styles. Here, we tell `tab_style()` that we want to modify the borders using the `cell_borders()` function, making our borders transparent. Then, we say that we want this transformation to apply to the `cells_body()` location. Other options include `cells_column_labels()` for the first row.
Doing this gives us a table with no gridlines at all in the body (Figure \@ref(fig:table-no-body-gridlines)).
```{r results='asis', include = TRUE, echo = FALSE}
print_nostarch_file_name(file_type_to_print = "png")
table <- gdp %>%
gt() %>%
tab_style(
style = cell_borders(color = "transparent"),
locations = cells_body()
)
```
```{r table-no-body-gridlines, fig.cap = "Figure 1-3 A table with gridlines only on the header row and the bottom"}
save_table_for_nostarch(table)
```
Let’s save this table as an object called `table_no_gridlines` so that we can add onto it later.
```{r}
table_no_gridlines <- gdp %>%
gt() %>%
tab_style(
style = cell_borders(color = "transparent"),
locations = cells_body()
)
```
### Principle Two: Differentiate the Header from the Body {-}
While reducing clutter is an important goal, going too far can have negative consequences. A table with no gridlines at all can make it hard to differentiate between the header row and the table body. Take Figure \@ref(fig:table-no-gridlines-at-all), for example.
```{r results='asis', include = TRUE, echo = FALSE}
print_nostarch_file_name(file_type_to_print = "png")
table <- gdp %>%
gt() %>%
opt_table_lines(extent = "none")
```
```{r table-no-gridlines-at-all, fig.cap = "A table with all gridlines removed"}
save_table_for_nostarch(table)
```
We’ve already covered how to use appropriate gridlines. But by making the header row bold, we can make it stand out even more:
```{r echo = TRUE, eval = FALSE}
table_no_gridlines %>%
tab_style(
style = cell_text(weight = "bold"),
locations = cells_column_labels()
)
```
We start with the `table_no_gridlines` object (our saved table from earlier). Then, we apply our formatting with the `tab_style()` function using two steps. First, we say that we want to alter the text by using the `cell_text()` function to set the weight to bold. Second, we say we want this to happen only to the header row using the `cells_column_labels()` function. In Figure \@ref(fig:table-bolded-header), we can see what our table looks like with headers bolded.
```{r results='asis', include = TRUE}
print_nostarch_file_name(file_type_to_print = "png")
table <- table_no_gridlines %>%
tab_style(
style = cell_text(weight = "bold"),
locations = cells_column_labels()
)
```
```{r table-bolded-header, fig.cap = "Table with header row bolded"}
save_table_for_nostarch(table)
```
Let’s save this table as `table_bold_header` in order to add additional formatting.
```{r echo = TRUE, include = FALSE}
table_bold_header <- table_no_gridlines %>%
tab_style(
style = cell_text(weight = "bold"),
locations = cells_column_labels()
)
```
### Principle Three: Align Appropriately {-}
A third principle of high-quality table design is appropriate alignment. Specifically, numbers in tables should be right-aligned. Tom Mock explains why:
> Left-alignment or center-alignment of numbers impairs the ability to clearly compare numbers and decimal places. Right-alignment lets you align decimal places and numbers for easy parsing.
Let’s see this principle in action. In Figure \@ref(fig:table-cols-aligned-lcr), we’ve left-aligned the 1952 column, center-aligned the 1972 column, and right-aligned the 1992 column. You can see how much easier it is to compare the values in the 1992 column than in the other two columns. In both 1952 and 1972, it is much more difficult to compare the numeric values because the numbers in the same columns (the tens place, for example) are not in the same vertical position. In the 1992 column, however, the number in the tens place in Afghanistan (4) aligns with the number in the tens place in Albania (9) and all other countries. This vertical alignment makes it easier to scan the table.
```{r results='asis', include = TRUE}
print_nostarch_file_name(file_type_to_print = "png")
table <- table_bold_header %>%
cols_align(
align = "left",
columns = 2
) %>%
cols_align(
align = "center",
columns = 3
) %>%
cols_align(
align = "right",
columns = 4
)
```
```{r table-cols-aligned-lcr, fig.cap = "Table with year columns aligned left, center, and right"}
save_table_for_nostarch(table)
```
As with other tables, we actually have to override the defaults to get the `gt` package to misalign the columns, as you can see in the following code.
```{r echo = TRUE, eval = FALSE}
table_bold_header %>%
cols_align(
align = "left",
columns = 2
) %>%
cols_align(
align = "center",
columns = 3
) %>%
cols_align(
align = "right",
columns = 4
)
```
By default, `gt` will right-align numeric values. Don’t change anything, and you’ll be golden.
Right alignment is best practice for numeric columns, but for text columns, use left alignment. As Jon Schwabish points out in his article "Ten Guidelines for Better Tables" in the *Journal of Benefit-Cost Analysis*, it’s much easier to read longer text cells when they are left aligned. To illustrate the benefit of left-aligning text, let’s add a country with a long name to the table. I’ve added Bosnia and Herzegovina and saved this as a data frame called `gdp_with_bosnia`. You’ll see that I’m using nearly the same code as I used to create the `gdp` data frame above:
```{r}
gdp_with_bosnia <- gapminder %>%
filter(country %in% c("Afghanistan", "Albania", "Algeria", "Angola", "Bosnia and Herzegovina")) %>%
select(country, year, gdpPercap) %>%
mutate(country = as.character(country)) %>%
pivot_wider(
id_cols = country,
names_from = year,
values_from = gdpPercap
) %>%
select(country, `1952`, `1972`, `1992`) %>%
rename(Country = country)
```
```{r echo = TRUE}
gdp_with_bosnia
```
Now take the `gdp_with_bosnia` data frame and create a table with the country column center aligned. In the table in Figure \@ref(fig:table-country-centered), it’s hard to scan the country names, and that center-aligned column just looks a bit weird.
```{r results='asis', include = TRUE}
print_nostarch_file_name(file_type_to_print = "png")
table <- gdp_with_bosnia %>%
gt() %>%
tab_style(
style = cell_borders(color = "transparent"),
locations = cells_body()
) %>%
tab_style(
style = cell_text(weight = "bold"),
locations = cells_column_labels()
) %>%
cols_align(
columns = "Country",
align = "center"
)
```
```{r table-country-centered, fig.cap = "A table with country column center aligned"}
save_table_for_nostarch(table)
```
This is another example where we’ve had to change the `gt` defaults to mess things up. In addition to right-aligning numeric columns by default, `gt` left-aligns character columns. So, if we don’t touch anything, it will give us the alignment we’re looking for (Figure \@ref(fig:table-country-left)).
```{r results='asis', include = TRUE}
print_nostarch_file_name(file_type_to_print = "png")
table <- gdp_with_bosnia %>%
gt() %>%
tab_style(
style = cell_borders(color = "transparent"),
locations = cells_body()
) %>%
tab_style(
style = cell_text(weight = "bold"),
locations = cells_column_labels()
)
```
```{r table-country-left, fig.cap = "A table with country column left aligned"}
save_table_for_nostarch(table)
```
If you ever do want to override the default alignments, you can use the `cols_align()` function. For example, here is how to make the table with the country names center aligned:
```{r eval = FALSE, echo = TRUE}
gdp_with_bosnia %>%
gt() %>%
tab_style(
style = cell_borders(color = "transparent"),
locations = cells_body()
) %>%
tab_style(
style = cell_text(weight = "bold"),
locations = cells_column_labels()
) %>%
cols_align(
columns = "Country",
align = "center"
)
```
Within this function, we use the `columns` argument to tell gt which columns to align and the `align` argument to select our alignment (`left`, `right`, or `center`).
### Principle Four: Use the Right Level of Precision {-}
In all of the tables we’ve made so far, we’ve used the data exactly as it came to us. The numeric columns, for example, extend their data to four decimal places. This is almost certainly too many. Having more decimal places makes a table harder to read, so you should always strike a balance between what Jon Schwabish describes as "necessary precision and a clean, spare table."
Here is another way I’ve heard this principle described: If adding additional decimal places would change some action, keep them; otherwise, take them out. In my experience, people tend to leave too many decimal places in, putting too much importance on a very high degree of accuracy (and, in the process, reducing the legibility of their tables).
In our GDP table, we can use the `fmt_currency()` function to format the numeric values. The `gt` package has a whole series of functions for formatting values in tables, all of which start with `fmt_`. In the following code, we apply `fmt_currency()` to the 1952, 1972, and 1992 columns, then use the decimals argument to tell `fmt_currency()` to format the values with zero decimal places. After all, the difference between a GDP of \$799.4453 and \$779 is unlikely to lead to different decisions, so I’m comfortable with sacrificing precision for legibility:
```{r echo = TRUE, eval = FALSE}
table_bold_header %>%
fmt_currency(
columns = c(`1952`, `1972`, `1992`),
decimals = 0
)
```
We end up with values formatted as dollars. The `fmt_currency()` function automatically adds a thousands-place comma to make the values even easier to read (Figure \@ref(fig:table-whole-numbers)).
```{r results='asis', include = TRUE}
print_nostarch_file_name(file_type_to_print = "png")
table <- table_bold_header %>%
fmt_currency(
columns = c(`1952`, `1972`, `1992`),
decimals = 0
)
```
```{r table-whole-numbers, fig.cap = "A table with numbers rounded to whole numbers and dollar sign added"}
save_table_for_nostarch(table)
```
Now save your table for reuse as table_whole_numbers.
```{r}
table_whole_numbers <- table_bold_header %>%
fmt_currency(
columns = c(`1952`, `1972`, `1992`),
decimals = 0
)
```
### Principle Five: Use Color Intentionally {-}
So far, our table hasn’t used any color. We’ll add some now to highlight outlier values. Especially for readers who want to scan your table, highlighting outliers with color can help significantly. Let’s make the highest value in the year 1952 a different color. To do this, we again use the `tab_style()` function:
```{r eval = FALSE, echo = TRUE}
table_whole_numbers %>%
tab_style(
style = cell_text(
color = "orange",
weight = "bold"
),
locations = cells_body(
columns = `1952`,
rows = `1952` == max(`1952`)
)
)
```
This function uses `cell_text()` to both change the color of the text to orange and make it bold. Within the `cells_body()` function, we use the locations() function specify the columns and rows to which we want to apply our change. You can see that we’ve simply set the `columns` argument to the year whose values we’re changing. To set the rows, we need a more complicated formula. The code `rows = `1952` == max(`1952`)` causes the text transformation to occur in rows whose value is equal to the maximum value in that year.
If we repeat this code for the 1972 and 1992 columns, we generate the result shown in Figure \@ref(fig:table-highlight-value).
```{r results='asis', include = TRUE}
print_nostarch_file_name(file_type_to_print = "png")
table <- table_whole_numbers %>%
tab_style(
style = cell_text(
color = "orange",
weight = "bold"
),
locations = cells_body(
columns = `1952`,
rows = `1952` == max(`1952`)
)
) %>%
tab_style(
style = cell_text(
color = "orange",
weight = "bold"
),
locations = cells_body(
columns = `1972`,
rows = `1972` == max(`1972`)
)
) %>%
tab_style(
style = cell_text(
color = "orange",
weight = "bold"
),
locations = cells_body(
columns = `1992`,
rows = `1992` == max(`1992`)
)
)
```
```{r table-highlight-value, fig.cap = "A table with color added to show the highest value in each year"}
save_table_for_nostarch(table)
```
The `gt` package makes it straightforward to add color to highlight outlier values.
```{r}
table_with_color <- table_whole_numbers %>%
tab_style(
style = cell_text(
color = "orange",
weight = "bold"
),
locations = cells_body(
columns = `1952`,
rows = `1952` == max(`1952`)
)
) %>%
tab_style(
style = cell_text(
color = "orange",
weight = "bold"
),
locations = cells_body(
columns = `1972`,
rows = `1972` == max(`1972`)
)
) %>%
tab_style(
style = cell_text(
color = "orange",
weight = "bold"
),
locations = cells_body(
columns = `1992`,
rows = `1992` == max(`1992`)
)
)
```
### Principle Six: Add Data Visualization Where Appropriate {-}
Adding color to highlight outliers is one way to help guide the reader’s attention. Another way is to incorporate graphs into tables. Tom Mock developed an add-on package for `gt` called `gtExtras` that makes it possible to do just this. For example, in our table, we might want to show how the GDP of each country changes over time. To do that, we’ll add a new column that visualizes this trend using a *sparkline* (essentially, a simple line chart):
```{r echo = TRUE}
gdp_with_trend <- gdp %>%
group_by(Country) %>%
mutate(Trend = list(c(`1952`, `1972`, `1992`))) %>%
ungroup()
```
The `gt_plt_sparkline()` function requires us to provide the values needed to make the sparkline in a single column. To accomplish this, we create a variable called `Trend`, using `group_by()` and `mutate()`, to hold a list of the values for each country. For Afghanistan, for example, Trend would contain 779.4453145, 739.9811058, and 649.3413952. We save this data as an object called `gdp_with_trend`.
Now we create our table as before, but add the `gt_plt_sparkline()` function to the end of the code. Within this function, we specify which column to use to create the sparkline (`Trend`):
```{r eval = FALSE, echo = TRUE}
gdp_with_trend %>%
gt() %>%
tab_style(
style = cell_borders(color = "transparent"),
locations = cells_body()
) %>%
tab_style(
style = cell_text(weight = "bold"),
locations = cells_column_labels()
) %>%
fmt_currency(
columns = c(`1952`, `1972`, `1992`),
decimals = 0
) %>%
tab_style(
style = cell_text(
color = "orange",
weight = "bold"
),
locations = cells_body(
columns = `1952`,
rows = `1952` == max(`1952`)
)
) %>%
tab_style(
style = cell_text(
color = "orange",
weight = "bold"
),
locations = cells_body(
columns = `1972`,
rows = `1972` == max(`1972`)
)
) %>%
tab_style(
style = cell_text(
color = "orange",
weight = "bold"
),
locations = cells_body(
columns = `1992`,
rows = `1992` == max(`1992`)
)
) %>%
gt_plt_sparkline(
column = Trend,
label = FALSE,
palette = c("black", "transparent", "transparent", "transparent", "transparent")
)
```
We set `label = FALSE` to remove text labels that `gt_plt_sparkline()` adds by default, then add a `palette` argument to make the sparkline black and all other elements of it transparent. (By default, the function will make different parts of the sparkline different colors.) The stripped-down sparkline in Figure \@ref(fig:table-sparkline) allows the reader to see the trend for each country at a glance.
```{r results='asis', include = TRUE}
print_nostarch_file_name(file_type_to_print = "png")
table <- gdp_with_trend %>%
gt() %>%
tab_style(
style = cell_borders(color = "transparent"),
locations = cells_body()
) %>%
tab_style(
style = cell_text(weight = "bold"),
locations = cells_column_labels()
) %>%
fmt_currency(
columns = c(`1952`, `1972`, `1992`),
decimals = 0
) %>%
tab_style(
style = cell_text(
color = "orange",
weight = "bold"
),
locations = cells_body(
columns = `1952`,
rows = `1952` == max(`1952`)
)
) %>%
tab_style(
style = cell_text(
color = "orange",
weight = "bold"
),
locations = cells_body(
columns = `1972`,
rows = `1972` == max(`1972`)
)
) %>%
tab_style(
style = cell_text(
color = "orange",
weight = "bold"
),
locations = cells_body(
columns = `1992`,
rows = `1992` == max(`1992`)
)
) %>%
gt_plt_sparkline(
column = Trend,
label = FALSE,
palette = c("black", "transparent", "transparent", "transparent", "transparent")
)
```
```{r table-sparkline, fig.cap = "A table with sparkline added to show trend over time"}
save_table_for_nostarch(table)
```
The `gtExtras` package can do way more than merely create sparklines. Its set of theme functions allow you to make your tables look like those published by *FiveThirtyEight*, *The New York Times*, *The Guardian*, and other news outlets. As an example, try removing the formatting we’ve applied so far and instead use the *gt_theme_538()* function to style the table:
```{r eval = FALSE, echo = TRUE}
gdp %>%
group_by(Country) %>%
mutate(Trend = list(c(`1952`, `1972`, `1992`))) %>%
ungroup() %>%
gt() %>%
tab_style(
style = cell_text(
color = "orange",
weight = "bold"
),
locations = cells_body(
columns = `1952`,
rows = `1952` == max(`1952`)
)
) %>%
tab_style(
style = cell_text(
color = "orange",
weight = "bold"
),
locations = cells_body(
columns = `1972`,
rows = `1972` == max(`1972`)
)
) %>%
tab_style(
style = cell_text(
color = "orange",
weight = "bold"
),
locations = cells_body(
columns = `1992`,
rows = `1992` == max(`1992`)
)
) %>%
fmt_currency(
columns = c(`1952`, `1972`, `1992`),
decimals = 0
) %>%
gt_plt_sparkline(
column = Trend,
label = FALSE,
palette = c("black", "transparent", "transparent", "transparent", "transparent")
) %>%
gt_theme_538()
```
Take a look at tables on the FiveThirtyEight website, and you’ll see similarities to the one in Figure \@ref(fig:table-fivethirtyeight).
```{r results='asis', include = TRUE}
print_nostarch_file_name(file_type_to_print = "png")
table <- gdp %>%
group_by(Country) %>%
mutate(Trend = list(c(`1952`, `1972`, `1992`))) %>%
ungroup() %>%
gt() %>%
tab_style(
style = cell_text(
color = "orange",
weight = "bold"
),
locations = cells_body(
columns = `1952`,
rows = `1952` == max(`1952`)
)
) %>%
tab_style(
style = cell_text(
color = "orange",
weight = "bold"
),
locations = cells_body(
columns = `1972`,
rows = `1972` == max(`1972`)
)
) %>%
tab_style(
style = cell_text(
color = "orange",
weight = "bold"
),
locations = cells_body(
columns = `1992`,
rows = `1992` == max(`1992`)
)
) %>%
fmt_currency(
columns = c(`1952`, `1972`, `1992`),
decimals = 0
) %>%
gt_plt_sparkline(
column = Trend,
label = FALSE,
palette = c("black", "transparent", "transparent", "transparent", "transparent")
) %>%
gt_theme_538()
```
```{r table-fivethirtyeight, fig.cap = "A table redone in FiveThirtyEight style"}
save_table_for_nostarch(table)
```
Add-on packages like `gtExtras` are common in the table-making landscape. If you’re working with the `reactable` package to make interactive tables, for example, you can also use the `reactablefmtr` to add interactive sparklines, themes, and more. You’ll learn more about making interactive tables in Chapter \@ref(websites-chapter).
## Conclusion {-}
Many of the tweaks we made to our table are quite subtle. Changes like removing excess gridlines, bolding header text, right-aligning numeric values, and adjusting the level of precision can often go unnoticed, but if you skip them, your table will be far less effective. Our final product isn’t flashy, but it does communicate clearly.
We used the gt package to make our high-quality table, and as we’ve repeatedly seen, this package has good defaults built in. Often, you don’t need to change much in your code to make effective tables. But no matter which package you use, it’s essential to treat tables as worthy of just as much thought as other kinds of data visualization.
In Chapter \@ref(rmarkdown-chapter), you’ll learn how to create reports using R Markdown, which can integrate your tables directly into the final document. What’s better than using just a few lines of code to make publication-ready tables?
## Learn More {-}
Consult the following resources to learn about table design principles and how to make high-quality tables with the `gt` package:
"Ten Guidelines for Better Tables" by Jon Schwabish (*Journal of Benefit-Cost Analysis*, 2020), https://doi.org/10.1017/bca.2020.11
"10+ Guidelines for Better Tables in R" by Tom Mock (2020), https://themockup.blog/posts/2020-09-04-10-table-rules-in-r/
"Creating beautiful tables in R with {gt}" by Albert Rapp (2022), https://gt.albert-rapp.de/