user13608970
user13608970

Reputation: 177

Number spacing on a stacked plot using ggplot2?

I've run the following code and get the following plot. How do I manipulate the spacing between the numbers per stacked plot so it becomes readable?

ggplot(data=dat, aes(x=SU,fill=factor(SCIENTIFIC_NAME)))+
  geom_bar(width=0.5)+xlab("Sampling Unit (SU)")+
  ylab("Count")+labs(fill="SCIENTIFIC NAME")+
  ggtitle("Inventory per sampling unit (SU) by species")+ 
  geom_text(stat='count', aes(label=..count..), vjust=-1)+
  scale_x_discrete(breaks=c(1,2,3,4,5,6,7,8,10,11,15))

enter image description here

Upvotes: 1

Views: 202

Answers (3)

Simon Woodward
Simon Woodward

Reputation: 2026

You can plot the bars and labels separately, and then a line segment to join them. I also handled overlapping labels in a simple way.

library(ggplot2)
library(dplyr)

df <- data.frame(group  = c("A","A","A",
                              "B","B","B"),
                   sector = c("x","y","z",
                              "x","y","z"),
                   value  = c(10,1,
                              2,1,2,100))

df <- df %>% # calculate label position
  group_by(group) %>% # for each bar
  arrange(desc(sector)) %>% # from bottom to top
  mutate(
    midy = cumsum(value) - value / 2, # base label position
    dmidy = diff(c(0, midy)), # gaps between labels (and axis)
    dmidy2 = pmax(dmidy, 10), # apply minimum label spacing
    labely = cumsum(dmidy2) # final label position
    ) %>%  #
  arrange(group, sector) # useful for debugging

ggplot(data = df) +
  geom_col(mapping = aes(x = group, y = value, fill = sector), width = 0.5) + # plot the bar
  geom_text(mapping = aes(x = group, y = labely, label = value), nudge_x = 0.5) + # plot the label
  geom_segment(mapping = aes(x = group, y = midy, xend = as.integer(group) + 0.4, yend = labely)) # plot the line

Created on 2020-07-06 by the reprex package (v0.3.0)

Upvotes: 0

Zhiqiang Wang
Zhiqiang Wang

Reputation: 6769

I think @Duck's solution is great. As some boxes are very small in OP, you may also want to try ggrepel to push the numbers away from each other.

library(ggplot2)
library(ggrepel)
#Data
data <- data.frame(group  = c("A","A","A",
                              "B","B","B"),
                   sector = c("x","y","z",
                              "x","y","z"),
                   value  = c(10,1,
                              2,1,2,100))
ggplot(data = data, aes(x = group, y = value, fill = sector)) +
  geom_col() +
   geom_text_repel(aes(label = value),
             position = position_stack(vjust = .5)) 

enter image description here

Upvotes: 1

Duck
Duck

Reputation: 39603

As long as data is not included, I hope this exercise with example data helps you:

library(ggplot2)
#Data
data <- data.frame(group  = c("A","A","A",
                             "B","B","B"),
                  sector = c("x","y","z",
                             "x","y","z"),
                  value  = c(10,20,70,
                             30,20,50))
#Plot
ggplot(data = data, aes(x = group, y = value, fill = sector)) +
  geom_col() +
  geom_text(aes(label = value),
            position = position_stack(vjust = .5))

enter image description here

Upvotes: 1

Related Questions