How to Center Stacked Percent Barchart Labels

How to center stacked percent barchart labels

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="")

Sample Image


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="")

Sample Image

Adding and aligning frequency labels to 100% stacked bar charts in R

We could do it this way:

library(ggplot2)
library(dplyr)

df %>%
mutate(Frequency = as.numeric(Frequency)) %>%
ggplot(aes(x = ID, y= Frequency, fill=Class)) +
geom_col(position = position_stack(reverse = TRUE))+
coord_flip() +
geom_text(aes(label = Frequency),
position = position_stack(reverse = TRUE, vjust = .5), size=6)

Sample Image

GGPLOT Align Labels in Stacked Barplot with Subset of Data

As an alternative for subsetting the data, you can wrap your text label in an ifelse statement that substitutes small values with empty strings.

Example below:

library(tidyverse)
library(ggplot2)
library(scales)

df <- data.frame("class" = rep("class_1", 13),
"grade" = c("A+", "A", "A-",
"B+", "B", "B-",
"C+", "C", "C-",
"D+", "D", "D-", "F"),
"n" = c(24, 29, 28, 9, 12, 5, 1, 2, 5, 1, 1, 2, 4)) %>%
mutate(Percent = n/sum(n))


df %>%
ggplot(aes(x=class, y=Percent, fill=grade)) +
geom_bar(position = "stack", stat = "identity", colour = "grey43") +
scale_y_continuous(labels = scales::percent) +
xlab("") +
ylab("Percent")+
geom_text(
data = df,
aes(y = Percent,
label = ifelse(Percent > 0.02, paste0(round(Percent*100, 1),"%"), "")),
stat = "identity",
size = 4,
position = position_stack(vjust = 0.5),
fontface = 2,
family = "Courier New"
)
#> Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
#> font family not found in Windows font database

Sample Image

Created on 2021-03-17 by the reprex package (v0.3.0)

How do I neatly align my stacked barchart labels, with differing alignments to each side of the bar?

Try fixing the x co-ordinate in the call to geom_text and managing alignment with hjust...

df3 <- data.frame(
Label = c("Dasher", "Dancer", "Comet", "Cupid", "Prancer", "Blitzen", "Rudolph"),
Amount = c(650.01, 601.01, 340.05, 330.20, 260.01, 250.80, 10.10)
)


library(ggplot2)
library(dplyr)
library(forcats)

level_order <- df3 %>%
arrange(desc(Amount))

ggplot(level_order, aes(fill=fct_inorder(Label), y=Amount, x="")) +
geom_bar(position="stack", stat="identity", width = 0.55) +
scale_fill_brewer(palette = "Blues", direction = -1) +
theme_void() +
geom_text(aes(x = 1.3, label = paste0("$", Amount)),
position = position_stack(vjust = 0.5),
hjust = 0,
size = 5) +
geom_text(aes(x = 0.6, label = Label),
position = position_stack(vjust = 0.5),
hjust = 0,
size = 5) +
theme(legend.position = "none") +
theme(plot.title = element_text(size = 50, hjust = .5, vjust = 0)) +
ggtitle("Food Costs by Reindeer")

Sample Image

Created on 2021-12-19 by the reprex package (v2.0.1)

geom_text position middle on the stacked bar chart

First use geom_bar and set stat = "identity". After that use position = position_stack(vjust = 0.5). You can use the following code:

# Construct a ggplot object according requirement above and assign it to 'plt'
plt <- ggplot(plotdata,aes(x = sector, y = n, fill = sex))+
geom_bar(stat="identity")+
geom_text(aes(label=n), position = position_stack(vjust = 0.5))+
labs(x = "",
y = "Number of persons",
title = "")


# Display the stacked bar chart
plt

Output:

Sample Image

Stacked Bar Chart with Centered Labels

Why you wrote va="bottom"? You have to use va="center".
Sample Image

Ggplot stacked bar plot with percentage labels

You need to group_by team to calculate the proportion and use pct in aes :

library(dplyr)
library(ggplot2)

ashes_df %>%
count(team, role) %>%
group_by(team) %>%
mutate(pct= prop.table(n) * 100) %>%
ggplot() + aes(team, pct, fill=role) +
geom_bar(stat="identity") +
ylab("Number of Participants") +
geom_text(aes(label=paste0(sprintf("%1.1f", pct),"%")),
position=position_stack(vjust=0.5)) +
ggtitle("England & Australia Team Make Up") +
theme_bw()

Sample Image

How to center labels over side-by-side bar chart in ggplot2

Hm. Unfortuantely I can't tell you what's the reason for this issue. Also, I'm not aware of any update of ggplot2 or ... Probably I miss something basic (maybe I need another cup of coffee). Anyway. I had a look at the layer_data and your text labels are simply dodged by only half the width of the bars. Hence, you could achieve your desired result by doubling the width, i.e. use position = position_dodge(width = 1.8) in geom_text

library(ggplot2)

ggplot(df, aes(x = Cycle, y = Count_Percentage_Mean, fill = Donor_Location)) +
geom_col(position = "dodge") +
scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
geom_text(aes(label = scales::percent(Count_Percentage_Mean, accuracy = 1)), position = position_dodge(width = 1.8), vjust = -0.5)

Sample Image

Calculating with y-axis labels of stacked bar plot (either *4 or into percent)

You could add this to your code:

scale_y_continuous(labels = function(x) paste0((x/max(x))*100, "%"))

For the given example dataset without(event_labels):
Sample Image



Related Topics



Leave a reply



Submit