class: center, middle, inverse, title-slide .title[ # Introduction to
] .author[ ###
Jason Thomas
R Working Group ] .date[ ###
October 23th, 2025 ] --- # Motivation * Plots are dope! (no motivation necessary) * OK, but why use ggplot2? + peer pressure? everybody is doing it <br> (lots of examples on the web & extensions) + efficiency -- same tool for many different plots + does a pretty good job --- # Outline * Basic logic & concepts + aesthetics & saving * Labels & Axes * Getting colorful * Tour of different "types" of plots (`geoms`) * Grouped data --- # R packages Several packages are used for making the plots we'll see today. You can install them with... ``` r install.packages(c("tidyverse", "RColorBrewer", "viridis", "gridExtra")) # only need to run this one time on your computer # (may need to install again if you upgrade R to a new version) ``` <p style="font-size:20px; text-align:center"> ("palletteer" is another package for adding different color options) <br> </p> and load them with ``` r library(tidyverse) ## this will load ggplot2 library(ggplot2) ## not needed if loading tidyverse library(RColorBrewer) library(viridis) library(gridExtra) ``` --- class: inverse, center, middle # Basic Logic & Concepts --- background-image: url("img/anatomy.png") background-color: white <p style="color:red; font-weight:bold; font-size:32px; position:absolute; top:0">Anatomy of a Plot</p> <p style="font-weight:bold; font-size:20px; position:absolute; bottom:0"> <a href="https://psu-psychology.github.io/r-bootcamp-2019/talks/ggplot_grammar.html"> Nate Hall (2019)</a></p> --- class: slide-font-25 # Anatomy of a plot The main function for creating a plot is `ggplot()`, which makes use of... * **Data** * **Aesthetics** -- `aes()` creates mappings of variables/values to objects appearing on the plot * **Layer(s)** consisting of + **Geometric** objects -- `geom` determines the type of plot (e.g., scatterplot or barchart) and get added as a layer with <br> `ggplot(data, aes()) + geom_xxxx()` + **Statistical** transformation, e.g., line fitted to a cloud of points + position adjustment for overlapping geoms/objects + (more data & aesthetic mapping) --- # Anatomy of a plot (cont.) * **Scales & coordinate systems** + `coord` is usually left out since the Cartesian system handles most cases... except maps! + scaling is largely done under the hood, but emerges when setting colors * **Faceting** -- using a 3rd "dimension" (plotting subsets of the data) * **Plot annotations** -- labeling and adjusting the theme --- # Aesthetics Each aesthetic can be mapped to a variable (or constant) using `aes()` or within geoms * vertical & horizontal position: `aes(x, y)` * size -- all geoms * color -- all geoms * shape -- `geom_point()` * linetype & linewidth -- `geom_line()` * fill -- `geom_bar()` * label -- `geom_text()` --- # Layering in action ``` r ggplot(data = mtcars) ``` <div class="figure" style="text-align: center"> <img src="ggplot2_files/figure-html/unnamed-chunk-3-1.png" alt="(just the data)" width="43%" /> <p class="caption">(just the data)</p> </div> --- # Layering in action ``` r ggplot(data = mtcars, mapping = aes(x = mpg, y = wt)) ``` <div class="figure" style="text-align: center"> <img src="ggplot2_files/figure-html/unnamed-chunk-4-1.png" alt="(mapping too)" width="43%" /> <p class="caption">(mapping too)</p> </div> --- # Layering in action ``` r ggplot(data = mtcars, mapping = aes(x = mpg, y = wt)) + ## don't forget the '+' !! geom_point() ``` <div class="figure" style="text-align: center"> <img src="ggplot2_files/figure-html/unnamed-chunk-5-1.png" alt="(now with geom)" width="43%" /> <p class="caption">(now with geom)</p> </div> --- # Structure of a ggplot ``` r p <- ggplot(mtcars, aes(x = mpg, y = wt, color=factor(cyl))) + geom_point() names(p) ``` ``` ## NULL ``` ``` r summary(p) ``` ``` ## data: mpg, cyl, disp, hp, drat, wt, qsec, vs, am, gear, carb [32x11] ## mapping: x = ~mpg, y = ~wt, colour = ~factor(cyl) ## faceting: <empty> ## ----------------------------------- ## geom_point: na.rm = FALSE ## stat_identity: na.rm = FALSE ## position_identity ``` --- # Global vs. Local ``` r ggplot(mtcars, aes(x = mpg, y = wt, color=factor(cyl))) + geom_point() + geom_smooth(method="lm") ``` <img src="ggplot2_files/figure-html/unnamed-chunk-7-1.png" width="50%" style="display: block; margin: auto;" /> --- # Global vs. Local ``` r ggplot(mtcars, aes(x = mpg, y = wt)) + geom_point(aes(color = factor(cyl))) + geom_smooth(method="lm") ``` <img src="ggplot2_files/figure-html/unnamed-chunk-8-1.png" width="50%" style="display: block; margin: auto;" /> --- # A few more aesthetics ``` r ggplot(mtcars, aes(x = mpg, y = wt, color = factor(cyl), * shape = factor(cyl))) + * geom_point(size = 3) ``` <img src="ggplot2_files/figure-html/unnamed-chunk-9-1.png" width="45%" style="display: block; margin: auto;" /> --- # A few more aesthetics ``` r ggplot(mtcars, aes(x = mpg, y = wt, color = factor(cyl), shape = factor(cyl), * size = cyl)) + geom_point() ``` <img src="ggplot2_files/figure-html/unnamed-chunk-10-1.png" width="45%" style="display: block; margin: auto;" /> --- # A few more aesthetics * Note that when a mapping is specified inside `aes()`, we get an extra legend that describes this mapping + we could have set the mapping in the geom: <br> `geom_point(aes(size = cyl))` * If we set the size outside of `aes()`, then it is not considered a mapping (so no legend) We'll return to a similar situation with color in a short bit... --- class: codefs-50 # A few more aesthetics ``` r rando <- data.frame(x = runif(10), y = runif(10)) ggplot(rando, aes(x = x, y = y)) + geom_point() + geom_abline(intercept = 0, slope = 1, linetype = 2) # another useful line ``` <img src="ggplot2_files/figure-html/unnamed-chunk-11-1.png" width="45%" style="display: block; margin: auto;" /> --- # A few more aesthetics ``` r ggplot(mtcars, aes(x = mpg, y = wt, color = factor(cyl))) + geom_point() + geom_hline(yintercept = mean(mtcars$wt), * linewidth = 2) ``` <img src="ggplot2_files/figure-html/unnamed-chunk-12-1.png" width="45%" style="display: block; margin: auto;" /> --- # A few more aesthetics So what is this doing? How can we improve it? ``` r ggplot(mtcars, aes(x = mpg, y = wt, color = factor(cyl))) + geom_point() + geom_hline(yintercept = mean(mtcars$wt[mtcars$cyl == 4]), linetype = 1) + geom_hline(yintercept = mean(mtcars$wt[mtcars$cyl == 6]), linetype = 2) + geom_hline(yintercept = mean(mtcars$wt[mtcars$cyl == 8]), linetype = 3) ``` --- # A few more aesthetics <img src="ggplot2_files/figure-html/unnamed-chunk-14-1.png" style="display: block; margin: auto;" /> --- # A few more aesthetics Improvement? ``` r ggplot(mtcars, aes(x = mpg, y = wt, color = factor(cyl))) + geom_point() + geom_hline(aes(yintercept = mean(wt), linetype = factor(cyl))) ``` --- # A few more aesthetics Biscuits! <img src="ggplot2_files/figure-html/unnamed-chunk-16-1.png" width="50%" style="display: block; margin: auto;" /> --- # A few more aesthetics Roll these dice? ``` r df_mean_wt <- mtcars %>% group_by(cyl) %>% summarize(mean_wt = mean(wt)) ggplot(mtcars, aes(x = mpg, y = wt, color = factor(cyl))) + geom_point() + geom_hline(aes(yintercept = mean_wt, linetype = factor(cyl)), * data = df_mean_wt) ``` --- # A few more aesthetics Thanks dplyr!! <img src="ggplot2_files/figure-html/unnamed-chunk-18-1.png" width="50%" style="display: block; margin: auto;" /> --- # Exercise Can you improve the previous plot by color coding the horizontal lines? <br><br> (Here is the code to produce the previous plot) ``` r df_mean_wt <- mtcars %>% group_by(cyl) %>% summarize(mean_wt = mean(wt)) ggplot(mtcars, aes(x = mpg, y = wt, color = factor(cyl))) + geom_point() + geom_hline(aes(yintercept = mean_wt, linetype = factor(cyl)), data = df_mean_wt) ``` --- class: inverse, center, middle # Labels & Axes --- # Labels ``` r ggplot(mpg, aes(x=cty, y=hwy)) + geom_point() + labs(x="does this", y="work?", title="Awesome?", subtitle="too much?", caption="really") ``` --- # Labels <img src="ggplot2_files/figure-html/unnamed-chunk-22-1.png" style="display: block; margin: auto;" /> --- # Axes: ranges ``` r ggplot(mpg, aes(x=cty, y=hwy)) + geom_point() + ylim(0, 50) + xlim(0, 50) ``` <img src="ggplot2_files/figure-html/unnamed-chunk-23-1.png" width="50%" style="display: block; margin: auto;" /> --- # Labels: legend ``` r ggplot(mpg, aes(x=cty, y=hwy)) + geom_point(aes(color = factor(cyl), shape = trans)) ``` <img src="ggplot2_files/figure-html/unnamed-chunk-24-1.png" width="50%" style="display: block; margin: auto;" /> --- # Labels: legend ``` r ggplot(mpg, aes(x=cty, y=hwy)) + geom_point(aes(color = factor(cyl), shape = trans)) + * labs(color = "Cylinder", shape = "Transmission") ``` <img src="ggplot2_files/figure-html/unnamed-chunk-25-1.png" width="50%" style="display: block; margin: auto;" /> --- # Labels: no legend ``` r ggplot(mtcars, aes(x = factor(cyl), fill = factor(cyl))) + geom_bar() + * guides(fill="none") ``` <img src="ggplot2_files/figure-html/unnamed-chunk-26-1.png" width="50%" style="display: block; margin: auto;" /> --- # Labels: legend position ``` r ggplot(mtcars, aes(x = factor(cyl), fill = factor(cyl))) + geom_bar() + scale_color_brewer(palette = "Pastel1") + theme(legend.position.inside = c(.50, .80)) ``` <img src="ggplot2_files/figure-html/unnamed-chunk-27-1.png" width="50%" style="display: block; margin: auto;" /> --- class: inverse, center, middle # Saving your work --- # Now what? OK, I've created a masterpiece, now what do I do? * First, store your art as an object <br> `p <- ggplot(data, aes) + geom_scatter` * Next, use `ggsave()` to save the plot as a + PDF, jpeg, tiff, png, bmp, svg, wmf (windows only) * You can specify the `width` and `height` as options + the default unit is inches, but you can use the `units` option with ("cm", "mm", or "px") --- # Saving ggplots Example ``` r p <- ggplot(mtcars, aes(x = mpg, y = wt, color = factor(cyl))) + geom_point() ggsave("my_plot.pdf", p) ``` --- # Saving ggplots: multiple pages Often it is useful to make a lot of related plots and arrange them across multiple pages (e.g., in a PDF doc). * the `gridExtra` package will help us out * basic idea is to make a `list()` of plots, then use `marrangeGrob` to specify the layout Let's look at at an example ``` r p1 <- ggplot(mtcars, aes(x = mpg, y = wt, color = factor(cyl))) + geom_point() p2 <- ggplot(mtcars, aes(x = mpg, y = hp, color = factor(cyl))) + geom_point() p3 <- ggplot(mtcars, aes(x = mpg, y = disp, color = factor(cyl))) + geom_point() ``` --- # Saving ggplots: multiple pages ``` r ## Saving multiple plots to one file my_plots <- list() my_plots[[1]] <- p1 my_plots[[2]] <- p2 my_plots[[3]] <- p3 ggsave( filename = "myplots.pdf", plot = marrangeGrob(my_plots, # top=NULL, # suppress page title nrow=1, ncol=1), width = 15, height = 9 ) ``` --- class: inverse, center, middle # Let's Get Colorful --- class: slide-font-28 # More on color * Easy to set colors manually (or using a grey scale) + The R function `colors()` will print out over 600 options * There are several different tools for setting colors & ggplot2... + need to install packages (e.g. [RColorBrewer](https://cran.r-project.org/package=RColorBrewer), [viridis](https://cran.r-project.org/web/packages/viridis/index.html), [paletteer](https://cran.r-project.org/web/packages/paletteer/index.html)) + [useful reference with examples](https://r-graph-gallery.com/ggplot2-color.html) + Viridis gives color scales that are easier to read by those with colorblindness * Your options depend on if you are mapping color to a continuous variable (e.g., gradients) or categorical variable (e.g. color brewer) --- # Setting color: manually ``` r ggplot(mtcars, aes(x = mpg, y = wt, color = factor(cyl))) + geom_point() + geom_vline(aes(xintercept = mean(mpg)), * color = "red") ``` <img src="ggplot2_files/figure-html/unnamed-chunk-31-1.png" width="50%" style="display: block; margin: auto;" /> --- # Setting color: notes * When you want to map a color to a variable, then specify the `color` option *inside* of `aes()` * If you to set a color to a constant value then use the `color` option *outside* of `aes()` and within the `geom` * When you want to *change* the colors mapped to a variable, then there are several different tools we can use... + (you may need to install the corresponding R package for some of these) --- # Setting color: manually ``` r ggplot(mtcars, aes(x = mpg, y = wt, color = factor(cyl))) + geom_point() + * scale_color_manual(values = c("green", "red", "blue")) ``` <img src="ggplot2_files/figure-html/unnamed-chunk-32-1.png" width="50%" style="display: block; margin: auto;" /> --- # Setting color: grey scale ``` r ggplot(mtcars, aes(x = mpg, y = wt, color = factor(cyl))) + geom_point() + * scale_color_grey(start = 0.0, end = 0.4) ``` <img src="ggplot2_files/figure-html/unnamed-chunk-33-1.png" width="50%" style="display: block; margin: auto;" /> --- class: codefs-50 # Setting color: gradients ``` r ggplot(mtcars, aes(x = mpg, y = wt, color = cyl)) + # cyl now continuous geom_point() + * scale_color_gradient(low="red", high="blue") ``` <img src="ggplot2_files/figure-html/unnamed-chunk-34-1.png" width="50%" style="display: block; margin: auto;" /> --- class: slide-font-20 # Setting color: color brewer [R Color Brewer Palettes](https://r-graph-gallery.com/38-rcolorbrewers-palettes.html) ``` r ggplot(mtcars, aes(x = mpg, y = wt, color = factor(cyl))) + geom_point() + * scale_color_brewer(palette = "BuPu") ``` <img src="ggplot2_files/figure-html/unnamed-chunk-35-1.png" width="50%" style="display: block; margin: auto;" /> --- class: slide-font-20 # Setting color: Viridis [Viridis](https://cran.r-project.org/web/packages/viridis/vignettes/intro-to-viridis.html) ``` r ggplot(mtcars, aes(x = mpg, y = wt, color = factor(cyl))) + geom_point() + * scale_color_viridis(discrete = TRUE, option = "magma") ``` <img src="ggplot2_files/figure-html/unnamed-chunk-36-1.png" width="50%" style="display: block; margin: auto;" /> --- class: inverse, center, middle # Tour of `geoms` [list of geoms](https://ggplot2.tidyverse.org/reference/#geoms) --- # Tour of geoms: barchart ``` r ggplot(mtcars, aes(x = cyl)) + * geom_bar() ``` <img src="ggplot2_files/figure-html/unnamed-chunk-37-1.png" width="50%" style="display: block; margin: auto;" /> --- # Tour of geoms: barchar (ordered) ``` r ggplot(mtcars, aes(x = fct_infreq(factor(cyl)))) + # need tidyverse for this geom_bar() ``` <img src="ggplot2_files/figure-html/unnamed-chunk-38-1.png" width="50%" style="display: block; margin: auto;" /> --- # Tour of geoms: barchart (custom) ``` r mtcars %>% mutate(cyl2 = factor(cyl, levels = c(6, 4, 8))) %>% ggplot(aes(x = cyl2)) + geom_bar() ``` <img src="ggplot2_files/figure-html/unnamed-chunk-39-1.png" width="50%" style="display: block; margin: auto;" /> --- # Tour of geoms: barchart ``` r ggplot(mtcars, aes(x = cyl)) + * geom_bar(fill = c("blue", "pink4", "green")) ``` <img src="ggplot2_files/figure-html/unnamed-chunk-40-1.png" width="50%" style="display: block; margin: auto;" /> --- # Tour of geoms: barchart ``` r ggplot(mtcars, aes(x = factor(cyl), fill = factor(cyl))) + geom_bar() + * scale_color_brewer(palette = "Pastel1") ``` <img src="ggplot2_files/figure-html/unnamed-chunk-41-1.png" width="50%" style="display: block; margin: auto;" /> --- # Tour of geoms: boxplot ``` r ggplot(mtcars, aes(x = factor(cyl), y = mpg, color = factor(cyl))) + geom_boxplot() ``` <img src="ggplot2_files/figure-html/unnamed-chunk-42-1.png" width="50%" style="display: block; margin: auto;" /> --- # Tour of geoms: boxplot ``` r ggplot(mtcars, aes(x = factor(cyl), y = mpg, fill = factor(am))) + geom_boxplot() ``` <img src="ggplot2_files/figure-html/unnamed-chunk-43-1.png" width="50%" style="display: block; margin: auto;" /> --- # Tour of geoms: text ``` r ggplot(mtcars, aes(x = wt, mpg, * label = rownames(mtcars))) + * geom_text() ``` <img src="ggplot2_files/figure-html/unnamed-chunk-44-1.png" width="50%" style="display: block; margin: auto;" /> --- # Tour of geoms: text ``` r ggplot(mtcars, aes(x = wt, mpg, label = rownames(mtcars))) + geom_point() + * geom_text(hjust = "right", nudge_x = -0.15) ``` <img src="ggplot2_files/figure-html/unnamed-chunk-45-1.png" width="50%" style="display: block; margin: auto;" /> --- # Tour of geoms: text ``` r ggplot(mtcars, aes(x = wt, mpg, label = rownames(mtcars))) + geom_point() + * geom_text(vjust = 0, nudge_y = 0.5) ``` <img src="ggplot2_files/figure-html/unnamed-chunk-46-1.png" width="50%" style="display: block; margin: auto;" /> --- # Tour of geoms: different text ``` r ggplot(mtcars, aes(x = factor(cyl))) + geom_bar() + annotate("text", label = c("4 cyl", "6 cyl", "8 cyl"), x = 1:3, y = max(table(mtcars$cyl)) + 2, col = "red") ``` <img src="ggplot2_files/figure-html/unnamed-chunk-47-1.png" width="50%" style="display: block; margin: auto;" /> --- # Tour of geoms: density ``` r ggplot(mtcars, aes(mpg)) + geom_density() ``` <img src="ggplot2_files/figure-html/unnamed-chunk-48-1.png" width="50%" style="display: block; margin: auto;" /> --- # Tour of geoms: density ``` r ggplot(mtcars, aes(mpg, fill=factor(cyl))) + geom_density() ``` <img src="ggplot2_files/figure-html/unnamed-chunk-49-1.png" width="50%" style="display: block; margin: auto;" /> --- # Tour of geoms: density ``` r ggplot(mtcars, aes(mpg, fill=factor(cyl))) + * geom_density(alpha = 0.5) ``` <img src="ggplot2_files/figure-html/unnamed-chunk-50-1.png" width="50%" style="display: block; margin: auto;" /> --- # Tour of geoms: histogram ``` r ggplot(mpg, mapping = aes(x = hwy)) + geom_histogram(binwidth = 5) ``` <img src="ggplot2_files/figure-html/unnamed-chunk-51-1.png" width="50%" style="display: block; margin: auto;" /> --- # Tour of geoms: histogram ``` r mpg %>% filter(manufacturer == "audi") %>% ggplot(aes(x=hwy)) + geom_histogram(binwidth = 1) ``` <img src="ggplot2_files/figure-html/unnamed-chunk-52-1.png" width="50%" style="display: block; margin: auto;" /> --- # Tour of geoms: histogram ``` r mpg %>% filter(manufacturer == "audi") %>% ggplot(aes(x=log(hwy))) + geom_histogram(binwidth = .01) ``` <img src="ggplot2_files/figure-html/unnamed-chunk-53-1.png" width="50%" style="display: block; margin: auto;" /> --- # Tour of geoms: histogram ``` r ggplot(mpg, aes(x=log(hwy))) + geom_histogram(binwidth = .01) + * facet_wrap(vars(manufacturer, year)) ``` <img src="ggplot2_files/figure-html/unnamed-chunk-54-1.png" width="50%" style="display: block; margin: auto;" /> --- # More with Faceting * Possible to specify number of rows (and columns) with faceting * Can combine previous trick with summarized data set ``` r p <- ggplot(mtcars, aes(mpg, wt)) + geom_point() + * facet_wrap(~ cyl, nrow=2) df_wt <- mtcars %>% group_by(cyl) %>% summarize(avg_wt = mean(wt)) %>% as.data.frame() p + geom_hline(aes(yintercept = avg_wt), data=df_wt) ``` --- # More with Faceting <img src="ggplot2_files/figure-html/unnamed-chunk-56-1.png" style="display: block; margin: auto;" /> --- class: inverse, center, middle # Grouped data --- # Nested data? ``` r data("ChickWeight") ## let's look at the data ```
--- # Nested data? How does the weight vary over time? ``` r ggplot(ChickWeight, aes(Time, weight)) + geom_line() ``` <div class="figure" style="text-align: center"> <img src="ggplot2_files/figure-html/unnamed-chunk-59-1.png" alt="uhhhh...that ain't it" width="40%" /> <p class="caption">uhhhh...that ain't it</p> </div> --- # Group option Adding `group = Chick` to the aesthetic mapping... ``` r ggplot(ChickWeight, aes(Time, weight, group = Chick)) + geom_line() ``` <div class="figure" style="text-align: center"> <img src="ggplot2_files/figure-html/unnamed-chunk-60-1.png" alt="Bingo!" width="40%" /> <p class="caption">Bingo!</p> </div> --- # Group option Adding a layer with a different "grouping" (all Chicks together) ``` r ggplot(ChickWeight, aes(Time, weight, group = Chick)) + geom_line() + geom_smooth(aes(group = 1), linewidth = 2, se = FALSE) ``` <img src="ggplot2_files/figure-html/unnamed-chunk-61-1.png" width="40%" style="display: block; margin: auto;" /> --- # Group option: mixing types ``` r p <- ggplot(ChickWeight, aes(as.factor(Time), weight)) + geom_boxplot() p ``` <img src="ggplot2_files/figure-html/unnamed-chunk-62-1.png" width="40%" style="display: block; margin: auto;" /> --- # Group option: mixing types ``` r p + geom_line(aes(group = Chick, color = "pink4")) ``` <img src="ggplot2_files/figure-html/unnamed-chunk-63-1.png" width="40%" style="display: block; margin: auto;" /> --- # Group option: mixing types ``` r p + geom_line(aes(group = Chick), color = "pink4", alpha = .50) ``` <img src="ggplot2_files/figure-html/unnamed-chunk-64-1.png" width="40%" style="display: block; margin: auto;" /> --- # Group option: mixing types ``` r p + geom_smooth(aes(group = Chick), method="lm", se = FALSE) ``` <img src="ggplot2_files/figure-html/unnamed-chunk-65-1.png" width="40%" style="display: block; margin: auto;" /> --- # Group option: mixing types ``` r p + geom_line(stat = "smooth", aes(group = Chick), method = "lm", alpha = .20) ``` <img src="ggplot2_files/figure-html/unnamed-chunk-66-1.png" width="40%" style="display: block; margin: auto;" /> --- class: inverse, center, middle # Themes --- # Themes * The `theme()` function used for the previous plot has MANY different options + e.g., formatting legend, tick marks on axes, background, + [list of options](https://ggplot2.tidyverse.org/reference/theme.html) * There are also general themes you can apply + [list of themes](https://ggplot2.tidyverse.org/reference/ggtheme.html) + let's see a few examples --- # Themes: black & white ``` r ggplot(mtcars, aes(x = mpg, y = wt, color = factor(cyl))) + geom_point() + * theme_bw() ``` <img src="ggplot2_files/figure-html/unnamed-chunk-67-1.png" width="50%" style="display: block; margin: auto;" /> --- # Themes: classic ``` r ggplot(mtcars, aes(x = mpg, y = wt, color = factor(cyl))) + geom_point() + * theme_classic() ``` <img src="ggplot2_files/figure-html/unnamed-chunk-68-1.png" width="50%" style="display: block; margin: auto;" /> --- # Themes: dark ``` r ggplot(mtcars, aes(x = mpg, y = wt, color = factor(cyl))) + geom_point() + * theme_dark() ``` <img src="ggplot2_files/figure-html/unnamed-chunk-69-1.png" width="50%" style="display: block; margin: auto;" /> --- # Summary * Extensions + https://exts.ggplot2.tidyverse.org/gallery/