I'm trying to recreate the following plot as a ggplot2
multilayered object but I think I'm having a harder time than what I thought.
Right now I've been able to sketch out the general idea as a stack of three layers:
geom_rect
for vertical coloursgeom_rect
for horizontal striped/dotted patterns
(- geom_point
for what will be plotted on that)but some big issues appeared:
ggplot2
seems not to interpret my colours stored in a dataframe (neither as names [e.g. 'red'] nor as hexadecimals values). I tried to provide them as a named vector (see first solution here) but with no luck.
ggpattern
but it applies the same pattern across the whole chart spacegeom_rect
, but had the same outcome of issue n.1geom_point
does not recognise the field 'wtype' returning object not found
Unfortunately, I haven't been able to solve them after quite a bit of reading&testing at least half of StackOverflow.
I know it's a complex question but looked weird to open 3 different questions for what -to me- relates to a general problem of properly managing multiple layers.
Here the code and some data:
vparam.df = data.frame(
ymin = 0,
ymax = 15,
xmin = c(0, 7, 14, 21, 28),
xmax = c(7, 14, 21, 28, 35)
, xlabel = c(3.5, 10.5, 17.5, 24.5, 31.5)
, ylabel = rep(-1,5)
, fill = c("#1e8449", "#52be80", "#f4d03f", "#f39c12","#c0392b")
#, fill = c("red", "orange","yellow","lightgreen","darkgreen")
, label = c("low","mod. low","medium","pretty strong","strong")
)
hparam.df = data.frame(
xmin = 0,
xmax = 35,
ymin = c(5, 10),
ymax = c(10, 15)
, xlabel = rep(-1, 2)
, ylabel = c(7.5, 12.5)
#, fill = c("dots", "diagonals") # THIS IS HOW I IMAGINE IT
, fill = c( "#52be80", "#c0392b")
, label = c("medium","strong")
)
df = structure(list(xvar = c(13, 20, 16, 11, 21, 13, 13, 7, 9, 16,
11, 13, 15, 13, 22, 16), yvar = c(0, 2, 2, 4, 2, 4, 7, 5, 5,
0, 7, 2, 2, 7, 2, 7), wtype = c("Type4", "Type3",
"Type4", "Type4", "Type1", "Type1",
"Type4", "Type1", "Type1", "Type1",
"Type3", "Type1", "Type2", "Type4",
"Type2", "Type1")), row.names = c(NA, -16L), class = c("tbl_df",
"tbl", "data.frame"))
ggplot(df, aes(x=xvar, y=yvar )) +
geom_rect(
data = vparam.df,
aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, fill = fill),
inherit.aes = FALSE
) +
geom_rect(
data = hparam.df,
aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, fill = fill), alpha = .2,
inherit.aes = FALSE
) +
geom_point( size=1 ) +
geom_text(data=vparam.df, aes(x=xlabel, y=ylabel, label=label), size=2) +
geom_text(data=hparam.df, aes(x=xlabel, y=ylabel, label=label), size=2,angle=90) +
scale_y_discrete( limits=seq(0,15,5) ) +
scale_x_discrete( limits=seq(0,35,7) ) +
theme( legend.position="")
You could use scale_fill_identity
and scale_pattern_identity
to make your life easier here. Rather than using your data, I have reproduced the plot from scratch here - the following is a full reprex:
library(ggplot2)
library(ggpattern)
data.frame(xmin = c(0, 7, 14, 21, 28, 0, 0),
xmax = c(7, 14, 21, 28, 35, 35, 35),
ymin = c(0, 0, 0, 0, 0, 5, 10),
ymax = c(15, 15, 15, 15, 15, 10, 15),
pat = c('none', 'none', 'none', 'none', 'none', 'circle', 'stripe'),
fill = c('#fe0003', '#ff8347', '#ffff01', '#02ff07', '#008203',
'#00000000', '#00000000')) |>
ggplot() +
geom_rect_pattern(aes(xmin = xmin, ymin = ymin, xmax = xmax, ymax = ymax,
fill = fill, pattern = pat), pattern_fill = 'black') +
annotation_custom(grid::textGrob(x = c(0.1, 0.3, 0.5, 0.7, 0.9, rep(-0.1, 3)),
y = c(rep(-0.1, 5), 1/6, 3/6, 5/6),
gp = grid::gpar(col = 'gray', fontface = 4),
label = c('basso', 'abbastanza\nbasso',
'medio', 'abbastanza\nmedio',
'forte', 'basso', 'medio', 'forte'))) +
geom_point(aes(x = xvar, y = yvar, color = wtype), size = 4, data = df) +
scale_fill_identity() +
scale_pattern_identity() +
scale_color_manual(values = c(Type1 = 'white', Type2 = 'black',
Type3 = 'gray', Type4 = 'violet')) +
scale_x_continuous(breaks = 0:5 * 7,
labels = ~ ifelse(.x == 0, 0,
paste0(.x, ' (', scales::percent(.x/35), ')'))) +
scale_y_continuous(breaks = 1:3 * 5,
labels = ~ paste0(.x, ' (', scales::percent(.x/15), ')')) +
coord_cartesian(expand = FALSE, clip = 'off') +
theme(axis.text = element_text(color = 'black'),
plot.margin = margin(10, 30, 30, 30),
panel.border = element_rect(fill = NA))