R: Highlight points in boxplot with groups

Viewed 38

I want to highlight some points in a boxplot with groups. I have a dataset with 4 possible diagnostics, among which diagnostic 1 correspond to AN points and diagnostic 2 to CRC points.

It works fine for boxplot without groups. I plot only AN points first (with ggforce::geom_sina), then I add CRC points with geom_point :

# data generation
company_a <- sample(1:200, 100,replace = TRUE)
company_b <- sample(1:200, 100,replace = TRUE)
company_c <- sample(1:200, 100,replace = TRUE)
diagnostic<- sample(1:4, 100,replace = TRUE)
diagnostic<-as.factor(diagnostic)

df<-data.frame(company_a,company_b,company_c,diagnostic)
df_r=gather(df, "Companies", "FIT", 1:3)    


# extract subdataset
CRC_df = df_r[df_r$diagnostic==2,]
AN_df = df_r[df_r$diagnostic==1,]

# Changing diagnostic ID of CRC points to identify them as AN points
df_r["diagnostic"][df_r["diagnostic"] == 2]<-1
CRC_df["diagnostic"][CRC_df["diagnostic"] == 2]<-1

# Creating boxplot
cl <- qualitative_hcl(5, palette = "Dark 3")
ggboxplot(AN_df, x = "Companies", y = "FIT",
          fill = "Companies", palette = cl,alpha=0.1)+ 
  scale_y_continuous(breaks = seq(0, 200, 25))+
  ggforce::geom_sina(aes(x=Companies, y=FIT, color=Companies), size=1, alpha=0.8)+
  geom_point(                               # add the highlight points
    data=CRC_df, 
    aes(x=Companies, y=FIT,color=Companies),
    size=3)

producing this kind of graph where the highlighted points are on their corresponding boxplot: producing this kind of graph where the highlighted points are on their corresponding boxplot

But if I try to plot all the points in df_r and group boxplot by diagnostic ID:

ggboxplot(df_r, x = "diagnostic", y = "FIT",
          fill = "Companies", palette = cl,alpha=0.1)+  
  scale_y_continuous(breaks = seq(0, 200, 25))+
  ggforce::geom_sina(aes(x=diagnostic, y=FIT, color=Companies), size=1, alpha=0.8)+
  geom_point(                               # add the highlight points
    data=CRC_df, 
    aes(x=diagnostic, y=FIT,color=Companies),
    size=3)

So, it does not work as I expected as the points are not anymore on their corresponding boxplot. They collapse all on the middle boxplot corresponding to the AN group: it does not work as I expected as the points are not anymore on their corresponding boxplot

I would like the CRC points corresponding to company_a to be on the first boxplot of AN group, and same for other company.

Is there a solution to this problem?

1 Answers

Hi Rosalie and welcome to SO.

The main problem I see is that you have to define your diagnostic variable as a factor. Otherwise, R is using it as a normal number and cannot group it accordingly.

First, is a solution using only the base ggplot2 functions including the function geom_jitter() replacing geom_sina() from the ggforce package:

library(tidyverse)

#data generation
company_a <- sample(1:200, 100,replace = TRUE)
company_b <- sample(1:200, 100,replace = TRUE)
company_c <- sample(1:200, 100,replace = TRUE)
diagnostic<- sample(1:4, 100,replace = TRUE)

df<-data.frame(company_a,company_b,company_c,diagnostic)
df_r=gather(df, "Companies", "FIT", 1:3)

df_r$diagnostic <- as.factor(df_r$diagnostic)

#Creating boxplot
df_r %>%
  ggplot(aes(x = diagnostic, y = FIT, fill = Companies))+
  geom_boxplot(alpha = 0.1, position = "dodge2")+
  geom_point(aes(color = Companies), position = position_dodge(width = 0.75))+
  geom_jitter(aes(color = Companies), position = position_dodge2(width = 0.75), size = 1)+
  scale_y_continuous(breaks = seq(0, 200, 25))+
  theme_classic()+
  theme(legend.position = "top")

Second there is another solution also using the geom_sina() function:

#Creating boxplot
df_r %>%
  ggplot(aes(x = diagnostic, y = FIT, fill = Companies))+
  geom_boxplot(alpha = 0.1, position = "dodge2")+
  geom_point(aes(color = Companies), position = position_dodge(width = 0.75))+
  ggforce::geom_sina(aes(color = Companies), size = 1, position = position_dodge(width = 0.75))+
  scale_y_continuous(breaks = seq(0, 200, 25))+
  theme_classic()+
  theme(legend.position = "top")

Created on 2022-09-23 with reprex v2.0.2

Related