Search code examples
rggplot2facetfacet-wraperrorbar

How to use "pointrange" function with facet_wrap?


Suppose I have the mock data below:

example <- structure(list(country = c("Italy", "Italy", "Italy", "Italy", 
                       "Italy", "Italy", "Italy", "Italy", "Italy", "Austria", "Austria", 
                       "Austria", "Austria", "Austria", "Austria", "Austria", "Austria", 
                       "Austria", "Germany", "Germany", "Germany", "Germany", "Germany", 
                       "Germany", "Germany", "Germany", "Germany"), date = c(1000, 1200, 
                                                                             1300, 1400, 1500, 1600, 1700, 1750, 1800, 1000, 1200, 1300, 1400, 
                                                                             1500, 1600, 1700, 1750, 1800, 1000, 1200, 1300, 1400, 1500, 1600, 
                                                                             1700, 1750, 1800), fit.0.025quant = c(0.828708096446602, 2.4420979507703, 
                                                                                                                   2.62414677055878, 2.63329989559212, 2.53354700323539, 1.65000976000248, 
                                                                                                                   0.752830563369601, 0.662779471528981, 0.633370287301323, 0.631451022500498, 
                                                                                                                   0.649758893615039, 0.650073875566409, 0.650081079761908, 0.650081254451237, 
                                                                                                                   0.650081079637564, 0.650073875566409, 0.649758893615039, 0.631451022500498, 
                                                                                                                   0.631451022500498, 0.649758893615039, 0.650073875566409, 0.650081079761908, 
                                                                                                                   0.650081254451237, 0.650081079637564, 0.650073875566409, 0.649758893615039, 
                                                                                                                   0.631451022500498), fit.mean = c(1.1903534469417, 2.83004352114819, 
                                                                                                                                                    2.9806558994056, 2.9875417232584, 2.90452442326781, 1.99995962905406, 
                                                                                                                                                    1.09518775382276, 1.01031925709265, 1.00141486550036, 0.999999948657743, 
                                                                                                                                                    0.999999976399706, 0.999999973245836, 0.999999973352837, 0.999999968778261, 
                                                                                                                                                    0.999999973272607, 0.999999973245836, 0.999999976399706, 0.999999948657743, 
                                                                                                                                                    0.999999948657743, 0.999999976399706, 0.999999973245836, 0.999999973352837, 
                                                                                                                                                    0.999999968778261, 0.999999973272607, 0.999999973245836, 0.999999976399706, 
                                                                                                                                                    0.999999948657743), fit.0.975quant = c(1.61387277731566, 3.17388806195699, 
                                                                                                                                                                                           3.32641599958393, 3.33420679881888, 3.24684592681982, 2.34991876603736, 
                                                                                                                                                                                           1.46568276539042, 1.36373981325973, 1.37069925216457, 1.36867909649403, 
                                                                                                                                                                                           1.35026553811603, 1.34998364436204, 1.34997767551695, 1.34997753475153, 
                                                                                                                                                                                           1.34997767544381, 1.34998364436204, 1.35026553811603, 1.36867909649403, 
                                                                                                                                                                                           1.36867909649403, 1.35026553811603, 1.34998364436204, 1.34997767551695, 
                                                                                                                                                                                           1.34997753475153, 1.34997767544381, 1.34998364436204, 1.35026553811603, 
                                                                                                                                                                                           1.36867909649403)), row.names = c(NA, 27L), class = "data.frame")

There are three groups (country).

I want to use "pointrange" function for every country, so that for every date, the mean of a pointrange was equal to the corresponding fit.mean, upper point to the corresponding "fit.0.975quant", lower point to "fit.0.025quant"

For now, I can only suggest chopping the data and then plotting each country separately, like this:

example.italy <- example[-c(10:27), ]
example.italy$date <- as.factor(example.italy$date)

figure <- ggplot(example.italy,
             aes(x = date, y = fit.mean)) + aes(y = fit.mean, group=1) + xlab("Time periods") + ylab("DV") + theme(legend.position = "none") + annotate("pointrange", x = "1000", y = example.italy[1,4], ymin = example.italy[1,3], ymax = example.italy[1,5], 
       colour = "red", size = 1.5) + annotate("pointrange", x = "1200", y = example.italy[2,4], ymin = example.italy[2,3], ymax = example.italy[2,5], 
       colour = "red", size = 1.5) + annotate("pointrange", x = "1300", y = example.italy[3,4], ymin = example.italy[3,3], ymax = example.italy[3,5], 
       colour = "red", size = 1.5) + annotate("pointrange", x = "1400", y = example.italy[4,4], ymin = example.italy[4,3], ymax = example.italy[4,5], 
       colour = "red", size = 1.5) + annotate("pointrange", x = "1500", y = example.italy[5,4], ymin = example.italy[5,3], ymax = example.italy[5,5], 
       colour = "red", size = 1.5) + annotate("pointrange", x = "1600", y = example.italy[6,4], ymin = example.italy[6,3], ymax = example.italy[6,5], 
       colour = "red", size = 1.5) + annotate("pointrange", x = "1700", y = example.italy[7,4], ymin = example.italy[7,3], ymax = example.italy[7,5], 
       colour = "red", size = 1.5) + annotate("pointrange", x = "1750", y = example.italy[8,4], ymin = example.italy[8,3], ymax = example.italy[8,5], 
       colour = "red", size = 1.5) + annotate("pointrange", x = "1800", y = example.italy[9,4], ymin = example.italy[9,3], ymax = example.italy[9,5], 
       colour = "red", size = 1.5)

Which will produce:

enter image description here

But what if the data contains 15-20 groups (countries)? Then chopping the data and plotting each country separately would be inpracticable.

Any suggestions guys on how to plot pointranges across different facets in one go?

You can suggest other functions similar to pointrange (may be errorbars?). Basically, for every row in data, I want to show the range spanning from "fit.0.025quant" to "fit.0.975quant", and fit.mean can be dropped.


Solution

  • You need to read a bit into ggplot. Instead of using annotate, I suggest to use geom_pointrange, and then you can simply pass the columns as aesthetics into a single (!) call to that geom. Using facet_wrap then becomes really easy.

    ggplot(example, aes(x = date, y = fit.mean)) +
      geom_pointrange(aes(ymin = fit.0.025quant, ymax = fit.0.975quant), color = "red") +
      facet_wrap(~country)
    

    Created on 2023-04-03 with reprex v2.0.2