ggplot2positiongeom-textlabeling

How do I adjust the position of geom_text over geom_bar columns in ggplot?


I am attempting to make a bar graph in ggplot2 but when I add labels, they cluster over one middle bar rather than sitting on the bar the value itself represents.

The code I am using:

synch<-data.frame(Species = c("AMCO","AMCO","AMCO","GADW","GADW","GADW","AGWT","AGWT","AGWT","RNDU","RNDU","RNDU"),
                  Value=c(93.3,61.1,97.4,0.8,34.9,0.2,0.0,4.0,0.0,0.5,0.0,0.4),
                  SurveyType=c("A","B","C","A","B","C","A","B","C","A","B","C"))
synch
library(dplyr)
library(ggplot2)
synchAMCO = synch %>% filter(Species == "AMCO")
synchGADW = synch %>% filter(Species == "GADW")
synchAGWT = synch %>% filter(Species == "AGWT")
synchRNDU = synch %>% filter(Species == "RNDU")

synchplot.again<- ggplot(data=synch) +
  geom_bar(data = synchAMCO, 
           mapping = aes(x = Species, y = Value, fill = SurveyType), 
           stat='identity', position = position_dodge(width = 0.75), width=0.7) + theme_bw() + 
  scale_fill_manual(name = "Survey Type", 
                    labels = c("UAV Pre-plane","Plane","UAV Post-plane"),
                    values = c("darkblue","red","lightblue"),
                    aesthetics = "fill") +
  theme(legend.text = element_text(size = 10, family = "Arial", colour = "black")) +
  new_scale_fill() + 
  geom_bar(data = synchGADW, 
           mapping = aes(x = Species, y = Value, fill = SurveyType), 
           stat='identity', position = position_dodge(width = 0.75), width=0.7,show.legend = FALSE) +
  scale_fill_manual(name = "GADW", 
                    labels = c("UAV Pre-plane","Plane","UAV Post-plane"),
                    values = c("darkblue","red","lightblue"),
                    aesthetics = "fill")+
  new_scale_fill() + 
  geom_bar(data = synchAGWT, 
           mapping = aes(x = Species, y = Value, fill = SurveyType), 
           stat='identity', position = position_dodge(width = 0.75), width=0.7,show.legend = FALSE) +
  scale_fill_manual(name = "AGWT", 
                    labels = c("UAV Pre-plane","Plane","UAV Post-plane"),
                    values = c("darkblue","red","lightblue"),
                    aesthetics = "fill")+
  new_scale_fill() + 
  geom_bar(data = synchRNDU, 
           mapping = aes(x = Species, y = Value, fill = SurveyType), 
           stat='identity', position = position_dodge(width = 0.75), width=0.7,show.legend = FALSE) +
  scale_fill_manual(name = "RNDU", 
                    labels = c("UAV Pre-plane","Plane","UAV Post-plane"),
                    values = c("darkblue","red","lightblue"),
                    aesthetics = "fill") +
  geom_text(position = position_dodge(width = 0.75), 
            aes(x = Species, y = Value+2, label = Value))+
  theme(plot.title = element_text(hjust = 0.5)) +
  theme(panel.border = element_blank(), panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(), 
        axis.line = element_line(colour = "black"),
        text = element_text(size = 16,
                            family = "Arial"))+
  labs(y="Proportion of Count") +
  ggtitle("Species Proportion of Total Survey Count by Survey Type - 
            Swan Creek Dewatering Unit, Late Season") + 
  theme(legend.title = element_text(size = 12, family = "Arial")) +
  theme(plot.title = element_text(size = 15, family = "Arial")) 

synchplot.again

This is the resulting graph:

Figure

I simply just want the labels to be over their respective bars.

I have seen this question several times asked and answered and I have tried code from each of the different answers. I have those three questions linked below:

  1. How to put labels over geom_bar in R with ggplot2
  2. geom_text labelling bars incorrectly
  3. ggplot geom_text not seating on top of bars

Each of these discusses a different way to adjust the position of the label created by geom_text and none of them worked for me. Any suggestions? Thank you in advance.


Solution

  • You need to add group = SurveyType to the aes() of geom_text() to achieve to correct placement of the text labels.

    Additionally, you can simplify your code as you don’t need to introduce new scales with ggnewscale::new_scale_fill(), and you don’t need to prepare subsets of the synch data.frame.

    library(dplyr)
    library(ggplot2)
    
    ggplot(data = synch) +
      geom_bar(
        mapping = aes(x = Species, y = Value, fill = SurveyType),
        stat = 'identity',
        position = position_dodge(width = 0.75),
        width = 0.7
      ) + theme_bw() +
      scale_fill_manual(
        name = "Survey Type",
        labels = c("UAV Pre-plane", "Plane", "UAV Post-plane"),
        values = c("darkblue", "red", "lightblue"),
        aesthetics = "fill"
      ) +
      geom_text(aes(
        x = Species,
        y = Value + 2,
        label = Value,
        group = SurveyType
      ),
      position = position_dodge(width = 0.75)) +
      theme(
        legend.title = element_text(size = 12, family = "Arial"),
        legend.text = element_text(
          size = 10,
          family = "Arial",
          colour = "black"
        ),
        plot.title = element_text(hjust = 0.5),
        panel.border = element_blank(),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        axis.line = element_line(colour = "black"),
        text = element_text(size = 16,
                            family = "Arial")
      ) +
      labs(y = "Proportion of Count") +
      ggtitle(
        "Species Proportion of Total Survey Count by Survey Type -
              Swan Creek Dewatering Unit, Late Season"
      )