Skip to content
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

guide_legend() label.position = "bottom" mess up the theme() legend.key.size option #5082

Closed
YoannPa opened this issue Dec 3, 2022 · 5 comments · Fixed by #5083
Closed
Labels
bug an unexpected problem or unintended behavior

Comments

@YoannPa
Copy link

YoannPa commented Dec 3, 2022

I recently updated ggplot2 to version 3.4.0. I can't remember which version I was using before.
And since so the keys from a legend of one of my plot have disproportionated height. Also the theme()parameters legend.key.height and legend.key.width are not working as supposed (haven't really figured out how it is working in this specific configuration). The guide_legend() label.position = "bottom" parameter is causing the problem. When I remove it, labels stay on the left of keys, and key dimensions parameter provided in theme() work as intended.
Here is the ggplot2 code I use causing the issue:

ggplot() +
    geom_boxplot(
      data = dt.rs,
      mapping = aes(x = genotype, color = allele, group = allele),
      position = position_dodge(0)) +
    theme(
      axis.text.y = element_blank(),
      axis.ticks.y = element_blank(), 
      axis.text.x = element_text(size = 12, color = "black"),
      axis.title.x = element_blank(),
      legend.position = "bottom",
      legend.direction = "horizontal",
      legend.title = element_text(size = 12),
      legend.text = element_text(size = 11),
      legend.key = element_blank(),
      panel.background = element_rect(fill = "white", color = "black"),
      panel.grid.major.x = element_line(color = "grey"),
      panel.grid.minor.x = element_blank(),
      panel.grid.major.y = element_blank(),
      panel.grid.minor.y = element_blank(),
      plot.margin = margin(0,0.5,0.1,0.1, unit = "cm")) +
    guides(color = guide_legend(
      title.position = "top", title.hjust = 0.5, label.position = "bottom")) +
    scale_color_manual(values = c("#2166AC", "#E6C952", "#B2182B")) +
    scale_x_continuous(expand = c(0, 0), limits = c(0, 1)) +
    scale_y_continuous(expand = c(0.01, 0.01)) +
    labs(color = "Allele categories")

Here is an example of the legend I was getting before my update to 3.4.0 (which was fine for my use):
Capture du 2022-12-03 22-23-52

Here is an example of the legend I get after updating ggplot2 to 3.4.0:
Capture du 2022-12-03 22-24-31

I realize only since I am encountering this issue that actually the middle key (The yellow boxplot) is slightly bigger than the 2 others on both screen capture... probably another issue to have a look at.

So in total there are 3 issues related to guide_legend() label.position = "bottom":

  1. The disproportion of height and width of the keys.
  2. legend.key.height and legend.key.width not working as expected.
  3. And the size difference between the middle key and the keys on the right and on the left.

For now I will just remove label.position = "bottom"from my plot to get something working.
So no emergency on my side, but I guess this issue is of interest to fix.
Thank you.

> sessionInfo()
R version 4.2.2 Patched (2022-11-10 r83330)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 16.04.7 LTS

Matrix products: default
BLAS:   /usr/lib/openblas-base/libblas.so.3
LAPACK: /usr/lib/libopenblasp-r0.2.18.so

locale:
 [1] LC_CTYPE=fr_FR.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=fr_FR.UTF-8        LC_COLLATE=fr_FR.UTF-8    
 [5] LC_MONETARY=fr_FR.UTF-8    LC_MESSAGES=fr_FR.UTF-8   
 [7] LC_PAPER=fr_FR.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=fr_FR.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
 [1] parallel  grid      stats4    stats     graphics  grDevices utils    
 [8] datasets  methods   base     

other attached packages:
 [1] RnBeads.hg19_1.30.0                    
 [2] methview.qc_0.0.44                     
 [3] BiocompR_0.0.171                       
 [4] RnBeads_2.15.1                         
 [5] plyr_1.8.8                             
 [6] methylumi_2.44.0                       
 [7] minfi_1.44.0                           
 [8] bumphunter_1.40.0                      
 [9] locfit_1.5-9.6                         
[10] iterators_1.0.14                       
[11] foreach_1.5.2                          
[12] Biostrings_2.66.0                      
[13] XVector_0.38.0                         
[14] SummarizedExperiment_1.28.0            
[15] MatrixGenerics_1.10.0                  
[16] FDb.InfiniumMethylation.hg19_2.2.0     
[17] org.Hs.eg.db_3.16.0                    
[18] TxDb.Hsapiens.UCSC.hg19.knownGene_3.2.2
[19] GenomicFeatures_1.50.2                 
[20] AnnotationDbi_1.60.0                   
[21] reshape2_1.4.4                         
[22] scales_1.2.1                           
[23] Biobase_2.58.0                         
[24] illuminaio_0.40.0                      
[25] matrixStats_0.63.0                     
[26] limma_3.54.0                           
[27] gridExtra_2.3                          
[28] gplots_3.1.3                           
[29] fields_14.1                            
[30] viridis_0.6.2                          
[31] viridisLite_0.4.1                      
[32] spam_2.9-1                             
[33] ff_4.0.7                               
[34] bit_4.0.5                              
[35] cluster_2.1.4                          
[36] MASS_7.3-58.1                          
[37] GenomicRanges_1.50.1                   
[38] GenomeInfoDb_1.34.3                    
[39] IRanges_2.32.0                         
[40] S4Vectors_0.36.0                       
[41] BiocGenerics_0.44.0                    
[42] data.table_1.14.6                      
[43] ggplot2_3.4.0                          

loaded via a namespace (and not attached):
  [1] BiocFileCache_2.6.0       splines_4.2.2            
  [3] BiocParallel_1.32.1       digest_0.6.30            
  [5] fansi_1.0.3               magrittr_2.0.3           
  [7] memoise_2.0.1             tzdb_0.3.0               
  [9] readr_2.1.3               annotate_1.76.0          
 [11] askpass_1.1               siggenes_1.72.0          
 [13] prettyunits_1.1.1         colorspace_2.0-3         
 [15] blob_1.2.3                rappdirs_0.3.3           
 [17] xfun_0.35                 dplyr_1.0.10             
 [19] crayon_1.5.2              RCurl_1.98-1.9           
 [21] genefilter_1.80.0         GEOquery_2.66.0          
 [23] survival_3.4-0            glue_1.6.2               
 [25] gtable_0.3.1              zlibbioc_1.44.0          
 [27] DelayedArray_0.24.0       Rhdf5lib_1.20.0          
 [29] maps_3.4.1                HDF5Array_1.26.0         
 [31] DBI_1.1.3                 rngtools_1.5.2           
 [33] Rcpp_1.0.9                xtable_1.8-4             
 [35] progress_1.2.2            mclust_6.0.0             
 [37] preprocessCore_1.60.0     dotCall64_1.0-2          
 [39] httr_1.4.4                RColorBrewer_1.1-3       
 [41] ellipsis_0.3.2            farver_2.1.1             
 [43] pkgconfig_2.0.3           reshape_0.8.9            
 [45] XML_3.99-0.12             dbplyr_2.2.1             
 [47] utf8_1.2.2                labeling_0.4.2           
 [49] tidyselect_1.2.0          rlang_1.0.6              
 [51] munsell_0.5.0             tools_4.2.2              
 [53] cachem_1.0.6              cli_3.4.1                
 [55] generics_0.1.3            RSQLite_2.2.18           
 [57] evaluate_0.18             stringr_1.4.1            
 [59] fastmap_1.1.0             yaml_2.3.6               
 [61] knitr_1.41                bit64_4.0.5              
 [63] beanplot_1.3.1            caTools_1.18.2           
 [65] scrime_1.3.5              purrr_0.3.5              
 [67] KEGGREST_1.38.0           egg_0.4.5                
 [69] nlme_3.1-160              doRNG_1.8.2              
 [71] sparseMatrixStats_1.10.0  nor1mix_1.3-0            
 [73] xml2_1.3.3                biomaRt_2.54.0           
 [75] compiler_4.2.2            rstudioapi_0.14          
 [77] filelock_1.0.2            curl_4.3.3               
 [79] png_0.1-7                 tibble_3.1.8             
 [81] stringi_1.7.8             highr_0.9                
 [83] lattice_0.20-45           Matrix_1.5-3             
 [85] multtest_2.54.0           vctrs_0.5.1              
 [87] pillar_1.8.1              lifecycle_1.0.3          
 [89] rhdf5filters_1.10.0       bitops_1.0-7             
 [91] rtracklayer_1.58.0        R6_2.5.1                 
 [93] BiocIO_1.8.0              KernSmooth_2.23-20       
 [95] codetools_0.2-18          gtools_3.9.3             
 [97] assertthat_0.2.1          rhdf5_2.42.0             
 [99] openssl_2.0.4             rjson_0.2.21             
[101] withr_2.5.0               GenomicAlignments_1.34.0 
[103] Rsamtools_2.14.0          GenomeInfoDbData_1.2.9   
[105] hms_1.1.2                 quadprog_1.5-8           
[107] tidyr_1.2.1               base64_2.0.1             
[109] DelayedMatrixStats_1.20.0 restfulr_0.0.15
@teunbrand
Copy link
Collaborator

teunbrand commented Dec 3, 2022

With regards to your points;

The disproportion of height and width of the keys.

The size of key is the maximum of the text label and what you give as theme/legend setting.

legend.key.height and legend.key.width not working as expected.

I suspect this also due to the text.

And the size difference between the middle key and the keys on the right and on the left.

Likely because your middle label is longer than the left/right labels.

However, I suspect the true issue here lies elsewhere, namely that the boxplot flipping doesn't work 100% as it should.

A more minimal reprex:

library(ggplot2)
#> Warning: package 'ggplot2' was built under R version 4.2.2

ggplot(mtcars, aes(mpg, factor(cyl), colour = factor(cyl))) +
  geom_boxplot() +
  scale_colour_discrete(
    labels = paste0("A longer label than the key width ", 1:3)
  ) +
  guides(
    colour = guide_legend(label.position = "bottom")
  ) +
  theme(
    legend.position = "bottom"
  )

I suppose it is the viewport rotation of the boxplot key drawing function that is misbehaving here. To fix it, one could write a new key drawing function.

library(grid)
library(rlang)

draw_key_boxplot2 <- function(data, params, size) {
  gp <- gpar(
    col = data$colour %||% "grey20",
    fill = alpha(data$fill %||% "white", data$alpha),
    lwd = (data$linewidth %||% 0.5) * .pt,
    lty = data$linetype %||% 1,
    lineend = params$lineend %||% "butt",
    linejoin = params$linejoin %||% "mitre"
  )
  if (isTRUE(params$flipped_aes)) {
    grobTree(
      linesGrob(c(0.1, 0.25), 0.5),
      linesGrob(c(0.75, 0.9), 0.5),
      rectGrob(width = 0.5, height = 0.75),
      linesGrob(0.5, c(0.125, 0.875)),
      gp = gp
    )
  } else {
    grobTree(
      linesGrob(0.5, c(0.1, 0.25)),
      linesGrob(0.5, c(0.75, 0.9)),
      rectGrob(height = 0.5, width = 0.75),
      linesGrob(c(0.125, 0.875), 0.5),
      gp = gp
    )
  }
}

ggplot(mtcars, aes(mpg, factor(cyl), colour = factor(cyl))) +
  geom_boxplot(key_glyph = draw_key_boxplot2) +
  scale_colour_discrete(
    labels = paste0("A longer label than the key width ", 1:3)
  ) +
  guides(
    colour = guide_legend(label.position = "bottom")
  ) +
  theme(
    legend.position = "bottom"
  )

Created on 2022-12-03 by the reprex package (v2.0.1)

@teunbrand
Copy link
Collaborator

teunbrand commented Dec 3, 2022

The same applies to the crossbar legend too:

library(ggplot2)
#> Warning: package 'ggplot2' was built under R version 4.2.2

ggplot(mtcars, aes(mpg, factor(cyl), colour = factor(cyl))) +
  geom_crossbar(
    stat = "summary"
  ) +
  scale_colour_discrete(
    labels = paste0("A longer label than the key width ", 1:3)
  ) +
  guides(
    colour = guide_legend(label.position = "bottom")
  ) +
  theme(
    legend.position = "bottom"
  )
#> No summary function supplied, defaulting to `mean_se()`

Created on 2022-12-03 by the reprex package (v2.0.1)

@YoannPa
Copy link
Author

YoannPa commented Dec 4, 2022

@teunbrand Thank you very much for your explanations ! It makes already a lot more sense now.
I will try the custom function you proposed to fix the issue and will let you know if it works well on my data.
Funny issue anyway. Thank you for providing a proper reprex.

@YoannPa
Copy link
Author

YoannPa commented Dec 5, 2022

library(grid)
library(rlang)

draw_key_boxplot2 <- function(data, params, size) {
  gp <- gpar(
    col = data$colour %||% "grey20",
    fill = alpha(data$fill %||% "white", data$alpha),
    lwd = (data$linewidth %||% 0.5) * .pt,
    lty = data$linetype %||% 1,
    lineend = params$lineend %||% "butt",
    linejoin = params$linejoin %||% "mitre"
  )
  if (isTRUE(params$flipped_aes)) {
    grobTree(
      linesGrob(c(0.1, 0.25), 0.5),
      linesGrob(c(0.75, 0.9), 0.5),
      rectGrob(width = 0.5, height = 0.75),
      linesGrob(0.5, c(0.125, 0.875)),
      gp = gp
    )
  } else {
    grobTree(
      linesGrob(0.5, c(0.1, 0.25)),
      linesGrob(0.5, c(0.75, 0.9)),
      rectGrob(height = 0.5, width = 0.75),
      linesGrob(c(0.125, 0.875), 0.5),
      gp = gp
    )
  }
}

@teunbrand This is very elegantly written with rlang. I like it, I am not using rlang so often so I am not used to the operator you are using. Apparently ggplot2 has rlang as a dependency but it doesn't load the package when I library(ggplot2)... maybe because I am not using the entire Tidyverse.
So for my purpose I have re-written the function without the rlang operator you use, I don't want to load too many packages to execute my functions. But your version is definitely the most elegant, thanks for the tip!

Should I close the issue then ?

library(grid)

null_default <- function(x, y){
  if (is.null(x)){ y } else { x }
}

draw_key_boxplot2 <- function(data, params, size) {
  gp <- gpar(
    col = null_default(data$colour, "grey20"),
    fill = alpha(null_default(data$fill, "white"), data$alpha),
    lwd = null_default(data$linewidth, 0.5) * .pt,
    lty = null_default(data$linetype, 1),
    lineend = null_default(params$lineend, "butt"),
    linejoin = null_default(params$linejoin, "mitre")
  )
  if (isTRUE(params$flipped_aes)) {
    grobTree(
      linesGrob(c(0.1, 0.25), 0.5),
      linesGrob(c(0.75, 0.9), 0.5),
      rectGrob(width = 0.5, height = 0.75),
      linesGrob(0.5, c(0.125, 0.875)),
      gp = gp
    )
  } else {
    grobTree(
      linesGrob(0.5, c(0.1, 0.25)),
      linesGrob(0.5, c(0.75, 0.9)),
      rectGrob(height = 0.5, width = 0.75),
      linesGrob(c(0.125, 0.875), 0.5),
      gp = gp
    )
  }
}

@teunbrand
Copy link
Collaborator

I've opened up a pull request to fix the boxplot legend keys in #5083, where I've mentioned that it would fix this issue. Through GitHub voodoo-witchcraft, merging that PR would automatically close this issue. Until then, I think this issue serves a function as a reminder before the next release, so you're free to leave this issue open.

@teunbrand teunbrand added the bug an unexpected problem or unintended behavior label Dec 23, 2022
@teunbrand teunbrand modified the milestone: ggplot2 3.4.1 Jan 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug an unexpected problem or unintended behavior
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants