Identifying geom types from chart object

I'm starting to look at using R in an elementary teaching context with particular respect to accessibility requirements.

A couple of things we're looking at are BrailleR, which can generate text descriptions of ggplot2 charts, and vatrious simple sonification tools.

Looking at the str() and ggplot_build(g) of ggplot2 chart objects, I wonder if there's a way of identifying particular structures, or providing metadata in the chart object, that describe the geom(s) used to create the chart? This could make it easier to select appropriate textualisations/sonifications?

The aim would be able to easily identify the original geoms from a chart object g by passing it to BrailleR::VI.ggplot(g), for example?

--tony

1 Like

Have you looked at the structure of the ggplot2-generated object from the generated data? There's definitely more information than you'd want in there (e.g. the elements that are just function, etc), but the specific geoms are included, as well as the source data:

suppressPackageStartupMessages(library(tidyverse))

mpg <- mpg %>% 
  filter(cyl == 4 | cyl == 8)

p <- ggplot(mpg, aes(displ, cty)) + 
  geom_point() +
  facet_grid(cols = vars(cyl))

p[["layers"]][[1]][["geom"]]
#> <ggproto object: Class GeomPoint, Geom, gg>
#>     aesthetics: function
#>     default_aes: uneval
#>     draw_group: function
#>     draw_key: function
#>     draw_layer: function
#>     draw_panel: function
#>     extra_params: na.rm
#>     handle_na: function
#>     non_missing_aes: size shape colour
#>     optional_aes: 
#>     parameters: function
#>     required_aes: x y
#>     setup_data: function
#>     use_defaults: function
#>     super:  <ggproto object: Class Geom, gg>

