I used a post-hoc approach. ggplot creates its own data frame for drawing a figure. The data frame has all details, and you can wisely use them.

# Let's create a data set with set.seed().
library(dplyr)
library(tidyr)
library(ggplot2)
library(gridExtra)
set.seed(111)
tmp_df <- data.frame(a = rnorm(100, 0, 1),
b = rnorm(100, 0.5, 1),
c = rnorm(100, -0.5, 1),
d = rnorm(100, 1, 1),
e = rnorm(100, -1, 1)) %>%
tidyr::gather()
# Save the original data
tmp_df %>%
ggplot(aes(x = value, fill = key)) +
geom_histogram(binwidth = 0.1, position = 'stack') -> g

Now you create a new data frame using g. You can see how this data frame looks like below.

# Create a data frame
ggplot_build(g)$data[[1]] %>%
data.frame -> temp
# fill y count x xmin xmax density ncount ndensity PANEL group ymin ymax colour size linetype
#1 #E76BF3 1 1 -4.2 -4.25 -4.15 0.1 0.125 1.25 1 5 0 1 NA 0.5 1
#2 #00B0F6 1 0 -4.2 -4.25 -4.15 0.0 0.000 0.00 1 4 1 1 NA 0.5 1
#3 #00BF7D 1 0 -4.2 -4.25 -4.15 0.0 0.000 0.00 1 3 1 1 NA 0.5 1
#4 #A3A500 1 0 -4.2 -4.25 -4.15 0.0 0.000 0.00 1 2 1 1 NA 0.5 1
#5 #F8766D 1 0 -4.2 -4.25 -4.15 0.0 0.000 0.00 1 1 1 1 NA 0.5 1
#6 #E76BF3 0 0 -4.1 -4.15 -4.05 0.0 0.000 0.00 1 5 0 0 NA 0.5 1

I wanted to check how colors were assigned to each group. So I took a part of data which has 0 for x-axis. This information will be used later.

# Check how colors are assigned to each group
filter(temp, x == 0) %>%
select(fill) %>%
unlist %>%
rev
# fill5 fill4 fill3 fill2 fill1
# "#F8766D" "#A3A500" "#00BF7D" "#00B0F6" "#E76BF3"

Then, I wanted to manipulate the data frame a bit. In order to find the top 2 groups for each group (for each bin), I subtracted ymin from ymax and created a new column called y2. The values in this column tells which groups stay in the top two positions. So, for each group (each x value), I arranged the data in descending order with y2. Then, I replaced the values in y2 for the groups staying in the 3rd-5th position. If there were ties, in each group, the first one was chosen here.

temp %>%
mutate(y2 = ymax - ymin) %>%
arrange(x, desc(y2)) %>%
group_by(x) %>%
mutate(group = as.character(c(group[1:2], rep(6, times = 3)))) %>%
ungroup -> temp2

The final step was to draw a figure again. As eipi10 used geom_bar, I used the same function.

ggplot(data = temp2, aes(x = x, y = y2, fill = group)) +
geom_bar(width = 0.1, stat = "identity") +
scale_fill_manual(name = "key", labels = c("a", "b", "c", "d", "e", "others"),
values = c("#F8766D", "#A3A500", "#00BF7D", "#00B0F6", "#E76BF3", "#000000")) +
labs(x = "value", y = "count") -> g2

enter image description here

For the comparison graphic below

arrangeGrobe(g, g2, ncol = 2) -> g3
ggsave(g3, file = "whatever.png", width = 12, height = 9)

Comparison with the original figure (left)

enter image description here

You are watching: In ggplot2, how do you combine small valued bars in a stacked histogram together?. Info created by GBee English Center selection and synthesis along with other related topics.