3

I'm also having some trouble with annotating text to individual facets in ggplot2 (w/ reference to related post: Annotating text on individual facet in ggplot2).

Data frame:

str(cfit_2)
'data.frame':   186 obs. of  5 variables:
 $ Participant: Factor w/ 31 levels "2","3","4","5",..: 1 2 3 4 5 6 7 8 9 10 ...
 $ Condition  : Factor w/ 2 levels "Active control group",..: 1 2 2 2 1 1 2 2 1 1 ...
 $ Time       : Factor w/ 2 levels "Pretest","Posttest": 1 1 1 1 1 1 1 1 1 1 ...
 $ CFIT       : num  10 13 17 11 19 15 19 11 15 16 ...
 $ Version    : Factor w/ 3 levels "Total CFIT","CFIT version 1",..: 1 1 1 1 1 1 1 1 1 1 ...

Code:

p<-ggplot(cfit_2,aes(Time,CFIT,fill=Condition))+
  scale_y_continuous(breaks=1:20)+
  scale_fill_manual(values=c("white","lightgrey"))+
  geom_violin()+
  theme_classic()+
  coord_cartesian(ylim=c(1, 20),xlim=c(1, 2))+
  theme(axis.line=element_blank())+
  facet_grid(.~Version)+ylab("CFIT raw score")+

  geom_segment(x=.3925,xend=.3925,y=1,yend=20)+
  geom_segment(x=1,xend=2,y=.015,yend=.015)+

 stat_summary(fun.y=mean,geom="point",position=position_dodge(w=.9))+
 stat_summary(fun.data=mean_cl_boot,geom="errorbar",position=position_dodge(w=.9),width=0)+

   geom_segment(data=data.segm_1,aes(x=x,xend=xend,y=y,yend=yend),inherit.aes=FALSE)+
   geom_segment(data=data.segm_2,aes(x=x,xend=xend,y=y,yend=yend),inherit.aes=FALSE)+
   geom_segment(data=data.segm_3,aes(x=x,xend=xend,y=y,yend=yend),inherit.aes=FALSE)+
   geom_segment(data=data.segm_1_2,aes(x=x,xend=xend,y=y,yend=yend),inherit.aes=FALSE)+
   geom_segment(data=data.segm_2_2,aes(x=x,xend=xend,y=y,yend=yend),inherit.aes=FALSE)+
   geom_segment(data=data.segm_3_2,aes(x=x,xend=xend,y=y,yend=yend),inherit.aes=FALSE)

Violin plot

What I want to do is to add "NS" or "*" next to every segment. Using the following data frame:

ann_text<-data.frame(Time=c("Pretest","Posttest","Pretest","Posttest","Pretest","Posttest"),CFIT=c(8,7,3,2,2,3),
       lab=c("NS","*","NS","*","NS","*"),
       Version=factor(c("Total CFIT","Total CFIT","CFIT version 1","CFIT version 1","CFIT version 2","CFIT version 2"),
                levels=c("Total CFIT","CFIT version 1","CFIT version 2")))

ann_text:

Time CFIT lab        Version
1  Pretest    8  NS     Total CFIT
2 Posttest    7   *     Total CFIT
3  Pretest    3  NS CFIT version 1
4 Posttest    2   * CFIT version 1
5  Pretest    2  NS CFIT version 2
6 Posttest    3   * CFIT version 2

... I get the following result from p+geom_text(data=ann_text,aes(label=lab)):

**Error in eval(expr, envir, enclos) : object 'Condition' not found**

Moving aes(fill=Condition) to geom_violin() gives the following plot:

Violin plot #2

Community
  • 1
  • 1
  • 2
    Any variable used in the global setting of aes is passed down to all other layers. So in this case, it is probably better to move fill=Condition to geom_violin() – Heroka Jan 05 '16 at 10:13
  • Thanks @Heroka! That works fine, except now I'm having trouble with the stat_summary(fun.data=mean_cl_boot,geom="errorbar",position=position_dodge(w=.9),width=0; above). – Eric Per Anders Karlsson Jan 05 '16 at 10:23
  • 1
    Hm. I didn't see all of your code due to the formatting (and I can't do a quick tinker myself as your q is not reproducible), but you could use override.aes. As an aside, you could consider combining data to create all your segments, creates cleaner and easier code. – Heroka Jan 05 '16 at 10:26

1 Answers1

7

The easiest way is to tell geom_text to not use Condition for the fill, by setting it to NULL. This way, you can keep fill in the ggplot call and have it applied to all other geoms, without the need to specify it each time.

Create data (since you didn't supply any)

cfit_2 <- data.frame(
  Time = c('Pretest', 'Posttest'),
  Condition = rep(c('Active control group', 'Training group'), each = 2),
  Version = rep(c('Total CFIT', 'CFIT version 1', 'CFIT version 2'), each = 40),
  CFIT = rnorm(120, 10, 3)
)

Use your plotting code

p<-ggplot(cfit_2,aes(Time,CFIT,fill=Condition))+
  #scale_y_continuous(breaks=1:20)+
  scale_fill_manual(values=c("white","lightgrey"))+
  geom_violin()+
  theme_classic()+
  #coord_cartesian(ylim=c(1, 20),xlim=c(1, 2))+
  theme(axis.line=element_blank())+
  facet_grid(.~Version)+ylab("CFIT raw score")+

  geom_segment(x=.3925,xend=.3925,y=1,yend=20)+
  geom_segment(x=1,xend=2,y=.015,yend=.015)+

  stat_summary(fun.y=mean,geom="point",position=position_dodge(w=.9))+
  stat_summary(fun.data=mean_cl_boot,geom="errorbar",position=position_dodge(w=.9),width=0)

(Note that I commented out two lines about the axes, since they were giving me troubles. I also removed the annotated lines, since you didn't supply data for those.)

Add the text

First create the coordinates where you want the asterisks and "NS"es.

ann_text<-read.table(text="
Time CFIT lab        Version
Pretest    15  NS     'Total CFIT'
Posttest    7   *     'Total CFIT'
Pretest    3  NS 'CFIT version 1'
Posttest    2   * 'CFIT version 1'
Pretest    2  NS 'CFIT version 2'
Posttest    3   * 'CFIT version 2'
",header=T)

Then annotate.

p + geom_text(data = ann_text, aes(label = lab, fill = NULL))

Result

enter image description here

Of course, the text doesn't look that nice (it's at the wrong y level), but that is because my data is different.

CrunchyTopping
  • 803
  • 7
  • 17
Axeman
  • 32,068
  • 8
  • 81
  • 94
  • Thank you @Axeman, that works great with my admittedly messy code. – Eric Per Anders Karlsson Jan 05 '16 at 18:17
  • Yeah, it's usually better to provide a minimal example that still has the same problem (i.e. remove all the extra bits like theme calls etc.). Also, supplied (fake) data is always nice! – Axeman Jan 05 '16 at 18:19
  • 1
    Yes, lots of unnecessary information. I'm sorry about that. Obviously I'm very new to this (basically no experience with coding, R or stack). Nice of you to point it out. (Btw I don't even know how to supply data.) – Eric Per Anders Karlsson Jan 05 '16 at 18:33