slowkow / ggrepel

:round_pushpin: Repel overlapping text labels away from each other in your ggplot2 figures.
https://ggrepel.slowkow.com
GNU General Public License v3.0
1.21k stars 95 forks source link

Function to print ggplot2 code for final round of manual adjustment #235

Closed kendonB closed 1 year ago

kendonB commented 1 year ago

Summary

ggrepel seldom gets it right first time. It would be good to be able to have some code to print the ggplot code to copy paste then do some fine adjustment.

image

slowkow commented 1 year ago

Hi Kendon, thanks for the issue.

Honestly, I typically do the last step (moving labels manually, adjusting font sizes, aligning things) in a program like Adobe Illustrator or Affinity Designer. But I hear you: the more we can do in R, the better.

Since 2016, many users have been trying to extract information from ggplot2 objects to get the ggrepel coordinates: https://github.com/slowkow/ggrepel/issues/24

You might find that one of the replies in #24 has a code snippet that is suitable for you.

The underlying issue is this: the data given to ggplot2 is necessary but insufficient for ggrepel to position labels. We need more information: the dimensions of the plotting area, the dimensions of each label, the dimensions of the data points, etc. The relative sizes of these visual elements is undefined up until the moment that R creates a viewport to render the ggplot2 object to a device. After creating a viewport on a visual device (png, pdf, etc.), that's when the ggrepel coordinates become available.

By the way, that's why ggrepel can automatically reposition labels when we resize the plotting area in X11 or RStudio. It is re-running the repel_boxes2() code again each time the plotting area is resized. So the ggrepel coordinates are dependent on the size of the plotting area.

I have had a hard time trying to implement a built-in function in ggrepel that gives users access to the coordinates. It's been difficult for me to figure out how to do it right, considering the dependency on the viewport.

Thankfully, @alexvpickering forked ggrepel and implemented a function that seems like it might do what you want (I have not tested this code): https://github.com/hms-dbmi/repel/blob/master/R/repel_text.R

@kendonB Could I please ask if you would try the repel_text() function by Alex? (It may need some tweaking.) If you find that this function is useful to you, then maybe we can start a PR to get this merged?

We need to:

Pull requests are welcome!

alexvpickering commented 1 year ago

Just a few vague memories from when I worked on the above in case it is helpful:

Happy to experiment a bit if anyone has suggestions on how to improve :)

slowkow commented 1 year ago

Thanks, @alexvpickering for describing your implementation.

To anyone reading this, pull requests are welcome!

Good luck.