Is there a way to search the entire output from ggplot_build() (or any other function), almost like searching the complete content of every subdirectory of a folder?
The details:
I was looking for a solution to Retrieve values for axis labels in ggplot2_3.0.0, and one of the early answers revealed that, depending on the ggplot2 version, the correct answer most likely would contain the parts $layout and / or $x.labels in the output from ggplot_build(g). So I started checking the ggplot_build() output each step of the way. One of the steps looks like the output below.
Snippet 1:
ggplot_build(g)$layout
Output 1:
<ggproto object: Class Layout, gg>
    coord: <ggproto object: Class CoordCartesian, Coord, gg>
        aspect: function
        clip: on
        [...]
    map_position: function
    panel_params: list
    panel_scales_x: list
    panel_scales_y: list
    render: function
        [...]
    ylabel: function
    super:  <ggproto object: Class Layout, gg>
>
And deep down there, under panel params, x.labels can be found along with lots of useful information like this:
Snippet 2:
ggplot_build(g)$layout$panel_params
Output 2:
[[1]]
[[1]]$`x.range`
[1]  7.7 36.3
[[1]]$x.labels
[1] "10" "15" "20" "25" "30" "35"
[[1]]$x.major
[1] 0.08041958 0.25524476 0.43006993 0.60489510 0.77972028 0.95454545
And it can be referenced directly like this:
Snippet 3:
ggplot_build(g)$layout$panel_params[[1]]$x.labels
Output 3:
[1] "10" "15" "20" "25" "30" "35"
My attempt for a more elegant approach:
I was certain I could do this with capture.output() like you can with str() as described here, but as far as I can tell, you won't find x.labels there either. I'm not going to flood the question with that output since it's about 300 lines long.
Thank you for any suggestions!
%>% is a pipe operator reexported from the magrittr package. Start by reading the vignette. Adding things to a ggplot changes the object that gets created. The print method of ggplot draws an appropriate plot depending upon the contents of the variable.
Integrating the pipe operator with ggplot2 The pipe operator can also be used to link data manipulation with consequent data visualization.
To customize the plot, the following arguments can be used: alpha, color, dotsize and fill. Learn more here: ggplot2 dot plot.
Elements that are normally added to a ggplot with operator + , such as scales, themes, aesthetics can be replaced with the %+% operator.
This function goes through a nested list structure and finds the paths through that structure that contain a given character string:
find_name <- function(obj, name) {
  # get all named paths through obj
  find_paths <- function(obj, path) {
    if ((!is.list(obj) && is.null(names(obj))) || identical(obj, .GlobalEnv)) {
      return (path)
    } else {
      if (is.null(names(obj))) {
        return(c(path,
                 lapply(seq_along(obj), function(x) find_paths(obj[[x]], paste0(path, "[[", x, "]]")))
              ))
      } else {
        return(c(path,
                 lapply(names(obj), function(x) find_paths(obj[[x]], paste(path, x, sep = "$")))
              ))
      }  
    }
  }
  # get all the paths through the nested structure
  all_paths <- unlist(find_paths(obj, deparse(substitute(obj))))
  # find the requested name
  path_to_name <- grep(paste0("\\$", name, "$"), all_paths, value = TRUE)
  return (path_to_name)
}
Here is an example of using this function with a ggplot_built object:
library(ggplot2)
p <- ggplot(mtcars) + geom_point(aes(x = disp, y = mpg, col = as.factor(cyl)))
gb <- ggplot_build(p)
find_name(gb, "x.labels")
## [1] "gb$layout$panel_params[[1]]$x.labels"
You can also directly get the contents of x.labels:
eval(parse(text = find_name(gb, "x.labels")))
## [1] "100" "200" "300" "400"
A few remarks on how this works:
find_paths() goes through the nested structure and returns all "paths" through the structure in a form similar to "gb$layout$panel_params[[1]]$x.labels".FALSE for is.list() and environments. One has to take care of all these situations.ggplot_built contains a reference to the global environment (gb$layout$facet_params$plot_env), which leads to an infinite loop if it is not properly treated.find_paths() is a nested list again, but the structure can easily be simplified with unlist().find_name(gb, "x") will not return "gb$layout$panel_params[[1]]$x.labels".I have tested the function with the ggplot_built object from my example and with a nested list. I cannot guarantee that it works for all situations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With