2

I have built a diverging bar chart using the following code:

regions  <- c("North East", "Northern Ireland", "Wales", "Yorkshire and the Humber", "East Midlands","West Midlands","Scotland",
              "South West", "North West", "London", "East of England", "South East")

First <- c(553,561,600,1192,1718,1777,2091,2296,3147,3590,5105,6975)
Last  <- c(629,647,716,1401,2074,2782,2331,2159,3165,4899,5662,6665)

df  <- data.frame(regions, First, Last)

df$difference = df$Last-df$First 

# Data Prep
df$type <- ifelse(df$difference < 0, "below", "above")  # above / below avg flag
df <- df[order(df$difference), ]  # sort
df$regions <- factor(df$regions, levels = df$regions)  # convert to factor to retain sorted order in plot.

# Diverging Barcharts
ggplot(df, aes(x=`regions`, y=difference, label=difference)) + 
  geom_bar(stat='identity', aes(fill=type), width=.5)  +
  geom_text(aes(label=difference), vjust=0, hjust=1) +
  scale_fill_manual(name="Mileage", 
                    labels = c("Increase", "Decrease"), 
                    values = c("above"="#00ba38", "below"="#f8766d")) + 
coord_flip()

Which produces this:

enter image description here

I want the text labels to be adjusted depending on if it is positive or negative values i.e. if the bar is positive, put the text label to the right of the bar, and if it is negative, put the text label to the left of the bar.

I have tried to add an if statement into the plot, but that gives me an error of Error: Cannot add ggproto objects together.How would one go about doing this?

Thank you

Nicholas
  • 3,517
  • 13
  • 47
  • 86
  • 2
    Possible duplicate of [How to put lables over geom\_bar when the value is negative in R](https://stackoverflow.com/questions/46300666/how-to-put-lables-over-geom-bar-when-the-value-is-negative-in-r). Also, [Nudge ggplot text based on value](https://stackoverflow.com/questions/54535180/nudge-ggplot-text-based-on-value). – Dan Feb 18 '19 at 11:41

2 Answers2

3

Here is an option using hjust = ifelse(df$difference < 0, 0, 1) as you mentioned

# Diverging Barcharts
ggplot(df, aes(x=`regions`, y=difference, label=difference)) + 
  geom_bar(stat='identity', aes(fill=type), width=.5)  +
  geom_text(aes(label=difference), vjust=0, 
            hjust=ifelse(df$difference < 0, 0, 1)) + # here it is
  scale_fill_manual(name="Mileage", 
                    labels = c("Increase", "Decrease"), 
                    values = c("above"="#00ba38", "below"="#f8766d")) + 
  coord_flip()

enter image description here

markus
  • 25,843
  • 5
  • 39
  • 58
  • Thank you very much, just what I wanted! – Nicholas Feb 18 '19 at 11:41
  • 1
    I think this is a better answer than the accepted answer in the duplicate link. You should consider adding it to that question. This will work irrespective of scale, unlike that accepted answer, which uses a scale-specific increment. If you do add it, let me know so I can upvote. – LMc May 14 '21 at 19:25
3

You need to pass hjust argument to geom_text as a vector with 1 for right adjustment and 0 for left adjustment. So you can use df$difference > 0. Something like this:

ggplot(df, aes(x=`regions`, y=difference, label=difference)) + 
  geom_bar(stat='identity', aes(fill=type), width=.5)  +
  geom_text(aes(label=difference), vjust=0, hjust=df$difference > 0) +
  scale_fill_manual(name="Mileage", 
                    labels = c("Increase", "Decrease"), 
                    values = c("above"="#00ba38", "below"="#f8766d")) + 
coord_flip()
Istrel
  • 2,508
  • 16
  • 22