0

I have repeatedly measured a given behavior in male and female animals over four different reproductive states (virgin, mated, expecting and parent). I would like to represent my data (x: reproductive state, y: behavior value) in the following manner:

  1. dot plot where dots of the same behavior value spread horizontally instead of overlapping
  2. each subgroup (e.g. virgin males) should also have a segment showing the mean value of the behavior
  3. each individual animal should also be tractable with thin lines connecting the dots that correspond to that individual in each reproductive state

I have managed to do 1) and 2), but couldn't combine them with my 3)rd objective. Can someone help me?

Here is an example:

library(ggplot2)

Function to obtain a mean segment for each group
MinMeanSEMMax <- function(x) {
  v <- c(min(x), mean(x) - sd(x)/sqrt(length(x)), mean(x), mean(x) + sd(x)/sqrt(length(x)), max(x))
  names(v) <- c("ymin", "lower", "middle", "upper", "ymax")
  v
}

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

# Prepare mean value for plotting of mean segments
  g<-ggplot(d, aes(x=factor(State), y=Behavior, colour=Sex))+
    stat_summary(fun.data=MinMeanSEMMax, geom="boxplot", position=position_dodge(), outlier.shape = 21, outlier.size = 3, size=1)+
    scale_x_discrete(limits=c("virgin", "mated", "expecting", "parent"), labels=c("virgin"="Virgin", "mated"="Mated", "expecting"="Expecting", "parent"="Parent"))+
  dat.g <- ggplot_build(g)$d[[1]]
  g

  # The plot

  b<-ggplot(d, aes(x=factor(State), y=Behavior, colour=factor(Sex)))+
    geom_segment(data=dat.g, aes(x=xmin, xend=xmax,y=middle, yend=middle), colour=c("blue3","brown2","blue3","brown2","blue3","brown2","blue3","brown2"), size=1)+
    geom_dotplot(aes(fill=Sex),binaxis="y", stackdir="center", position=position_dodge(width=1), binwidth = 0.3)+
    labs(x="",y="Behavior")+
    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

enter image description here

aosmith
  • 34,856
  • 9
  • 84
  • 118
Mehdi.K
  • 371
  • 4
  • 15

1 Answers1

2

You can try this

library(tidyverse)
d %>% 
  mutate(State=factor(str_to_title(State), levels = c("Virgin", "Mated", "Expecting", "Parent"))) %>% 
  mutate(State2=ifelse(Sex=="F", as.numeric(State) + 0.25, as.numeric(State) - 0.25)) %>% 
  ggplot(aes(x=State, y=Behavior, fill=Sex)) + 
   geom_blank()+
   geom_dotplot(aes(x=State2,group=interaction(State,Sex)), binaxis="y", stackdir="center", binwidth = 0.3)+
   stat_summary(aes(x=State2),fun.y = "mean", geom="point",
               shape=95,size=8, show.legend = F) +
   geom_line(aes(x=State2, group=interaction(ID, Sex), color= Sex), alpha=0.5)

enter image description here

The idea is similar to the answer here. Do the dodging by your own to get the lines on track.In addition you have to work with interaction to get the right position of the dots and lines.

Roman
  • 17,008
  • 3
  • 36
  • 49