如何在ggplot2中使用多色拟合线将颜色分配给多色散点图
How to assign colors to multicolor scatter plot with multicolor fitted lines in ggplot2
问题
我在 data.frame
中存储了一些数据点,其中包含三个变量,x
、y
和 gender
。我的目标是在散点图上画出几条一般拟合的线和专门适合 male/female 的线,点按性别着色。听起来很简单,但仍然存在一些问题。
我目前所做的是使用一组新的 x
并为每个模型预测 y
,将拟合线组合在 data.frame
中,然后然后将 wide 转换为 long,将它们的型号名称作为第三个 var(从这个 post: ggplot2: how to add the legend for a line added to a scatter plot? and this: Add legend to ggplot2 line plot 我了解到应该使用映射而不是单独设置 colours/legends)。然而,虽然我可以获得多色线图,但正如我从我引用的 post 中预期的那样,这些点没有 gender
(已经是 factor
)的特定颜色。
我也知道可以使用aes=(y=predict(model))
,但我遇到了其他问题。我也尝试直接在 aes
中给点上色,并为每条线分别分配颜色,但是除非我使用 lty
,否则无法生成图例,这使得图例在 中具有相同的颜色.
不胜感激,也欢迎修改整个方法。
代码
请注意,两对线重叠。所以看起来只有两条线。我想在数据中添加一些 jitter
可能会使它看起来不同。
slrmen<-lm(tc~x+I(x^2),data=data[data['gender']==0,])
slrwomen<-lm(tc~x+I(x^2),data=data[data['gender']==1,])
prdf <- data.frame(x = seq(from = range(data$x)[1],
to = range(data$x)[2], length.out = 100),
gender = as.factor(rep(1,100)))
prdm <- data.frame(x = seq(from = range(data$x)[1],
to = range(data$x)[2], length.out = 100),
gender = as.factor(rep(0,100)))
prdf$fit <- predict(fullmodel, newdata = prdf)
prdm$fit <- predict(fullmodel, newdata = prdm)
rawplotdata<-data.frame(x=prdf$x, fullf=prdf$fit, fullm=prdm$fit,
linf=predict(slrwomen, newdata = prdf),
linm=predict(slrmen, newdata = prdm))
plotdata<-reshape2::melt(rawplotdata,id.vars="x",
measure.vars=c("fullf","fullm","linf","linm"),
variable.name="fitmethod", value.name="y")
plotdata$fitmethod<-as.factor(plotdata$fitmethod)
plt <- ggplot() +
geom_line(data = plotdata, aes(x = x, y = y, group = fitmethod,
colour=fitmethod)) +
scale_colour_manual(name = "Fit Methods",
values = c("fullf" = "lightskyblue",
"linf" = "cornflowerblue",
"fullm"="darkseagreen", "linm" = "olivedrab")) +
geom_point(data = data, aes(x = x, y = y, fill = gender)) +
scale_fill_manual(values=c("blue","green")) ## This does not work as I expected...
show(plt)
生成同色图例和多色图的另一种方法代码(省略两行):
ggplot(data = prdf, aes(x = x, y = fit)) + # prdf and prdm are just data frames containing the x's and fitted values for different models
geom_line(aes(lty="Female"),colour = "chocolate") +
geom_line(data = prdm, aes(x = x, y = fit, lty="Male"), colour = "darkblue") +
geom_point(data = data, aes(x = x, y = y, colour = gender)) +
scale_colour_discrete(name="Gender", breaks=c(0,1),
labels=c("Male","Female"))
这与在您自己的(第一个)示例中使用 colour
线条美学和 fill
点美学有关。在第二个示例中,它之所以有效,是因为 colour
美学用于线和点。
默认情况下,geom_point
无法将变量映射到 fill
,因为默认点形状 (19) 没有填充。
要使 fill
处理点,您必须在 geom_point()
中指定 shape = 21:25
,在 aes()
之外指定 shape = 21:25
。
也许这个可重现的小例子有助于说明这一点:
模拟数据
set.seed(4821)
x1 <- rnorm(100, mean = 5)
set.seed(4821)
x2 <- rnorm(100, mean = 6)
data <- data.frame(x = rep(seq(20,80,length.out = 100),2),
tc = c(x1, x2),
gender = factor(c(rep("Female", 100), rep("Male", 100))))
适合模特
slrmen <-lm(tc~x+I(x^2), data = data[data["gender"]=="Male",])
slrwomen <-lm(tc~x+I(x^2),data = data[data["gender"]=="Female",])
newdat <- data.frame(x = seq(20,80,length.out = 200))
fitted.male <- data.frame(x = newdat,
gender = "Male",
tc = predict(object = slrmen, newdata = newdat))
fitted.female <- data.frame(x = newdat,
gender = "Female",
tc = predict(object = slrwomen, newdata = newdat))
情节使用colour
美学
对点和线使用 colour
美学(在 ggplot
中指定,以便它在整个过程中得到继承)。默认情况下,geom_point
可以将变量映射到 colour
.
library(ggplot2)
ggplot(data, aes(x = x, y = tc, colour = gender)) +
geom_point() +
geom_line(data = fitted.male) +
geom_line(data = fitted.female) +
scale_colour_manual(values = c("tomato","blue")) +
theme_bw()
情节使用colour
和fill
美学
对点使用 fill
美学,对线使用 colour
美学(在 geom_*
中指定美学以防止它们被继承)。这将重现问题。
ggplot(data, aes(x = x, y = tc)) +
geom_point(aes(fill = gender)) +
geom_line(data = fitted.male, aes(colour = gender)) +
geom_line(data = fitted.female, aes(colour = gender)) +
scale_colour_manual(values = c("tomato","blue")) +
scale_fill_manual(values = c("tomato","blue")) +
theme_bw()
要解决此问题,请将 geom_point
中的 shape
参数更改为可以填充的点形状 (21:25)。
ggplot(data, aes(x = x, y = tc)) +
geom_point(aes(fill = gender), shape = 21) +
geom_line(data = fitted.male, aes(colour = gender)) +
geom_line(data = fitted.female, aes(colour = gender)) +
scale_colour_manual(values = c("tomato","blue")) +
scale_fill_manual(values = c("tomato","blue")) +
theme_bw()
由 reprex package (v2.0.1)
于 2021-09-19 创建
请注意,如果同一变量映射到两种美学,颜色和填充的比例会自动合并。
在我看来,您真正想做的是使用 ggplot2::stat_smooth
而不是试图预测自己。
从@scrameri 借用数据:
ggplot(data, aes(x = x, y = tc, color = gender)) +
geom_point() +
stat_smooth(aes(linetype = "X^2"), method = 'lm',formula = y~x + I(x^2)) +
stat_smooth(aes(linetype = "X^3"), method = 'lm',formula = y~x + I(x^2) + I(x^3)) +
scale_color_manual(values = c("darkseagreen","lightskyblue"))
问题
我在 data.frame
中存储了一些数据点,其中包含三个变量,x
、y
和 gender
。我的目标是在散点图上画出几条一般拟合的线和专门适合 male/female 的线,点按性别着色。听起来很简单,但仍然存在一些问题。
我目前所做的是使用一组新的 x
并为每个模型预测 y
,将拟合线组合在 data.frame
中,然后然后将 wide 转换为 long,将它们的型号名称作为第三个 var(从这个 post: ggplot2: how to add the legend for a line added to a scatter plot? and this: Add legend to ggplot2 line plot 我了解到应该使用映射而不是单独设置 colours/legends)。然而,虽然我可以获得多色线图,但正如我从我引用的 post 中预期的那样,这些点没有 gender
(已经是 factor
)的特定颜色。
我也知道可以使用aes=(y=predict(model))
,但我遇到了其他问题。我也尝试直接在 aes
中给点上色,并为每条线分别分配颜色,但是除非我使用 lty
,否则无法生成图例,这使得图例在 中具有相同的颜色.
不胜感激,也欢迎修改整个方法。
代码
请注意,两对线重叠。所以看起来只有两条线。我想在数据中添加一些 jitter
可能会使它看起来不同。
slrmen<-lm(tc~x+I(x^2),data=data[data['gender']==0,])
slrwomen<-lm(tc~x+I(x^2),data=data[data['gender']==1,])
prdf <- data.frame(x = seq(from = range(data$x)[1],
to = range(data$x)[2], length.out = 100),
gender = as.factor(rep(1,100)))
prdm <- data.frame(x = seq(from = range(data$x)[1],
to = range(data$x)[2], length.out = 100),
gender = as.factor(rep(0,100)))
prdf$fit <- predict(fullmodel, newdata = prdf)
prdm$fit <- predict(fullmodel, newdata = prdm)
rawplotdata<-data.frame(x=prdf$x, fullf=prdf$fit, fullm=prdm$fit,
linf=predict(slrwomen, newdata = prdf),
linm=predict(slrmen, newdata = prdm))
plotdata<-reshape2::melt(rawplotdata,id.vars="x",
measure.vars=c("fullf","fullm","linf","linm"),
variable.name="fitmethod", value.name="y")
plotdata$fitmethod<-as.factor(plotdata$fitmethod)
plt <- ggplot() +
geom_line(data = plotdata, aes(x = x, y = y, group = fitmethod,
colour=fitmethod)) +
scale_colour_manual(name = "Fit Methods",
values = c("fullf" = "lightskyblue",
"linf" = "cornflowerblue",
"fullm"="darkseagreen", "linm" = "olivedrab")) +
geom_point(data = data, aes(x = x, y = y, fill = gender)) +
scale_fill_manual(values=c("blue","green")) ## This does not work as I expected...
show(plt)
生成同色图例和多色图的另一种方法代码(省略两行):
ggplot(data = prdf, aes(x = x, y = fit)) + # prdf and prdm are just data frames containing the x's and fitted values for different models
geom_line(aes(lty="Female"),colour = "chocolate") +
geom_line(data = prdm, aes(x = x, y = fit, lty="Male"), colour = "darkblue") +
geom_point(data = data, aes(x = x, y = y, colour = gender)) +
scale_colour_discrete(name="Gender", breaks=c(0,1),
labels=c("Male","Female"))
这与在您自己的(第一个)示例中使用 colour
线条美学和 fill
点美学有关。在第二个示例中,它之所以有效,是因为 colour
美学用于线和点。
默认情况下,geom_point
无法将变量映射到 fill
,因为默认点形状 (19) 没有填充。
要使 fill
处理点,您必须在 geom_point()
中指定 shape = 21:25
,在 aes()
之外指定 shape = 21:25
。
也许这个可重现的小例子有助于说明这一点:
模拟数据
set.seed(4821)
x1 <- rnorm(100, mean = 5)
set.seed(4821)
x2 <- rnorm(100, mean = 6)
data <- data.frame(x = rep(seq(20,80,length.out = 100),2),
tc = c(x1, x2),
gender = factor(c(rep("Female", 100), rep("Male", 100))))
适合模特
slrmen <-lm(tc~x+I(x^2), data = data[data["gender"]=="Male",])
slrwomen <-lm(tc~x+I(x^2),data = data[data["gender"]=="Female",])
newdat <- data.frame(x = seq(20,80,length.out = 200))
fitted.male <- data.frame(x = newdat,
gender = "Male",
tc = predict(object = slrmen, newdata = newdat))
fitted.female <- data.frame(x = newdat,
gender = "Female",
tc = predict(object = slrwomen, newdata = newdat))
情节使用colour
美学
对点和线使用 colour
美学(在 ggplot
中指定,以便它在整个过程中得到继承)。默认情况下,geom_point
可以将变量映射到 colour
.
library(ggplot2)
ggplot(data, aes(x = x, y = tc, colour = gender)) +
geom_point() +
geom_line(data = fitted.male) +
geom_line(data = fitted.female) +
scale_colour_manual(values = c("tomato","blue")) +
theme_bw()
情节使用colour
和fill
美学
对点使用 fill
美学,对线使用 colour
美学(在 geom_*
中指定美学以防止它们被继承)。这将重现问题。
ggplot(data, aes(x = x, y = tc)) +
geom_point(aes(fill = gender)) +
geom_line(data = fitted.male, aes(colour = gender)) +
geom_line(data = fitted.female, aes(colour = gender)) +
scale_colour_manual(values = c("tomato","blue")) +
scale_fill_manual(values = c("tomato","blue")) +
theme_bw()
要解决此问题,请将 geom_point
中的 shape
参数更改为可以填充的点形状 (21:25)。
ggplot(data, aes(x = x, y = tc)) +
geom_point(aes(fill = gender), shape = 21) +
geom_line(data = fitted.male, aes(colour = gender)) +
geom_line(data = fitted.female, aes(colour = gender)) +
scale_colour_manual(values = c("tomato","blue")) +
scale_fill_manual(values = c("tomato","blue")) +
theme_bw()
由 reprex package (v2.0.1)
于 2021-09-19 创建请注意,如果同一变量映射到两种美学,颜色和填充的比例会自动合并。
在我看来,您真正想做的是使用 ggplot2::stat_smooth
而不是试图预测自己。
从@scrameri 借用数据:
ggplot(data, aes(x = x, y = tc, color = gender)) +
geom_point() +
stat_smooth(aes(linetype = "X^2"), method = 'lm',formula = y~x + I(x^2)) +
stat_smooth(aes(linetype = "X^3"), method = 'lm',formula = y~x + I(x^2) + I(x^3)) +
scale_color_manual(values = c("darkseagreen","lightskyblue"))