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

fix "inward" and "outward" hjust and vjust in geom_text() with angle > 45 #4447

Merged
merged 12 commits into from
May 6, 2021

Conversation

aphalo
Copy link
Contributor

@aphalo aphalo commented Apr 24, 2021

Fix #4169

In geom_text() when abs(angle) > 45 justification applied based on the orientation of the text labels is done along the x axis for vjust and along the y axis for hjust. For "outward" and "inward" to behave correctly, the value tested against 0.5 needs to change from x to y and vice versa based on the value of angle in each row in data.

This pull request adds code to draw_panel in GeomText to handle "outward" and "inward" as special cases.

Reprex with 'ggplot2' 3.3.3

library(ggplot2)

my.cars <- mtcars[c(TRUE, FALSE, FALSE, FALSE), ]

p <- ggplot(my.cars, aes(wt, mpg, label = rownames(my.cars))) +
  geom_point(colour = "red")

p + geom_text(hjust = "outward")

p + geom_text(hjust = "outward", angle = 30)

p + geom_text(hjust = "outward", angle = 70)

Created on 2021-04-24 by the reprex package (v2.0.0)

Session info
sessioninfo::session_info()
#> - Session info ---------------------------------------------------------------
#>  setting  value                       
#>  version  R version 4.0.5 (2021-03-31)
#>  os       Windows 10 x64              
#>  system   x86_64, mingw32             
#>  ui       RTerm                       
#>  language (EN)                        
#>  collate  English_Finland.1252        
#>  ctype    English_Finland.1252        
#>  tz       Europe/Helsinki             
#>  date     2021-04-24                  
#> 
#> - Packages -------------------------------------------------------------------
#>  package     * version date       lib source        
#>  assertthat    0.2.1   2019-03-21 [1] CRAN (R 4.0.0)
#>  backports     1.2.1   2020-12-09 [1] CRAN (R 4.0.3)
#>  cli           2.4.0   2021-04-05 [1] CRAN (R 4.0.4)
#>  colorspace    2.0-0   2020-11-11 [1] CRAN (R 4.0.3)
#>  crayon        1.4.1   2021-02-08 [1] CRAN (R 4.0.3)
#>  curl          4.3     2019-12-02 [1] CRAN (R 4.0.0)
#>  DBI           1.1.1   2021-01-15 [1] CRAN (R 4.0.3)
#>  digest        0.6.27  2020-10-24 [1] CRAN (R 4.0.3)
#>  dplyr         1.0.5   2021-03-05 [1] CRAN (R 4.0.4)
#>  ellipsis      0.3.1   2020-05-15 [1] CRAN (R 4.0.0)
#>  evaluate      0.14    2019-05-28 [1] CRAN (R 4.0.0)
#>  fansi         0.4.2   2021-01-15 [1] CRAN (R 4.0.3)
#>  farver        2.1.0   2021-02-28 [1] CRAN (R 4.0.4)
#>  fs            1.5.0   2020-07-31 [1] CRAN (R 4.0.2)
#>  generics      0.1.0   2020-10-31 [1] CRAN (R 4.0.3)
#>  ggplot2     * 3.3.3   2020-12-30 [1] CRAN (R 4.0.5)
#>  glue          1.4.2   2020-08-27 [1] CRAN (R 4.0.2)
#>  gtable        0.3.0   2019-03-25 [1] CRAN (R 4.0.0)
#>  highr         0.9     2021-04-16 [1] CRAN (R 4.0.4)
#>  htmltools     0.5.1.1 2021-01-22 [1] CRAN (R 4.0.3)
#>  httr          1.4.2   2020-07-20 [1] CRAN (R 4.0.2)
#>  knitr         1.32    2021-04-14 [1] CRAN (R 4.0.4)
#>  labeling      0.4.2   2020-10-20 [1] CRAN (R 4.0.3)
#>  lifecycle     1.0.0   2021-02-15 [1] CRAN (R 4.0.4)
#>  magrittr      2.0.1   2020-11-17 [1] CRAN (R 4.0.3)
#>  mime          0.10    2021-02-13 [1] CRAN (R 4.0.3)
#>  munsell       0.5.0   2018-06-12 [1] CRAN (R 4.0.0)
#>  pillar        1.6.0   2021-04-13 [1] CRAN (R 4.0.5)
#>  pkgconfig     2.0.3   2019-09-22 [1] CRAN (R 4.0.0)
#>  purrr         0.3.4   2020-04-17 [1] CRAN (R 4.0.0)
#>  R6            2.5.0   2020-10-28 [1] CRAN (R 4.0.3)
#>  reprex        2.0.0   2021-04-02 [1] CRAN (R 4.0.4)
#>  rlang         0.4.10  2020-12-30 [1] CRAN (R 4.0.3)
#>  rmarkdown     2.7     2021-02-19 [1] CRAN (R 4.0.4)
#>  scales        1.1.1   2020-05-11 [1] CRAN (R 4.0.0)
#>  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 4.0.0)
#>  stringi       1.5.3   2020-09-09 [1] CRAN (R 4.0.2)
#>  stringr       1.4.0   2019-02-10 [1] CRAN (R 4.0.0)
#>  styler        1.4.1   2021-03-30 [1] CRAN (R 4.0.4)
#>  tibble        3.1.1   2021-04-18 [1] CRAN (R 4.0.4)
#>  tidyselect    1.1.0   2020-05-11 [1] CRAN (R 4.0.0)
#>  utf8          1.2.1   2021-03-12 [1] CRAN (R 4.0.4)
#>  vctrs         0.3.7   2021-03-29 [1] CRAN (R 4.0.4)
#>  withr         2.4.2   2021-04-18 [1] CRAN (R 4.0.4)
#>  xfun          0.22    2021-03-11 [1] CRAN (R 4.0.4)
#>  xml2          1.3.2   2020-04-23 [1] CRAN (R 4.0.0)
#>  yaml          2.2.1   2020-02-01 [1] CRAN (R 4.0.0)
#> 
#> [1] C:/Users/Aphalo/Documents/R/win-library/4.0
#> [2] C:/Program Files/R/R-4.0.5/library

