adding geom_text from different dataset to geom_bar

8.4k views Asked by At

I have a bar plot with a facet grid, and I would like to add the number of observations per sub-plot which are stored in a separate dataframe.

The bar plot is produced with

bar.plot <- ggplot(BarDiff.m.s, aes(x=value.change, fill=incompatibility))+
  geom_bar(binwidth=1)+
  labs(x="score differences", y="count / years since start of PSA")+
  geom_vline(aes(xintercept=0), linetype="dotted")+
  theme(plot.title=element_text(face="bold", size=10),
        legend.position= "bottom")+
  scale_fill_brewer(palette="Set1")+
 facet_grid(years.since.peace ~ strategy.cm6.YP, space="free")

I tried to add the geom_text by adding after the geom_bar line

   geom_text(data=num.obs, aes(label=paste("obs=",num.obs),y=4,x=min(BarDiff.m.s$value.change)))

however, I obtain the error message

Error in eval(expr, envir, enclos) : object 'incompatibility' not found

Apparently, for some reason, I have to consider the "fill" variable in geom_text; I tried to add group=BarDiff.m.s$incompatibility to geom_text, but to no avail.

I have seen How to add custom labels from a dataset on top of bars using ggplot/geom_bar in R? , but if possible I would like to keep the two data.frames separate and understand how to solve the "fill" issue. Any suggestion would be very much welcome! thx.

enter image description here

The pertaining data for the plot is

BarDiff.m.s <- structure(list(value.change = c(-1, -1, -2, -2, 1, NA, 0, -2, 
-1, -2, NA, 2, -3, NA, NA, -3, -2, -1, -4, -1, -3, -1, 2, 2, 
NA, 1, -1, 0, 0, -2, -2, -2, -1, 1, NA, -1, -1, 0, -2, NA, 0, 
-4, NA, NA, NA, -3, -1, -4, -2, -3, -2, -1, 0, NA, NA, 0, -4, 
NA, -2, -2, -3, -1, NA, NA, -1, -1, 0, -2, NA, 0, NA, NA, NA, 
NA, -4, NA, -4, -2, -3, -2, -2, 2, NA, NA, 0, -4, -2, NA, NA, 
NA, NA, NA, NA, -1, NA, NA, NA, NA, 0, NA, NA, NA, NA, NA, NA, 
-4, NA, -2, -1, -2, NA, NA, NA, NA, -3, 1), incompatibility = structure(c(1L, 
1L, 1L, 2L, 2L, 2L, 2L, 1L, 2L, 1L, 2L, 1L, 1L, 1L, 2L, 2L, 2L, 
2L, 1L, 2L, 2L, 2L, 1L, 1L, 2L, 1L, 2L, 1L, 1L, 1L, 1L, 1L, 2L, 
2L, 2L, 2L, 1L, 2L, 1L, 2L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 1L, 2L, 
2L, 2L, 1L, 1L, 2L, 1L, 2L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 
1L, 2L, 1L, 2L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 1L, 2L, 2L, 2L, 1L, 
1L, 2L, 1L, 2L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 1L, 2L, 1L, 
2L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 1L, 2L, 2L, 2L, 1L, 1L, 2L, 1L, 
2L, 1L, 1L), .Label = c("territory", "government"), class = "factor"), 
    years.since.peace = structure(c(5L, 5L, 5L, 5L, 5L, 5L, 5L, 
    5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 
    5L, 5L, 5L, 5L, 5L, 5L, 5L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 
    6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 
    6L, 6L, 6L, 6L, 6L, 6L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 
    7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 
    7L, 7L, 7L, 7L, 7L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 
    8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 
    8L, 8L, 8L, 8L), .Label = c("y0", "y10", "y15", "y20", "diff.y5", 
    "diff.y10", "diff.y15", "diff.y20"), class = "factor"), strategy.cm6.YP = structure(c(4L, 
    4L, 5L, 1L, 1L, 4L, 3L, 4L, 3L, 1L, 1L, 1L, 3L, 4L, 4L, 4L, 
    4L, 3L, 3L, 4L, 4L, 4L, 1L, 4L, 5L, 1L, 4L, 1L, 4L, 4L, 4L, 
    5L, 1L, 1L, 4L, 3L, 4L, 3L, 1L, 1L, 1L, 3L, 4L, 4L, 4L, 4L, 
    3L, 3L, 4L, 4L, 4L, 1L, 4L, 5L, 1L, 4L, 1L, 4L, 4L, 4L, 5L, 
    1L, 1L, 4L, 3L, 4L, 3L, 1L, 1L, 1L, 3L, 4L, 4L, 4L, 4L, 3L, 
    3L, 4L, 4L, 4L, 1L, 4L, 5L, 1L, 4L, 1L, 4L, 4L, 4L, 5L, 1L, 
    1L, 4L, 3L, 4L, 3L, 1L, 1L, 1L, 3L, 4L, 4L, 4L, 4L, 3L, 3L, 
    4L, 4L, 4L, 1L, 4L, 5L, 1L, 4L, 1L, 4L), .Label = c("none", 
    "only offered", "communication/\nfacilitation", "procedural", 
    "directive", "unspecified"), class = "factor")), .Names = c("value.change", 
"incompatibility", "years.since.peace", "strategy.cm6.YP"), class = "data.frame", row.names = c(1298L, 
1299L, 1335L, 1339L, 1340L, 1341L, 1344L, 1372L, 1379L, 1386L, 
1387L, 1402L, 1415L, 1439L, 1449L, 1454L, 1455L, 1456L, 1463L, 
1466L, 1470L, 1496L, 1497L, 1498L, 1525L, 1536L, 1542L, 1546L, 
1563L, 1617L, 1618L, 1654L, 1658L, 1659L, 1660L, 1663L, 1691L, 
1698L, 1705L, 1706L, 1721L, 1734L, 1758L, 1768L, 1773L, 1774L, 
1775L, 1782L, 1785L, 1789L, 1815L, 1816L, 1817L, 1844L, 1855L, 
1861L, 1865L, 1882L, 1936L, 1937L, 1973L, 1977L, 1978L, 1979L, 
1982L, 2010L, 2017L, 2024L, 2025L, 2040L, 2053L, 2077L, 2087L, 
2092L, 2093L, 2094L, 2101L, 2104L, 2108L, 2134L, 2135L, 2136L, 
2163L, 2174L, 2180L, 2184L, 2201L, 2255L, 2256L, 2292L, 2296L, 
2297L, 2298L, 2301L, 2329L, 2336L, 2343L, 2344L, 2359L, 2372L, 
2396L, 2406L, 2411L, 2412L, 2413L, 2420L, 2423L, 2427L, 2453L, 
2454L, 2455L, 2482L, 2493L, 2499L, 2503L, 2520L))

