Define different label size by category in geom_bar
Asked Answered
B

1

6

I am trying to plot a stacked barchart using geom_bar and label each category with its value within the barchart. Because some categories have small values, the height of the corresponding segment of the barchart is sometimes small. So, I am trying to adjust the size of the labels using geom_text.
I have tried to define a vector, called size, that varies according to the value of the variable I am trying to plot but,although the size of the labels does vary between categories, it does not seem to be related to the values. Also, I am not sure why I am getting a legend for my label size on the right-hand side of the graph.
Here is a stripped version of the code I am using:

library(ggplot2)
library(plyr)
library(scales)

Var1 = as.factor(rep(c("A", "B", "C", "D", "E", "F"),2))
Var2 = as.factor(rep(c("Y1","Y2"),each=6))
Freq = c(0.4, 0.1, 0.3, 0.1, 0.05, 0.05,0.2,0.2,0.3,0.2,0.05,0.05)
Data = data.frame(Var1, Var2, Freq)
Data <- ddply(Data, .(Var2), mutate, y = cumsum(Freq)-Freq/2)

size = ifelse(Data$Freq > 0.05, 10, 3)
label = paste(round(Data$Freq*100,0),"%", sep = "")
p = ggplot(data = Data, aes(x = factor(''), y = Freq, fill = Var1)) +
  geom_bar(stat = "identity",position = "fill", width = 1) +
  scale_fill_brewer(palette = 3) +
  facet_grid(facets = . ~ Var2) +
  geom_text(aes(y = y, label = label, 
                position ="identity", face = "bold"), size = size, hjust=0.5, vjust=0.5) +
  xlab('') + ylab('') + labs(fill = '') + ggtitle('Example') +
  theme(axis.text.y = element_text(size=14,face="bold"),
        panel.background = element_blank(),
        plot.title = element_text(size = 20, colour = "black", face = "bold"))
p

As far as I can see, the issue is caused by the facets since this slightly simplified version (i.e. without the facets) works fine:

library(ggplot2)
library(plyr)
library(scales)

Var1 = as.factor(c("A", "B", "C", "D", "E", "F"))
Freq = c(0.4, 0.1, 0.3, 0.1, 0.05, 0.05)
y = cumsum(Freq)-Freq/2
Data = data.frame(Var1, Freq, y)

size = ifelse(Data$Freq > 0.05, 10, 3)
label = paste(round(Data$Freq*100,0),"%", sep = "")
p = ggplot(data = Data, aes(x = factor(''), y = Freq, fill = Var1)) +
  geom_bar(stat = "identity",position = "fill", width = 1) +
  scale_fill_brewer(palette = 3) +
  geom_text(aes(y = y, label = label, 
                position ="identity", face = "bold"), size = size, hjust=0.5, vjust=0.5) +
  xlab('') + ylab('') + labs(fill = '') + ggtitle('Example') +
  theme(axis.text.y = element_text(size=14,face="bold"),
        panel.background = element_blank(),
        plot.title = element_text(size = 20, colour = "black", face = "bold"))
p
Behn answered 27/12, 2013 at 9:37 Comment(2)
so the error you get for the first block of code is the incompatible lengths with size, hjust etc?Wacker
Yes, this is the error I am getting. What I do not understand is that the length of size is the same as that of y and label.Behn
W
2

By adding a size to your data frame and moving those parameters within your geom_text aes()` this seems to plot ok for me. I think..

Data$size <- size

p <- ggplot(data = Data, aes(x = factor(''), y = Freq, fill = Var1)) +
       geom_bar(stat = "identity",position = "fill", width = 1) +
       scale_fill_brewer(palette = 3) +
       geom_text(aes(y = y, label = label, 
                     position ="identity", face = "bold", size = size), hjust=0.5, 
                     vjust=0.5) +
       xlab('') + ylab('') + labs(fill = '') + ggtitle('Example') +
       theme(axis.text.y = element_text(size=14,face="bold"),
             panel.background = element_blank(),
             plot.title = element_text(size = 20, colour = "black", face = "bold")) + 
             facet_grid(facets = . ~ Var2) + 
             guides(size=FALSE)

Also if you add + guides(size=FALSE) to the end as I have done this will remove your size legend.

My explanation for this, might be wrong, is that once you facet you were still providing a full length size and not allowing facet to chop the size data according to Var2 .

I think your problem with the sizing is that size you only have two sizes you are getting big differences (there must be some relative scaling maybe), perhaps add + scale_size(range=c(6,10)) and play with this to get something more appropriate? The 6,10 size range looks much better to me.

enter image description here

Wacker answered 27/12, 2013 at 10:17 Comment(3)
Thanks for the + guides(size = FALSE). This works. However, I still cannot get the size to work. If I change the size = ifelse(Data$Freq > 0.05, 10, 3) into size = ifelse(Data$Freq > 0.05, 10, 8), even with size inside the data frame, the labels for the small categories are still small, when they should not be anymore. So I am not sure that the size argument in R is read correctly in my code.Behn
Check my update @Stéphane , how does that improve things for you.Wacker
I just checked on my main code after making your suggested changes and this works perfectly. The issues were the guides(size = FALSE) at the end and the range of the scale_size. Excellent!Behn

© 2022 - 2024 — McMap. All rights reserved.