Skip to content

update_geom_defaults ignores pointrange's "fatten" #2798

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
drammock opened this issue Aug 2, 2018 · 12 comments
Closed

update_geom_defaults ignores pointrange's "fatten" #2798

drammock opened this issue Aug 2, 2018 · 12 comments

Comments

@drammock
Copy link

drammock commented Aug 2, 2018

update_geom_defaults appears to ignore the fatten parameter of geom_pointrange. Reprex:

library(ggplot2)
library(dplyr)

iris %>%
    group_by(Species) %>%
    summarise(y=mean(Sepal.Length),
              ymin=min(Sepal.Length),
              ymax=max(Sepal.Length)) %>%
    rename(x=Species) ->
    summary_df

ggplot(summary_df, aes(x=x, y=y, ymin=ymin, ymax=ymax)) + geom_pointrange()

Default settings

it works with size

update_geom_defaults("pointrange", list(size=3))
ggplot(summary_df, aes(x=x, y=y, ymin=ymin, ymax=ymax)) + geom_pointrange()

it doesn't work with fatten

update_geom_defaults("pointrange", list(fatten=1))
ggplot(summary_df, aes(x=x, y=y, ymin=ymin, ymax=ymax)) + geom_pointrange()

update_geom_defaults("pointrange", list(fatten=10))
ggplot(summary_df, aes(x=x, y=y, ymin=ymin, ymax=ymax)) + geom_pointrange()

fatten does work within the geom call

ggplot(summary_df, aes(x=x, y=y, ymin=ymin, ymax=ymax)) + geom_pointrange(fatten=10)

Created on 2018-08-02 by the reprex package (v0.2.0).

Session info
devtools::session_info()
#> Session info -------------------------------------------------------------
#>  setting  value                       
#>  version  R version 3.4.4 (2018-03-15)
#>  system   x86_64, linux-gnu           
#>  ui       X11                         
#>  language en_US                       
#>  collate  en_US.UTF-8                 
#>  tz       America/Los_Angeles         
#>  date     2018-08-02
#> Packages -----------------------------------------------------------------
#>  package    * version    date       source                            
#>  assertthat   0.2.0      2017-04-11 CRAN (R 3.4.3)                    
#>  backports    1.1.2      2017-12-13 CRAN (R 3.4.4)                    
#>  base       * 3.4.4      2018-03-16 local                             
#>  bindr        0.1.1      2018-03-13 CRAN (R 3.4.4)                    
#>  bindrcpp     0.2.2      2018-03-29 CRAN (R 3.4.4)                    
#>  colorspace   1.3-2      2016-12-14 CRAN (R 3.4.1)                    
#>  compiler     3.4.4      2018-03-16 local                             
#>  crayon       1.3.4      2017-09-16 CRAN (R 3.4.4)                    
#>  curl         3.2        2018-03-28 CRAN (R 3.4.4)                    
#>  datasets   * 3.4.4      2018-03-16 local                             
#>  devtools     1.13.6     2018-06-27 CRAN (R 3.4.4)                    
#>  digest       0.6.15     2018-01-28 CRAN (R 3.4.4)                    
#>  dplyr      * 0.7.6      2018-06-29 CRAN (R 3.4.4)                    
#>  evaluate     0.11       2018-07-17 CRAN (R 3.4.4)                    
#>  ggplot2    * 3.0.0.9000 2018-08-02 Github (tidyverse/ggplot2@0770163)
#>  glue         1.3.0      2018-07-17 CRAN (R 3.4.4)                    
#>  graphics   * 3.4.4      2018-03-16 local                             
#>  grDevices  * 3.4.4      2018-03-16 local                             
#>  grid         3.4.4      2018-03-16 local                             
#>  gtable       0.2.0      2016-02-26 CRAN (R 3.4.1)                    
#>  htmltools    0.3.6      2017-04-28 CRAN (R 3.4.1)                    
#>  httr         1.3.1      2017-08-20 CRAN (R 3.4.3)                    
#>  knitr        1.20       2018-02-20 CRAN (R 3.4.4)                    
#>  labeling     0.3        2014-08-23 CRAN (R 3.4.1)                    
#>  lazyeval     0.2.1      2017-10-29 CRAN (R 3.4.4)                    
#>  magrittr     1.5        2014-11-22 CRAN (R 3.4.1)                    
#>  memoise      1.1.0      2017-04-21 CRAN (R 3.4.3)                    
#>  methods    * 3.4.4      2018-03-16 local                             
#>  mime         0.5        2016-07-07 CRAN (R 3.4.1)                    
#>  munsell      0.5.0      2018-06-12 CRAN (R 3.4.4)                    
#>  pillar       1.3.0      2018-07-14 CRAN (R 3.4.4)                    
#>  pkgconfig    2.0.1      2017-03-21 CRAN (R 3.4.3)                    
#>  plyr         1.8.4      2016-06-08 CRAN (R 3.4.1)                    
#>  purrr        0.2.5      2018-05-29 CRAN (R 3.4.4)                    
#>  R6           2.2.2      2017-06-17 CRAN (R 3.4.1)                    
#>  Rcpp         0.12.18    2018-07-23 CRAN (R 3.4.4)                    
#>  rlang        0.2.1      2018-05-30 CRAN (R 3.4.4)                    
#>  rmarkdown    1.10       2018-06-11 CRAN (R 3.4.4)                    
#>  rprojroot    1.3-2      2018-01-03 CRAN (R 3.4.4)                    
#>  scales       0.5.0      2017-08-24 CRAN (R 3.4.1)                    
#>  stats      * 3.4.4      2018-03-16 local                             
#>  stringi      1.2.4      2018-07-20 CRAN (R 3.4.4)                    
#>  stringr      1.3.1      2018-05-10 CRAN (R 3.4.4)                    
#>  tibble       1.4.2      2018-01-22 CRAN (R 3.4.4)                    
#>  tidyselect   0.2.4      2018-02-26 CRAN (R 3.4.4)                    
#>  tools        3.4.4      2018-03-16 local                             
#>  utils      * 3.4.4      2018-03-16 local                             
#>  withr        2.1.2      2018-03-15 CRAN (R 3.4.4)                    
#>  xml2         1.2.0      2018-01-24 CRAN (R 3.4.4)                    
#>  yaml         2.1.19     2018-05-01 CRAN (R 3.4.4)
@dpseidel
Copy link
Collaborator

dpseidel commented Aug 3, 2018

This is because fatten is not a default aesthetic of the geom, rather an argument unique to geom_pointrange() and geom_crossbar(). The defaults of geom that can be affected by update_geom_defaults() can be seen by extracting a geom's default_aes:

library(ggplot2)
GeomPointrange$default_aes
#> Aesthetic mapping: 
#> * `colour`   -> "black"
#> * `size`     -> 0.5
#> * `linetype` -> 1
#> * `shape`    -> 19
#> * `fill`     -> NA
#> * `alpha`    -> NA
#> * `stroke`   -> 1

@drammock
Copy link
Author

drammock commented Aug 3, 2018

So, this is a feature, not a bug? Can you point me toward a reference that will help me understand why it works this way?

@batpigandme
Copy link
Contributor

batpigandme commented Aug 3, 2018

If you take a look at the source code for geom_pointrange() I think what @dpseidel's describing will be a bit clearer.
fatten is a parameter that can be passed to the function geom_pointrange(), '

params = list(
fatten = fatten,
na.rm = na.rm,

but not one of the default aesthetics of the GeomPointrange ggproto object.
GeomPointrange <- ggproto("GeomPointrange", Geom,
default_aes = aes(colour = "black", size = 0.5, linetype = 1, shape = 19,
fill = NA, alpha = NA, stroke = 1),

@dpseidel
Copy link
Collaborator

dpseidel commented Aug 3, 2018

So the docs for the update_geom_defaults() does specify that it accepts a named list of aesthetics but admittedly this could be clarified. Aesthetics themselves are discussed in detail their own vignette
and the list of aesthetics accepted by point_range is here.

Fatten is actually a parameter not an aesthetic, and thus it can't be updated with update_geom_defaults().

library(ggplot2)
GeomPointrange$parameters()
#> [1] "fatten"

Broadly you can think of aesthetics as those things that can be mapped to data and a scale, but parameters as things that can only be set to a constant for any given layer.

Beyond that, the easiest way to see why this doesn't work is to look at the function itself:

update_geom_defaults <- function(geom, new) {
g <- check_subclass(geom, "Geom", env = parent.frame())
old <- g$default_aes
g$default_aes <- defaults(rename_aes(new), old)
invisible()
}

Even without going to deeper to investigate what rename_aes() is exactly doing, you can see that the function updates only g$default_aes which is the list I posted above.

Does that help?

@dpseidel
Copy link
Collaborator

dpseidel commented Aug 3, 2018

woops! @batpigandme beat me to it!

@drammock
Copy link
Author

drammock commented Aug 3, 2018

Thanks for the reference to the source. I understand how it is implemented such that fatten can't be used in this way. What I'm trying to understand is the rationale for the API decision to make it this way, since clearly fatten could have been part of the default_aes for GeomPointrange.

Perhaps it helps to understand my motivation: a script makes several plots; some have points, some have pointranges. I want the points in all plots to end up the same size, so I do some initial calls to update_geom_defaults... having never used geom_pointrange before, I'm surprised that the points on the pointrange plots are 4x bigger than the points on the other plots (because default is fatten=4). So I check the docs, discover fatten, and try to set fatten=1 globally, but I can't. Why not? What is the rationale for having a geom that has some properties that have defaults defined in the ggproto object, and others only defined in the function? A related question would be why the default for fatten is 4 instead of 1; it effectively makes size behave differently for point vs pointrange.

@drammock
Copy link
Author

drammock commented Aug 3, 2018

whoops, when I posted my last message I hadn't seen your explanation about aesthetics vs parameters, @dpseidel. That does clarify why it makes sense to do it this way from an API standpoint. I guess I'm still left wondering why the default is fatten=4 rather than fatten=1 (for the same reasons outlined above), but I've gotten the insight I was missing, so thanks!

@drammock drammock closed this as completed Aug 3, 2018
@dpseidel
Copy link
Collaborator

dpseidel commented Aug 3, 2018

Oh good, glad I could help. I admit there are some inconsistencies in defaults! Your issue in fact led me to realize for geom_errorbar width is listed as an aesthetic AND a parameter, also impeding updating because of the priority given to calculated or set parameters over aesthetics. I'll open a separate issue to address this with a full reprex.

In the mean time for your issue, in both cases, the size aesthetic is controlling the size of the entire object as expected, but yes, the default settings do make the "point" size different
across layers. Unless I am missing something there isn't a good way to globally set parameters like this, but if you want to control your line and point sizes separately, it may be simpler to use geom_point() in combination geom_errorbar(width = 0), though as I mention above currently updating the width aesthetic globally with update_geom_defaults() for geom_errorbar doesn't actually impact the plot due to the internal calculation of the width parameter.

@drammock
Copy link
Author

drammock commented Aug 3, 2018

Can you either reference this issue or tag me in the new one, so I can track when that gets merged? You're right that separate calls to point and errorbar would get me what I want (once errorbar width is globally controllable).

@clauswilke
Copy link
Member

The distinction between aesthetics and parameters is sometimes not so clear. Historically, ggplot2 has used a fairly limited set of aesthetics, and everything else was parameters. My personal opinion is that we can be more liberal with making things aesthetics, there's no strong technical reason not to. For geom_pointrange(), it might make sense to have three size aesthetics, size, point_size, and line_size, with the latter two deriving from the first unless explicitly specified.

The problem is these kinds of choices need to be manually implemented separately for each geom, and different geom authors may have slightly different perspectives on how to name things and what to make aesthetics or parameters.

@drammock
Copy link
Author

drammock commented Aug 3, 2018

@clauswilke 👍 for GeomPointrange having separate size aesthetics for point and line (which would eliminate the need for a fatten parameter). I would have thought that the naming consistency issue could be solved within ggplot by a combination of dictatorial fiat and a generous deprecation timeline with warnings, but for third-party geoms in other packages I agree it wouldn't be enforceable.

@lock
Copy link

lock bot commented Jan 30, 2019

This old issue has been automatically locked. If you believe you have found a related problem, please file a new issue (with reprex) and link to this issue. https://reprex.tidyverse.org/

@lock lock bot locked and limited conversation to collaborators Jan 30, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants