Search code examples
rggplot2tidyverse

Spaces at start of new lines ggplot label


When I try to add labels to a plot in ggplot, some new lines have an additional space, while others don't. I think it's to do with the paste part of my code, but I cannot figure it out. I'd like my labels to be all aligned on the left so it looks better.

library(tidyverse)
library(metrica)

df = data.frame(x = 1:100 * rnorm(100,50,7),
           y = c(1:100))

label <- df %>%
  summarise(R2 = metrica::R2(obs = y, pred = x)$R2,
            RMSE = metrica::RMSE(obs = y, pred = x)$RMSE,
            rRMSE = metrica::RRMSE(obs = y, pred = x)$RRMSE,
            n = n()) %>%
  mutate(label = paste("R² = ", round(R2, 2), 
                       "\nRMSE = ", round(RMSE, 2), 
                       "\nrRMSE = ", round(rRMSE, 2),
                       '\nn = ',n, sep=''))

plt <- 
  ggplot(df,aes(x=x,y=y)) +
  geom_point() +
  geom_text(data = label, aes(x = -Inf, y = Inf, label = label), hjust = -0.1, vjust = 1.1,size=4); plt

labels with spaces at beginning


Solution

  • This is a prime example why using hjust or vjust to nudge labels or to add some padding should be avoided.

    hjust or vjust are meant to set the justification and as the docs make clear should be

    either a string (“top”, “middle”, “bottom”, “left”, “center”, “right”) or a number between 0 and 1

    and

    you can use numbers outside the range (0, 1), but it’s not recommended.

    The reason is that, while hardly visible in most cases, the amount by which the labels are nudged when you use values outside of the range (0, 1) depends on the value of the x and y positions but also the width or height of the label, i.e. as the length of your labels differ, the labels are nudged or shifted by a different amount which looks like a "space" was added.

    Instead, as already suggested by @Edward in the comments set hjust=0 to align your labels on the left.

    And to add some padding you could set the x position as suggested by @Edward or what would be my preferred approach use geom_label (with fill=NA and label.size=0) which by default adds some padding around the label and which can be set via the label.padding parameter:

    # Seed used to create df
    set.seed(123)
    
    library(ggplot2)
    
    ggplot(df, aes(x = x, y = y)) +
      geom_point() +
      geom_label(
        data = label, aes(x = -Inf, y = Inf, label = label), hjust = 0,
        vjust = 1, size = 4, label.padding = unit(5, "pt"),
        fill = NA, label.size = 0
      )