Intro Thoughts

Status Quo

library(tidyverse)

Get namespace, pull out exported geom_ and stat_ functions, grab function definition

"https://raw.githubusercontent.com/tidyverse/ggplot2/refs/heads/main/NAMESPACE" |>
read_lines() ->
ggplot2_namespace

ggplot2_namespace %>% 
  tibble(text = .) %>% 
  filter(str_detect(text, "export\\(")) %>% 
  filter(str_detect(text, "\\(geom_|\\(stat_")) %>% 
  mutate(exported_fun = str_remove_all(text, "export\\(|\\)")) ->
df_exported_geom_stat

fun_contents <- list()


for (i in 1:nrow(df_exported_geom_stat)){

  if(df_exported_geom_stat$exported_fun[i] != "stat_manual"){
  
fun_contents[[i]] <- capture.output(get(df_exported_geom_stat$exported_fun[i]))

}

}


df_exported_geom_stat$fun_contents <- fun_contents    

head(df_exported_geom_stat)
## # A tibble: 6 × 3
##   text                exported_fun fun_contents
##   <chr>               <chr>        <list>      
## 1 export(geom_abline) geom_abline  <chr [30]>  
## 2 export(geom_area)   geom_area    <chr [13]>  
## 3 export(geom_bar)    geom_bar     <chr [11]>  
## 4 export(geom_bin2d)  geom_bin2d   <chr [9]>   
## 5 export(geom_bin_2d) geom_bin_2d  <chr [9]>   
## 6 export(geom_blank)  geom_blank   <chr [9]>

Cleaning to understand composition

df_exported_geom_stat %>% 
  unnest() %>% 
  filter(fun_contents %>% str_detect("geom = |stat = |position =")) %>% 
  mutate(stat = str_extract(fun_contents, "stat = .*?,")) %>% 
  mutate(geom = str_extract(fun_contents, "geom = .*?,")) %>% 
  mutate(position = str_extract(fun_contents, "position = .*?,")) %>% 
  mutate(position = ifelse(position == "position = position,", NA, position)) %>% 
  mutate(stat = ifelse(stat == "stat = stat,", NA, stat)) %>% 
  mutate(geom = ifelse(geom == "geom = geom,", NA, geom)) %>% 
  select(-text, -fun_contents) %>%
  pivot_longer(cols = stat:position) %>% 
  remove_missing() %>%
  rename(argument = value,
         type = name) %>% 
  mutate(argument = argument %>% str_remove(".+ = ") %>% str_remove(",")) %>% 
  mutate(default_or_fixed = ifelse(str_detect(argument, '"'), "default", "fixed")) %>% 
  mutate(object = str_remove_all(argument, '"')) %>% 
  mutate(object = ifelse(default_or_fixed == "default",
                         str_replace_all(object, "_", " ") %>% 
                           str_to_title() %>% 
                           str_remove_all(" ") %>%
                           paste0(str_to_title(type), .), 
                         object)) %>% 
  mutate(expected_object = exported_fun %>% 
           str_replace_all("_", " ") %>% 
           str_to_title() %>% 
           str_remove_all(" ")
           ) %>% 
  mutate(fun_prefix = str_extract(exported_fun, ".*?_")) %>% 
  mutate(expected_type = fun_prefix %>% str_remove("_")) ->
exported_layer_fun_composition

write_csv(exported_layer_fun_composition, "ggplot2_exported_layer_fun_composition.csv")

head(exported_layer_fun_composition)
## # A tibble: 6 × 8
##   exported_fun type  argument default_or_fixed object expected_object fun_prefix
##   <chr>        <chr> <chr>    <chr>            <chr>  <chr>           <chr>     
## 1 geom_abline  stat  "StatId… fixed            StatI… GeomAbline      geom_     
## 2 geom_abline  geom  "GeomAb… fixed            GeomA… GeomAbline      geom_     
## 3 geom_abline  posi… "Positi… fixed            Posit… GeomAbline      geom_     
## 4 geom_area    stat  "\"alig… default          StatA… GeomArea        geom_     
## 5 geom_area    posi… "\"stac… default          Posit… GeomArea        geom_     
## 6 geom_area    geom  "GeomAr… fixed            GeomA… GeomArea        geom_     
## # ℹ 1 more variable: expected_type <chr>