Similar reprex, adding one example, after applying this pull request to current 'master' branch from GitHub.

library(ggplot2)

my.cars <- mtcars[c(TRUE, FALSE, FALSE, FALSE), ]

p <- ggplot(my.cars, aes(wt, mpg, label = rownames(my.cars))) +
  geom_point(colour = "red")

p + geom_text(hjust = "outward")

p + geom_text(hjust = "outward", angle = 30)

p + geom_text(hjust = "outward", angle = 70)

p + geom_text(hjust = "outward", angle = 90)

Created on 2021-04-25 by the reprex package (v2.0.0)

Session info
sessioninfo::session_info()
#> - Session info ---------------------------------------------------------------
#>  setting  value                       
#>  version  R version 4.0.5 (2021-03-31)
#>  os       Windows 10 x64              
#>  system   x86_64, mingw32             
#>  ui       RTerm                       
#>  language (EN)                        
#>  collate  English_Finland.1252        
#>  ctype    English_Finland.1252        
#>  tz       Europe/Helsinki             
#>  date     2021-04-25                  
#> 
#> - Packages -------------------------------------------------------------------
#>  package     * version    date       lib source        
#>  assertthat    0.2.1      2019-03-21 [1] CRAN (R 4.0.0)
#>  backports     1.2.1      2020-12-09 [1] CRAN (R 4.0.3)
#>  cli           2.4.0      2021-04-05 [1] CRAN (R 4.0.4)
#>  colorspace    2.0-0      2020-11-11 [1] CRAN (R 4.0.3)
#>  crayon        1.4.1      2021-02-08 [1] CRAN (R 4.0.3)
#>  curl          4.3        2019-12-02 [1] CRAN (R 4.0.0)
#>  DBI           1.1.1      2021-01-15 [1] CRAN (R 4.0.3)
#>  digest        0.6.27     2020-10-24 [1] CRAN (R 4.0.3)
#>  dplyr         1.0.5      2021-03-05 [1] CRAN (R 4.0.4)
#>  ellipsis      0.3.1      2020-05-15 [1] CRAN (R 4.0.0)
#>  evaluate      0.14       2019-05-28 [1] CRAN (R 4.0.0)
#>  fansi         0.4.2      2021-01-15 [1] CRAN (R 4.0.3)
#>  farver        2.1.0      2021-02-28 [1] CRAN (R 4.0.4)
#>  fs            1.5.0      2020-07-31 [1] CRAN (R 4.0.2)
#>  generics      0.1.0      2020-10-31 [1] CRAN (R 4.0.3)
#>  ggplot2     * 3.3.3.9000 2021-04-24 [1] local         
#>  glue          1.4.2      2020-08-27 [1] CRAN (R 4.0.2)
#>  gtable        0.3.0      2019-03-25 [1] CRAN (R 4.0.0)
#>  highr         0.9        2021-04-16 [1] CRAN (R 4.0.4)
#>  htmltools     0.5.1.1    2021-01-22 [1] CRAN (R 4.0.3)
#>  httr          1.4.2      2020-07-20 [1] CRAN (R 4.0.2)
#>  knitr         1.32       2021-04-14 [1] CRAN (R 4.0.4)
#>  labeling      0.4.2      2020-10-20 [1] CRAN (R 4.0.3)
#>  lifecycle     1.0.0      2021-02-15 [1] CRAN (R 4.0.4)
#>  magrittr      2.0.1      2020-11-17 [1] CRAN (R 4.0.3)
#>  mime          0.10       2021-02-13 [1] CRAN (R 4.0.3)
#>  munsell       0.5.0      2018-06-12 [1] CRAN (R 4.0.0)
#>  pillar        1.6.0      2021-04-13 [1] CRAN (R 4.0.5)
#>  pkgconfig     2.0.3      2019-09-22 [1] CRAN (R 4.0.0)
#>  purrr         0.3.4      2020-04-17 [1] CRAN (R 4.0.0)
#>  R6            2.5.0      2020-10-28 [1] CRAN (R 4.0.3)
#>  reprex        2.0.0      2021-04-02 [1] CRAN (R 4.0.4)
#>  rlang         0.4.10     2020-12-30 [1] CRAN (R 4.0.3)
#>  rmarkdown     2.7        2021-02-19 [1] CRAN (R 4.0.4)
#>  scales        1.1.1      2020-05-11 [1] CRAN (R 4.0.0)
#>  sessioninfo   1.1.1      2018-11-05 [1] CRAN (R 4.0.0)
#>  stringi       1.5.3      2020-09-09 [1] CRAN (R 4.0.2)
#>  stringr       1.4.0      2019-02-10 [1] CRAN (R 4.0.0)
#>  styler        1.4.1      2021-03-30 [1] CRAN (R 4.0.4)
#>  tibble        3.1.1      2021-04-18 [1] CRAN (R 4.0.4)
#>  tidyselect    1.1.0      2020-05-11 [1] CRAN (R 4.0.0)
#>  utf8          1.2.1      2021-03-12 [1] CRAN (R 4.0.4)
#>  vctrs         0.3.7      2021-03-29 [1] CRAN (R 4.0.4)
#>  withr         2.4.2      2021-04-18 [1] CRAN (R 4.0.4)
#>  xfun          0.22       2021-03-11 [1] CRAN (R 4.0.4)
#>  xml2          1.3.2      2020-04-23 [1] CRAN (R 4.0.0)
#>  yaml          2.2.1      2020-02-01 [1] CRAN (R 4.0.0)
#> 
#> [1] C:/Users/Aphalo/Documents/R/win-library/4.0
#> [2] C:/Program Files/R/R-4.0.5/library

