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

Try using
geom_pointinstead ofgeom_dotplotBTW I don't think your data and x labels are matching because the
Statecolumn in yourddata frame isfactorvariable ordered alphabetically. You will need to reorder the levelslevels = c("virgin", "mated", "expecting", "parent")So it will be something like: