CCID
CCID

Reputation: 1448

Add horizontal lines to stacked barplot in ggplot2 in R, and show in legend

I have a stacked barplot, something like the example below.

I want to add one or two sets of horizontal lines (specifying colour and line type) across each bar, at different values for each bar, and add these to the legend.

Titanic.df <- as.data.frame(Titanic)

Titanic.ag <- aggregate( Freq ~ Sex + Class + Age, data=Titanic.df, sum, subset = Survived == "Yes")

bars <- rep(c(0.5, NA, 0.7, NA, 0.6, NA, 0.9, NA), 2)

ggplot(Titanic.ag, aes(x = Class, y = Freq, fill = Sex)) + 
  geom_bar(position = "fill", stat = "identity") + 
  facet_grid(~Age) +
  geom_errorbar(aes(y = bars, ymin = bars, ymax = bars,  col = "Ref1")) + 
  scale_fill_manual(values = c("darkgreen", "darkblue") ) + 
  labs(col = "Reference",
       fill= "",
       y = "Proportion",
       x = "Class")

titanic stacked bar plot with horizontal lines

I have tried using geom_errorbar() as suggested on several questions, but I am stuck with two things:

If I add a vector of values for the error bars, then ggplot expects the same length as in the dataframe (eg 16 in Titanic.ag), but there are only 8 bars as they are stacked. This is why I have used NAs in bars above. Is there an alternative?

More importantly, I want to control colour and line type, but if I add these to geom_bar(), I lose my legend. e.g.

  geom_errorbar(aes(y = bars, ymin=bars, ymax=bars,  col = "Ref1"), col = "red", linetype = 2)

Is geom_segment() an alternative?

Edited typos, clarified different values of horziontal lines.

Upvotes: 8

Views: 14719

Answers (2)

CCID
CCID

Reputation: 1448

The answer above doesn't produce a legend. It does change the linetype and colour, but I also showed this in my original question. After some searching I've found a way to add a legend, so I've posted here.

library(ggplot2)

Titanic.df <- as.data.frame(Titanic)

Titanic.ag <- aggregate( Freq ~ Sex + Class + Age, data=Titanic.df, sum, subset = Survived == "Yes")

bars <- rep(c(0.5, NA, 0.7, NA, 0.6, NA, 0.9, NA), 2)

ggplot(Titanic.ag, aes(x = Class, y = Freq, fill = Sex)) + 
  geom_bar(position = "fill", stat = "identity") + 
  facet_grid(~Age) +
  geom_errorbar(aes(y = bars, ymin = bars, ymax = bars,  col = "Ref1"), linetype = 2, size = 1) + 
  scale_fill_manual(values = c("darkgreen", "darkblue") ) + 

  scale_colour_manual(name='', values=c("Ref1" = "darkred"), guide ="legend") +
  guides(col = guide_legend(override.aes = list(linetype=2), title = "Reference")) + 

  labs(fill= "",
       y = "Proportion",
       x = "Class")

This can be adapted to add a further geom_errorbar().

I still get the warning due to the workaround with the the NAs in the geom_errorbar() vector for y, ymin and ymax, this gets more complicated with more facets, but it works.

Upvotes: 2

Matias Andina
Matias Andina

Reputation: 4230

I'm not completely sure that you need this but. Individual geom_abline calls let you customize easily as you wish each line.

ggplot(Titanic.ag, aes(x = Class, y = Freq, fill = Sex)) + 
  geom_bar(position = "fill", stat = "identity") + 
  facet_grid(~Age) +
  geom_abline(slope=0, intercept=0.5,  col = "red",lty=2) +
  geom_abline(slope=0, intercept=0.75,  col = "lightblue",lty=2) +
  scale_fill_manual(values = c("darkgreen", "darkblue") ) + 
  labs(col = "Reference",
       fill= "",
       y = "Proportion",
       x = "Class")

Produces this plot

enter image description here

Also, maybe this could help with the labels.

UPDATE

Ok, Now I understood...A quick approximation with the same approach would be to use more than one bars vector and error bar call. It's a bit exhausting but might work and a data.frame might not work because you want each bar to be custom several times. Also, take into account that NAs are removed so they are not working as one would like to...Maybe using a number higher than 1 and adjusting the ylim to 1 so they won't show

bars1 <- rep(c(0.5, NA, 0.7, NA, 0.6, NA, 0.9, NA), 2)
bars2 <- rep(c(NA, 0.9, 0.1, 0.1, NA, NA, NA, 0.5), 2)
bars3 <- rep(c(0.1, NA, NA, NA, NA, NA, NA, 0.1), 2)

ggplot(Titanic.ag, aes(x = Class, y = Freq, fill = Sex)) + 
  geom_bar(position = "fill", stat = "identity") + 
  facet_grid(~Age) +
  geom_errorbar(aes(y = bars1, ymin = bars1, ymax = bars1), color="Orange",lty=2) + 
  geom_errorbar(aes(y=bars2,ymin=bars2,ymax=bars2),color="White",lty=2)+
  geom_errorbar(aes(y=bars3,ymin=bars3,ymax=bars3),color="Purple",lty=2)+
  scale_fill_manual(values = c("darkgreen", "darkblue") ) + 
  labs(col = "Reference",
       fill= "",
       y = "Proportion",
       x = "Class")

enter image description here

Upvotes: 11

Related Questions