Reputation: 356
I have a plot where I am trying to compare the linear regression lines for various groups of interest to the linear fit for the sample as a whole.
library(ggplot2);library(curl)
df<-read.csv(curl("https://raw.githubusercontent.com/megaraptor1/mydata/main/example.csv"))
df$group<-as.factor(df$group)
ggplot(df %>% group_by(group),
aes(x,y,col=group))+
geom_point(size=2.5,shape=21,aes(fill=group),col="black")+
scale_x_continuous(breaks=seq(1,3.25,0.25))+
scale_y_continuous(breaks=seq(0,17,1))+
geom_smooth(data=df %>% group_by(group),
formula=y~x,method="lm",level=0.9,se=F)+
geom_smooth(data=df,linetype="dashed",fill="white",colour="black",size=.75)+
geom_smooth(data=df,linetype="dashed",fill="white",colour="black",size=1)+
labs(color="group",fill="group")+
guides(color=guide_legend(ncol=2),fill=guide_legend(ncol=2))+
theme_classic()+
theme(legend.position = "none")
In this graph the fit for all specimens is represented by a black dashed line. However this line doesn't stand out very much from the surrounding data and is hard to see. I would like to put a white outline surrounding the dashed black line in order to make it pop and stand out from the surrounding data.
However, I have been unable to do so via ggplot2. I know it is possible to do so via a non-dashed line by plotting a slightly thicker white line behind the black line. But if I try to do so with a dashed line it does not produce the desired affect (see above code), because changing the thickness of the line also changes the length and spacing of the dashes, and hence the two do not line up and make the black dashed line pop out.
Is there any way to set the border of a dashed line in ggplot to plot a white border around a black dashed line?
Upvotes: 2
Views: 1530
Reputation: 79184
Or we could just add alpha=0.2
to geom_point()
ggplot(df %>% group_by(group),
aes(x,y,col=group))+
geom_point(size=2.5,shape=21,aes(fill=group),col="black", alpha = 0.2)+
scale_x_continuous(breaks=seq(1,3.25,0.25))+
scale_y_continuous(breaks=seq(0,17,1))+
geom_smooth(data=df %>% group_by(group),
formula=y~x,method="lm",level=0.9,se=F)+
geom_smooth(data=df,linetype="dashed",fill="white",colour="black",size=.75)+
geom_smooth(data=df,linetype="dashed",fill="white",colour="black",size=1)+
labs(color="group",fill="group")+
guides(color=guide_legend(ncol=2),fill=guide_legend(ncol=2))+
theme_classic()+
theme(legend.position = "none")
Upvotes: 0
Reputation: 38023
We could reparameterise the data as segments to represent a dashed line. First we get the data we need for the fit.
library(tidyverse)
library(ggplot2)
df<-read.csv(curl::curl("https://raw.githubusercontent.com/megaraptor1/mydata/main/example.csv"))
df$group<-as.factor(df$group)
line <- layer_data(ggplot(mapping = aes(x, y)) + geom_smooth(data = df))
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
Then, we can interpolate the line at fixed distances to yield us the dashed segments.
dash_length <- 0.025
xrange <- range(line$x)
xstart <- seq(xrange[1], xrange[2], by = dash_length * 2)
xend <- xstart + dash_length
linedat <- data.frame(
x = xstart,
xend = xend,
y = approx(line$x, line$y, xout = xstart, rule = 2)$y,
yend = approx(line$x, line$y, xout = xend, rule = 2)$y
)
You can then add these dashed segments as a wide white line and a thinner black line to give the appearance of a white outline.
ggplot(df %>% group_by(group),
aes(x,y,col=group))+
geom_point(size=2.5,shape=21,aes(fill=group),col="black")+
scale_x_continuous(breaks=seq(1,3.25,0.25))+
scale_y_continuous(breaks=seq(0,17,1))+
geom_smooth(data=df %>% group_by(group),
formula=y~x,method="lm",level=0.9,se=F)+
geom_segment(
data = linedat,
aes(x = x, y = y, xend = xend, yend = yend),
colour = "white", size = 2, lineend = "round"
) +
geom_segment(
data = linedat,
aes(x = x, y = y, xend = xend, yend = yend),
colour = "black", size = 1
) +
labs(color="group",fill="group")+
guides(color=guide_legend(ncol=2),fill=guide_legend(ncol=2))+
theme_classic()+
theme(legend.position = "none")
Created on 2021-04-05 by the reprex package (v1.0.0)
Note that this method can give skewed results if the line is not straight.
Upvotes: 3
Reputation: 76641
The trick is to plot the smoothers first, then plot the dashed line on top of them.
In order to have a white background and make the black dashed line stand out, plot a larger white line before the dashed black line.
library(ggplot2)
library(curl)
df <- read.csv(curl("https://raw.githubusercontent.com/megaraptor1/mydata/main/example.csv"))
df$group <- factor(df$group)
ggplot(df, aes(x, y, color = group)) +
geom_point(aes(fill = group), size = 2.5, shape = 21, color = "black") +
geom_smooth(formula = y ~ x, method = "lm", se = FALSE) +
# First plot the background solid white line
geom_smooth(
method = loess,
formula = y ~ x,
se = FALSE,
linetype = "solid",
colour = "white",
size = 2
) +
# Then a dashed black line on top of it
# This line is narrower than the background one
geom_smooth(
method = loess,
formula = y ~ x,
se = FALSE,
linetype = "dashed",
colour = "black",
size = 1.5
) +
#
scale_x_continuous(breaks = seq(1,3.25,0.25)) +
scale_y_continuous(breaks = seq(0,17,1)) +
theme_classic() +
theme(legend.position = "none")
Upvotes: 1