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

geom_textsegment() with arrow() draws line to the top left of the plot #66

Closed
erikvona opened this issue Feb 4, 2022 · 4 comments · Fixed by #67
Closed

geom_textsegment() with arrow() draws line to the top left of the plot #66

erikvona opened this issue Feb 4, 2022 · 4 comments · Fixed by #67

Comments

@erikvona
Copy link

erikvona commented Feb 4, 2022

As in the title, geom_textsegment() with arrow() draws a line starting from where the text starts to the top left of the plot.

Using the example from the docs:

ggplot(mapping = aes(x, y)) +
    geom_col(
        data = data.frame(x = c(1, 2), y = c(1, 10))
    ) +
    annotate(
        "textsegment",
        x = 1, xend = 2, y = 1, yend = 10,
        label = "10x increase", arrow = arrow()
    )

The output:

image

sessionInfo():

R version 4.1.2 (2021-11-01)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 18363)

Matrix products: default

locale:
[1] LC_COLLATE=Dutch_Netherlands.1252  LC_CTYPE=Dutch_Netherlands.1252    LC_MONETARY=Dutch_Netherlands.1252 LC_NUMERIC=C                      
[5] LC_TIME=Dutch_Netherlands.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] geomtextpath_0.1.0 ggplot2_3.3.5     

loaded via a namespace (and not attached):
 [1] magrittr_2.0.1    tidyselect_1.1.1  munsell_0.5.0     colorspace_2.0-2  R6_2.5.1          rlang_0.4.12      fansi_0.5.0       dplyr_1.0.7      
 [9] tools_4.1.2       grid_4.1.2        gtable_0.3.0      utf8_1.2.2        DBI_1.1.2         withr_2.4.3       systemfonts_1.0.3 ellipsis_0.3.2   
[17] digest_0.6.29     assertthat_0.2.1  tibble_3.1.6      lifecycle_1.0.1   crayon_1.4.2      textshaping_0.3.6 farver_2.1.0      purrr_0.3.4      
[25] vctrs_0.3.8       glue_1.6.0        labeling_0.4.2    compiler_4.1.2    pillar_1.6.4      generics_0.1.1    scales_1.1.1      pkgconfig_2.0.3  

This happens regardless if I use geom_textsegment as an annotation.

@teunbrand
Copy link
Collaborator

Hi there, thanks for letting us know!

I can reproduce this on the default windows device, but not using the {ragg} graphics device. Reprex with default windows device:

library(geomtextpath)
#> Warning: package 'geomtextpath' was built under R version 4.1.2
#> Loading required package: ggplot2

ggplot(mapping = aes(x, y)) +
  geom_col(
    data = data.frame(x = c(1, 2), y = c(1, 10))
  ) +
  annotate(
    "textsegment",
    x = 1, xend = 2, y = 1, yend = 10,
    label = "10x increase", arrow = arrow()
  )

The graphical object should consist of 4 points, two of which for the path before the text and another two points for after the text. This seems to be correct as far is I can tell.

g <- layer_grob(last_plot(), 2)[[1]]
g <- grid::makeContent(g)$children[[1]]

g$x
#> [1] 1.82535885167464inches 3.19303238122172inches 3.80683014391654inches
#> [4] 5.17464114832536inches
g$y
#> [1] 0.681818181818182inches 2.35233370719354inches  3.10204383162793inches 
#> [4] 4.77272727272727inches

Created on 2022-02-04 by the reprex package (v2.0.1)

Whereas with ragg everything goes fine:
image

@erikvona
Copy link
Author

erikvona commented Feb 4, 2022

Thanks for the swift reply! While it would be nice to get this fixed for others (regardless of whether it's a bug in this package or in the Windows default graphics device), now I can make the plot I wanted using ragg.

@AllanCameron
Copy link
Owner

AllanCameron commented Feb 4, 2022

Although this is a quirk in the Windows device, we can track it down specifically to how it handles multiple arrow specifications for a polylinegrob. In particular, it seems to be thrown by having an NA passed as one of the angle arguments.

If I start by recreating the plot:

library(geomtextpath)
#> Loading required package: ggplot2
library(grid)

ggplot(mapping = aes(x, y)) +
  geom_col(
    data = data.frame(x = c(1, 2), y = c(1, 10))
  ) +
  annotate(
    "textsegment",
    x = 1, xend = 2, y = 1, yend = 10,
    label = "10x increase", arrow = arrow()
  )

Now we'll isolate the textpath and get it to generate grobs through makeContent

g <- layer_grob(last_plot(), 2)[[1]]
g <- grid::makeContent(g)

grid.newpage()
grid.draw(g$children)

Where we can see the problem persists.

Now if we look at the arrow argument

g$children[[1]]$arrow
#> $angle
#> [1] NA 30
#> 
#> $length
#> [1] 0.25inches 0.25inches
#> 
#> $ends
#> [1] 2 2
#> 
#> $type
#> [1] 1 1
#> 
#> attr(,"class")
#> [1] "arrow"

We will see that the first arrow isn't drawn because its angle is NA.

I'm not sure whether handling multiple arrow arguments, one of which is NA, is a defined behaviour in a polyline grob. Therefore, we could fix this problem by changing the angle = NA method of switching off the arrow to giving it a length value of 0:

g$children[[1]]$arrow$angle <- c(30, 30)
g$children[[1]]$arrow$length <- unit(c(0, 0.25), "in")

grid.newpage()
grid.draw(g$children)

There is no guarantee that this case would be handled well by other / future graphics devices, so I would be inclined to consider this a fixable bug in our code.

Created on 2022-02-04 by the reprex package (v2.0.1)

@teunbrand
Copy link
Collaborator

Nice sleuthing Alan! I'll PR in a fix

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 a pull request may close this issue.

3 participants