Search code examples
rggplot2geom-text

adding geom_text from different dataset to geom_bar


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")

Solution

  • 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.