Reputation: 337
I am attempting to make summary scatter plots that have error bars for both the x and y axes. I want the error bar hashes to be the same size. However, because I have axes that are of different scale (eg. urchin abundance vs. coral growth rates), my error bars hashes are not the same size.
I have utilized the "width" and "height" arguments for the geom_errorbar()
and geom_errorbarh()
to change the widths and heights manually. However, because I have many figures, I want to see if there is a way to code for the error bar hashes to be the same size generally so that I can use this code on other figures with different axes.
urchin_vs_growth_summary_data <- structure(list(Site_long = c("Waikiki", "Waikiki", "Hanauma Bay",
"Hanauma Bay"), Treatment_long = c("Closed", "Open", "Closed",
"Open"), growth_mean = c(1.60941173649527, 1.40241172055135,
0.977166214960325, 1.99458408579477), growth_sd = c(0.685274483494003,
0.7123570094737, 0.303273008779028, 1.00414981259471), growth_lower = c(1.41159003273825,
1.18762800080554, 0.853355527582455, 1.58464164143337), growth_upper = c(1.80723344025229,
1.61719544029716, 1.1009769023382, 2.40452653015617), urchin_mean = c(0.166666666666667,
0.375, 3.66666666666667, 22.75), urchin_sd = c(0.372677996249965,
0.414578098794425, 2.73353657780945, 17.3066701977398), urchin_lower = c(0.0590837959386828,
0.255321611530458, 2.87756262714768, 17.7539946512794), urchin_upper = c(0.27424953739465,
0.494678388469542, 4.45577070618566, 27.7460053487206), Shelter = structure(c(1L,
2L, 1L, 2L), .Label = c("Low", "High"), class = "factor")), row.names = c(NA,
-4L), groups = structure(list(Site_long = c("Hanauma Bay", "Waikiki"
), .rows = list(3:4, 1:2)), row.names = c(NA, -2L), class = c("tbl_df",
"tbl", "data.frame"), .drop = TRUE), class = c("grouped_df",
"tbl_df", "tbl", "data.frame"))
urchin_vs_growth_plot <- ggplot(data = urchin_vs_growth_summary_data,
aes(x = urchin_mean, y = growth_mean,
fill = interaction(Site_long, Shelter),
shape = interaction(Site_long, Shelter))) +
geom_point(aes(size = 5)) +
ggtitle("Urchin Abundance vs. Coral Growth") +
scale_x_continuous(breaks = seq(0,24,3)) +
scale_y_continuous(breaks = seq(0, 3, 0.5)) +
scale_shape_manual(name = 'Site x Shelter', values = c(21, 24, 21, 24),
labels = c("Hanauma Bay - Low", "Waikiki - Low",
"Hanauma Bay - High", "Waikiki - High")) +
scale_fill_manual(name = "Site x Shelter", values = c(NA, NA, 1, 1),
labels = c("Hanauma Bay - Low", "Waikiki - Low",
"Hanauma Bay - High", "Waikiki - High")) +
geom_smooth(aes(group = 1), method ="lm", show.legend = FALSE) +
guides(size = FALSE, linetype = FALSE,
shape = guide_legend(override.aes = list(size = 4.5)),
color = guide_legend(override.aes = list(fill = NA))) +
theme(text = element_text(size = 15)) +
geom_errorbar(aes(ymin = growth_lower, ymax = growth_upper), width = 0.5) +
geom_errorbarh(aes(xmin = urchin_lower, xmax = urchin_upper), height = 0.5) +
labs(x = "Mean urchin abundance ± SEM",
y = expression(paste("Mean coral growth (cm"^"2","/quarter) ± 95% SEM"))) +
theme_bw() +
theme(panel.border = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.line = element_line(colour = "black"),
axis.title = element_text(size = rel(1.5)),
axis.title.y = element_text(size = rel(1)),
axis.text = element_text(size = rel(1.5)),
axis.text.y = element_text(angle = 90),
legend.text = element_text(size = rel(1)),
legend.title = element_text(size = rel(1), face = "bold"),
legend.position = "none",
plot.title = element_text(size = 20, hjust = 0.5, vjust = -1.5))
I am looking to create general code that will allow me to scale error bar hashes to be the same size in all my figures (most if not all have x and y axes with different units or scales). Thanks for your input!
Upvotes: 3
Views: 4035
Reputation: 2816
One approach would be to create the plot, extract the x and y ranges (as described here), and scale the error bar hashes based on those ranges. This will produce hashes that are proportional to the overall aspect ratio of the plot; the horizontal and vertical hashes will be exactly equal only when the plot itself is perfectly square. But if you're only looking for a way to make the hashes look roughly similar, that might be good enough.
Create the plot (without error bars):
urchin_vs_growth_plot <- ggplot(data = urchin_vs_growth_summary_data,
aes(x = urchin_mean, y = growth_mean,
fill = interaction(Site_long, Shelter),
shape = interaction(Site_long, Shelter))) +
geom_point(size = 5) +
ggtitle("Urchin Abundance vs. Coral Growth") +
scale_x_continuous(breaks = seq(0,24,3)) +
scale_y_continuous(breaks = seq(0, 3, 0.5)) +
scale_shape_manual(name = 'Site x Shelter', values = c(21, 24, 21, 24),
labels = c("Hanauma Bay - Low", "Waikiki - Low",
"Hanauma Bay - High", "Waikiki - High")) +
scale_fill_manual(name = "Site x Shelter", values = c(NA, NA, 1, 1),
labels = c("Hanauma Bay - Low", "Waikiki - Low",
"Hanauma Bay - High", "Waikiki - High")) +
geom_smooth(aes(group = 1), method ="lm", show.legend = FALSE) +
guides(size = FALSE, linetype = FALSE,
shape = guide_legend(override.aes = list(size = 4.5)),
color = guide_legend(override.aes = list(fill = NA))) +
theme(text = element_text(size = 15)) +
labs(x = "Mean urchin abundance ± SEM",
y = expression(paste("Mean coral growth (cm"^"2","/quarter) ± 95% SEM"))) +
theme_bw() +
theme(panel.border = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.line = element_line(colour = "black"),
axis.title = element_text(size = rel(1.5)),
axis.title.y = element_text(size = rel(1)),
axis.text = element_text(size = rel(1.5)),
axis.text.y = element_text(angle = 90),
legend.text = element_text(size = rel(1)),
legend.title = element_text(size = rel(1), face = "bold"),
legend.position = "none",
plot.title = element_text(size = 20, hjust = 0.5, vjust = -1.5))
Set hash width to one-twentieth the size of the x and y axes (adjust the actual value as desired, of course):
hash.width.x = diff(layer_scales(urchin_vs_growth_plot)$x$range$range) / 20
hash.width.y = diff(layer_scales(urchin_vs_growth_plot)$y$range$range) / 20
Add error bars:
urchin_vs_growth_plot = urchin_vs_growth_plot +
geom_errorbar(aes(ymin = growth_lower, ymax = growth_upper), width = hash.width.x) +
geom_errorbarh(aes(xmin = urchin_lower, xmax = urchin_upper), height = hash.width.y)
The result:
To do this for many plots, you could create a little function that takes the first plot (with no error bars), gets the axis ranges, and adds error bars appropriately; then wrap all your plots in that function.
Upvotes: 2