Home > front end >  Add geom_text into geom_dotplot 's dots
Add geom_text into geom_dotplot 's dots

Time:06-27

Here is a dataset that resembles my own :

set.seed(1)
CRD2 <- data.frame(Response = c(rnorm(10, 5, 1), rnorm(10, 4, 1), rnorm(10, 3, 1)),
                   Treatment = c(rep("A", 10), rep("B", 10), rep("C", 10)),
                   Labels = rep(1:5, each = 2))

Using ggplot2 I made the following plot with the code below:

CRD2 %>% 
        ggplot(aes(x = Treatment, y = Response, fill = Treatment))  
        geom_boxplot()  
        geom_dotplot(binaxis = "y", stackdir = "center")   
        geom_text(aes(label = Labels), size = 3, fontface = "bold")

enter image description here

My expected output is to produce a plot in which, for every level of 'Treatment', all the observations that have the same 'Response' value are put side by side but aligned to the center of the boxplot. In addition to that, I want the values of the 'Labels' variable of my dataset to be inside of each of the dots.

So far, the geom_dotplot() function is the one that gives me all the observations with the same 'Response' value in the possition I want. However, I can't make the text to be inside the dot. I have no need to stick to geom_dotplot or geom_text so whatever suggestion is welcomed :)


What I've tried so far : In addition to the code to produce the plot above, I also tried using geom_point and geom_text with the same jitter, as is shown in the following code:

set.seed(1)
CRD2 %>% 
        ggplot(aes(x = Treatment, y = Response, fill = Treatment))  
        geom_boxplot()  
        geom_point(aes(color = Treatment), position = position_jitter(width = 0.5, height = 0), size = 3)   
        geom_text(aes(label = Labels), size = 3, fontface = "bold", position = position_jitter(width = 0.5, height = 0))

enter image description here

However, it didn't produce the plot I'm expecting to generate since the dots are not aligned to the center and there is no way to make the label to be inside the dots even if I use the same width for the jitter of both, geom_text and geom_point.


EDIT : I changed the title from "add labels inside dots aligned to the center of each boxplot" to "Add geom_text into geom_dotplot 's dots" because this is closer to what I wanted originally.

CodePudding user response:

It's not generally possible to get the text inside the dots generated by geom_dotplot because of the way that it is drawn. Often in ggplot, one can apply the same stat_ transformation to points layers and text layers, but geom_dotplot has its own custom grob and recalculates its position every time the window is resized. You therefore cannot use it with geom_text.

You could simply work out the positions yourself of course:

CRD2 %>%
  mutate(Response_round = round(5 * Response) / 5) %>%
  group_by(Treatment, Response_round) %>% 
  mutate(x = 0.1 * (seq_along(Response_round) - (0.5 * (n()   1)))) %>%
  ungroup() %>%
  mutate(x = x   as.numeric(as.factor(Treatment))) %>%
  ggplot(aes(x = Treatment, y = Response, fill = Treatment))  
  geom_boxplot()  
  geom_point(shape = 21, size = 6, aes(x = x, y = Response_round))  
  geom_text(aes(label = Labels, x = x, y = Response_round), size = 4, 
            fontface = "bold")

enter image description here

You can achieve your second method, of lining up the random jitter of points and text using the seed argument of position_jitter

CRD2 %>% 
  ggplot(aes(x = Treatment, y = Response, fill = Treatment))  
  geom_boxplot()  
  geom_point(shape = 21, size = 5,
             position = position_jitter(width = 0.1, height = 0, seed = 1))   
  geom_text(aes(label = Labels), size = 3, fontface = "bold", 
            position = position_jitter(width = 0.1, height = 0, seed = 1))

enter image description here

CodePudding user response:

If switching to an other package is an option for you then maybe the ggbeeswarm package offers some options to get a plot similar to geom_dotplot.

One option would be geom_quasirandom if similar to geom_point you want to show all data points:

library(ggbeeswarm)
#> Loading required package: ggplot2
library(ggplot2)
set.seed(1)
CRD2 <- data.frame(Response = c(rnorm(10, 5, 1), rnorm(10, 4, 1), rnorm(10, 3, 1)),
                   Treatment = c(rep("A", 10), rep("B", 10), rep("C", 10)),
                   Labels = rep(1:5, each = 2))

ggplot(CRD2, aes(x = Treatment, y = Response, fill = Treatment))  
  geom_boxplot()  
  geom_quasirandom(size = 5, show.legend = FALSE)  
  geom_text(aes(label = Labels), size = 3, fontface = "bold", color = "white", position = position_quasirandom())

A second option would be to manually do the binning of the data and use geom_beeswarm:

library(dplyr)

CRD2 <- CRD2 |> 
  mutate(Response_binned = cut_width(Response, width = 1/10 * diff(range(Response)))) |> 
  group_by(Response_binned) |> 
  mutate(Response_binned_mean = mean(Response))

ggplot(CRD2, aes(x = Treatment, y = Response, fill = Treatment))  
  geom_boxplot()  
  geom_beeswarm(aes(y = Response_binned_mean), size = 5, cex = 4, show.legend = FALSE)  
  geom_text(aes(label = Labels, y = Response_binned_mean), size = 3, fontface = "bold", color = "white", position = position_beeswarm(cex = 4))

  • Related