1

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

example plot with added lines and medians

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...: example with crossbar

How can I easily add accurate median bars? Thanks

Mehdi.K
  • 371
  • 4
  • 15

1 Answers1

0

Try using geom_point instead of geom_dotplot

p<-ggplot(d, aes(x=factor(State), y=Behavior, colour=factor(Sex)))+

  geom_point(aes(x=State2, group=interaction(State, Sex), fill=Sex), size = 5)+

  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"))

BTW I don't think your data and x labels are matching because the State column in your d data frame is factor variable ordered alphabetically. You will need to reorder the levels levels = c("virgin", "mated", "expecting", "parent")

So it will be something like:

d<-data.frame(ID,Sex,Behavior,State)

# Reorder State levels
d$State <- factor(d$State, levels = c("virgin", "mated", "expecting", "parent"))

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
MKa
  • 2,248
  • 16
  • 22