Mike
Mike

Reputation: 1141

How to add a geom_text label containing data in the top right of a ggplot

I've got a grouped plot in which I've already labelled the peak with it's x-axis value. However, I'd like another label in the top right of the plot with another measure, but I can't get it to work. Here's an example.

d <- data.frame(USArrests)
nrow(d)
d$predictor <- factor(c(rep(c(1, 2), times = 25)))

label <- d %>% 
  group_by(predictor) %>%
  filter(Assault == max(Assault))
label$measure1 <- c(1.45, 5.67)
label$measure2 <- c(4.55, 6.11)

library(ggplot2)
ggplot(d, aes(x=UrbanPop, y=Assault, fill=predictor)) +
  geom_col(position=position_dodge(width = 0, preserve = "single"), width = 5) +
  geom_text(data = label, aes(label = UrbanPop)) +
  geom_text(data = label, aes(label = measure), hjust="right", vjust="top")

I want the second label in the top right to say in red "measure1 = 1.45" then on a new line "measure2 = 4.55", then below it in green "measure1 = 5.67" and on a new line "measure2=6.11". Obviously "measures" are dynamic objects, so I don't just want to insert a static caption. Any help much appreciated!

Upvotes: 1

Views: 1879

Answers (2)

nniloc
nniloc

Reputation: 4243

It's a bit clunky, but you could create the full labels in a data.frame and force them to be on different lines with \n.

d <- data.frame(USArrests)
d$predictor <- factor(c(rep(c(1, 2), times = 25)))

label <- d %>% 
  group_by(predictor) %>%
  filter(Assault == max(Assault))
label$measure1 <- c(1.45, 5.67)
label$measure2 <- c(4.55, 6.11)

label2 <- label %>%
  pivot_longer(measure1:measure2, 'measure', 'value') %>%
  mutate(label = case_when(
    predictor == 1 & measure == 'measure1' ~ paste0(measure, ' = ', value),
    predictor == 1 & measure == 'measure2' ~ paste0('\n', measure, ' = ', value),
    predictor == 2 & measure == 'measure1' ~ paste0('\n\n', measure, ' = ', value),
    predictor == 2 & measure == 'measure2' ~ paste0('\n\n\n', measure, ' = ', value)
  ))

ggplot(d, aes(x=UrbanPop, y=Assault, fill=predictor)) +
  geom_col(position=position_dodge(width = 0, preserve = "single"), width = 5) +
  geom_text(data = label, aes(label = UrbanPop)) +
  geom_text(data = label2, 
            aes(x = Inf, y = Inf, label = label, color = predictor), 
            hjust="right", vjust="top")

enter image description here

Upvotes: 1

tjebo
tjebo

Reputation: 23737

E.g., use x and y = Inf. In your example, faceting makes sense, because you pass the label to different data-sets.

library(tidyverse)
d <- data.frame(USArrests)

d$predictor <- factor(c(rep(c(1, 2), times = 25)))

label <- d %>% 
  group_by(predictor) %>%
  filter(Assault == max(Assault))
label$measure1 <- c(1.45, 5.67)
label$measure2 <- c(4.55, 6.11)

ggplot(d, aes(x=UrbanPop, y=Assault, fill=predictor)) +
  geom_col(position=position_dodge(width = 0, preserve = "single"), width = 5) +
  geom_text(data = label, aes(label = UrbanPop)) +
  geom_text(data = label, aes(x = Inf, y = Inf, label = measure2), hjust="right", vjust="top")+
  facet_grid(~predictor)
#> Warning: position_dodge requires non-overlapping x intervals

#> Warning: position_dodge requires non-overlapping x intervals

Created on 2020-04-17 by the reprex package (v0.3.0)

Upvotes: 0

Related Questions