Viewed   4.1k times

How can I use geom_text to add percentage labels on top of each bar in ggplot2? I know there are several similar questions which are already answered. But they either use only 1 categorical variable or compute the percentages before plotting.
I have following plot:

ggplot(data = mtcars)+
  geom_bar(aes(x = factor(cyl), 
               y = (..count..)/sum(..count..)*100,
               fill = factor(gear)),
           position = "dodge")  

Now I want to add the percentage labels on the top. If I use y = (..count..)/sum(..count..)*100 in geom_text, it says Error in eval(expr, envir, enclos) : object 'count' not found.

 Answers

4

It's easiest to calculate the quantities you need beforehand, outside of ggplot, as it's hard to track what ggplot calculates and where those quantities are stored and available.

First, summarize your data:

library(dplyr)
library(ggplot2)

mtcars %>% 
    count(cyl = factor(cyl), gear = factor(gear)) %>% 
    mutate(pct = prop.table(n))
#> # A tibble: 8 x 4
#>   cyl   gear      n    pct
#>   <fct> <fct> <int>  <dbl>
#> 1 4     3         1 0.0312
#> 2 4     4         8 0.25  
#> 3 4     5         2 0.0625
#> 4 6     3         2 0.0625
#> 5 6     4         4 0.125 
#> 6 6     5         1 0.0312
#> 7 8     3        12 0.375 
#> 8 8     5         2 0.0625

Save that if you like, or pipe directly into ggplot:

mtcars %>% 
    count(cyl = factor(cyl), gear = factor(gear)) %>% 
    mutate(pct = prop.table(n)) %>% 
    ggplot(aes(x = cyl, y = pct, fill = gear, label = scales::percent(pct))) + 
    geom_col(position = 'dodge') + 
    geom_text(position = position_dodge(width = .9),    # move to center of bars
              vjust = -0.5,    # nudge above top of bar
              size = 3) + 
    scale_y_continuous(labels = scales::percent)

If you really want to keep it all internal to ggplot, you can use geom_text with stat = 'count' (or stat_count with geom = "text", if you prefer):

ggplot(data = mtcars, aes(x = factor(cyl), 
                          y = prop.table(stat(count)), 
                          fill = factor(gear), 
                          label = scales::percent(prop.table(stat(count))))) +
    geom_bar(position = "dodge") + 
    geom_text(stat = 'count',
              position = position_dodge(.9), 
              vjust = -0.5, 
              size = 3) + 
    scale_y_continuous(labels = scales::percent) + 
    labs(x = 'cyl', y = 'pct', fill = 'gear')

which plots exactly the same thing.

Saturday, August 6, 2022
 
javram
 
4

I would approach this by defining another variable (which I call pos) in df that calculates the position of text labels. I do this with dplyr but you could also use other methods of course.

library(dplyr)
library(ggplot2)

df <- df %>% group_by(year) %>% mutate(pos = cumsum(quantity)- quantity/2)

ggplot(data=df, aes(x=factor(1), y=quantity, fill=factor(prod))) +
  geom_bar(stat="identity") +
  geom_text(aes(x= factor(1), y=pos, label = quantity), size=10) +  # note y = pos
  facet_grid(facets = .~year, labeller = label_value) +
  coord_polar(theta = "y")

Tuesday, September 20, 2022
 
4

I do not think there is a text wrap option in ggplot2 (I have always just inserted n manually). You can, however, shrink the size of the title's text by altering your code in the following way:

title.size<-10
r + geom_smooth() + opts(title = my_title,plot.title=theme_text(size=title.size))

In fact, you all aspects of text with the theme_text function.

Saturday, December 17, 2022
4

You could do something like this...

#set positions for labels
example.melt$labelpos <- ifelse(example.melt$variable=="percent.bad",
                         example.melt$value/2, 1 - example.melt$value/2)
ggplot(example.melt, aes(x=example.Category, y=value, fill = variable)) +
  geom_bar(position = "fill", stat = "identity",color='black',width=0.9) +
  scale_y_continuous(labels = scales::percent) +
#use positions to plot labels
  geom_text(aes(label = paste0(100*value,"%"),y=labelpos),size = 3)

Thursday, December 1, 2022
 
1

I think you've mixed up your labels. Try this:

ax = graph_by_duration.plot(kind='bar', width=0.5)
[label.set_rotation(25) for label in ax.get_xticklabels()]

labels = [int(round(graph_by_duration.loc[i, y]))
          for y in graph_by_duration.columns.tolist()
          for i in graph_by_duration.index]

for rect, label in zip(rects, labels):
    height = rect.get_height()
    ax.text(rect.get_x() + rect.get_width()/2, height + 5, label,     
    ha='center', va='bottom', rotation=15)

plt.show()

Friday, November 18, 2022
 
sknecht
 
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :