Showing Data Values on Stacked Bar Chart in Ggplot2

Showing data values on stacked bar chart in ggplot2

From ggplot 2.2.0 labels can easily be stacked by using position = position_stack(vjust = 0.5) in geom_text.

ggplot(Data, aes(x = Year, y = Frequency, fill = Category, label = Frequency)) +
geom_bar(stat = "identity") +
geom_text(size = 3, position = position_stack(vjust = 0.5))

Sample Image

Also note that "position_stack() and position_fill() now stack values in the reverse order of the grouping, which makes the default stack order match the legend."


Answer valid for older versions of ggplot:

Here is one approach, which calculates the midpoints of the bars.

library(ggplot2)
library(plyr)

# calculate midpoints of bars (simplified using comment by @DWin)
Data <- ddply(Data, .(Year),
transform, pos = cumsum(Frequency) - (0.5 * Frequency)
)

# library(dplyr) ## If using dplyr...
# Data <- group_by(Data,Year) %>%
# mutate(pos = cumsum(Frequency) - (0.5 * Frequency))

# plot bars and add text
p <- ggplot(Data, aes(x = Year, y = Frequency)) +
geom_bar(aes(fill = Category), stat="identity") +
geom_text(aes(label = Frequency, y = pos), size = 3)

Resultant chart

R ggplot labels on stacked bar chart

Just use n/2 as the y position for geom_text(), and it will always fall "inside" the bar:

library(tidyverse)

data.frame(AgeGroup = sample(c(rep("Over",10),"Under"), 6000, replace = TRUE),
DueDate = sample(
seq( as.Date("2015-01-01"),
as.Date("2015-06-30"), by="1 month") ,
6000,replace = TRUE),
stringsAsFactors = TRUE) %>%
group_by(AgeGroup,DueDate) %>%
tally() %>% ungroup %>%
ggplot() +
geom_bar(aes(x=DueDate, y=n, fill = AgeGroup),stat = "identity") +
geom_text(aes(x=DueDate, y=n/2
,label = prettyNum(n,big.mark = ","))
, vjust = 0, size = 2) +
scale_y_continuous(labels = scales::comma) +
theme_bw() +
labs(title="Where are the labels")

Sample Image

EDIT: That quick solution will only work for your specific example. If you have more than two categories per bar, or if the values are more evenly distributed, it will not fly. i.e.:

set.seed(999)
data.frame(Direction = sample(rep(c("South", "West", "East", "North")), 6000, replace = TRUE),
DueDate = sample(
seq( as.Date("2015-01-01"),
as.Date("2015-06-30"), by="1 month") ,
6000,replace = TRUE),
stringsAsFactors = TRUE) %>%
group_by(Direction, DueDate) %>%
tally() %>%
ungroup %>%
arrange(desc(Direction)) %>%
group_by(DueDate) %>%
mutate(pos = cumsum(n) - n/2) %>%
ggplot() +
geom_bar(aes(x=DueDate, y=n, fill = Direction),stat = "identity") +
geom_text(aes(x=DueDate, y=pos, label = prettyNum(n,big.mark = ","))
, vjust = 0, size = 2) +
scale_y_continuous(labels = scales::comma) +
theme_bw() +
labs(title="Where are the labels")

Sample Image

So here's a general solution, that adds a "position" column to the dataframe (arrange(desc(Direction)) %>% group_by(DueDate) %>% mutate(pos = cumsum(n) - n/2)), to use with geom_text() and place the labels exactly where they belong:

set.seed(999)
data.frame(Direction = sample(rep(c("South", "West", "East", "North")), 6000, replace = TRUE),
DueDate = sample(
seq( as.Date("2015-01-01"),
as.Date("2015-06-30"), by="1 month") ,
6000,replace = TRUE),
stringsAsFactors = TRUE) %>%
group_by(Direction, DueDate) %>%
tally() %>%
ungroup %>%
arrange(desc(Direction)) %>%
group_by(DueDate) %>%
mutate(pos = cumsum(n) - n/2) %>%
ggplot() +
geom_bar(aes(x=DueDate, y=n, fill = Direction),stat = "identity") +
geom_text(aes(x=DueDate, y=pos, label = prettyNum(n,big.mark = ","))
, vjust = 0, size = 2) +
scale_y_continuous(labels = scales::comma) +
theme_bw() +
labs(title="Where are the labels")

Sample Image

Force bars/rows in stacked bar chart (ggplot showing percent, zero decimal places) to be of same lenght?

A very simple solution to your problem is to change from position = position_stack() to position = position_fill().

library(tidyverse)
library(scales)

# Creating some data
df <- data.frame(matrix(floor(runif(12*7200, 1, 6)), ncol = 12, dimnames = list(NULL, paste0("item", 1:12))))

# Drawing the ggplot with 0 (zero) decimal places
df %>%
gather %>%
group_by(key, value) %>%
tally %>%
mutate(n = round(n/sum(n) * 100, 0)) %>%
ggplot(aes(x = key, y = n, fill = as.factor(value))) +
geom_col(position = position_fill(reverse = T)) +
labs(title = "Some title", x = " ", fill = " ") +
scale_y_continuous(name = "%", labels = percent) +
geom_text(aes(label = n), position = position_fill(reverse = TRUE, vjust = 0.5), size = 3, colour = "white") +
theme(legend.position = "top") +
coord_flip() +
theme_minimal()

Sample Image

Created on 2022-04-06 by the reprex package (v2.0.1)

Create bar chart in R

I think a grouped bar would make the most sense here:

df  <- read.table(text = "Gender    Season  count
male fall 300
male spring 350
male summer 320
male winter 305
female fall 120
female spring 350
female winter 320
female summer 500", header = TRUE)

library(ggplot2)

ggplot(
data = df,
mapping = aes(
x = Season,
y = count
)) +
geom_bar(
mapping = aes(fill = Gender),
position = "dodge",
stat = "identity"
)

Sample Image



Related Topics



Leave a reply



Submit