str(p)
#> List of 9
#>  $ data       :Classes 'tbl_df', 'tbl' and 'data.frame': 151 obs. of  11 variables:
#>   ..$ manufacturer: chr [1:151] "audi" "audi" "audi" "audi" ...
#>   ..$ model       : chr [1:151] "a4" "a4" "a4" "a4" ...
#>   ..$ displ       : num [1:151] 1.8 1.8 2 2 1.8 1.8 2 2 4.2 5.3 ...
#>   ..$ year        : int [1:151] 1999 1999 2008 2008 1999 1999 2008 2008 2008 2008 ...
#>   ..$ cyl         : int [1:151] 4 4 4 4 4 4 4 4 8 8 ...
#>   ..$ trans       : chr [1:151] "auto(l5)" "manual(m5)" "manual(m6)" "auto(av)" ...
#>   ..$ drv         : chr [1:151] "f" "f" "f" "f" ...
#>   ..$ cty         : int [1:151] 18 21 20 21 18 16 20 19 16 14 ...
#>   ..$ hwy         : int [1:151] 29 29 31 30 26 25 28 27 23 20 ...
#>   ..$ fl          : chr [1:151] "p" "p" "p" "p" ...
#>   ..$ class       : chr [1:151] "compact" "compact" "compact" "compact" ...
#>  $ layers     :List of 1
#>   ..$ :Classes 'LayerInstance', 'Layer', 'ggproto', 'gg' <ggproto object: Class LayerInstance, Layer, gg>
#>     aes_params: list
#>     compute_aesthetics: function
#>     compute_geom_1: function
#>     compute_geom_2: function
#>     compute_position: function
#>     compute_statistic: function
#>     data: waiver
#>     draw_geom: function
#>     finish_statistics: function
#>     geom: <ggproto object: Class GeomPoint, Geom, gg>
#>         aesthetics: function
#>         default_aes: uneval
#>         draw_group: function
#>         draw_key: function
#>         draw_layer: function
#>         draw_panel: function
#>         extra_params: na.rm
#>         handle_na: function
#>         non_missing_aes: size shape colour
#>         optional_aes: 
#>         parameters: function
#>         required_aes: x y
#>         setup_data: function
#>         use_defaults: function
#>         super:  <ggproto object: Class Geom, gg>
#>     geom_params: list
#>     inherit.aes: TRUE
#>     layer_data: function
#>     map_statistic: function
#>     mapping: NULL
#>     position: <ggproto object: Class PositionIdentity, Position, gg>
#>         compute_layer: function
#>         compute_panel: function
#>         required_aes: 
#>         setup_data: function
#>         setup_params: function
#>         super:  <ggproto object: Class Position, gg>
#>     print: function
#>     show.legend: NA
#>     stat: <ggproto object: Class StatIdentity, Stat, gg>
#>         aesthetics: function
#>         compute_group: function
#>         compute_layer: function
#>         compute_panel: function
#>         default_aes: uneval
#>         extra_params: na.rm
#>         finish_layer: function
#>         non_missing_aes: 
#>         parameters: function
#>         required_aes: 
#>         retransform: TRUE
#>         setup_data: function
#>         setup_params: function
#>         super:  <ggproto object: Class Stat, gg>
#>     stat_params: list
#>     super:  <ggproto object: Class Layer, gg> 
#>  $ scales     :Classes 'ScalesList', 'ggproto', 'gg' <ggproto object: Class ScalesList, gg>
#>     add: function
#>     clone: function
#>     find: function
#>     get_scales: function
#>     has_scale: function
#>     input: function
#>     n: function
#>     non_position_scales: function
#>     scales: list
#>     super:  <ggproto object: Class ScalesList, gg> 
#>  $ mapping    :List of 2
#>   ..$ x: language ~displ
#>   .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
#>   ..$ y: language ~cty
#>   .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
#>   ..- attr(*, "class")= chr "uneval"
#>  $ theme      : list()
#>  $ coordinates:Classes 'CoordCartesian', 'Coord', 'ggproto', 'gg' <ggproto object: Class CoordCartesian, Coord, gg>
#>     aspect: function
#>     clip: on
#>     default: TRUE
#>     distance: function
#>     expand: TRUE
#>     is_free: function
#>     is_linear: function
#>     labels: function
#>     limits: list
#>     modify_scales: function
#>     range: function
#>     render_axis_h: function
#>     render_axis_v: function
#>     render_bg: function
#>     render_fg: function
#>     setup_data: function
#>     setup_layout: function
#>     setup_panel_params: function
#>     setup_params: function
#>     transform: function
#>     super:  <ggproto object: Class CoordCartesian, Coord, gg> 
#>  $ facet      :Classes 'FacetGrid', 'Facet', 'ggproto', 'gg' <ggproto object: Class FacetGrid, Facet, gg>
#>     compute_layout: function
#>     draw_back: function
#>     draw_front: function
#>     draw_labels: function
#>     draw_panels: function
#>     finish_data: function
#>     init_scales: function
#>     map_data: function
#>     params: list
#>     setup_data: function
#>     setup_params: function
#>     shrink: TRUE
#>     train_scales: function
#>     vars: function
#>     super:  <ggproto object: Class FacetGrid, Facet, gg> 
#>  $ plot_env   :<environment: R_GlobalEnv> 
#>  $ labels     :List of 2
#>   ..$ x: chr "displ"
#>   ..$ y: chr "cty"
#>  - attr(*, "class")= chr [1:2] "gg" "ggplot"

Created on 2018-09-05 by the reprex package (v0.2.0.9000).

1 Like

I had started to look but had missed some of the easily extractable bits, such as p[["layers"]][[1]] and things like class(p[["layers"]][[1]][['geom']])[1]

Thanks for the prompt:-)

--tony

2 Likes

BrailleR sounds like a really cool package! Automatically generating text captions of ggplot2 plots is a fabtastic idea.

I think Mara's put you on the right path. I know that you can identify the geoms inside the grid hierarchy that ggplot builds, but I think getting them from the ggplot_build value is probably cleaner and easier.

FWIW, I think an idea like this could and should be supported in a more general R context, such as being an option for automatic RMarkdown captions.

2 Likes