class: center, middle, inverse, title-slide # Designing ggplots ## making clear figures that communicate ### 2019-11-22 --- class: middle, inverse ## "We need to do everything we can to help our readers understand the meaning of our visualizations and see the same patterns in the data that we see. This usually means less is more. *Simplify your figures* as much as possible. *Remove all features that are tangential to your story*" ### — Claus O. Wilke --- class: center, inverse, takeaways ## **act one: focus and declutter** --- class: center, inverse, takeaways ## ~~act one: focus and declutter~~ ## **act two: narrate and put in context** --- class: middle, center, inverse ## **The cast of characters** --- class: inverse ## Packages 1. `ggplot2` 1. `gghighlight` 1. `cowplot` 1. `patchwork` --- class: inverse ## data 1. `emperors` (`data/emperors.csv`) 1. `gapminder` (`library(gapminder)`) 1. `nyc_squirrels` (`data/nyc_squirrels.csv` + `data/central_park/`) 1. `diabetes` (`data/diabetes.csv`) 1. `la_heat_income` (`data/los-angeles.geojson`) --- ## Themes <img src="ggplot_designing_files/figure-html/unnamed-chunk-1-1.png" style="display: block; margin: auto;" /> --- ## Themes: cowplot <img src="ggplot_designing_files/figure-html/unnamed-chunk-2-1.png" style="display: block; margin: auto;" /> --- ## Themes: cowplot <img src="ggplot_designing_files/figure-html/unnamed-chunk-3-1.png" style="display: block; margin: auto;" /> --- ## Themes: cowplot <img src="ggplot_designing_files/figure-html/unnamed-chunk-4-1.png" style="display: block; margin: auto;" /> --- ## Themes: cowplot <img src="ggplot_designing_files/figure-html/unnamed-chunk-5-1.png" style="display: block; margin: auto;" /> --- ## Palettes <img src="ggplot_designing_files/figure-html/unnamed-chunk-6-1.png" style="display: block; margin: auto;" /> ## Okabe-Ito (`colorblindr::palette_OkabeIto()`) --- ## Palettes <img src="ggplot_designing_files/figure-html/unnamed-chunk-7-1.png" style="display: block; margin: auto;" /> ## viridis inferno (`viridis::inferno()`) --- ## Palettes <img src="ggplot_designing_files/figure-html/unnamed-chunk-8-1.png" style="display: block; margin: auto;" /> ## greys (`"grey**"`, `grey(.**)`) --- class: middle, inverse, center ## **act one: focus and declutter** -- ## **or: reducing mental burden in figures** --- class: inverse, center ## How do we reduce mental burden in our plots? --- class: inverse, center ## How do we reduce mental burden in our plots? ## **simplify aesthetics and highlight** --- ```r emperors <- read_csv(file.path("data", "emperors.csv")) emperors ``` ``` ## # A tibble: 68 x 16 ## index name name_full birth death birth_cty ## <dbl> <chr> <chr> <date> <date> <chr> ## 1 1 Augu… IMPERATO… 0062-09-23 0014-08-19 Rome ## 2 2 Tibe… TIBERIVS… 0041-11-16 0037-03-16 Rome ## 3 3 Cali… GAIVS IV… 0012-08-31 0041-01-24 Antitum ## 4 4 Clau… TIBERIVS… 0009-08-01 0054-10-13 Lugdunum ## 5 5 Nero NERO CLA… 0037-12-15 0068-06-09 Antitum ## 6 6 Galba SERVIVS … 0002-12-24 0069-01-15 Terracina ## 7 7 Otho MARCVS S… 0032-04-28 0069-04-16 Terentin… ## 8 8 Vite… AVLVS VI… 0015-09-24 0069-12-20 Rome ## 9 9 Vesp… TITVS FL… 0009-11-17 0079-06-24 Falacrine ## 10 10 Titus TITVS FL… 0039-12-30 0081-09-13 Rome ## # … with 58 more rows, and 10 more variables: ## # birth_prv <chr>, rise <chr>, reign_start <date>, ## # reign_end <date>, cause <chr>, killer <chr>, … ``` --- ```r emperors %>% * count(cause) %>% ggplot(aes(x = n, y = cause)) + * geom_col() + * geom_text( * aes(label = n, x = n - .25), color = "white", size = 5, hjust = 1 ) + cowplot::theme_minimal_vgrid(16) + theme( axis.title.y = element_blank(), legend.position = "none" ) + xlab("number of emperors") ``` --- <img src="ggplot_designing_files/figure-html/unnamed-chunk-10-1.png" style="display: block; margin: auto;" /> --- ```r emperors %>% count(cause) %>% * arrange(n) %>% * mutate(cause = fct_inorder(cause)) %>% ggplot(aes(x = n, y = cause)) + geom_col() + geom_text( aes(label = n, x = n - .25), color = "white", size = 5, hjust = 1 ) + cowplot::theme_minimal_vgrid(16) + theme( axis.title.y = element_blank(), legend.position = "none" ) + xlab("number of emperors") ``` --- <img src="ggplot_designing_files/figure-html/unnamed-chunk-11-1.png" style="display: block; margin: auto;" /> --- ```r emperors_assassinated <- emperors %>% count(cause) %>% arrange(n) %>% mutate( * assassinated = ifelse(cause == "Assassination", TRUE, FALSE), cause = fct_inorder(cause) ) ``` --- ```r emperors_assassinated %>% * ggplot(aes(x = n, y = cause, fill = assassinated)) + geom_col() + geom_text( aes(label = n, x = n - .25), color = "white", size = 5, hjust = 1 ) + cowplot::theme_minimal_vgrid(16) + theme( axis.title.y = element_blank(), legend.position = "none" ) + * scale_fill_manual( * name = NULL, * values = c("#B0B0B0D0", "#D55E00D0") ) + xlab("number of emperors") ``` --- <img src="ggplot_designing_files/figure-html/unnamed-chunk-12-1.png" style="display: block; margin: auto;" /> --- ## Your Turn 1 <img src="ggplot_designing_files/figure-html/unnamed-chunk-13-1.png" style="display: block; margin: auto;" /> --- ## Your Turn 1 #### Read in the emperors data (no need to change this part of the code) #### Sort the data using `arrange()` by the number of each type of killer #### Take a look at the data up until this point. Pick something you find interesting that you want to highlight. Then, in `mutate()`, create a new variable that is `TRUE` if `killer` matches the category you want to highlight and `FALSE` otherwise #### Use the variable you just created in the `fill` aesthetic of the ggplot call #### Finally, use `scale_fill_manual()` to add the fill colors. Set `values` to `c("#B0B0B0D0", "#D55E00D0")`. --- ```r emperor_killers <- emperors %>% # group the least common killers to "other" mutate(killer = fct_lump(killer, 10)) %>% count(killer) %>% * arrange(n) ``` --- ```r emperor_killers ``` ``` ## # A tibble: 14 x 2 ## killer n ## <fct> <int> ## 1 Aneurism 1 ## 2 Court Officials 1 ## 3 Fire 1 ## 4 Heart Failure 1 *## 5 Lightning 1 ## 6 Usurper 1 ## 7 Wife 2 ## 8 Senate 3 ## 9 Own Army 5 ## 10 Unknown 5 ## 11 Opposing Army 6 ## 12 Praetorian Guard 7 ## 13 Disease 16 ## 14 Other Emperor 18 ``` --- ```r lightning_plot <- emperor_killers %>% mutate( * lightning = ifelse(killer == "Lightning", TRUE, FALSE), # use `fct_inorder()` to maintain the way we sorted the data killer = fct_inorder(killer) ) %>% * ggplot(aes(x = n, y = killer, fill = lightning)) + geom_col() + geom_text( aes(label = n, x = n - .25), color = "white", size = 5, hjust = 1 ) + cowplot::theme_minimal_vgrid(16) + theme( axis.title.y = element_blank(), legend.position = "none" ) + * scale_fill_manual(values = c("#B0B0B0D0", "#D55E00D0")) + xlab("number of emperors") lightning_plot ``` --- <img src="ggplot_designing_files/figure-html/unnamed-chunk-16-1.png" style="display: block; margin: auto;" /> --- class: inverse, center # Use color to focus attention <br> # *1 2 3 4* **5** *6 7 8 9* --- class: inverse, center # Use color to focus attention <br> # ~~1 2 3 4 5 6 7 8 9~~ <br> # ~~1 2~~ *3* ~~4 5 6 7 8 9~~ --- class: inverse, center ## How do we reduce mental burden in our plots? ## ~~simplify aesthetics and highlight~~ ## **design figures without legends** --- ```r library(gapminder) gapminder ``` ``` ## # A tibble: 1,704 x 6 ## country continent year lifeExp pop gdpPercap ## <fct> <fct> <int> <dbl> <int> <dbl> ## 1 Afghanistan Asia 1952 28.8 8425333 779. ## 2 Afghanistan Asia 1957 30.3 9240934 821. ## 3 Afghanistan Asia 1962 32.0 10267083 853. ## 4 Afghanistan Asia 1967 34.0 11537966 836. ## 5 Afghanistan Asia 1972 36.1 13079460 740. ## 6 Afghanistan Asia 1977 38.4 14880372 786. ## 7 Afghanistan Asia 1982 39.9 12881816 978. ## 8 Afghanistan Asia 1987 40.8 13867957 852. ## 9 Afghanistan Asia 1992 41.7 16317921 649. ## 10 Afghanistan Asia 1997 41.8 22227415 635. ## # … with 1,694 more rows ``` --- ```r gapminder %>% filter(year == 2007) %>% * ggplot(aes(log(gdpPercap), lifeExp)) + * geom_point( * aes(color = country), size = 3.5, alpha = .9 ) + theme_minimal(14) + theme(panel.grid.minor = element_blank()) + labs( x = "log(GDP per capita)", y = "life expectancy" ) ``` --- class: center <img src="ggplot_designing_files/figure-html/unnamed-chunk-18-1.png" style="display: block; margin: auto;" /> --- class: inverse, center # Direct labeling 1. Label data directly (maybe a subset) 2. Remove the legend 3. Use proximity and similarity (e.g. same color) --- <img src="img/direct_labeling.png" width="95%" style="display: block; margin: auto;" /> --- <img src="img/direct_labeling_geom_legend.png" width="95%" style="display: block; margin: auto;" /> --- <img src="img/direct_labeling_data.png" width="95%" style="display: block; margin: auto;" /> --- background-image: url(http://hexb.in/hexagons/ggrepel.png) background-position: 90% 52% # ggrepel: Repel overlapping text ```r library(ggrepel) ``` -- ## `geom_text_repel()` <br> ## `geom_label_repel()` --- ```r gapminder %>% filter(year == 2007) %>% ggplot(aes(log(gdpPercap), lifeExp)) + geom_point( size = 3.5, alpha = .9, shape = 21, col = "white", fill = "#0162B2" ) + * geom_text_repel(aes(label = country)) + theme_minimal(14) + theme(panel.grid.minor = element_blank()) + labs( x = "log(GDP per capita)", y = "life expectancy" ) ``` --- <img src="ggplot_designing_files/figure-html/unnamed-chunk-23-1.png" style="display: block; margin: auto;" /> --- ## Your Turn 2 ### Use `sample()` to select 10 random countries to plot (run the `set.seed()` line first if you want the same results) ### In the `mutate()` call, check if `country` is one of the countries in `ten_countries`. If it's not, make the label an empty string (""), ### Add the text repel geom from ggrepel. Set the `label` aesthetic using the variable just created in `mutate()` --- ```r library(gapminder) library(ggrepel) set.seed(42) ten_countries <- gapminder$country %>% levels() %>% * sample(10) ten_countries ``` ``` ## [1] "Ghana" "Italy" "Lesotho" "Swaziland" "Zimbabwe" ## [6] "Thailand" "Gambia" "Chile" "Korea, Rep." "Paraguay" ``` --- ```r p1 <- gapminder %>% filter(year == 2007) %>% mutate( * label = ifelse( * country %in% ten_countries, * as.character(country), * "" * ) ) %>% ggplot(aes(log(gdpPercap), lifeExp)) + geom_point( size = 3.5, alpha = .9, shape = 21, col = "white", fill = "#0162B2" ) ``` --- ```r scatter_plot <- p1 + * geom_text_repel( * aes(label = label), size = 4.5, * point.padding = .2, * box.padding = .3, * force = 1, * min.segment.length = 0 ) + theme_minimal(14) + theme( legend.position = "none", panel.grid.minor = element_blank() ) + labs( x = "log(GDP per capita)", y = "life expectancy" ) scatter_plot ``` --- <img src="ggplot_designing_files/figure-html/unnamed-chunk-26-1.png" style="display: block; margin: auto;" /> --- ```r p1 + * geom_text( * data = function(x) filter(x, country == "Gabon"), aes(label = country), size = 4.5, * hjust = 0, * nudge_x = .06 ) + theme_minimal(14) + theme( legend.position = "none", panel.grid.minor = element_blank() ) + labs( x = "log(GDP per capita)", y = "life expectancy" ) ``` --- <img src="ggplot_designing_files/figure-html/unnamed-chunk-27-1.png" style="display: block; margin: auto;" /> --- class: inverse, center ## How do we reduce mental burden in our plots? ## ~~simplify aesthetics and highlight~~ ## ~~design figures without legends~~ ## **hack geoms and legends and even the plot itself** --- # Inserting plot objects into the axis ```r library(cowplot) ``` --- # Inserting plot objects into the axis ```r library(cowplot) *marginal_histogram <- axis_canvas(scatter_plot, "y") + * geom_histogram( data = gapminder %>% filter(year == 2007), bins = 40, aes(y = lifeExp), fill = "#0162B2E6", color = "white" ) scatter_plot %>% * insert_yaxis_grob(marginal_histogram) %>% * ggdraw() ``` --- <img src="ggplot_designing_files/figure-html/unnamed-chunk-28-1.png" style="display: block; margin: auto;" /> --- <img src="img/axis_grob.png" width="95%" style="display: block; margin: auto;" /> --- <img src="img/axis_grob_canvas.png" width="95%" style="display: block; margin: auto;" /> --- <img src="img/axis_grob_insert.png" width="95%" style="display: block; margin: auto;" /> --- <img src="img/axis_grob_ggdraw.png" width="95%" style="display: block; margin: auto;" /> --- ## Your Turn 3 <img src="ggplot_designing_files/figure-html/unnamed-chunk-33-1.png" style="display: block; margin: auto;" /> --- ## Your Turn 3 #### Calculate the placement of the labels: in the `summarize()` call, create a variable called `y` that is the maximum `lifeExp` value for every continent For the labels, we'll use the continent names, which will be retained automatically. #### Remove the legend from the line plot. There are [several ways to do so in ggplot2](http://www.cookbook-r.com/Graphs/Legends_%28ggplot2%29/#removing-the-legend). I like setting `legend.position = "none"` in `theme()`. #### `axis_canvas(line_plot, axis = "y")` creates a new ggplot2 canvas based on the y axis from `line_plot`. Add a text geom (using `+` as you normally would). In the text geom: set data to `direct_labels`; in `aes()`, set `y = y`, `label = continent`; Outside of `aes()` set `x` to `0.05` (to add a little buffer); Make the size of the text `4.5`; Set the horizontal justification to `0` #### Use `insert_yaxis_grob()` to take `lineplot` and insert `direct_labels_axis`. #### Draw the new plot with `ggdraw()` --- ```r library(cowplot) # get the mean life expectancy by continent and year continent_data <- gapminder %>% group_by(continent, year) %>% summarise(lifeExp = mean(lifeExp)) direct_labels <- continent_data %>% group_by(continent) %>% * summarize(y = max(lifeExp)) ``` --- ```r line_plot <- continent_data %>% ggplot(aes(year, lifeExp, col = continent)) + geom_line(size = 1) + theme_minimal_hgrid() + * theme(legend.position = "none") + scale_color_manual(values = continent_colors) + scale_x_continuous(expand = expansion()) + labs(y = "life expectancy") ``` --- ```r direct_labels_axis <- axis_canvas(line_plot, axis = "y") + * geom_text( data = direct_labels, aes(y = y, label = continent), x = .05, size = 4.5, hjust = 0 ) *p_direct_labels <- insert_yaxis_grob(line_plot, direct_labels_axis) *ggdraw(p_direct_labels) ``` --- <img src="ggplot_designing_files/figure-html/unnamed-chunk-36-1.png" style="display: block; margin: auto;" /> --- class: inverse, center ## How do we reduce mental burden in our plots? ## ~~simplify aesthetics and highlight~~ ## ~~design figures without legends~~ ## ~~hack geoms and legends and even the plot itself~~ ## **use facets and data shadows to plot overlapping data** --- class: inverse, center # Using facets to declutter data 1. Facets (or small multiples) are direct labeling for subsets 2. Put them into context with data shadows --- ```r *nyc_squirrels <- read_csv(file.path("data", "nyc_squirrels.csv")) *central_park <- sf::read_sf(file.path("data", "central_park")) ``` -- ```r nyc_squirrels %>% drop_na(primary_fur_color) %>% ggplot() + * geom_sf(data = central_park, color = "grey85") + * geom_point( * aes(x = long, y = lat, color = primary_fur_color), * size = .8 * ) + cowplot::theme_map(16) + colorblindr::scale_color_OkabeIto(name = "primary fur color") ``` --- <img src="ggplot_designing_files/figure-html/unnamed-chunk-38-1.png" style="display: block; margin: auto;" /> --- ```r nyc_squirrels %>% drop_na(primary_fur_color) %>% ggplot() + geom_sf(data = central_park, color = "grey85") + geom_point( aes(x = long, y = lat, color = primary_fur_color), size = .8 ) + * facet_wrap(vars(primary_fur_color)) + cowplot::theme_map(16) + * theme(legend.position = "none") + colorblindr::scale_color_OkabeIto() ``` --- <img src="ggplot_designing_files/figure-html/unnamed-chunk-39-1.png" style="display: block; margin: auto;" /> --- ```r label_colors <- c("all squirrels" = "grey75", "highlighted group" = "#0072B2") nyc_squirrels %>% drop_na(primary_fur_color) %>% ggplot() + geom_sf(data = central_park, color = "grey85") + * geom_point( * data = function(x) select(x, -primary_fur_color), * aes(x = long, y = lat, color = "all squirrels"), * size = .8 * ) + geom_point( * aes(x = long, y = lat, color = "highlighted group"), size = .8 ) + cowplot::theme_map(16) + theme( legend.position = "bottom", legend.justification = "center" ) + facet_wrap(vars(primary_fur_color)) + scale_color_manual(name = NULL, values = label_colors) + guides(color = guide_legend(override.aes = list(size = 3))) ``` --- <img src="ggplot_designing_files/figure-html/unnamed-chunk-40-1.png" style="display: block; margin: auto;" /> --- <img src="img/data_shadows.png" width="95%" style="display: block; margin: auto;" /> --- <img src="img/data_shadows_geoms.png" width="95%" style="display: block; margin: auto;" /> --- <img src="img/data_shadows_select.png" width="95%" style="display: block; margin: auto;" /> --- <img src="img/data_shadows_legend.png" width="95%" style="display: block; margin: auto;" /> --- ## Your Turn 4 <img src="ggplot_designing_files/figure-html/unnamed-chunk-45-1.png" style="display: block; margin: auto;" /> --- ## Your Turn 4 #### Run the code below and take a look at the resulting plot. #### In the `ggplot()` function, add `y = ..count..` to `aes()` #### Add an additional `geom_density()` to the plot. This should go *before* the existing `geom_density()` so that it shows up in the background. #### In the new `geom_density()`, set the `data` argument to be a function. This function should take a data frame and remove gender (which we're about to facet on). #### Use `aes()` to set `color` and `fill`. Both should equal "all participants", *not* `gender`. #### Use `facet_wrap()` to facet the plot by `gender`. --- ```r diabetes %>% drop_na(glyhb, gender) %>% * ggplot(aes(glyhb, y = ..count..)) + * geom_density( * data = function(x) select(x, -gender), * aes(fill = "all participants", color = "all participants") * ) + geom_density(aes(fill = gender, color = gender)) + * facet_wrap(vars(gender)) + scale_x_log10(name = "glycosylated hemoglobin a1c") + scale_color_manual(name = NULL, values = density_colors) + scale_fill_manual(name = NULL, values = density_colors) + theme_minimal_hgrid(16) + theme(legend.position = "bottom", legend.justification = "center") ``` --- <img src="ggplot_designing_files/figure-html/unnamed-chunk-46-1.png" style="display: block; margin: auto;" /> --- # gghighlight: Highlight geoms ```r library(gghighlight) ``` ## `gghighlight(predicate)` ## Works with points, lines, and histograms ## Facets well --- ## Your Turn 5 <img src="ggplot_designing_files/figure-html/unnamed-chunk-48-1.png" style="display: block; margin: auto;" /> --- ## Your Turn 5 #### Take a look at the first few paragraphs of code. First, we're subsetting only African countries and sorting them by their life expectancy in 1952. Then, we're pivoting the data to be able to compare life expectancy in 1992 to 2007, creating a new variable, `le_dropped`, that is `TRUE` if life expectancy was higher in 1992. Then, we join `le_dropped` back to the data so we can use it in `gghighlight()`. Run the code at each step. #### Remove the legend from the plot using the `legend.position` argument in `theme()`. Take a look at the base plot. #### Use `gghighlight()` to add direct labels to the plot. For the first argument, tell it which lines to highlight using `le_dropped`. Also add the arguments `use_group_by = FALSE` and `unhighlighted_colour = "grey90"`. #### Add `use_direct_label = FALSE` to `gghighlight()` and then facet the plot (using `facet_wrap()`) by country --- ```r le_line_plot + gghighlight( le_dropped, use_group_by = FALSE, unhighlighted_colour = "grey90" ) ``` --- <img src="ggplot_designing_files/figure-html/unnamed-chunk-51-1.png" style="display: block; margin: auto;" /> --- ```r le_line_plot + gghighlight( le_dropped, use_group_by = FALSE, use_direct_label = FALSE, unhighlighted_colour = "grey90" ) + facet_wrap(vars(country)) ``` --- <img src="ggplot_designing_files/figure-html/unnamed-chunk-52-1.png" style="display: block; margin: auto;" /> --- class: middle, inverse, center ## **act two: narrate and put in context** -- ## **or: storytelling with data visualization** --- class: middle, inverse, center ## How do we augment plots to explain? --- class: middle, inverse, center ## How do we augment plots to explain? ## **Annotate plots using text geoms and arrows** --- ## Squirrels and dogs ```r dog_sighting <- nyc_squirrels %>% mutate(dog = str_detect(other_activities, "dog")) %>% filter(dog) ``` --- ```r lbl <- "All other dog sightings involved a squirrel hiding or being chased. This squirrel, however, was actively teasing a dog." dog_plot <- nyc_squirrels %>% ggplot() + geom_sf(data = central_park, color = "grey80") + geom_point(aes(x = long, y = lat), size = .8) + geom_point( data = dog_sighting, aes( x = long, y = lat, color = "squirrel interacting\nwith a dog" ), size = 1.5 ) ``` --- ```r dog_plot + * ggrepel::geom_label_repel( data = filter( dog_sighting, * str_detect(other_activities, "teasing") ), aes(x = long, y = lat, label = lbl), nudge_x = .015, size = 3.5, lineheight = .8, segment.color = "grey70" ) + cowplot::theme_map() + theme(legend.position = c(.05, .9)) + scale_color_manual(name = NULL, values = "#FB1919") ``` --- <img src="ggplot_designing_files/figure-html/unnamed-chunk-53-1.png" style="display: block; margin: auto;" /> --- ```r label <- "Carus, Roman emperor from 282–283, allegedly died of a lightning strike while campaigning against the Empire of Iranians. He was succeded by his sons, Carinus, who died in battle, and Numerian, whose cause of death is unknown." lightning_plot + * geom_label( * data = data.frame(x = 5.8, y = 5, label = label), aes(x = x, y = y, label = label), hjust = 0, lineheight = .8, inherit.aes = FALSE, label.size = NA ) + * geom_curve( * data = data.frame(x = 5.6, y = 5, xend = 1.2, yend = 5), mapping = aes(x = x, y = y, xend = xend, yend = yend), colour = "grey75", size = 0.5, curvature = -0.1, arrow = arrow(length = unit(0.01, "npc"), type = "closed"), inherit.aes = FALSE ) ``` --- <img src="ggplot_designing_files/figure-html/unnamed-chunk-54-1.png" style="display: block; margin: auto;" /> --- <img src="img/annotating_ggplots.png" width="95%" style="display: block; margin: auto;" /> --- <img src="img/annotating_ggplots_df.png" width="95%" style="display: block; margin: auto;" /> --- ## Your Turn 6 <img src="ggplot_designing_files/figure-html/unnamed-chunk-57-1.png" style="display: block; margin: auto;" /> --- ## Your Turn 6 #### Run the first code chunk and take a look at the map of surface heat in Los Angeles. #### In the second code chunk, we need to create two new data frames to draw the annotations and arrows. Pick a name for each. #### Add `geom_text()` and `geom_curve()` to `base_map`. Give each geom the relevant data that you just named in (2). #### Let's clean up the geoms a bit. Reduce the `lineheight` of the text geom to `0.8`. Then, add arrows to the curve geom usiing the `arrow()` function. Give it two arguments: `length = unit(0.01, "npc")` and `type = "closed"`. Run the plot. #### One of the labels is being clipped because it runs off the main plotting panel. Add `coord_sf(clip = "off")` to prevent clipping the text. --- ```r *text_labels <- tibble::tribble( ~x, ~y, ~label, -118.90, 34.00, west_label, -118.20, 34.22, east_label ) *arrows <- tibble::tribble( ~x, ~y, ~xend, ~yend, -118.73, 34.035, -118.60, 34.10, -118.21, 34.195, -118.35, 34.18, -118.08, 34.185, -118.15, 34.10 ) ``` --- ```r base_map + * geom_text( * data = text_labels, aes(x, y, label = label), hjust = 0, vjust = 0.5, lineheight = .8 ) + * geom_curve( * data = arrows, aes(x =x, y = y, xend = xend, yend = yend), colour = "grey75", size = 0.3, curvature = -0.1, arrow = arrow(length = unit(0.01, "npc"), type = "closed") ) + * coord_sf(clip = "off") ``` --- <img src="ggplot_designing_files/figure-html/unnamed-chunk-60-1.png" style="display: block; margin: auto;" /> --- class: middle, inverse, center ## How do we augment plots to explain? ## ~~Annotate plots using text geoms and arrows~~ ## **Combine plots to build a cohesive narrative** --- class: inverse, center ## Combine plots to tell a story 1. Build plots up from simpler to more complex 2. Don't use the same type of plot in each panel 3. Use consistent color --- background-image: url(https://raw.githubusercontent.com/thomasp85/patchwork/master/man/figures/logo.png) background-position: 90% 55% # patchwork: Compose ggplots ```r library(patchwork) ``` --- <img src="img/patchwork.png" width="95%" style="display: block; margin: auto;" /> --- <img src="img/patchwork_combine.png" width="95%" style="display: block; margin: auto;" /> --- <img src="img/patchwork_control.png" width="95%" style="display: block; margin: auto;" /> --- ## Your Turn 7 <img src="ggplot_designing_files/figure-html/unnamed-chunk-69-1.png" style="display: block; margin: auto;" /> --- #### Run the first code chunk. `label_frames()` will help us label the `frame` variable better. `theme_multiplot()` is the theme we'll add to each plot. We'll use `diabetes_complete` for the plots (removing the missing values of the variables we're plotting produce the same plots as `diabetes` would, but it prevents ggplot2 from warning us that it's dropping the data internally). Nothing to change here! #### Run the code for `plot_a` and take a look. Nothing to change here, either! #### The colors in `plot_b` don't match `plot_a`. Add `scale_color_manual()` to make the colors consistent. #### Also add `scale_fill_manual()`. For the fill colors, we'll add a bit of transparency. Paste "B3" to the end of the colors in `plot_colors`. "B3" is equivalent to 70% transparency (or `alpha = .7`) in hex code (see [this GitHub page with translations from percent to hex](https://gist.github.com/lopspower/03fb1cc0ac9f32ef38f4), but note that in R you need to put the transparency at the end of the six character hex code). #### This plot doesn't have a `tag` label like the other two plots. Add one to the `labs()` call. #### The legend isn't working well, but let's take advantage of it. We'll move the legend to *above* the plot by setting `legend.position` to `c(1, 1.25)` in `theme()`. We wont' be able to see it in `plot_c`, but it will show up in the combined plot! #### Finally, combine the 3 plots using patchwork. Have `plot_a` and `plot_b` on top and `plot_c` on the bottom. --- ```r plot_b <- diabetes_complete %>% ggplot( aes(fct_rev(frame), waist/hip, fill = gender, col = gender) ) + geom_boxplot( outlier.color = NA, alpha = .8, width = .5 ) + theme_multiplot() + theme(axis.title.x = element_blank()) + * scale_color_manual(values = plot_colors) + * scale_fill_manual(values = paste0(plot_colors, "B0")) + scale_x_discrete(labels = label_frames) + labs(tag = "B") plot_b ``` --- <img src="ggplot_designing_files/figure-html/unnamed-chunk-70-1.png" style="display: block; margin: auto;" /> --- <div style = 'font-size: 73%'> ```r plot_c <- diabetes_complete %>% ggplot(aes(waist/hip, glyhb, col = gender)) + geom_point( shape = 21, col = "white", fill = "grey80", size = 2.5 ) + geom_smooth( method = "lm", formula = y ~ x, se = FALSE, size = 1.1 ) + theme_minimal(base_size = 14) + theme( * legend.position = c(1, 1.25), legend.justification = c(1, 0), legend.direction = "horizontal", panel.grid.minor = element_blank() ) + facet_wrap(~fct_rev(frame), labeller = as_labeller(label_frames)) + scale_y_log10(breaks = c(3.5, 5.0, 7.0, 10.0, 14.0)) + scale_color_manual(name = "", values = plot_colors) + guides(color = guide_legend(override.aes = list(size = 5))) + * labs(y = "hemoglobin a1c", tag = "C") plot_c ``` </span> --- <img src="ggplot_designing_files/figure-html/unnamed-chunk-71-1.png" style="display: block; margin: auto;" /> --- ```r library(patchwork) *(plot_a + plot_b) / plot_c ``` --- <img src="ggplot_designing_files/figure-html/unnamed-chunk-72-1.png" style="display: block; margin: auto;" /> --- class: inverse, center # Resources ## [Fundamentals of Data Visualization](https://serialmentor.com/dataviz/) by Claus O. Wilke ## [Storytelling with Data](http://www.storytellingwithdata.com/) by Cole Nussbaumer Knaflic ## [Better Presentations](https://policyviz.com/better-presentations/) by Jonathan Schwabish --- class: inverse, center, middle ![](https://media.giphy.com/media/3oz8xIsloV7zOmt81G/giphy.gif) ### <svg style="height:0.8em;top:.04em;position:relative;fill:#EDEEEF;" viewBox="0 0 496 512"><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg> [malcolmbarrett](https://github.com/malcolmbarrett/) ### <svg style="height:0.8em;top:.04em;position:relative;fill:#EDEEEF;" viewBox="0 0 512 512"><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"/></svg> [@malco_barrett](https://twitter.com/malco_barrett) .small[slides created via the R package [xaringan](https://github.com/yihui/xaringan).]