exploring

# exported_layer_fun_composition
exported_layer_fun_composition %>% 
  filter(type == "geom", 
         fun_prefix == "geom_",
         default_or_fixed == "default") 
## # A tibble: 2 × 8
##   exported_fun type  argument default_or_fixed object expected_object fun_prefix
##   <chr>        <chr> <chr>    <chr>            <chr>  <chr>           <chr>     
## 1 geom_qq      geom  "\"poin… default          GeomP… GeomQq          geom_     
## 2 geom_qq_line geom  "\"path… default          GeomP… GeomQqLine      geom_     
## # ℹ 1 more variable: expected_type <chr>
# exported_layer_fun_composition
exported_layer_fun_composition %>% 
  filter(type == "stat", 
         fun_prefix == "geom_",
         default_or_fixed == "fixed") 
## # A tibble: 6 × 8
##   exported_fun type  argument default_or_fixed object expected_object fun_prefix
##   <chr>        <chr> <chr>    <chr>            <chr>  <chr>           <chr>     
## 1 geom_abline  stat  StatIde… fixed            StatI… GeomAbline      geom_     
## 2 geom_dotplot stat  StatBin… fixed            StatB… GeomDotplot     geom_     
## 3 geom_hline   stat  StatIde… fixed            StatI… GeomHline       geom_     
## 4 geom_qq      stat  StatQq   fixed            StatQq GeomQq          geom_     
## 5 geom_qq_line stat  StatQqL… fixed            StatQ… GeomQqLine      geom_     
## 6 geom_vline   stat  StatIde… fixed            StatI… GeomVline       geom_     
## # ℹ 1 more variable: expected_type <chr>
# expectations about existence of a geom aren't met based on name
exported_layer_fun_composition %>% 
  filter(type == expected_type & object != expected_object) %>% 
  select(exported_fun, object, expected_object)
## # A tibble: 11 × 3
##    exported_fun   object     expected_object
##    <chr>          <chr>      <chr>          
##  1 geom_bin2d     GeomTile   GeomBin2d      
##  2 geom_bin_2d    GeomTile   GeomBin2d      
##  3 geom_count     GeomPoint  GeomCount      
##  4 geom_freqpoly  GeomPath   GeomFreqpoly   
##  5 geom_histogram GeomBar    GeomHistogram  
##  6 geom_jitter    GeomPoint  GeomJitter     
##  7 geom_qq        GeomPoint  GeomQq         
##  8 geom_qq_line   GeomPath   GeomQqLine     
##  9 geom_sf_label  GeomLabel  GeomSfLabel    
## 10 geom_sf_text   GeomText   GeomSfText     
## 11 stat_bin_hex   StatBinhex StatBinHex
exported_layer_fun_composition %>% 
  ggplot() + 
  aes(id = object) + 
  facet_wrap(~type) + 
  ggcirclepack::geom_circlepack() + 
  ggcirclepack::geom_circlepack_text() +
  aes(size = after_stat(1/nchar(id)*area)) +
  coord_equal() + 
  labs(title = "ggplot2 geom-stat-position layer composition")

last_plot() + 
  aes(fill = default_or_fixed)

last_plot() + 
  facet_grid(fun_prefix~type) 

exported_layer_fun_composition %>%
  select(exported_fun, object) %>%
  ggedgelist:::ggedgelist_quick(
    layout = "kk", include_names = T)

exported_layer_fun_composition %>%
  filter(type != "position") %>%
  select(exported_fun, object) %>%
  ggedgelist:::ggedgelist_quick(
    layout = "fr", include_names = T)

exported_layer_fun_composition %>%
  filter(object != "PositionIdentity") %>%
  select(exported_fun, object) %>%
  ggedgelist:::ggedgelist_quick(
    layout = "fr", include_names = T) + 
  labs(subtitle = "Position is included if not StatIdentity")

exported_layer_fun_composition %>%
  filter(object != "PositionIdentity") %>%
  filter(object != "StatIdentity") %>%
  filter(object != "GeomPoint") %>% 
  select(exported_fun, object) %>%
  ggedgelist:::ggedgelist_quick(
    layout = "fr", include_names = T) + 
  labs(subtitle = "Objects not included if StatIdentity, Position Identity or GeomPoint")

Closing remarks, Other Relevant Work, Caveats