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")
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))
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 text into geom_dotplot 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")
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))
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))