我正在绘制一些多变量数据,其中有 3 个离散变量和一个连续变量。我希望每个点的大小代表变化的幅度而不是实际的数值。我认为我可以通过使用绝对值来实现这一点。考虑到这一点,我希望负值用蓝色表示,正值用红色表示,零值用白色表示。比制作一个图例看起来像这样的情节:
我想出了一个与我的数据集具有相同结构的虚拟数据集,以获得一个可重现的示例:
a1 <- c(-2, 2, 1, 0, 0.5, -0.5)
a2 <- c(-2, -2, -1.5, 2, 1, 0)
a3 <- c(1.5, 2, 1, 2, 0.5, 0)
a4 <- c(2, 0.5, 0, 1, -1.5, 0.5)
cond1 <- c("A", "B", "A", "B", "A", "B")
cond2 <- c("L", "L", "H", "H", "S", "S")
df <- data.frame(cond1, cond2, a1, a2, a3, a4)
#some data munging
df <- df %>%
pivot_longer(names_to = "animal",
values_to = "FC",
cols = c(a1:a4)) %>%
mutate(across(c("cond1", "cond2", "animal"),
as.factor)) %>%
mutate(fillCol = case_when(FC < 0 ~ "decrease",
FC > 0 ~ "increase",
FC == 0 ~ "no_change"))
# plot 1
plt1 <- ggplot(df, aes(x = cond2, y = animal)) +
geom_point(aes(size = abs(FC), color = FC)) +
scale_color_gradient2(low='blue',
mid='white',
high='red',
limits=c(-2,2),
breaks=c(-2, -1, 0, 1, 2))+
facet_wrap(~cond1)
plt1
#plot 2
plt2 <- ggplot(df, aes(x = cond2, y = animal)) +
geom_point(aes(size = abs(FC), color = factor(FC))) +
facet_wrap(~cond1)
plt2
#plot 3
cols <- c("decrease" = "blue", "no_change" = "white", "increase" = "red")
plt3 <- ggplot(df, aes(x = cond2, y = animal)) +
geom_point(aes(size = abs(FC), color = fillCol)) +
scale_color_manual(name = "FC",
values = cols,
labels = c("< 0", "0", "> 0"),
guide = "legend") +
facet_wrap(~cond1)
plt3
Run Code Online (Sandbox Code Playgroud)
因此,结果应该看起来基本上像 plt3,但图例应该看起来像是将这两个图例合并到 plt2 中。最小的点在中间为零,越来越大的点指向负和正方向,颜色红色=正,蓝色=负,白色=零,图例上的标签显示实际数字。我的任务是完成这个任务,但我无法弄清楚。这是我在 Stackoverflow 上的第一个问题,所以没有图片:(。我对 r 比较陌生。
谢谢你!
编辑 12/08/2021 根据下面@jared_mamrot 的回复,只有当 FC 变量中的值在某种程度上是规则的时,它才有效。但是当我更改一些数字时,它会显示为警告,并且不会显示绘图上的点。是否可以使用值范围定义手动比例或以某种方式对其进行分类?更改值的示例:
a1 <- c(-2, 2, 1.4, 0, 0.8, -0.5)
a2 <- c(-2, -2, -1.5, 2, 1, 0)
a3 <- c(1.8, 2, 1, 2, 0.6, 0.4)
a4 <- c(2, 0.2, 0, 1, -1.2, 0.5)
cond1 <- c("A", "B", "A", "B", "A", "B")
cond2 <- c("L", "L", "H", "H", "S", "S")
df <- data.frame(cond1, cond2, a1, a2, a3, a4)
df <- df %>% pivot_longer(names_to = "animal",
values_to = "FC",
cols = c(a1:a4)) %>%
mutate(across(everything(),
as.factor))
plt4 <- ggplot(df, aes(x = cond2, y = animal, color = FC, size = FC)) +
geom_point() +
scale_size_manual(values = c(10,8,6,4,3,4,6,8,10),
breaks = seq(-2, 2, 0.5),
limits = factor(seq(-2, 2, 0.5),
levels = seq(-2, 2, 0.5))) +
scale_color_manual(values = c("-2" = "#03254C",
"-1.5" = "#1167B1",
"-1" = "#187BCD",
"-0.5" = "#2A9DF4",
"0" = "white",
"0.5" = "#FAD65F",
"1" = "#F88E2A",
"1.5" = "#FC6400",
"2" = "#B72C0A"),
breaks = seq(-2, 2, 0.5),
limits = factor(seq(-2, 2, 0.5),
levels = seq(-2, 2, 0.5))) +
facet_wrap(~cond1)
plt4
Run Code Online (Sandbox Code Playgroud)
> Warning message:
> Removed 7 rows containing missing values (geom_point).
Run Code Online (Sandbox Code Playgroud)
问题是您想要将绝对值映射到大小,并将真实值映射到颜色(不同比例)。我认为对数据进行分箱是一个好主意,但它不是我的,所以我不会走这条路(我鼓励用户 Skaqqs 根据他们的建议尝试答案)。
我个人更愿意将您的大小保留为连续变量,因此您仍然可以使用scale_size_continuous
. 这需要:
尝试使用指南做一些奇特的事情很快就会变得非常棘手。我真的更喜欢将图例创建分离到一个新图(“假图例”)中,并将图例添加到其他图(例如,使用 {patchwork}),而不是用指南功能等做疯狂的事情。
外观/相对尺寸显然可以根据您的审美愿望进行更改,我认为这比处理真实指南时更容易。
library(tidyverse)
library(patchwork)
a1 <- c(-2, 2, 1.4, 0, 0.8, -0.5)
a2 <- c(-2, -2, -1.5, 2, 1, 0)
a3 <- c(1.8, 2, 1, 2, 0.6, 0.4)
a4 <- c(2, 0.2, 0, 1, -1.2, 0.5)
cond1 <- c("A", "B", "A", "B", "A", "B")
cond2 <- c("L", "L", "H", "H", "S", "S")
df <- data.frame(cond1, cond2, a1, a2, a3, a4)
df <-
df %>% pivot_longer(names_to = "animal", values_to = "FC", cols = c(a1:a4)) %>%
## keep your continuous variable continuous:
## make a new column which tells you what is negative and positve and zero
## turn FC into absolute values
mutate(across(-FC, as.factor),
signFC = ifelse(FC == 0, 0, sign(FC)),
FC = abs(FC))
## move data and certain aesthetics from main call to layers
## I am also using fillable points, in order to be able to show "zero" in white
p <- ggplot(mapping = aes(x = cond2, y = animal, size = FC)) +
geom_point(data = filter(df, signFC == -1), aes(fill = FC), shape = 21) +
scale_fill_fermenter(palette = "Blues", direction = 1) +
## to show negative and positives differently, but size information still
## mapped to continuous scale
ggnewscale::new_scale_fill()+
geom_point(data = filter(df, signFC == 1), aes(fill = FC), shape = 21, show.legend = FALSE) +
scale_fill_fermenter(palette = "Reds", direction = 1) +
geom_point(data = filter(df, signFC == 0), fill = "white", shape = 21) +
scale_size_continuous(limits = c(0, 2)) +
facet_wrap(~cond1) +
theme(legend.position = "none")
## When dealing with guides gets too messy, I prefer to cleanly build the legend
## as a different plot
leg_df <-
data.frame(breaks = seq(-2, 2, 0.5)) %>%
mutate(br_sign = ifelse(breaks == 0, 0, sign(breaks)),
vals = abs(breaks),
y = seq_along(vals))
## Do all the above, again :)
p_leg <-
ggplot(mapping = aes(x = 1, y = y, size = vals)) +
geom_text(data = leg_df, aes(x = 1, label = breaks, y = y), inherit.aes = FALSE,
nudge_x = .01, hjust = 0) +
geom_point(data = filter(leg_df, br_sign == -1), aes(fill = vals), shape = 21) +
scale_fill_fermenter(palette = "Blues", direction = 1) +
## to show negative and positives differently, but size information still
## mapped to continuous scale
ggnewscale::new_scale_fill()+
geom_point(data = filter(leg_df, br_sign == 1), aes(fill = vals), shape = 21, show.legend = FALSE) +
scale_fill_fermenter(palette = "Reds", direction = 1) +
geom_point(data = filter(leg_df, br_sign == 0), fill = "white", shape = 21) +
scale_size_continuous(limits = c(0, 2)) +
theme_void() +
theme(legend.position = "none",
plot.margin = margin(l = 10, r = 15, unit = "pt")) +
coord_cartesian(clip = "off")
p + p_leg + plot_layout(widths = c(1, .05))
Run Code Online (Sandbox Code Playgroud)
由reprex 包于 2021 年 12 月 10 日创建(v2.0.1)
一种可能的解决方案是手动指定每个比例的值,例如
library(tidyverse)
a1 <- c(-2, 2, 1, 0, 0.5, -0.5)
a2 <- c(-2, -2, -1.5, 2, 1, 0)
a3 <- c(1.5, 2, 1, 2, 0.5, 0)
a4 <- c(2, 0.5, 0, 1, -1.5, 0.5)
cond1 <- c("A", "B", "A", "B", "A", "B")
cond2 <- c("L", "L", "H", "H", "S", "S")
df <- data.frame(cond1, cond2, a1, a2, a3, a4)
#some data munging
df %>%
pivot_longer(names_to = "animal",
values_to = "FC",
cols = c(a1:a4)) %>%
mutate(across(everything(),
as.factor)) %>%
ggplot(aes(x = cond2, y = animal, color = FC, size = FC)) +
geom_point() +
scale_size_manual(values = c(10,8,6,4,3,4,6,8,10),
breaks = seq(-2, 2, 0.5),
limits = factor(seq(-2, 2, 0.5),
levels = seq(-2, 2, 0.5))) +
scale_color_manual(values = c("-2" = "#03254C",
"-1.5" = "#1167B1",
"-1" = "#187BCD",
"-0.5" = "#2A9DF4",
"0" = "white",
"0.5" = "#FAD65F",
"1" = "#F88E2A",
"1.5" = "#FC6400",
"2" = "#B72C0A"),
breaks = seq(-2, 2, 0.5),
limits = factor(seq(-2, 2, 0.5),
levels = seq(-2, 2, 0.5))) +
facet_wrap(~cond1)
Run Code Online (Sandbox Code Playgroud)
由reprex 包于 2021 年 12 月 8 日创建(v2.0.1)
我的理解是,如果比例由相同的变量(FC_num
)、中断和标签定义,则 ggplot 将自动组合图例中的比例。这意味着我们不必使用scale...manual()
,这应该使我们的代码更加灵活和简洁(!)。
这里有两个选项:
library(ggplot2)
library(dplyr)
library(tidyr)
a1 <- c(-2, 2, 1.4, 0, 0.8, -0.5)
a2 <- c(-2, -2, -1.5, 2, 1, 0)
a3 <- c(1.8, 2, 1, 2, 0.6, 0.4)
a4 <- c(2, 0.2, 0, 1, -1.2, 0.5)
cond1 <- c("A", "B", "A", "B", "A", "B")
cond2 <- c("L", "L", "H", "H", "S", "S")
dff <- data.frame(cond1, cond2, a1, a2, a3, a4)
#some data munging
df <- dff %>%
pivot_longer(names_to = "animal",
values_to = "FC",
cols = c(a1:a4)) %>%
mutate(across(everything(),
as.factor))
# Make focal variable numeric
df$FC_num <- as.numeric(paste(df$FC))
# Define breaks based on focal variable
breaks <- seq(min(df$FC_num), max(df$FC_num), 0.5)
# Option 1
transAbs <- scales::trans_new(name="abs", transform=abs, inverse=abs)
ggplot(data=df, aes(x=cond2, y=animal, fill=FC_num, size=FC_num)) +
geom_point(pch=21) +
scale_size_continuous(range=c(3,10), trans=transAbs, breaks=breaks, labels=breaks) +
scale_fill_distiller(palette="RdBu", breaks=breaks, labels=breaks) +
guides(fill=guide_legend(reverse=TRUE), size=guide_legend(reverse=TRUE)) +
facet_wrap(~cond1)
# Option 2
ggplot(data=df, aes(x=cond2, y=animal, fill=FC_num, size=FC_num)) +
geom_point(pch=21) +
scale_size_binned_area(max_size=10, breaks=breaks, labels=breaks) +
scale_fill_distiller(palette="RdBu", breaks=breaks, labels=breaks) +
guides(fill=guide_legend(reverse=TRUE), size=guide_legend(reverse=TRUE)) +
facet_wrap(~cond1)
Run Code Online (Sandbox Code Playgroud)