--- title: "Extracting Plot Specifications with ggspec" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Extracting Plot Specifications with ggspec} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ## Introduction `ggspec` provides a family of `spec_*()` functions that inspect a ggplot2 object and return its declarative specification as tidy data frames. This makes it easy to answer questions like: - Which geoms does this plot use? - What variables are mapped to which aesthetics, and at which layer? - Does this plot use `facet_wrap()`, and on which variable? ```{r} library(ggspec) library(ggplot2) ``` ## A motivating example ```{r} p <- ggplot(mpg, aes(displ, hwy)) + geom_point(aes(colour = class)) + geom_smooth(method = "lm", se = FALSE) + facet_wrap(~drv) + scale_colour_brewer(palette = "Set1") + labs(title = "Engine displacement vs highway MPG", x = "Displacement (L)", y = "Highway MPG (hwy)") p ``` ## Layer specification `spec_layers()` returns one row per layer, with columns for the geom, stat, position adjustment, and resolved aesthetic mappings. ```{r} spec_layers(p) ``` The `mapping` column is a list-column of named character vectors, where each name is an aesthetic and each value is the variable mapped to it. ```{r} # Inspect the mapping for layer 1 (geom_point) spec_layers(p)$mapping[[1]] ``` ### Controlling inheritance By default (`inherit = "resolve"`), global mappings set in `ggplot()` are merged with layer-local mappings, with the local mapping taking precedence for any aesthetic defined in both. ```{r} # inherit = FALSE: only mappings explicitly set on the layer spec_layers(p, inherit = FALSE)$mapping ``` ## Aesthetic specification (long format) `spec_aes()` pivots the mapping information into long format — one row per (layer-aesthetic) pair — making it easy to filter and inspect with standard `dplyr` operations. ```{r} spec_aes(p) ``` The `source` column distinguishes: - `"global"` — set in `ggplot(aes(...))` only - `"local"` — set in the layer only (e.g. `geom_point(aes(...))`) - `"resolved"` — set in both; the local value takes precedence ```{r} library(dplyr) spec_aes(p) |> filter(aesthetic == "colour") ``` ## Scale specification `spec_scales()` lists only explicitly added scales (default scales inferred at render time are not included, as they do not exist in the object before rendering). ```{r} spec_scales(p) ``` ## Facet specification `spec_facets()` returns a single-row data frame describing the faceting. ```{r} spec_facets(p) ``` For an unfaceted plot, `facet_type` is `"null"`. ## Label specification ```{r} spec_labels(p) ``` ## Coordinate system specification ```{r} spec_coord(p) # Flipped coordinates spec_coord(p + coord_flip()) ``` ## The master summary: `spec_plot()` `spec_plot()` joins all of the above into a single wide data frame with one row per layer. Scale, facet, coordinate, and label information are embedded as list-columns, so all plot information is reachable from a single object. ```{r} sp <- spec_plot(p) sp # Access per-layer aesthetics sp$aes_long[[1]] # Access the facet spec (same in every row) sp$facets[[1]] ```