I have a long format data frame like this

> head(df)

1:  CCL28   2.030674       2.023333 1.921508    1.952007
2:  CXCL2   2.204847       2.275296 2.175790    2.241554
3:  CXCR4   2.121186       2.147181 1.950065    1.982639
4: IFNGR1   2.311390       2.324111 2.220727    2.255556

And by this code

ggplot(df, aes(variable,value)) +
  stat_boxplot(geom="errorbar", width=.5)+
  theme(axis.title.x=element_blank(), axis.title.y=element_blank())+
  stat_summary(fun.y=median, colour="red", geom="line", aes(group = 1))+
  geom_jitter(position = position_jitter(0.2))

I have this box

I have added this line to my code where I got

geom_text(data = df_melt, aes(x = variable, y = value, label = gene), size = 5) 

[![enter image description here][2]][2]

I want to show the name of genes in box plot but I don't how, cam you help?


  • 3
    $\begingroup$ Surprisingly the first link on google for "add text to boxplot ggplot" gave the answer: stackoverflow.com/questions/23096108/… $\endgroup$ – ATpoint Feb 9 '20 at 17:43
  • $\begingroup$ I think you need to edit your question because the colnames of head(df) and the df you use in ggplot2 are not the same (no mention of the column variable and value. So, I believed that you reshape your dataframe. Please indicate all step and provide a reproducible example $\endgroup$ – dc37 Feb 9 '20 at 18:55

In addition, to have several errors in your code for plotting (for example, you are using df for plotting and then df_melt for geom_text but you didnot mention what is it). Based on your graph, it seems that you have issues with the melting part.

However, these are quite secondary issues that are probably be fixed with the code below. with your example, there is one trick because you are using jitter to plot your points (that is not addressed by the link that @ATpoint provided in comments). This will randomly position the point at the right y value but with different x position in order to not overlap points.

So, when you will add your text label, the labeling won't fit to the position of points. But you can make the jitter reproducible by adding a seed (see this github discussion: https://github.com/tidyverse/ggplot2/pull/1996). However, geom_jitter function does not have the argument seed, so you can use geom_point function and the argument position_jitter instead.

So, using the few genes that you provided as an example. I have to reshape it (a step you probably did but you did not provide in your question), here I'm using pivot_longer function from tidyr package:

DF <- df %>% pivot_longer(., -gene, names_to = "variable", values_to = "value")

# A tibble: 16 x 3
   gene   variable       value
   <chr>  <chr>          <dbl>
 1 CCL28  Res_immune      2.03
 2 CCL28  Non_res_immune  2.02
 3 CCL28  Res_OBP         1.92
 4 CCL28  Non_res_OBP     1.95
 5 CXCL2  Res_immune      2.20
 6 CXCL2  Non_res_immune  2.28
 7 CXCL2  Res_OBP         2.18
 8 CXCL2  Non_res_OBP     2.24
 9 CXCR4  Res_immune      2.12
10 CXCR4  Non_res_immune  2.15
11 CXCR4  Res_OBP         1.95
12 CXCR4  Non_res_OBP     1.98
13 IFNGR1 Res_immune      2.31
14 IFNGR1 Non_res_immune  2.32
15 IFNGR1 Res_OBP         2.22
16 IFNGR1 Non_res_OBP     2.26

And then, for the plotting part, you can use geom_text_repel function of the ggrepel package to add labeling without overlapping your points:

ggplot(DF, aes(x = variable, y = value, fill = variable, label = gene))+
  geom_boxplot(alpha = 0.2)+
  geom_point(position = position_jitter(width = 0.2, seed = 2), show.legend = FALSE)+
  geom_text_repel(position = position_jitter(0.2, seed = 2), show.legend = FALSE)

enter image description here


If you have a long list of genes, it will be pointless to show all of them on the boxplot. It will makes things really illisible. If you want to show some particular genes of interest, make a subset of the original dataframe. A lot of posts on SO and here have addressed this subsetting.

Reproducible data example

structure(list(gene = c("CCL28", "CXCL2", "CXCR4", "IFNGR1"), 
    Res_immune = c(2.030674, 2.204847, 2.121186, 2.31139), Non_res_immune = c(2.023333, 
    2.275296, 2.147181, 2.324111), Res_OBP = c(1.921508, 2.17579, 
    1.950065, 2.220727), Non_res_OBP = c(1.952007, 2.241554, 
    1.982639, 2.255556)), row.names = c(NA, -4L), class = c("data.table", 
"data.frame"), .internal.selfref = <pointer: 0x563d91b65350>)
  • $\begingroup$ Did OP add comments and then delete them? This seems to be a one-way conversation and OP either deleted their comments or edited their posts, adding their comments in-post. $\endgroup$ – Ram RS Feb 10 '20 at 17:41
  • $\begingroup$ You're right. OP deleted his comments. It was mainly asking for explanation about error message that I presumed have been solved. I will remove my comments and they are not anymore relevant $\endgroup$ – dc37 Feb 10 '20 at 18:54
  • $\begingroup$ That behavior is both entitled and ungrateful. Wow. $\endgroup$ – Ram RS Feb 10 '20 at 19:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.