This may change the rendering of some old plots, but the old behavior is in my view wrong, and this pull request a bug fix.

In geom_text() when abs(angle) %% 90  > 45 justification applied based on the orientation of the text labels is done along x axis for vjust and along y axis for hjust. For "outward" and "inward" to behave correctly, the position tested against 0.5 needs to change from x to y and vice versa based on the value of angle for each row in data.
abs(angle) > 45 should work in most cases, handling correctly angles up to -135 and +135 degrees. For angles < -135 and > +135, the "inward" behaves as "outward" and vice versa but still with respect to the correct axis middle point. Using `%% 90` in the previous commit was wrong.
@aphalo aphalo marked this pull request as ready for review April 24, 2021 21:15
@aphalo aphalo changed the title fix "inward" and "outward" hjust and vjust in geom_text() with angle %% 90 > 45 fix "inward" and "outward" hjust and vjust in geom_text() with angle > 45 Apr 24, 2021
Copy link
Member

@thomasp85 thomasp85 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I think I would prefer if all the angle logic was contained in compute_just() rather than getting repeated...

so, compute_just() would be:

compute_just <- function(just, x, y, angle) {
  ...
}

@thomasp85 thomasp85 added this to the ggplot2 3.3.4 milestone Apr 27, 2021
@aphalo
Copy link
Contributor Author

aphalo commented Apr 27, 2021

@thomasp85 I think angle is relevant only to geom_text() but compute_just() is also used elsewhere... so one would need to have NULL as default for angle not to break the use of compute_just() elsewhere. I guess what is best depends on how widespread support for angle will be in the future. In principle support could be expanded to other geoms as grobs can be rotated. While I write this I convinced myself that you are correct. I will revise the code during the weekend.

aphalo added 4 commits May 1, 2021 23:05
The cleanest way to encapsulate all the tests within compute_just() is to pass `data` as an argument to this function. This is not the suggested approach, but I think it is better. Performance impact may need to be tested.
In its new version compute_just() handles more situations than earlier so the number of test cases needed in larger.
Cater with case when "inward" and/or "outward" are used together with "right", "center", "middle" or "left", as only "inward" and "outward" should be responsive to "angle". Edit and add test cases.
This commit reverts some of the edits in the three previous commits.
Set signature of compute_just() as suggested by thomasp85. As angle is set in default aes to zero, we can assume angle will be always available: remove corresponding test. Set default arguments for new parameters of compute_just() so that geom_label() does not need edits and so that existing test cases remain valid. Add new test cases.
@aphalo
Copy link
Contributor Author

