ggrepel
ggrepel copied to clipboard
inwards/outwards output exchanged in network plot
Summary
inwards produces outwards look and viceversa
Minimal code example
Here is the minimum amount of code needed to demonstrate the issue:
library(ggplot2)
library(ggnetwork)
library(ggrepel)
finalxy2 <- structure(list(
xpos = c(-2, 0, 0, 6, 2, 6, 4, 6, 2, -6, -4, 0,
4, 0, 8, 8, -4, -2, -2, 8, 10, 2, 0, -4, -2, 4)
, ypos = c(4, 2, 4, 4, 0, 2, -2, -2, 2, -2, -2, 0, -4, -2, -4, -2, 0, 0, -2,
0, 0, -2, -4, -4, -4, 4)
, vertex.names = paste("name",1:26) )
, row.names = c(NA, -26L)
, class = "data.frame")
posData1<-structure(list(xorig = c(0, 0, 2, 0, 0, 4, 2, 6, 6, 6, 2, 6,
0, 6, -4, 0, -2, 0, 8, 0, -2, 6, 10, 2, 8, -2, -2, 6, 0, -2,
2, 10, 6, 6, 0, -2, -2, 2, 6), yorig = c(2, 4, 0, 0, 2, 4, 0,
2, 2, -2, 0, 2, 2, 2, -2, 0, -4, -2, -4, 0, -4, -2, 0, 0, -4,
0, -2, 2, 0, -4, 0, 0, 2, 2, -4, -4, -4, 0, 2), xtarg = c(-1.8,
-1.8, 0.2, 0, 0, 0.2, 5.8, 6, 4.2, 4.2, 5.8, 6, 1.8, 2.2, -5.8,
-5.8, -3.8, 3.8, 4.2, 0, -0.2, 7.8, 8.2, 7.8, 8, -3.8, -3.8,
-1.8, -1.8, -2, 7.8, 8.2, 9.8, 2.2, 1.8, -0.2, -3.8, 3.8, 4.2
), ytarg = c(3.8, 4, 1.8, 1.8, 3.8, 4, 3.8, 3.8, -1.8, -2, -1.8,
-1.8, 2, 2, -2, -1.8, -2.2, -3.8, -4, -1.8, -2.2, -3.8, -3.8,
-1.8, -2.2, 0, -0.2, 0.2, -1.8, -2.2, 0, 0, 0.2, -1.8, -2.2,
-4, -4, 3.8, 3.8)), row.names = c(NA, -39L), class = "data.frame"
)
ggplot(finalxy2) +
geom_edges(data=posData1, aes(x = xorig, y = yorig, xend = xtarg, yend = ytarg),
arrow = arrow(length = unit(10, "pt"), type = "closed")
) +
geom_nodes(aes(x=xpos, y=ypos ), size = 4) +
geom_label_repel(aes(x=xpos, y=ypos, label = vertex.names ),
hjust="inward", # results in outwards look
vjust="inward" # results in outwards look
,fontface = "italic", size=3
) + theme_blank()
Here is an image of the output produced by the code:
Version information
Here is the output from sessionInfo()
in my R session:
R version 4.0.5 (2021-03-31)
Platform: i386-w64-mingw32/i386 (32-bit)
Running under: Windows 10 x64 (build 19042)
Matrix products: default
locale:
[1] LC_COLLATE=English_United Kingdom.1252 LC_CTYPE=English_United Kingdom.1252
[3] LC_MONETARY=English_United Kingdom.1252 LC_NUMERIC=C
[5] LC_TIME=English_United Kingdom.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] ggrepel_0.9.1 ggnetwork_0.5.8 ggplot2_3.3.3
loaded via a namespace (and not attached):
[1] Rcpp_1.0.6 magrittr_2.0.1 tidyselect_1.1.0 munsell_0.5.0 colorspace_2.0-0 R6_2.5.0
[7] rlang_0.4.10 fansi_0.4.2 dplyr_1.0.5 tools_4.0.5 grid_4.0.5 gtable_0.3.0
[13] utf8_1.2.1 withr_2.4.1 ellipsis_0.3.1 digest_0.6.27 tibble_3.1.0 lifecycle_1.0.0
[19] crayon_1.4.1 farver_2.1.0 purrr_0.3.4 vctrs_0.3.7 glue_1.4.2 labeling_0.4.2
[25] compiler_4.0.5 pillar_1.6.0 generics_0.1.0 scales_1.1.1 pkgconfig_2.0.3
@slowkow This new reprex makes it clear why the labels end on the wrong side not only in the network plot, but also in other plots. So, it is not that justification starts wrong but that the repulsion moves the labels in the wrong direction. It seems then that the long standing issue that inward and outward justification had the opposite effect than in ggplot2 is not related to the handling of justification itself. (I think this also explains why adding nudging seems to help...) In the reprex below I used only 0 and 1000 for max.iter
, but using values like 10, 50, etc. shows how they slowly migrate to the "wrong side" of the point.
library(ggplot2)
#library(ggnetwork)
library(ggrepel)
finalxy2 <- structure(list(
xpos = c(-2, 0, 0, 6, 2, 6, 4, 6, 2, -6, -4, 0,
4, 0, 8, 8, -4, -2, -2, 8, 10, 2, 0, -4, -2, 4)
, ypos = c(4, 2, 4, 4, 0, 2, -2, -2, 2, -2, -2, 0, -4, -2, -4, -2, 0, 0, -2,
0, 0, -2, -4, -4, -4, 4)
, vertex.names = paste("name",1:26) )
, row.names = c(NA, -26L)
, class = "data.frame")
# output is correct
ggplot(finalxy2) +
geom_point(aes(x=xpos, y=ypos ), size = 2) +
geom_label_repel(aes(x=xpos, y=ypos, label = vertex.names),
vjust = 0.5,
hjust = "outward",
fontface = "italic", size=2, fill = NA, max.iter = 0
) + expand_limits(y = c(-5, 5), x = c(-7, 12))
# output is correct
ggplot(finalxy2) +
geom_point(aes(x=xpos, y=ypos ), size = 2) +
geom_label_repel(aes(x=xpos, y=ypos, label = vertex.names),
vjust = 0.5,
hjust = "inward",
fontface = "italic", size=2, fill = NA, max.iter = 0
) + expand_limits(y = c(-5, 5), x = c(-7, 12))
# justification is wrong (as vjust = 0 in geom_label() ), and repulsion moves labels upwards which is good for vjust = 0
ggplot(finalxy2) +
geom_point(aes(x=xpos, y=ypos ), size = 2) +
geom_label_repel(aes(x=xpos, y=ypos, label = vertex.names),
vjust = 1,
hjust = 0.5,
fontface = "italic", size=2, fill = NA, max.iter = 1000
) + expand_limits(y = c(-5, 5), x = c(-7, 12))
# justification is correct, but repulsion moves labels to the left which is wrong for hjust = 1
ggplot(finalxy2) +
geom_point(aes(x=xpos, y=ypos ), size = 2) +
geom_label_repel(aes(x=xpos, y=ypos, label = vertex.names),
vjust = 0.5,
hjust = 1,
fontface = "italic", size=2, fill = NA, max.iter = 0
) + expand_limits(y = c(-5, 5), x = c(-7, 12))
# justification is correct, but repulsion moves all labels inwards
# which which is not good for hjust = "outward"
ggplot(finalxy2) +
geom_point(aes(x=xpos, y=ypos ), size = 2) +
geom_label_repel(aes(x=xpos, y=ypos, label = vertex.names),
vjust = "outward",
hjust = 0.5,
fontface = "italic", size=2, fill = NA, max.iter = 1000
) + expand_limits(y = c(-5, 5), x = c(-7, 12))
# justification is correct, but repulsion moves all labels outwards
# which which is not good for vjust = "inward"
ggplot(finalxy2) +
geom_point(aes(x=xpos, y=ypos ), size = 2) +
geom_label_repel(aes(x=xpos, y=ypos, label = vertex.names),
vjust = "inward",
hjust = 0.5,
fontface = "italic", size=2, fill = NA, max.iter = 1000
) + expand_limits(y = c(-5, 5), x = c(-7, 12))
# justification is correct, but repulsion moves labels inwards which is not
# good with hjust = "outward"
ggplot(finalxy2) +
geom_point(aes(x=xpos, y=ypos ), size = 2) +
geom_label_repel(aes(x=xpos, y=ypos, label = vertex.names),
vjust = 0.5,
hjust = "outward",
fontface = "italic", size=2, fill = NA, max.iter = 1000
) + expand_limits(y = c(-5, 5), x = c(-7, 12))
# justification is correct, but repulsion moves labels outwards which is not
# good with hjust = "inward"
ggplot(finalxy2) +
geom_point(aes(x=xpos, y=ypos ), size = 2) +
geom_label_repel(aes(x=xpos, y=ypos, label = vertex.names),
vjust = 0.5,
hjust = "inward",
fontface = "italic", size=2, fill = NA, max.iter = 1000
) + expand_limits(y = c(-5, 5), x = c(-7, 12))
Created on 2021-11-05 by the reprex package (v2.0.1)
Session info
sessioninfo::session_info()
#> - Session info ---------------------------------------------------------------
#> setting value
#> version R version 4.1.1 (2021-08-10)
#> 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-11-05
#>
#> - Packages -------------------------------------------------------------------
#> package * version date lib source
#> assertthat 0.2.1 2019-03-21 [1] CRAN (R 4.1.0)
#> backports 1.3.0 2021-10-27 [1] CRAN (R 4.1.1)
#> cli 3.1.0 2021-10-27 [1] CRAN (R 4.1.1)
#> colorspace 2.0-2 2021-06-24 [1] CRAN (R 4.1.0)
#> crayon 1.4.2 2021-10-29 [1] CRAN (R 4.1.1)
#> curl 4.3.2 2021-06-23 [1] CRAN (R 4.1.0)
#> DBI 1.1.1 2021-01-15 [1] CRAN (R 4.1.0)
#> digest 0.6.28 2021-09-23 [1] CRAN (R 4.1.1)
#> dplyr 1.0.7 2021-06-18 [1] CRAN (R 4.1.0)
#> ellipsis 0.3.2 2021-04-29 [1] CRAN (R 4.1.0)
#> evaluate 0.14 2019-05-28 [1] CRAN (R 4.1.0)
#> fansi 0.5.0 2021-05-25 [1] CRAN (R 4.1.0)
#> farver 2.1.0 2021-02-28 [1] CRAN (R 4.1.0)
#> fastmap 1.1.0 2021-01-25 [1] CRAN (R 4.1.0)
#> fs 1.5.0 2020-07-31 [1] CRAN (R 4.1.0)
#> generics 0.1.1 2021-10-25 [1] CRAN (R 4.1.1)
#> ggplot2 * 3.3.5 2021-06-25 [1] CRAN (R 4.1.0)
#> ggrepel * 0.9.1 2021-11-05 [1] local
#> glue 1.4.2 2020-08-27 [1] CRAN (R 4.1.0)
#> gtable 0.3.0 2019-03-25 [1] CRAN (R 4.1.0)
#> highr 0.9 2021-04-16 [1] CRAN (R 4.1.0)
#> htmltools 0.5.2 2021-08-25 [1] CRAN (R 4.1.1)
#> httr 1.4.2 2020-07-20 [1] CRAN (R 4.1.0)
#> knitr 1.36 2021-09-29 [1] CRAN (R 4.1.1)
#> labeling 0.4.2 2020-10-20 [1] CRAN (R 4.1.0)
#> lifecycle 1.0.1 2021-09-24 [1] CRAN (R 4.1.1)
#> magrittr 2.0.1 2020-11-17 [1] CRAN (R 4.1.0)
#> mime 0.12 2021-09-28 [1] CRAN (R 4.1.1)
#> munsell 0.5.0 2018-06-12 [1] CRAN (R 4.1.0)
#> pillar 1.6.4 2021-10-18 [1] CRAN (R 4.1.1)
#> pkgconfig 2.0.3 2019-09-22 [1] CRAN (R 4.1.0)
#> purrr 0.3.4 2020-04-17 [1] CRAN (R 4.1.0)
#> R.cache 0.15.0 2021-04-30 [1] CRAN (R 4.1.0)
#> R.methodsS3 1.8.1 2020-08-26 [1] CRAN (R 4.1.0)
#> R.oo 1.24.0 2020-08-26 [1] CRAN (R 4.1.0)
#> R.utils 2.11.0 2021-09-26 [1] CRAN (R 4.1.1)
#> R6 2.5.1 2021-08-19 [1] CRAN (R 4.1.0)
#> Rcpp 1.0.7 2021-07-07 [1] CRAN (R 4.1.0)
#> reprex 2.0.1 2021-08-05 [1] CRAN (R 4.1.0)
#> rlang 0.4.12 2021-10-18 [1] CRAN (R 4.1.1)
#> rmarkdown 2.11 2021-09-14 [1] CRAN (R 4.1.1)
#> rstudioapi 0.13 2020-11-12 [1] CRAN (R 4.1.0)
#> scales 1.1.1 2020-05-11 [1] CRAN (R 4.1.0)
#> sessioninfo 1.1.1 2018-11-05 [1] CRAN (R 4.1.0)
#> stringi 1.7.5 2021-10-04 [1] CRAN (R 4.1.1)
#> stringr 1.4.0 2019-02-10 [1] CRAN (R 4.1.0)
#> styler 1.6.2 2021-09-23 [1] CRAN (R 4.1.1)
#> tibble 3.1.5 2021-09-30 [1] CRAN (R 4.1.1)
#> tidyselect 1.1.1 2021-04-30 [1] CRAN (R 4.1.0)
#> utf8 1.2.2 2021-07-24 [1] CRAN (R 4.1.0)
#> vctrs 0.3.8 2021-04-29 [1] CRAN (R 4.1.0)
#> withr 2.4.2 2021-04-18 [1] CRAN (R 4.1.0)
#> xfun 0.27 2021-10-18 [1] CRAN (R 4.1.1)
#> xml2 1.3.2 2020-04-23 [1] CRAN (R 4.1.0)
#> yaml 2.2.1 2020-02-01 [1] CRAN (R 4.1.0)
#>
#> [1] C:/Users/Aphalo/Documents/R/win-library/4.1
#> [2] C:/Program Files/R/R-4.1.1/library
I think that the problem is caused in part by the balance between pull and push forces, but playing with the multipliers shows that the current values are needed to avoid labels moving too far away from the points. If my idea of what is going on is correct, the amount and direction of nudging will need to depend on the values of hjust
and vjust
and on the length of the character string mapped to label
which is tricky to implement. @slowkow Maybe something could be tweaked in the repulsion code to get the labels moving in the "most natural" way for the current justification. Here is an example with nudging after manually guessing a suitable value for x
nudge.
library(ggplot2)
#library(ggnetwork)
library(ggrepel)
finalxy2 <- structure(list(
xpos = c(-2, 0, 0, 6, 2, 6, 4, 6, 2, -6, -4, 0,
4, 0, 8, 8, -4, -2, -2, 8, 10, 2, 0, -4, -2, 4)
, ypos = c(4, 2, 4, 4, 0, 2, -2, -2, 2, -2, -2, 0, -4, -2, -4, -2, 0, 0, -2,
0, 0, -2, -4, -4, -4, 4)
, vertex.names = paste("name",1:26) )
, row.names = c(NA, -26L)
, class = "data.frame")
### playing with nudging
# justification and repulsion are correct if we add nudging
ggplot(finalxy2) +
geom_point(aes(x=xpos, y=ypos ), size = 2) +
geom_label_repel(aes(x=xpos, y=ypos, label = vertex.names),
position = ggpp::position_nudge_center(x = 0.3, center_x = 2.5),
point.padding = 5,
vjust = 0.5,
hjust = "outward",
fontface = "italic", size=2, fill = NA, max.iter = 10000, direction = "x",
) + expand_limits(y = c(-5, 5), x = c(-7, 12))
Created on 2021-11-07 by the reprex package (v2.0.1)
Here is a simpler/clearer reprex for this problem:
library(ggplot2)
library(ggrepel)
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_repel(hjust = "outward", max.iter = 0)
p + geom_text_repel(hjust = "outward", max.iter = 100)
p + geom_text_repel(hjust = "outward", max.iter = 10000)
Created on 2021-11-09 by the reprex package (v2.0.1)
Session info
sessioninfo::session_info()
#> - Session info --------------------------------------------------------------
#> hash: tiger, puzzle piece, wine glass
#>
#> setting value
#> version R version 4.1.1 (2021-08-10)
#> os Windows 10 x64 (build 19043)
#> system x86_64, mingw32
#> ui RTerm
#> language (EN)
#> collate English_Finland.1252
#> ctype English_Finland.1252
#> tz Europe/Helsinki
#> date 2021-11-09
#> pandoc 2.14.0.3 @ C:/Program Files/RStudio/bin/pandoc/ (via rmarkdown)
#>
#> - Packages -------------------------------------------------------------------
#> package * version date (UTC) lib source
#> assertthat 0.2.1 2019-03-21 [1] CRAN (R 4.1.0)
#> backports 1.3.0 2021-10-27 [1] CRAN (R 4.1.1)
#> cli 3.1.0 2021-10-27 [1] CRAN (R 4.1.1)
#> colorspace 2.0-2 2021-06-24 [1] CRAN (R 4.1.0)
#> crayon 1.4.2 2021-10-29 [1] CRAN (R 4.1.1)
#> curl 4.3.2 2021-06-23 [1] CRAN (R 4.1.0)
#> DBI 1.1.1 2021-01-15 [1] CRAN (R 4.1.0)
#> digest 0.6.28 2021-09-23 [1] CRAN (R 4.1.1)
#> dplyr 1.0.7 2021-06-18 [1] CRAN (R 4.1.0)
#> ellipsis 0.3.2 2021-04-29 [1] CRAN (R 4.1.0)
#> evaluate 0.14 2019-05-28 [1] CRAN (R 4.1.0)
#> fansi 0.5.0 2021-05-25 [1] CRAN (R 4.1.0)
#> farver 2.1.0 2021-02-28 [1] CRAN (R 4.1.0)
#> fastmap 1.1.0 2021-01-25 [1] CRAN (R 4.1.0)
#> fs 1.5.0 2020-07-31 [1] CRAN (R 4.1.0)
#> generics 0.1.1 2021-10-25 [1] CRAN (R 4.1.1)
#> ggplot2 * 3.3.5 2021-06-25 [1] CRAN (R 4.1.0)
#> ggrepel * 0.9.1.9999 2021-11-09 [1] local
#> glue 1.4.2 2020-08-27 [1] CRAN (R 4.1.1)
#> gtable 0.3.0 2019-03-25 [1] CRAN (R 4.1.0)
#> highr 0.9 2021-04-16 [1] CRAN (R 4.1.0)
#> htmltools 0.5.2 2021-08-25 [1] CRAN (R 4.1.1)
#> httr 1.4.2 2020-07-20 [1] CRAN (R 4.1.0)
#> knitr 1.36 2021-09-29 [1] CRAN (R 4.1.1)
#> labeling 0.4.2 2020-10-20 [1] CRAN (R 4.1.0)
#> lifecycle 1.0.1 2021-09-24 [1] CRAN (R 4.1.1)
#> magrittr 2.0.1 2020-11-17 [1] CRAN (R 4.1.0)
#> mime 0.12 2021-09-28 [1] CRAN (R 4.1.1)
#> munsell 0.5.0 2018-06-12 [1] CRAN (R 4.1.0)
#> pillar 1.6.4 2021-10-18 [1] CRAN (R 4.1.1)
#> pkgconfig 2.0.3 2019-09-22 [1] CRAN (R 4.1.0)
#> purrr 0.3.4 2020-04-17 [1] CRAN (R 4.1.0)
#> R.cache 0.15.0 2021-04-30 [1] CRAN (R 4.1.0)
#> R.methodsS3 1.8.1 2020-08-26 [1] CRAN (R 4.1.0)
#> R.oo 1.24.0 2020-08-26 [1] CRAN (R 4.1.0)
#> R.utils 2.11.0 2021-09-26 [1] CRAN (R 4.1.1)
#> R6 2.5.1 2021-08-19 [1] CRAN (R 4.1.0)
#> Rcpp 1.0.7 2021-07-07 [1] CRAN (R 4.1.0)
#> reprex 2.0.1 2021-08-05 [1] CRAN (R 4.1.0)
#> rlang 0.4.12 2021-10-18 [1] CRAN (R 4.1.1)
#> rmarkdown 2.11 2021-09-14 [1] CRAN (R 4.1.1)
#> rstudioapi 0.13 2020-11-12 [1] CRAN (R 4.1.0)
#> scales 1.1.1 2020-05-11 [1] CRAN (R 4.1.0)
#> sessioninfo 1.2.1 2021-11-02 [1] CRAN (R 4.1.1)
#> stringi 1.7.5 2021-10-04 [1] CRAN (R 4.1.1)
#> stringr 1.4.0 2019-02-10 [1] CRAN (R 4.1.0)
#> styler 1.6.2 2021-09-23 [1] CRAN (R 4.1.1)
#> tibble 3.1.5 2021-09-30 [1] CRAN (R 4.1.1)
#> tidyselect 1.1.1 2021-04-30 [1] CRAN (R 4.1.0)
#> utf8 1.2.2 2021-07-24 [1] CRAN (R 4.1.0)
#> vctrs 0.3.8 2021-04-29 [1] CRAN (R 4.1.0)
#> withr 2.4.2 2021-04-18 [1] CRAN (R 4.1.0)
#> xfun 0.27 2021-10-18 [1] CRAN (R 4.1.1)
#> xml2 1.3.2 2020-04-23 [1] CRAN (R 4.1.0)
#> yaml 2.2.1 2020-02-01 [1] CRAN (R 4.1.0)
#>
#> [1] C:/Users/Aphalo/Documents/R/win-library/4.1
#> [2] C:/Program Files/R/R-4.1.1/library
#>
#> ------------------------------------------------------------------------------
OK, I am having trouble following along across different issue pages, so forgive me if I'm missing something. I want to try to summarize what I've learned so far.
It sounds like we have three issues:
-
The initial text placement (
max.iter = 0
) is different inggrepel::geom_text_repel()
versusggplot2::geom_text()
-
The text repulsion for
hjust = "inward"
orhjust = "outward"
is going in the wrong direction. -
Text justification is not working as expected when the angle of the text is not equal to 0, 90, 180, or 270.
Am I missing anything? I think the same lines of code might be related to all three of the issues.
Yes, what started as one problem, seems to have three different components.
-
and 3. Seem to be relevant to
geom_text_repel()
. Further checking using print statements and doing small "exploratory" edits to the code, show thatx.orig
andy.orig
are identical ingeom_text_repel()
to thex
andy
positions ingeom_text()
. i.e., assigningx.orig
tox_adj
andy.orig
toy_adj
instead of using the adjustent based on trigonometry onx
andy
results in identical plots from both geoms. Even withmax.iter = 0
and no nudgingx
is different tox.orig
andy
is different toy.orig
. Considering angles,x.orig
andy.orig
are correct for all the angles I have tried. However, I do see a mix of "native" and "npc" units being used in the original computation ofx_adj
andy_adj
. -
Yes, this seems to be the case. When using "inward" and "outward" after conversion to numeric the
vjust
andhjust
columns contain -1, +1 and possibly 0 depending on the row in data. This could be messing things up. However, I think getting 1 and 3 working is more important and any changes there could be reflected in the repulsion problem (2.).
@slowkow Commit 443105a3e21eb2693c5d6235dca8195f4cf6e71e in #196 fixes 1. and 3. The causes were multiple, I briefly explain the new code in a comment. 2. The problem with repulsion starting towards the point instead of away from it remains to be fixed. "4." For some rotation angles the segment seems to end on the wrong side of the text label.