Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to center stacked percent barchart labels

I am trying to plot nice stacked percent barchart using ggplot2. I've read some material and almost manage to plot, what I want. Also, I enclose the material, it might be useful in one place:

How do I label a stacked bar chart in ggplot2 without creating a summary data frame?

Create stacked barplot where each stack is scaled to sum to 100%

R stacked percentage bar plot with percentage of binary factor and labels (with ggplot)

My problem is that I can't place labels where I want - in the middle of the bars. enter image description here

You can see the problem in the picture above - labels looks awfull and also overlap each other.

What I am looking for right now is:

  1. How to place labels in the midde of the bars (areas)

  2. How to plot not all the labels, but for example which are greather than 10%?

  3. How to solve overlaping problem?

For the Q 1. @MikeWise suggested possible solution. However, I still can't deal with this problem.

Also, I enclose reproducible example, how I've plotted this grahp.

library('plyr') library('ggplot2') library('scales') set.seed(1992) n=68  Category <- sample(c("Black", "Red", "Blue", "Cyna", "Purple"), n, replace = TRUE, prob = NULL) Brand <- sample("Brand", n, replace = TRUE, prob = NULL) Brand <- paste0(Brand, sample(1:5, n, replace = TRUE, prob = NULL)) USD <- abs(rnorm(n))*100  df <- data.frame(Category, Brand, USD)  # Calculate the percentages df = ddply(df, .(Brand), transform, percent = USD/sum(USD) * 100)   # Format the labels and calculate their positions df = ddply(df, .(Brand), transform, pos = (cumsum(USD) - 0.5 * USD))  #create nice labes df$label = paste0(sprintf("%.0f", df$percent), "%")      ggplot(df, aes(x=reorder(Brand,USD,                               function(x)+sum(x)),  y=percent, fill=Category))+   geom_bar(position = "fill", stat='identity',  width = .7)+   geom_text(aes(label=label, ymax=100, ymin=0), vjust=0, hjust=0,color = "white",  position=position_fill())+   coord_flip()+   scale_y_continuous(labels = percent_format())+   ylab("")+   xlab("") 
like image 676
AK47 Avatar asked Jan 20 '16 14:01

AK47


People also ask

How do I change the order of a stacked bar chart?

Under Chart Tools, on the Design tab, in the Data group, click Select Data. In the Select Data Source dialog box, in the Legend Entries (Series) box, click the data series that you want to change the order of. Click the Move Up or Move Down arrows to move the data series to the position that you want.

How do you show values in a stacked bar chart in Python?

plot. bar(stacked=True) , or pandas. DataFrame. plot(kind='bar', stacked=True) , is the easiest way to plot a stacked bar plot.

How do you use a stacked bar chart?

A stacked bar chart is used to show the total or average of each category. The taller a bar is, the larger the volume of those numeric values. The bars in the stacked bar chart below show how each category compares to the average. The bottom bar shows the total for all of the categories.


2 Answers

Here's how to center the labels and avoid plotting labels for small percentages. An additional issue in your data is that you have multiple bar sections for each colour. Instead, it seems to me all the bar sections of a given colour should be combined. The code below uses dplyr instead of plyr to set up the data for plotting:

library(dplyr)  # Initial data frame    df <- data.frame(Category, Brand, USD)  # Calculate percentages df.summary = df %>% group_by(Brand, Category) %>%    summarise(USD = sum(USD)) %>%   # Within each Brand, sum all values in each Category   mutate(percent = USD/sum(USD)) 

With ggplot2 version 2, it is no longer necessary to calculate the coordinates of the text labels to get them centered. Instead, you can use position=position_stack(vjust=0.5). For example:

ggplot(df.summary, aes(x=reorder(Brand, USD, sum), y=percent, fill=Category)) +   geom_bar(stat="identity", width = .7, colour="black", lwd=0.1) +   geom_text(aes(label=ifelse(percent >= 0.07, paste0(sprintf("%.0f", percent*100),"%"),"")),                 position=position_stack(vjust=0.5), colour="white") +   coord_flip() +   scale_y_continuous(labels = percent_format()) +   labs(y="", x="") 

enter image description here


With older versions, we need to calculate the position. (Same as above, but with an extra line defining pos):

# Calculate percentages and label positions df.summary = df %>% group_by(Brand, Category) %>%    summarise(USD = sum(USD)) %>%   # Within each Brand, sum all values in each Category   mutate(percent = USD/sum(USD),          pos = cumsum(percent) - 0.5*percent) 

Then plot the data using an ifelse statement to determine whether a label is plotted or not. In this case, I've avoided plotting a label for percentages less than 7%.

ggplot(df.summary, aes(x=reorder(Brand,USD,function(x)+sum(x)), y=percent, fill=Category)) +   geom_bar(stat='identity',  width = .7, colour="black", lwd=0.1) +   geom_text(aes(label=ifelse(percent >= 0.07, paste0(sprintf("%.0f", percent*100),"%"),""),                 y=pos), colour="white") +   coord_flip() +   scale_y_continuous(labels = percent_format()) +   labs(y="", x="") 

enter image description here

like image 133
eipi10 Avatar answered Oct 05 '22 22:10

eipi10


I followed the example and found the way how to put nice labels for simple stacked barchart. I think it might be usefull too.

df <- data.frame(Category, Brand, USD)  # Calculate percentages and label positions df.summary = df %>% group_by(Brand, Category) %>%    summarise(USD = sum(USD)) %>%   # Within each Brand, sum all values in each Category   mutate( pos = cumsum(USD)-0.5*USD)  ggplot(df.summary, aes(x=reorder(Brand,USD,function(x)+sum(x)), y=USD, fill=Category)) +   geom_bar(stat='identity',  width = .7, colour="black", lwd=0.1) +   geom_text(aes(label=ifelse(USD>100,round(USD,0),""),                 y=pos), colour="white") +   coord_flip()+   labs(y="", x="") 

enter image description here

like image 34
AK47 Avatar answered Oct 05 '22 22:10

AK47