havij
havij

Reputation: 1170

Labling bars in grouped barplot in ggplot

The main goal of this plot is to make a comparison between A and B in three groups, but I want to have one, two, and three besides them, as well. Using below code, I can make a grouped barplot which is almost what I want. But I need to have the names of each bar below it since the legend is so ugly.

How can I do it?

m.names <- c("A1","B1","one","A2","B2","two","A3","B3","three")
m.group <- c(1,1,1,2,2,2,3,3,3)
m.value <- c(5,10,1,20,15,2,10,20,3)
df <- data.frame(m.names, m.group, m.value)
df


ggplot(df, aes(x = m.group, y = m.value)) + 
  geom_bar(aes(fill = m.names), position = "dodge", stat = "identity") +
  scale_fill_manual(values=c("gray75", "gray75","gray75", "gray40","gray40","gray40", "blue", "red", "green" ))

enter image description here

Upvotes: 1

Views: 88

Answers (4)

www
www

Reputation: 4224

Seems like you might want this:

require(ggplot2)

ggplot(df, aes(x = m.names, y = m.value)) + 
  geom_bar(aes(fill = m.names), stat = "identity") +
  scale_fill_manual(values=c("gray75", "gray75","gray75", "gray40",
                             "gray40","gray40", "blue", "red", "green" )) +
  facet_grid(~m.group, scales = "free_x", space = "free_x") +
  theme(strip.text.x = element_blank(),
        panel.spacing = unit(0, "lines"))

Output:

enter image description here

The trick is to plot x by m.names here instead of m.groups. Then later we can facet the bars by m.group to keep them presented the way you want.

Upvotes: 1

akrun
akrun

Reputation: 887168

We could use geom_label

dodger = position_dodge(width = 0.9)
ggplot(df, aes(x = m.group, y = m.value)) + 
    geom_bar(aes(fill = m.names), position = dodger, stat = "identity") +
    scale_fill_manual(values=c("gray75", "gray75","gray75", 
                  "gray40","gray40","gray40", "blue", "red", "green" ),
                      guide = "none") +
     theme(axis.text.x=element_blank(),  
      axis.ticks.x=element_blank()) +
    geom_label(aes(x = m.group, group = m.names, label = m.names, y = 0), 
              position = dodger,
              vjust = 1, colour = "black")

enter image description here

Upvotes: 1

Z.Lin
Z.Lin

Reputation: 29085

Faceting by group may work for this case as well:

fill.values = c("gray75", "gray75","gray75", 
                "gray40","gray40","gray40", 
                "blue", "red", "green")
names(fill.values) = levels(df$m.names)

> fill.values
      A1       A2       A3       B1       B2       B3      one    three      two 
"gray75" "gray75" "gray75" "gray40" "gray40" "gray40"   "blue"    "red"  "green" 

ggplot(df,
       aes(x = m.names, y = m.value, fill = m.names)) +
  geom_col() +
  scale_fill_manual(values = fill.values, guide = F) +
  facet_wrap(~m.group, scales = "free_x") +
  theme_bw()

enter image description here

Upvotes: 3

Marius
Marius

Reputation: 60070

Adding geom_text and making sure it's dodged in the same way as the bars:

# width = 0.9 should be the default for dodged bars but set
#  it explicitly to be sure
dodger = position_dodge(width = 0.9)
ggplot(df, aes(x = m.group, y = m.value)) + 
    geom_bar(aes(fill = m.names), position = dodger, stat = "identity") +
    scale_fill_manual(values=c("gray75", "gray75","gray75", "gray40","gray40","gray40", "blue", "red", "green" ),
                      guide = "none") +
    geom_text(aes(x = m.group, group = m.names, label = m.names, y = 0), 
              position = dodger,
              vjust = 1, colour = "black")

enter image description here

Upvotes: 3

Related Questions