Search code examples
rggplot2geom-text

Move the position of the text describing the y-axis of a given point in geom_text with R


I want to move the position of the text describing the y-axis of a particular point in geom_text with R, so that the percentages are not mixed up and the graph is more readable. I only want to change the position of the text for the second point on the graph, and vjust changes the position of all the ordinates on the curve. I know my x-axis is not good but this is not my point here.

Here is my code:

library(tidyverse)
library(scales)
library(ggplot2)

ageC <- c("18-34","35", "35", "35","35","18-34","18-34","35","18-34","35")
sexe <- c("w","m", "m", "w", "w", "w", "m", "m", "m", "w")
sexuality <- c("no","yes", "no", "yes", "no", "no", "yes", "yes", "no", "yes")

df <- data.frame(ageC,sexe,sexuality)

# base with women
b_w <-
  df %>%
  select(ageC,sexe,sexuality) %>%
  filter(sexe != "m") %>%
  mutate(sexuality = factor(sexuality))

bb_w <-
  b_w  %>%
  mutate(age_c = factor(ageC, labels = c("26", "35")) %>% as.character %>%  as.numeric,
         sexuality_c = as.numeric(sexuality=="yes")) %>%
  group_by(age_c) %>%
  summarise(sexuality_pct = mean(sexuality_c))

# base with men

b_m <-
  df %>%
  select(ageC,sexe,sexuality) %>%
  filter(sexe != "w") %>%
  mutate(sexuality = factor(sexuality))

bb_m <-
  b_m  %>%
  mutate(age_c = factor(ageC, labels = c("26", "35")) %>% as.character %>%  as.numeric,
         sexuality_c = as.numeric(sexuality=="yes")) %>%
  group_by(age_c) %>%
  summarise(sexuality_pct = mean(sexuality_c))


ggplot() +
  geom_point(data = bb_w, aes(x = age_c, y = sexuality_pct, fill = "w"), 
             color = "#6a51a3", size = 1.5) + 
  geom_text(data = bb_w, aes(x = age_c, y = sexuality_pct,  label=percent(sexuality_pct, accuracy = .1)),  
            family = "Times New Roman",vjust = -0.4, size = 3.5) + 
  geom_point(data = bb_m, aes(x = age_c, y = sexuality_pct, fill = "m"), 
             color = "#41ae76", size = 1.5) + 
  geom_text(data = bb_m, aes(x = age_c, y = sexuality_pct,  label=percent(sexuality_pct, accuracy = .1)),  
            family = "Times New Roman",vjust = +0.2, size = 3.5) + 
  geom_line(data = bb_w, aes(x = age_c, y = sexuality_pct), color = "#6a51a3", lwd = 1, alpha= 0.5) +
  geom_line(data = bb_m, aes(x = age_c, y = sexuality_pct), color = "#41ae76", lwd = 1, alpha= 0.5 ) +
  labs(x = "Age class", y = "Percentage") +
  scale_y_continuous(labels = scales::percent) +
  expand_limits(x = 15, y = 0) + 
  scale_x_continuous(limits = c(26,50), breaks = bb_w$age_c, labels = levels(b_w$age10)) + 
  theme(plot.title = element_text(hjust = 0.5), plot.subtitle = element_text(hjust = 0.5)) +
  scale_fill_manual(name = NULL, values=c("w"="#6a51a3", 
                                          "m"="#41ae76"  )) +
  guides(fill = guide_legend(override.aes = list(shape=21, size = 5))) +
  theme(text = element_text(family = "Times New Roman", size = 18))

Here is the result of the plot


Solution

  • You can streamline your prep and put vjust into the aes() for the geom_text layer. (I presume you put the two categories into different tables so you could use separate layers with their own colors -- this can be done more concisely in most cases using an approach like scale_color_manual below.) In this case I specify that the 2nd "w" point should be labelled underneath, while the other labels should be on top of their point.

    df %>%
      group_by(sexe, ageC) %>%
      summarize(sexuality_pct = mean(sexuality == "yes"), .groups = "drop") %>%
      ggplot(aes(ageC, sexuality_pct, color = sexe, group = sexe)) +
      geom_point(size = 1.5) +
      geom_line(show.legend = FALSE) +
      geom_text(aes(label = percent(sexuality_pct, accuracy = .1),
                    vjust = ifelse(sexe == "w" & ageC == "35", 2, -1)), show.legend = FALSE) +
      scale_color_manual(values = c("m" = "#41ae76", "w" = "#6a51a3")) 
    

    enter image description here

    You can also use ggrepel to un-overlap labels for you.

    ... +
    ggrepel::geom_text_repel(aes(label = percent(sexuality_pct, accuracy = .1)), 
                             show.legend = FALSE) +
    

    enter image description here