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:
facet_wrap(), and on which
variable?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
#> `geom_smooth()` using formula = 'y ~ x'spec_layers() returns one row per layer, with columns
for the geom, stat, position adjustment, and resolved aesthetic
mappings.
spec_layers(p)
#> # A tibble: 3 × 8
#> layer geom stat position mapping params inherit_aes data_id
#> <int> <chr> <chr> <chr> <list> <list> <lgl> <int>
#> 1 0 <NA> <NA> <NA> <chr [2]> <list [0]> NA 1
#> 2 1 point identity identity <chr [3]> <named list [2]> TRUE NA
#> 3 2 smooth smooth identity <chr [2]> <named list [7]> TRUE NAThe 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.
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.
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.
spec_aes(p)
#> # A tibble: 7 × 5
#> layer geom aesthetic variable source
#> <int> <chr> <chr> <chr> <chr>
#> 1 0 <NA> x displ global
#> 2 0 <NA> y hwy global
#> 3 1 point x displ global
#> 4 1 point y hwy global
#> 5 1 point colour class local
#> 6 2 smooth x displ global
#> 7 2 smooth y hwy globalThe 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
precedencespec_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).
spec_facets() returns a single-row data frame describing
the faceting.
spec_facets(p)
#> # A tibble: 1 × 6
#> facet_type rows cols scales space labeller
#> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 wrap <NA> drv fixed <NA> params$labellerFor an unfaceted plot, facet_type is
"null".
spec_coord(p)
#> # A tibble: 1 × 5
#> coord_type xlim ylim expand clip
#> <chr> <list> <list> <lgl> <chr>
#> 1 cartesian <NULL> <NULL> TRUE on
# Flipped coordinates
spec_coord(p + coord_flip())
#> # A tibble: 1 × 5
#> coord_type xlim ylim expand clip
#> <chr> <list> <list> <lgl> <chr>
#> 1 flip <NULL> <NULL> TRUE onspec_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.
sp <- spec_plot(p)
sp
#> # A tibble: 3 × 14
#> layer geom stat position mapping params inherit_aes data_id aes_long
#> <int> <chr> <chr> <chr> <list> <list> <lgl> <int> <list>
#> 1 0 <NA> <NA> <NA> <chr> <list [0]> NA 1 <tibble>
#> 2 1 point ident… identity <chr> <named list> TRUE NA <tibble>
#> 3 2 smooth smooth identity <chr> <named list> TRUE NA <tibble>
#> # ℹ 5 more variables: datasets <list>, scales <list>, facets <list>,
#> # coord <list>, labels <list>
# Access per-layer aesthetics
sp$aes_long[[1]]
#> # A tibble: 2 × 5
#> layer geom aesthetic variable source
#> <int> <chr> <chr> <chr> <chr>
#> 1 0 <NA> x displ global
#> 2 0 <NA> y hwy global
# Access the facet spec (same in every row)
sp$facets[[1]]
#> # A tibble: 1 × 6
#> facet_type rows cols scales space labeller
#> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 wrap <NA> drv fixed <NA> params$labeller