I'm making a plot with facet_grid()
and use both geom_point()
and geom_errorbar()
to make something resembling a coefficient plot, but where I have two groups I'm plotting on top of each other.
In order to not make them overlap, I've specified position = position_jitter(seed=100)
within both geom_point()
and geom_errorbar()
, so that the points and bars stay together.
However, because jittering is inherently random (as far as I'm aware), across different facets I'm ending up with the points/bars for each group sometimes being on one side and then sometimes being on the other. See below for a visual example of what I mean.
The distance between them also seems to be random; sometimes the points/bars are right next to each other, sometimes a bit far apart.
So my question is: Is there a way to be able to specify the magnitude and direction of the jittering, by group? (Or perhaps a totally different way to do this without jitter)?
EDIT: ADDED CODE/DATA HERE IN CASE THERE'S A NON-JITTER WAY TO DO THIS
library(ggplot2)
library(dplyr)
library(patchwork)
dex$group <- factor(dex$outcome_type2, c("TPW", "Money", "Support"))
plot_fun <- function(.data) {
remove_facet <- if (unique(.data$group) %in% c("TPW", "Money")) {
theme(strip.text.y = element_blank())
}
.data$outcome_type <- forcats::fct_relevel(
.data$outcome_type,
"TPW T", "TPW I", "TPW E", "Money1", "Money2", "Support1", "Support2")
.data %>%
tidyr::complete(outcome_type, wave = unique(dex$wave), attend) %>%
ggplot(aes(x = outcome_type, y = Mean, color = attend,
ymin = LowCI, ymax = UpperCI)) +
geom_errorbar(linewidth = 1,
width = 0,
position = position_jitter(width = 0.25, seed = 100)) +
geom_point(size = 1.9,
shape = 16,
position = position_jitter(width = 0.25, seed = 100)) +
facet_grid(wave ~ outcome_type,
scales = "free") +
scale_fill_manual(values = c("Attend" = "red",
"Not_Attend" = "blue"),
aesthetics = c("fill", "color"), guide = guide_legend(element_blank)) +
theme_classic(base_size = 13) +
remove_facet
}
dex_split <- split(dex, dex$group)
lapply(dex_split, plot_fun) %>%
wrap_plots() +
plot_layout(widths = c(3, 2, 2),
guides = "collect") &
labs(x = NULL, y = NULL, fill = NULL) &
theme(axis.text.x = element_blank(),
strip.text.x = element_text(size = 11),
legend.position = "bottom",
legend.title = element_blank(),
plot.title = element_text(size = 15,
face = "bold"),
plot.subtitle = element_text(size = 13),
panel.grid.major = element_blank())
Data:
dex <- structure(list(v1 = c("tpw_e_w1", "tpw_e_w1", "tpw_e_w2", "tpw_e_w2",
"tpw_e_w3", "tpw_e_w3", "tpw_i_w1", "tpw_i_w1", "tpw_i_w2", "tpw_i_w2",
"tpw_i_w3", "tpw_i_w3", "tpw_t_w1", "tpw_t_w1", "tpw_t_w2", "tpw_t_w2",
"tpw_t_w3", "tpw_t_w3", "money1_w1", "money1_w1", "money1_w3",
"money1_w3", "money2_w2", "money2_w2", "money2_w3", "money2_w3",
"support1_score_w1", "support1_score_w1", "support1_score_w3",
"support1_score_w3", "support2_score_w1", "support2_score_w1",
"support2_score_w3", "support2_score_w3"), attend = c("Not_Attend",
"Attend", "Not_Attend", "Attend", "Not_Attend", "Attend", "Not_Attend",
"Attend", "Not_Attend", "Attend", "Not_Attend", "Attend", "Not_Attend",
"Attend", "Not_Attend", "Attend", "Not_Attend", "Attend", "Not_Attend",
"Attend", "Not_Attend", "Attend", "Not_Attend", "Attend", "Not_Attend",
"Attend", "Not_Attend", "Attend", "Not_Attend", "Attend", "Not_Attend",
"Attend", "Not_Attend", "Attend"), Mean = c(-0.01, 0.32, -0.01,
0.35, -0.03, 0.65, 0, 0.12, 0, 0.26, -0.03, 0.65, -0.01, 0.23,
-0.01, 0.32, -0.03, 0.69, 0.01, 0.45, 0, 0.44, 0, 0.56, 0.1,
0.73, 0.01, -0.23, 0, -0.12, 0.01, -0.16, -0.01, -0.22), LowCI = c(-0.05,
0.07, -0.05, 0.05, -0.08, 0.34, -0.04, -0.12, -0.05, -0.05, -0.07,
0.35, -0.05, -0.02, -0.05, 0.02, -0.08, 0.38, -0.04, 0.17, -0.05,
0.17, -0.05, 0.25, 0.05, 0.39, -0.03, -0.45, -0.05, -0.39, -0.03,
-0.32, -0.06, -0.5), UpperCI = c(0.03, 0.56, 0.04, 0.65, 0.01,
0.97, 0.04, 0.37, 0.04, 0.57, 0.02, 0.95, 0.03, 0.47, 0.04, 0.62,
0.01, 0.99, 0.05, 0.73, 0.04, 0.71, 0.04, 0.87, 0.15, 1.07, 0.05,
-0.01, 0.05, 0.16, 0.06, 0, 0.05, 0.06), outcome_type = c("TPW E",
"TPW E", "TPW E", "TPW E", "TPW E", "TPW E", "TPW I", "TPW I",
"TPW I", "TPW I", "TPW I", "TPW I", "TPW T", "TPW T", "TPW T",
"TPW T", "TPW T", "TPW T", "Money1", "Money1", "Money1", "Money1",
"Money2", "Money2", "Money2", "Money2", "Support1", "Support1",
"Support1", "Support1", "Support2", "Support2", "Support2", "Support2"
), wave = c("Wave 1", "Wave 1", "Wave 2", "Wave 2", "Wave 3",
"Wave 3", "Wave 1", "Wave 1", "Wave 2", "Wave 2", "Wave 3", "Wave 3",
"Wave 1", "Wave 1", "Wave 2", "Wave 2", "Wave 3", "Wave 3", "Wave 1",
"Wave 1", "Wave 3", "Wave 3", "Wave 2", "Wave 2", "Wave 3", "Wave 3",
"Wave 1", "Wave 1", "Wave 3", "Wave 3", "Wave 1", "Wave 1", "Wave 3",
"Wave 3"), outcome_type2 = c("TPW", "TPW", "TPW", "TPW", "TPW",
"TPW", "TPW", "TPW", "TPW", "TPW", "TPW", "TPW", "TPW", "TPW",
"TPW", "TPW", "TPW", "TPW", "Money", "Money", "Money", "Money",
"Money", "Money", "Money", "Money", "Support", "Support", "Support",
"Support", "Support", "Support", "Support", "Support")), row.names = c(NA,
-34L), spec = structure(list(cols = list(v1 = structure(list(), class = c("collector_character",
"collector")), attend = structure(list(), class = c("collector_character",
"collector")), Mean = structure(list(), class = c("collector_double",
"collector")), LowCI = structure(list(), class = c("collector_double",
"collector")), UpperCI = structure(list(), class = c("collector_double",
"collector")), outcome_type = structure(list(), class = c("collector_character",
"collector")), wave = structure(list(), class = c("collector_character",
"collector")), outcome_type2 = structure(list(), class = c("collector_character",
"collector"))), default = structure(list(), class = c("collector_guess",
"collector")), delim = ","), class = "col_spec"), class = c("spec_tbl_df",
"tbl_df", "tbl", "data.frame"))