This is an awkward question, and I don't want to offend anyone. I'd like to recreate the following figure in R. The plot is based on a published work. I'm not sure what the backstory is. How should I proceed using ggplot?

- 902
- 4
- 10
-
1I'd use ggh4x::geom_pointpath https://stackoverflow.com/q/70534245/7941188 – tjebo Apr 11 '22 at 10:52
-
1and for the background, you could use ggpattern. https://coolbutuseless.github.io/2020/04/01/introducing-ggpattern-pattern-fills-for-ggplot/ – tjebo Apr 11 '22 at 10:52
-
1@tjebo surely you mean `geom_textsegment` from geomtextpath! ;) And since R 4.1 you can get pattern and gradient fills in grid graphics directly - see below. – Allan Cameron Apr 11 '22 at 12:19
3 Answers
We can get arbitrarily close in ggplot as long as we are prepared to put the work into preparing the data.
Firstly, we need a data frame of the labels and the segment positions:
df <- data.frame(text = c('Africa', 'Asia', 'Countries in transition',
'North America', 'South America',
'Western Europe'),
y = 6:1,
x = c(0, 0, 1.5, 6.5, 0, 6),
xend = c(5, 6.5, 6, 10, 5, 10))
Secondly, we need the x axis labels:
xlabs <- c('early EIAs,\noften donor\nfunded',
'EIA regulation/guidance\nenacted, increasing EIAs\nquality variable',
'EIA mainstream,\nfine-tuning of\nregulation/guidance')
If you want the polka-dot background, it is possible to do this via ggpattern
, but if you want to stick to CRAN-based repositories, we can now use a pattern fill in grid
, which you already have installed. You will need to have the latest version of R installed to do this though:
library(grid)
small_circ1 <- circleGrob(
r = unit(0.5, 'mm'),
gp = gpar(fill = '#d4dbed', col = '#d4dbed')
)
small_circ2 <- circleGrob(
r = unit(0.5, 'mm'),
gp = gpar(fill = '#c5d0e5', col = '#c5d0e5')
)
small_circle_pattern1 <- pattern(
small_circ1,
width = unit(2.5, 'mm'),
height = unit(2.5, 'mm'),
extend = 'repeat'
)
small_circle_pattern2 <- pattern(
small_circ2,
width = unit(2.5, 'mm'),
height = unit(2.5, 'mm'),
extend = 'repeat'
)
Now we are ready to plot. The easiest way to get the broken line segments with text is using geom_textsegment
from geomtextpath
library(geomtextpath)
ggplot(df, aes(x, y)) +
annotation_custom(rectGrob(gp = gpar(fill = small_circle_pattern1,
col = NA)),
ymin = -Inf, ymax = Inf, xmin = 2, xmax = 6) +
annotation_custom(rectGrob(gp = gpar(fill = '#e6e9f9', col = '#e6e9f9')),
ymin = -Inf, ymax = Inf, xmin = 6, xmax = 10) +
annotation_custom(rectGrob(gp = gpar(fill = small_circle_pattern2,
col = NA)),
ymin = -Inf, ymax = Inf, xmin = 6, xmax = 10) +
geom_textsegment(aes(yend = y, xend = xend, label = text, fontface = 2),
colour = '#556fa1', linewidth = 0.7, size = 5) +
scale_x_continuous(breaks = c(0, 2, 6),
labels = xlabs, expand = c(0, 0)) +
theme_classic() +
theme(axis.text.x = element_text(size = 14, hjust = 0,
margin = margin(20, 0, 0, 0),
colour = '#556fa1'),
axis.line = element_line(colour = '#556fa1'),
axis.ticks = element_blank(),
axis.text.y = element_blank(),
axis.title = element_blank())

- 147,086
- 7
- 49
- 87
-
thank you for your explanation and code! When I run the first part I receive this error Error in pattern(small_circ1, width = unit(2.5, "mm"), height = unit(2.5, : could not find function "pattern". I assume this is on my side? Is this because some libraries are overlapping? – user11418708 Apr 11 '22 at 12:27
-
@user11418708 it is most likely because you do not have the latest version of R (and grid) installed. If you are unable to update, the best thing would be to simply change the polka-dot backgrounds to plain colours. Just set the `fill = ` inside the `annotation_custom` call to a colour of your choice. – Allan Cameron Apr 11 '22 at 12:33
-
hah! I kind of suspected that geom_textpath would be the better go to. Still marveling about all those cool stuff one can do with it – tjebo Apr 11 '22 at 12:34
-
1@tjebo thanks. I have been a bit dismayed by some of the ugly geomtextpath examples popping up on Twitter (though there are some very nice ones too). I thought this plot makes a reasonable use case though. – Allan Cameron Apr 11 '22 at 12:37
-
1I think `ggpattern` is in CRAN now (https://cran.r-project.org/web/packages/ggpattern/index.html) – benson23 Apr 11 '22 at 15:29
It remains unclear, how detailed the reproduction ought to be (same background or same in general=). It is also unclear, which graphics system you want to work in. Should you want to try that in base graphics, the following might provide you with a workable starting point:
dat <- data.frame(continent = c("Afrika", "Asia", "North America",
"South America", "Europe"),
from = c(0, 0, 6, 0, 5),
to = c(4, 5.5, 10, 5, 10))
dat$mean <- (dat$from + dat$to) / 2
plot(NA, xlim = c(0, 10), ylim = c(0,6), xaxt = "n", yaxt = "n",
xlab = "", ylab = "")
for(i in 1:5){
print(c(dat$from[i], dat$to[i]))
lines(x = c(dat$from[i], dat$to[i]),
y = c(6-i, 6-i),
col = "lightblue", lwd = 2)
}
text(dat$mean, y = (5:1)+.3, labels = dat$continent,
col = "lightblue")

- 4,272
- 1
- 13
- 23
-
-
1In base graphics, you can add text to the axes using the `axis` command. `axis(side = 1, labels = c("A\na", "B\nb", "quite some text\nhere"), at = c(2, 4, 7), lwd.ticks = -1)`. – Bernhard Apr 11 '22 at 11:58
-
-
I just saw from the question tags that you did mean to use `ggplot2`. It will be possible to reproduce this with `ggplot2` but that is another answer. – Bernhard Apr 11 '22 at 11:59
As a mere starting point on how to possibly approach the problem in ggplot2
:
dat <- data.frame(no = 1:5,
continent = c("Afrika", "Asia", "North America",
"South America", "Europe"),
from = c(0, 0, 6, 0, 5),
to = c(4, 5.5, 10, 5, 10))
library(ggplot2)
ggplot(dat) +
geom_segment(aes(x = from, y = 6-no, xend = to, yend = 6-no), lwd = 2) +
geom_text(aes(x = mean, y = 6.2-no, label = continent)) +
theme_bw()

- 4,272
- 1
- 13
- 23