Reputation: 61
I'm building a plot with a discrete Y-axis with multiple pairwise comparisons. However, instead of using text for the labels, I created a secondary plot with color points indicating the 2 groups involved in the comparison, with a segment connecting the 2 dots for clarity. See figure, left side:
The code I used to generate the left-side plot is:
p_left <- ggplot(tb_deg) +
geom_segment(aes(y=comparison, x=var1, xend=var2), size=2, color="slategrey", show.legend = F) +
geom_point(aes(y=comparison, x=var1, fill=var1), shape=21, size=5, show.legend = F) +
geom_point(aes(y=comparison, x=var2, fill=var2), shape=21, size=5, show.legend = F) +
scale_fill_manual(name="Group",
values=c('ControlD1' = "limegreen",
'HSP90iD1' = "firebrick1",
'PRRTD1' = "deepskyblue",
'CombinationD1' = "orchid1",
'HSP90iD3' = "firebrick4",
'PRRTD3' = "deepskyblue3",
'CombinationD3' = "purple3")
) +
scale_x_discrete(limits=rev(levels(md$group)) ) +
theme_void() +
labs(x=NULL, y=NULL, title = NULL) +
theme(legend.position = "none",
aspect.ratio = 2,
axis.text.x = element_text(angle=90, hjust=1),
axis.text.y = element_blank())
Right now I am making the connecting segment grey, but I was wondering if I can make the segment into a gradient between the colors of the 2 connected dots. Yes, it will probably be ugly AF and I won't use it in the final figure, but I wanted to try.
I've been searching how to do this, but all the solutions I've found are using a fixed (gradient) color scale that is the same for all the plotted segments (mainly using geom_link). I couldn't find any example where the color of the tips of the segment depends on variables. Ideally, I'd be looking for something like
... + geom_segment(aes(y=comparison, x=var1, xend=var2,
***color_start=var1, color_end=var2***) ) + ...
Is there any way to this without manually coding a gradient with a different scale for each of the 15 comparisons?
Thanks,
Edit: The data:
> dput(unique(tb_deg[,c("comparison","var1","var2")]))
structure(list(comparison = structure(c(3L, 7L, 8L, 15L, 6L,
10L, 11L, 1L, 4L, 13L, 2L, 9L, 5L, 12L, 14L), levels = c("without001 - HSP90iD1_vs_ControlD1",
"without001 - PRRTD1_vs_ControlD1", "without001 - CombinationD1_vs_ControlD1",
"without001 - HSP90iD3_vs_ControlD1", "without001 - PRRTD3_vs_ControlD1",
"without001 - CombinationD3_vs_ControlD1", "without001 - CombinationD1_vs_HSP90iD1",
"without001 - CombinationD1_vs_PRRTD1", "without001 - PRRTD1_vs_HSP90iD1",
"without001 - CombinationD3_vs_HSP90iD3", "without001 - CombinationD3_vs_PRRTD3",
"without001 - PRRTD3_vs_HSP90iD3", "without001 - HSP90iD3_vs_HSP90iD1",
"without001 - PRRTD3_vs_PRRTD1", "without001 - CombinationD3_vs_CombinationD1"
), class = "factor"), var1 = structure(c(4L, 4L, 4L, 7L, 7L,
7L, 7L, 2L, 5L, 5L, 3L, 3L, 6L, 6L, 6L), levels = c("ControlD1",
"HSP90iD1", "PRRTD1", "CombinationD1", "HSP90iD3", "PRRTD3",
"CombinationD3"), class = "factor"), var2 = structure(c(1L, 2L,
3L, 4L, 1L, 5L, 6L, 1L, 1L, 2L, 1L, 2L, 1L, 5L, 3L), levels = c("ControlD1",
"HSP90iD1", "PRRTD1", "CombinationD1", "HSP90iD3", "PRRTD3",
"CombinationD3"), class = "factor")), class = c("grouped_df",
"tbl_df", "tbl", "data.frame"), row.names = c(NA, -15L), groups = structure(list(
comparison = structure(1:15, levels = c("without001 - HSP90iD1_vs_ControlD1",
"without001 - PRRTD1_vs_ControlD1", "without001 - CombinationD1_vs_ControlD1",
"without001 - HSP90iD3_vs_ControlD1", "without001 - PRRTD3_vs_ControlD1",
"without001 - CombinationD3_vs_ControlD1", "without001 - CombinationD1_vs_HSP90iD1",
"without001 - CombinationD1_vs_PRRTD1", "without001 - PRRTD1_vs_HSP90iD1",
"without001 - CombinationD3_vs_HSP90iD3", "without001 - CombinationD3_vs_PRRTD3",
"without001 - PRRTD3_vs_HSP90iD3", "without001 - HSP90iD3_vs_HSP90iD1",
"without001 - PRRTD3_vs_PRRTD1", "without001 - CombinationD3_vs_CombinationD1"
), class = "factor"), var1 = structure(c(2L, 3L, 4L, 5L,
6L, 7L, 4L, 4L, 3L, 7L, 7L, 6L, 5L, 6L, 7L), levels = c("ControlD1",
"HSP90iD1", "PRRTD1", "CombinationD1", "HSP90iD3", "PRRTD3",
"CombinationD3"), class = "factor"), .rows = structure(list(
8L, 11L, 1L, 9L, 13L, 5L, 2L, 3L, 12L, 6L, 7L, 14L, 10L,
15L, 4L), ptype = integer(0), class = c("vctrs_list_of",
"vctrs_vctr", "list"))), class = c("tbl_df", "tbl", "data.frame"
), row.names = c(NA, -15L), .drop = TRUE))
Upvotes: 1
Views: 51
Reputation: 125398
Just as a reference: Here is a slightly modified version of the approach by @dkysh which - as long as no legend is desired - does not require ggnewscale
but uses scales::pal_seq_gradient
to create the list of color palettes. Additionally, instead of a for
loop it uses purrr::imap
to create a list
of geom_link
layers.
Note: The code below requires ggplot2 >= 3.5.0
as I make use of the new functionality to render colors inside aes()
by wrapping in I()
.
library(ggforce)
library(ggplot2)
packageVersion("ggplot2")
#> [1] '3.5.1'
palettes <- purrr::map2(
color_list[tb_deg$var1],
color_list[tb_deg$var2],
scales::pal_seq_gradient
)
names(palettes) <- tb_deg$comparison
p_left_segments <- tb_deg |>
split(~comparison) |>
purrr::imap(\(x, y) {
pal <- palettes[[y]]
geom_link(
data = x,
aes(
y = comparison, yend = comparison,
x = var1, xend = var2,
color = I(after_stat(pal(index)))
), size = 2
)
})
p_left +
p_left_segments
Upvotes: 1
Reputation: 61
Using both ggforce's geom_link and ggnewscale, it is possible to make a loop, element by element, creating a new colorscale for each of them:
library(ggforce)
library(ggnewscale)
## Index with colors
color_list <- c('ControlD1' = "limegreen",
'HSP90iD1' = "firebrick1",
'PRRTD1' = "deepskyblue",
'CombinationD1' = "orchid1",
'HSP90iD3' = "firebrick4",
'PRRTD3' = "deepskyblue3",
'CombinationD3' = "purple3")
## old-ish code
p_left <- ggplot(tb_deg) +
geom_segment(aes(y=comparison, x=var1, xend=var2), size=2, color="slategrey", show.legend = F) +
geom_point(aes(y=comparison, x=var1, fill=var1), shape=21, size=5, show.legend = F) +
geom_point(aes(y=comparison, x=var2, fill=var2), shape=21, size=5, show.legend = F) +
scale_fill_manual(name="Group",
values=color_list ) +
scale_x_discrete(limits=rev(levels(md$group)) ) +
theme_minimal() +
labs(x=NULL, y=NULL, title = NULL) +
theme(legend.position = "none",
aspect.ratio = 2,
axis.text.x = element_text(angle=90, hjust=1),
axis.text.y = element_blank(),
panel.grid.major.y = element_blank())
p_left
### Loop through each element of the Y-axis, creating a geom_link + a new color scale
p2<-p_left
for (comp in unique(tb_deg$comparison)) {
v1 <- unique(tb_deg[tb_deg$comparison==comp, c("comparison","var1","var2")])$var1
v2 <- unique(tb_deg[tb_deg$comparison==comp, c("comparison","var1","var2")])$var2
p2 <- p2 +
new_scale_color() +
geom_link(data=unique(tb_deg[tb_deg$comparison==comp, c("comparison","var1","var2")]),
aes(y=comparison, yend=comparison, x=var1, xend=var2, color=stat(index)), size=2) +
scale_color_gradient(high=color_list[v2],low=color_list[v1])
}
p2
Still, I wonder if there is a more straightforward way to do this.
Upvotes: 2