Search code examples
rggplot2positiongeom-bargeom-text

The geom_text label does not want to dodge on my bar chart


I have an issue with the labels on my bar plot. I have tried different solutions from this website but nothing changes.

Here is a sample of my data:

   <date>     <chr>                     <int>
 1 2019-03-01 Membershiptype1               2
 2 2019-04-01 Membershiptype1               1
 3 2019-07-01 Membershiptype1               1
 4 2019-08-01 Membershiptype1               1
 5 2019-09-01 Membershiptype1               2
 6 2019-10-01 Membershiptype1               1
 7 2019-11-01 Membershiptype1               1
 8 2020-01-01 Membershiptype1               2
 9 2020-01-01 Membershiptype2               2
10 2020-02-01 Membershiptype1               4

I used these packages: library(dbplot) library(modeldb) library(tidypredict) library(tidyverse) library(lubridate)

This is the the code that I used to make the bar plot:

signupMT <- ggplot(SignupPM, aes(fill=`Membership type`,  y=count_by_Name, x=month)) + 
  geom_bar(position=position_dodge(preserve = 'single'), stat="identity") +
  scale_fill_manual(values=c("#2381EB", "#8442D1", "#CF07BA"), name = NULL, labels = c("Student/Unemployed", "Full member", "Online member")) +
  theme_classic() +
  labs( x= NULL, y= "Number of sign-ups", title = "Sing-ups per month by membership type")+
  theme(legend.position="bottom", 
        axis.text.x = element_text(angle = 45, hjust = 0.1, vjust = 0))+
  scale_x_date(breaks= "month",date_labels = "%b %Y") +
  geom_text(aes(label= count_by_Name, group = month), position=position_dodge(width = 1), vjust=-0.5)

I also tried group = 'membership type' or playing with the width value but nothing changes.

I also tried this suggestion but then I get the error message: stat_count() can only have an x or y aesthetic.

geom_text(aes(y=count_by_Name, label = stat(count)), stat = 'count', position=position_dodge(2), vjust=-0.5, size = 3)

This is the bar plot I get:

Bar plot

What am I missing here?


Solution

  • As far as the grid graphics system (on which ggplot2 is based) is concerned, text elements have zero width, and therefore cannot be dodged the way that plot columns can. Once solution to this is to use hjust as an aesthetic mapping:

    ggplot(SignupPM, aes(y = count_by_Name, x = month)) + 
      geom_col(aes(fill = `Membership type`),
                position = position_dodge(preserve = 'single')) +
      geom_text(aes(label= count_by_Name, 
                    hjust = - 2 * as.numeric(`Membership type`) + 4.3),
                vjust = -0.5) +
      scale_x_date(breaks = "month", date_labels = "%b %Y") +
      scale_fill_manual(values = c("#2381EB", "#8442D1", "#CF07BA"), 
                        name = NULL, 
                        labels = c("Student/Unemployed", 
                                   "Full member", "Online member")) +
      labs( x = NULL, y = "Number of sign-ups", 
            title = "Sign-ups per month by membership type") +
      theme_classic() +
      theme(legend.position = "bottom", 
            axis.text.x     = element_text(angle = 45, hjust = 0.1, vjust = 0))
    

    enter image description here

    Data (as inferred from plot in question)

    SignupPM <- structure(list(count_by_Name = c(2L, 1L, 1L, 1L, 2L, 1L, 1L, 
      2L, 2L, 4L, 2L, 4L, 1L, 4L, 2L, 5L, 5L, 5L, 4L, 1L, 3L, 2L, 8L
      ), month = structure(c(17928, 17956, 18048, 18078, 18109, 18140, 
      18170, 18231, 18231, 18262, 18262, 18293, 18293, 18322, 18322, 
      18353, 18353, 18383, 18383, 18383, 18414, 18414, 18414), class = "Date"), 
          `Membership type` = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 
          1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 3L, 1L, 2L, 
          3L), .Label = c("Membershiptype1", "Membershiptype2", "Membershiptype3"
          ), class = "factor")), row.names = c(NA, -23L), class = "data.frame")