I measured a given behaviour in animals (males and females) of various reproductive states (from virgin to parent).
I am drawing a dotplot with dodged dots, and I would like to add a median bar for each subgroup. I previously asked a similar question, and I was told to use stat_summary
with geom="point"
to add a median bar (see example code below).
My problem is that the bar seems erratically placed around the real median value, instead of being accurately located on the median value (see plot below)
# Mock dataframe:
Sex<-rep(c("M","F"), times=12)
ID<-rep(seq(from=1, to=6), times=4)
Behavior<-rnorm(24, mean=10, sd=3)
State<-rep(c("virgin", "virgin", "mated", "mated", "expecting", "expecting", "parent", "parent"), times=3)
d<-data.frame(ID,Sex,Behavior,State)
d$State2=ifelse(d$Sex=="F", as.numeric(d$State) + 0.15, as.numeric(d$State) - 0.15) # horizontally dodging males to the left, females to the right
# The plot
b<-ggplot(d, aes(x=factor(State), y=Behavior, colour=factor(Sex)))+
geom_dotplot(aes(x=State2, group=interaction(State, Sex), fill=Sex),binaxis="y", stackdir="center", stackratio=1.5, binwidth = 0.3, binpositions="all", dotsize=1)+
stat_summary(aes(x=State2),fun.y = "median", geom="point", shape=45, size=20, show.legend = F, alpha=0.6) +
labs(x="",y="Behavior")+
geom_line(aes(x=State2, group=interaction(ID, Sex), color=Sex), alpha=0.5, size=0.2)+
theme_classic()+
theme(axis.line.x = element_line(color="black", size = 1),
axis.line.y = element_line(color="black", size = 1))+
theme(legend.position="none")+
theme(axis.text.x =element_text(size=10),axis.text.y=element_text(size=10), axis.title=element_text(size=11,face="bold"))+
scale_fill_manual(name="Sex", values=c("brown2", "blue3"), breaks=c("F", "M"))+
scale_colour_manual(name="Sex",values=c("brown2","blue3"),breaks=c("F", "M"),labels=c("Female", "Male"))+
scale_x_discrete(limits=c("virgin", "mated", "expecting", "parent"), labels=c("virgin"="Virgin", "mated"="Mated", "expecting"="Expecting", "parent"="Parent"))+
theme(text=element_text(family="serif"))
b
Edit:
I have looked up other possibilities, like using geom=crossbar
in the stat_summary
statement, like so:
stat_summary(aes(x=State2),fun.y = "median", fun.ymax="median", fun.ymin="median", geom="crossbar", show.legend = F) +
But the problem is the same, the bars are not placed accurately...:
How can I easily add accurate median bars? Thanks