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_text_repel with hjust and vjust #188

Open
glorious1 opened this issue Mar 15, 2021 · 6 comments
Open

geom_text_repel with hjust and vjust #188

glorious1 opened this issue Mar 15, 2021 · 6 comments

Comments

@glorious1
Copy link

Summary

This is just a question. I'm labeling points plotted on a map. To optimize position and avoid features in other layers of the map, the data has hJust and vJust columns with values customized for each point. All I want to do is put the labels in those positions, but moved away from the point so the point and text don't overlap. There is no problem with overlap between labels or edge of the map.

When I use the hjust and vjust aesthetics with geom_text_repel, all sorts of weird things happen. Is there any way to respect that, but just push them off the point? Of course the direction they need to move depends on the justification.

Minimal code example

Here is the minimum amount of code needed to demonstrate the issue:

ggplot(...) + geom_text_repel(...)

Here is an image of the output produced by the code:

IMAGE

Suggestions

This is my proposal for how to solve the issue.

Version information

Here is the output from sessionInfo() in my R session:

Paste output here
@slowkow
Copy link
Owner

slowkow commented Mar 15, 2021

@glorious1 Sorry, but I don't understand your question. You might consider sharing code or an image.

@glorious1
Copy link
Author

Thanks very much for the response. I'm making maps that are pretty busy. For labeling cities, I want to control the direction that the label is from the point, both to avoid obscuring other things, and to enhance the legibility of the text.

I started out with geom_text. I can easily control the direction from the point with hjust and vjust aesthetics, but the text sits on the point.

geom_text( data=CITIES.c, 
                 aes( label=City, geometry=geometry, 
                      hjust=hJust, vjust=vJust ),
                 stat = "sf_coordinates",
                 size=2.1 

image

Then I used geom_text repel. That got it nicely spaced from the point, but I couldn't control the direction. In fact, if I run the exact some code twice it can change direction. Look how I was lucky with Crestone one time, and the other time it landed in the mountains. I wish I could control that!

geom_text_repel( data=CITIES.c, 
                 aes( label=City, geometry=geometry ),
                 stat = "sf_coordinates",
                 point.padding=0.05, size=2.1 )

ggrepel_no_just_lucky
ggrepel_no_just_unlucky

Then I tried geom_text_repel again, adding hjust and vjust to aes. I didn't expect that to work based on the docs. It caused unpredictable havoc.

geom_text_repel( data=CITIES.c, 
                 aes( label=City, geometry=geometry, 
                      hjust=hJust, vjust=vJust ),
                 stat = "sf_coordinates",
                 point.padding=0.05, size=2.1 )

ggrepel_hvjust
Am I missing something easy? If not, I could imagine maybe writing a function that could calculate the amount and direction of nudging in geom_text, based on the values of the hJust and vJust fields. I'm not sure how that would work.

@slowkow
Copy link
Owner

slowkow commented Mar 15, 2021

if I run the exact some code twice it can change direction

set.seed() is the tool you're looking for when you want to get the same random result over multiple runs. This applies to any random function (e.g. runif(), rnorm(), etc.).

For example, if you run this code on your machine, you should (hopefully) get exactly the same layout that I got in this post. Since the size of the figure and font size also affects the layout, your plot might look a bit different.

library(ggrepel)
#> Loading required package: ggplot2
set.seed(1)
d <- data.frame(
  x = runif(10),
  y = runif(10),
  label = letters[1:10]
)
ggplot(d) +
  aes(x, y, label = label) +
  geom_point() +
  geom_text_repel()

Created on 2021-03-15 by the reprex package (v0.3.0)

@slowkow
Copy link
Owner

slowkow commented Mar 15, 2021

Luckily, I left a useful comment in the docs that might answer your question about text justification:

#' @section Alignment with \code{hjust} or \code{vjust}:
#' The arguments \code{hjust} and \code{vjust} are supported, but they only
#' control the initial positioning, so repulsive forces may disrupt alignment.
#' Alignment with \code{hjust} will be preserved if labels only move up and down
#' by using \code{direction="y"}. For \code{vjust}, use \code{direction="x"}.

In other words, we can't have our cake and eat it, too. Either the labels are going to move or not.

Suppose we restrict movement with geom_text_repel(direction = "y"), so that labels can move up and down but not left or right. In this case, it is sensible to allow horizontal justification with hjust. But vjust doesn't make sense anymore because ggrepel is pushing labels up and down.

I hope that gives you some clarity!

@slowkow
Copy link
Owner

slowkow commented Mar 15, 2021

I think you might want to try nudge_x and nudge_y instead of hjust and vjust.

The nudging parameters give you some control to change the initial starting position of each text label before the physical repulsion simulation runs.

@aphalo
Copy link
Contributor

aphalo commented Apr 24, 2021

@glorious1 Using values outside the range 0..1 for justification is problematic. You may want to use nudging and justification together. You could disable repulsion if you have manually set the location of the text.

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

No branches or pull requests

3 participants