The data for the number of observations is:

num.obs <- structure(list(years.since.peace = structure(c(5L, 5L, 5L, 5L, 
6L, 6L, 6L, 6L, 7L, 7L, 7L, 7L, 8L, 8L, 8L, 8L), .Label = c("y0", 
"y10", "y15", "y20", "diff.y5", "diff.y10", "diff.y15", "diff.y20"
), class = "factor"), strategy.cm6.YP = structure(c(1L, 3L, 4L, 
5L, 1L, 3L, 4L, 5L, 1L, 3L, 4L, 5L, 1L, 3L, 4L, 5L), .Label = c("none", 
"only offered", "communication/\nfacilitation", "procedural", 
"directive", "unspecified"), class = "factor"), num.obs = c(8L, 
5L, 14L, 2L, 8L, 5L, 14L, 2L, 8L, 5L, 14L, 2L, 8L, 5L, 14L, 2L
)), .Names = c("years.since.peace", "strategy.cm6.YP", "num.obs"
), row.names = c(NA, -16L), class = "data.frame")
1

There are 1 answers

1
r.bot On BEST ANSWER

Move the fill aesthetic to geom_bar and change the y position for geom_text should get you what you want.

bar.plot <- ggplot(BarDiff.m.s, aes(x = value.change)) +
  geom_bar(aes( fill = incompatibility), binwidth = 1) +
  geom_text(data = num.obs, aes(label = paste("obs=", num.obs),y = 4, x = -4)) +
  labs(x = "score differences", y = "count / years since start of PSA") +
  geom_vline(aes(xintercept = 0), linetype = "dotted") +
  theme(plot.title = element_text(face = "bold", size = 10),
        legend.position = "bottom") +
  scale_fill_brewer(palette = "Set1") +
  facet_grid(years.since.peace ~ strategy.cm6.YP, space = "free")

bar.plot

If you want the text labels to be positioned by value.change in the first data set, probably the easiest way to get that is to merge the relevant column into the second data set.