Stacked bar with labels at the right end using ggrepel and ggplot2

I need a bar chart that shows different segments of a dataframe, including years,
revenue sources, and revenue figures for a company. I can generate the chart,
but there are issues with the labels. They are disorganized, not properly
aligned with their respective segments, and don't have the same color as the corresponding
segment.

I have tried using base R, but most of all , I have used ggrepel and the geom_text_repel
function. The Function seems to work but renders the wrong result.

type_vec <- c(rep("ecommerce",4),rep("third_party",4),rep("retail",4),rep("services",4),
              rep("marketplace",4))
year_vec <- rep(c("2010","2011","2013","2014"),5)
revenue_vec <- c(8709, 8773, 8974, 9876, 1772, 1891, 1915, 2872, 5727, 5820, 5904, 6500,
  1, 2, 3, 6, 4370, 4463, 4479, 4817)


data_raw <- tibble(year=year_vec,type=type_vec,revenue=revenue_vec)

data_df <- data_raw %>% 
  mutate(group = as.factor(if_else(revenue < 11, "other", type ))) %>% 
  mutate(group = fct_relevel(group, "other", after=Inf),
         label_type = if_else(year == 2014,type, NA_character_))

theme_stacked_bar <- function( ) {
  
  theme(
    legend.position = "none",
    plot.margin = unit(c(2,7,2,2),"cm"),
    axis.text = element_text(size=3)
  )
}
  
data_plot <- ggplot(
  data_df %>% filter(group != "other"), 
  aes(year, revenue, group = type)
) + 

  geom_bar(
    stat = "identity",
    data = data_df %>% filter(group == "other"),
    fill = "grey85",
    alpha = .5) +
  geom_bar(
    stat = "identity",
    aes(fill = group)) +
  scale_fill_brewer() +
  theme_stacked_bar()
data_plot


data_plot <- data_plot +
  geom_text_repel(
    aes(color = group, label = label_type ),
    # family = "Lato",
    # fontface = "bold",
    size = 8,
    direction = "y",
    xlim = c(2014.8, NA),
    hjust = 0,
    segment.size = .7,
    segment.alpha = .5,
    segment.linetype = "dotted",
    box.padding = .4,
    segment.curvature = -0.1,
    segment.ncp = 3,
    segment.angle = 20
  ) +

  coord_cartesian(
    clip = "off",
    ylim = c(0,25000)
  )

data_plot

Expected

I want the labels aligned with the right segments , also i want the words to match the color palette used

Result
I got the stacked bar chart with the labels messy and wrong colors. I am unable to organize the labels and also I am unable to add the color of the color palette used in the bars.

Welcome to the community @edwinsane! I was unsuccessful achieving your desired output with ggrepel, so below is a slightly different approach that does not use the package. Instead, a new data frame is created that calculates the midpoints of each of the stacked sections, and this data is plotted with geom_text(). Since the color palette is so light, your theme function was modified to darken the panel background, as well as remove the gridlines. The additional "year" on the x-axis was also removed by specifying the breaks in scale_x_discrete().

theme_stacked_bar <- function( ) {
  theme(
    legend.position = "none",
    plot.margin = unit(c(2,7,2,2),"cm"),
    axis.text = element_text(size=3),
    panel.background = element_rect(fill = '#404040'),
    panel.grid = element_blank()
  )
}

# determine the midpoints of each group from latest year (arranged alphabetically in plot)
mids = data_df |>
  filter(year == max(year)) |>
  arrange(desc(group)) |>
  filter(group != 'other') |>
  mutate(midpoint = 0.5 * revenue) |>
  mutate(y = ifelse(row_number() == 1, midpoint, cumsum(revenue) - revenue + midpoint),
         year = as.character(as.numeric(year) + 1))

data_plot <- ggplot(
  data_df %>% filter(group != "other"), 
  aes(year, revenue, group = type)
) + 
  geom_bar(
    stat = "identity",
    data = data_df %>% filter(group == "other"),
    fill = "grey85",
    alpha = .5) +
  geom_bar(
    stat = "identity",
    aes(fill = group)) +
  geom_text(data = mids,
            aes(x = year, y = y, label = group, color = group)
            ) +
  scale_fill_brewer() +
  scale_color_brewer() +
  scale_x_discrete(breaks = data_df$year) +
  theme_stacked_bar() 

data_plot

Created on 2023-06-29 with reprex v2.0.2

1 Like

Hi, Thank you for taking the time to answer my question , I appreciate it. The solution is really good , I did not thought about it. One more question I tried to left justify the labels with "hjust=0", but they seem to be a little bit away from the 2014 bar, I understand they will take the x position of 2015 but it would look better to have them more close to the bar chart .

You're welcome! You can use the nudge_x argument (along with hjust = 0) to move the labels closer to the bars.

geom_text(data = mids,
            aes(x = year, y = y, label = group, color = group),
            hjust = 0,
            nudge_x = -0.5
            )

Great , that is what I was looking for. Thank you very much!! :ok_hand:

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.