library(ggplot2)
library(Hmisc)
data(mtcars)
myplot <- ggplot(mtcars, aes(x = as.factor(cyl), y = qsec)) +
geom_boxplot() +
stat_summary(fun.y = mean, geom = "point", shape = 5, size = 2) +
stat_summary(fun.data = mean_cl_normal, geom = "errorbar",
width = 0.2)
produces
I'd like to dodge the mean and error bars a bit to the right, such that the error bars don't obscure the IQR line of the boxplot. Specifying position=position_dodge(.5) doesn't seem to work, because geom_errorbardoesn't know about geom_boxplot.
You can introduce a new variable which you use as the x offset for your errorbars:
library(ggplot2)
library(Hmisc)
data(mtcars)
mtcars$cyl.n <- as.numeric(as.factor(mtcars$cyl)) + .5
(myplot <- ggplot(mtcars, aes(x = as.factor(cyl), y = qsec)) +
geom_boxplot() +
stat_summary(aes(x = cyl.n), fun.y = mean, geom = "point", shape = 5, size = 2) +
stat_summary(aes(x = cyl.n), fun.data = mean_cl_normal, geom = "errorbar",
width = 0.2))
The as.numeric(as.factor(.)) makes sure that the new error bar is spaced at the same position as the boxplots but shifted by 0.5 units.
Related
I need some help to figure out to estimate the standard error using the following R script:
library(ggplot2)
library(ggpubr)
library(Hmisc)
data("ToothGrowth")
ToothGrowth$dose <- as.factor(ToothGrowth$dose)
head(ToothGrowth, 4)
theme_set(
theme_classic() +
theme(legend.position = "top")
)
# Initiate a ggplot
e <- ggplot(ToothGrowth, aes(x = dose, y = len))
# Add mean points +/- SD
# Use geom = "pointrange" or geom = "crossbar"
e + geom_violin(trim = FALSE) +
stat_summary(
fun.data = "mean_sdl", fun.args = list(mult = 1),
geom = "pointrange", color = "black"
)
# Combine with box plot to add median and quartiles
# Change fill color by groups, remove legend
e + geom_violin(aes(fill = dose), trim = FALSE) +
geom_boxplot(width = 0.2)+
scale_fill_manual(values = c("#00AFBB", "#E7B800", "#FC4E07"))+
theme(legend.position = "none")
Many thanks for the help
Kind regards
A couple of things. First, you need to reassign e when you add geom_violin and stat_summary. Otherwise, it isn't carrying those changes forward when you add the boxplot in the next step. Second, when you add the boxplot last, it is mapping over the points and error bars from stat_summary so it looks like they're disappearing. If you add the boxplot first and then stat_summary the points and error bars will be placed on top of the boxplot. Here is an example:
library(ggplot2)
library(ggpubr)
library(Hmisc)
data("ToothGrowth")
ToothGrowth$dose <- as.factor(ToothGrowth$dose)
theme_set(
theme_classic() +
theme(legend.position = "top")
)
# Initiate a ggplot
e <- ggplot(ToothGrowth, aes(x = dose, y = len))
# Add violin plot
e <- e + geom_violin(trim = FALSE)
# Combine with box plot to add median and quartiles
# Change fill color by groups, remove legend
e <- e + geom_violin(aes(fill = dose), trim = FALSE) +
geom_boxplot(width = 0.2)+
scale_fill_manual(values = c("#00AFBB", "#E7B800", "#FC4E07"))+
theme(legend.position = "none")
# Add mean points +/- SE
# Use geom = "pointrange" or geom = "crossbar"
e +
stat_summary(
fun.data = "mean_se", fun.args = list(mult = 1),
geom = "pointrange", color = "black"
)
You said in a comment that you couldn't see any changes when you tried mean_se and mean_cl_normal. Perhaps the above solution will have solved the problem, but you should see a difference. Here is an example just comparing mean_se and mean_sdl. You should notice the error bars are smaller with mean_se.
ggplot(ToothGrowth, aes(x = dose, y = len)) +
stat_summary(
fun.data = "mean_sdl", fun.args = list(mult = 1),
geom = "pointrange", color = "black"
)
ggplot(ToothGrowth, aes(x = dose, y = len)) +
stat_summary(
fun.data = "mean_se", fun.args = list(mult = 1),
geom = "pointrange", color = "black"
)
Here is a simplified solution if you don't want to reassign at each step:
ggplot(ToothGrowth, aes(x = dose, y = len)) +
geom_violin(aes(fill = dose), trim = FALSE) +
geom_boxplot(width = 0.2) +
stat_summary(fun.data = "mean_se", fun.args = list(mult = 1),
geom = "pointrange", color = "black") +
scale_fill_manual(values = c("#00AFBB", "#E7B800", "#FC4E07")) +
theme(legend.position = "none")
I am trying to make a figure that will have density plots on the bottom and corresponding boxplots above the density plots. My density plots and boxplots are filled/colored by a categorical variable. I cannot figure out a way to get the boxplots to be above the density plots and also dodged. This is what I've been able to get so far:
d <- mtcars
d$cyl <- as.factor(d$cyl)
fig <- ggplot(data = d) +
geom_density(aes(x = mpg, fill = cyl),
position = "dodge",
na.rm = TRUE) +
geom_boxplot(aes(x = mpg, color = cyl),
position = ggstance::position_dodgev(height = 1),
width = .05, show.legend = FALSE,
na.rm = TRUE) +
facet_grid(~am, scales = "free_x") +
scale_fill_brewer(palette = "Set2") +
scale_color_brewer(palette = "Set2") +
theme_minimal() +
guides(color = FALSE, fill = FALSE)
fig
But, as you can see, this does not uniformly move the boxplots above the density plots. I've also used
geom_boxplot(aes(x = mpg, color = cyl),
position = position_nudge(x = 0, y = .3),
width = .05, show.legend = FALSE,
na.rm = TRUE) +
but I end up having my boxplots overlap (they are no longer vertically dodged). Basically, I'm looking for a way to set a vertical height for my group of boxplots so they're above my density plots AND keep them vertically dodged from one another. Any suggestions are much appreciated.
Map the value you want your boxes to be centered around to y, inside the aes for geom_boxplot. E.g.:
ggplot(data = d) +
geom_density(aes(x = mpg, fill = cyl)) +
geom_boxplot(aes(x = mpg, color = cyl, y = 1),
position = ggstance::position_dodgev(height = 0.2),
width = .05, show.legend = FALSE) +
facet_grid(~am, scales = "free_x") +
scale_fill_brewer(palette = "Set2") +
scale_color_brewer(palette = "Set2") +
theme_minimal() +
guides(color = FALSE, fill = FALSE)
Also, don't try to dodge geom_density.
I have the following data that I'm trying to plot. I'm trying to change the width of the error bar but I run into an error that says Width not defined. Set with position_dodge(width = ?). I tried doing the position_dodge..but it didn't help. Any suggestions?
library(ggplot2)
time <- c("t1","t1","t1","t1","t1","t1","t2","t2","t2","t2","t2","t2")
species <- c(1,1,1,2,2,2,1,1,1,2,2,2)
value <- c(1,2,3,11,12,13,4,5,6,11,12,13)
df <- data.frame(time, species,value)
df$time <- as.factor(df$time)
df$species <- as.factor(df$species)
ggplot(df,aes(x=time, y=value, color = species, group = species)) + # Change fill to color
theme_bw() +
geom_point() +
stat_summary(fun.y=mean, position = "dodge") +
stat_summary(
geom="errorbar",
fun.data= mean_cl_boot,
width = 0.1, size = 0.2, col = "grey57") +
# Lines by species using grouping
stat_summary(aes(group = species), geom = "line", fun.y = mean) +
ylab("Fitness")
Position dodge is used to show all data points when data points overlap, I am not sure if this is of any use in your example and you may find that just removing this argument solves the issue if your data are not overlapping. Keeping it constant alternatively solves the issue:
pd<-position_dodge(0.5)
ggplot(df,aes(x=time, y=value, color = species, group = species)) + # Change fill to color
theme_bw() +
geom_point(position = pd) +
stat_summary(fun.y=mean, position = pd) +
stat_summary(
geom="errorbar",
fun.data= mean_cl_boot,
width = 0.1, size = 0.2, col = "grey57",
position = pd) +
# Lines by species using grouping
stat_summary(aes(group = species), geom = "line", fun.y = mean, position = pd) +
ylab("Fitness")
Just edited to keep everything from breaking apart.
There was a warning when entering values in the boxplot using geom_text.
As a result of studying, it is judged that there is no 'fill' option in aes of geom_text.
I want to know what I should do to get rid of the warning message.
means <- aggregate(d13C~Species, data=scat, meam)
means$d13C <- round(means$d13C,2)
ggplot(data=scat,
mapping=aes(x=scat$Species, y=scat$d13C, fill=scat$Species)) +
geom_boxplot() +
stat_summary(fun.y=mean, colour='darkred', geom="point",
shape=3, size=3, show.legend=F) +
geom_text(data=means,
aes(x=means$Species, y = d13C+1, label=d13C, fill=Species))
Try the following
means <- aggregate(d13C ~ Species, data = scat, mean) # there was a typo here
means$d13C <- round(means$d13C, 2)
ggplot(data = scat, aes(x = Species, y = d13C)) +
geom_boxplot(aes(fill = Species)) +
stat_summary(
fun.y = mean,
colour = 'darkred',
geom = "point",
shape = 3,
size = 3,
show.legend = F
) +
geom_text(data = means, aes(x = Species, y = d13C + 1, label = d13C))
If not working properly, please share a minimal reproducible dataset.
A general advise: Don't write ggplot(data = scat, aes(x = scat$Species, y = scat$d13C)) + ... but use the bare column names in aes.
When I facet a plot I often want to point out interesting comparisons between groups. For instance, in the plot produced by this code I'd like to point out that the second and third columns are nearly identical.
library(tidyverse)
ggplot(mtcars, aes(x = as.factor(am), y = mpg)) +
stat_summary(fun.y = "mean", geom = "col") +
stat_summary(fun.data = mean_se, geom = "errorbar", width = .1) +
facet_grid(~ vs)
Currently I can only make this annotation by exporting my plot to another app like Preview or Powerpoint and manually adding the lines and text across facets.
My efforts to add an annotation across facets results in annotations that do not leave their own facet. See below.
ggplot(mtcars, aes(x = as.factor(am), y = mpg)) +
stat_summary(fun.y = "mean", geom = "col") +
stat_summary(fun.data = mean_se, geom = "errorbar", width = .1) +
facet_grid(~ vs) +
annotate("errorbarh", xmin = 2, xmax = 3, y = 25, height = .5,
color = "red") +
annotate("text", x = 2.5, y = 27, label = "NS", color = "red")
Any advice about how to extend lines and annotations across facets would be greatly appreciated.