aphalo commented May 2, 2021

@thomasp85 When revising the code at first and also in the original pull request I failed to realize that angle is set to zero in default_aes. Once I realized this I could simplify the code and easily implement the change you suggested. I also added a couple of test cases. At one point I edited geom_label() but I later reverted all these changes.

@thomasp85
Copy link
Member

Thanks! Can I get you to add a bulletpoint to the NEWS file?

aphalo added 2 commits May 4, 2021 00:40
The problem described in tidyverse#4169 has changed but is not solved yet.
@aphalo
Copy link
Contributor Author

aphalo commented May 3, 2021

@thomasp85 I added the bullet point but this created a conflict. Anyway you had linked to #4169 so I tested against the reprex there once I noticed this earlier issue and I am afraid the problem is not solved by my pull request yet. I will have a look at my pull request as this seems to be a problem due to negative angles more negative than -45 degrees that I haven't properly considered as a special case.

@thomasp85
Copy link
Member

Don't worry about the conflict - that is common with the news file and can be fixed just before merging. Thanks for looking into the reprex👍

aphalo added 2 commits May 4, 2021 11:28
 Add the logic needed to handle correctly the larger angles. The previous code worked correctly only for angle in -135...135. This also solves tidyverse#4169.
Resolve conflict in NEWs.md
@aphalo
Copy link
Contributor Author

aphalo commented May 4, 2021

I updated the code to handle correctly angles in -360...+360. To handle angles outside this range I could add angle <- angle %% 360 but this feels like costly overkill. What do you think? Now also #4169 is resolved. The reprex below shows several additional examples that were missing in my original reprex above and also the reprex from #4169. I also resolved the NEWS.md conflict.

I think that now this is ready. I renamed some variables to enhance readability of the code.

library(ggplot2)

my.cars <- mtcars[c(TRUE, FALSE, FALSE, FALSE), ]

p <- ggplot(my.cars, aes(wt, mpg, label = rownames(my.cars))) +
  geom_point(colour = "red")

p + geom_text(hjust = "outward")

p + geom_text(hjust = "outward", angle = 30)

p + geom_text(hjust = "outward", angle = 70)

p + geom_text(hjust = "outward", angle = 90)

p + geom_text(hjust = "outward", angle = 150)

p + geom_text(hjust = "outward", angle = 220)

p + geom_text(hjust = "outward", angle = 320)

p + geom_text(hjust = "outward", angle = -30)

p + geom_text(hjust = "outward", angle = -70)

p + geom_text(hjust = "outward", angle = -90)

p + geom_text(hjust = "outward", angle = -150)

p + geom_text(hjust = "outward", angle = -220)

p + geom_text(hjust = "outward", angle = -320)

# Issue #4169

print(ggplot(data.frame(x = c(0, 1, 2))) +
        geom_text(aes(
          x = x,
          y = 1,
          label = paste0("Annotation", x),
          angle = x * 60 - 90, 
          hjust = "outward"
        )) + 
        coord_polar() +
        scale_x_continuous(limits = c(0, 3))
)

Created on 2021-05-04 by the reprex package (v2.0.0)

@thomasp85
Copy link
Member

I think you should add angle <- angle %% 360 — a quick test shows that for 1mil angles. it would take around 15ms on my computer which is negligible to plotting 1mil labels

Add a modulo 360 to force all angles to the -360 to +360 degrees. Add three test cases: a) for negative angles, 2) for angle > 135 degrees and 3) for angle > 360.
@aphalo
Copy link
Contributor Author

aphalo commented May 5, 2021

@thomasp85 In addition to your request I added three new test cases. I think they will not be a burden as they directly test compute_just().

Copy link
Member

@thomasp85 thomasp85 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost there - sorry for not catching these two small issues earlier

R/geom-label.R Outdated
@@ -67,6 +67,7 @@ GeomLabel <- ggproto("GeomLabel", Geom,
}

data <- coord$transform(data, panel_params)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you avoid touching files and functions that you don't change

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, this was an accident. Left from from en edit that I reverted during development. Will fix in a minute.

R/geom-text.r Outdated
Comment on lines 244 to 265
bottom = 0, middle = 0.5, top = 1)[just])
bottom = 0, middle = 0.5, top = 1)[just])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as other comment - don't touch code format in unrelated code

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will also fix.

Copy link
Member

@thomasp85 thomasp85 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for all your work on this!

@aphalo
Copy link
Contributor Author

aphalo commented May 6, 2021

Thank you for helping me get the pull request in good shape!

@thomasp85 thomasp85 merged commit 800c5b4 into tidyverse:master May 6, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

hjust = "outward" not working for some angles
2 participants