Nick
Nick

Reputation: 10499

Plot segment between point and line

I have the following dataset:

x <- 1:5
y <- c(1, 2, 1.3, 3.75, 2.25)

And I need to draw the straight line that fits my dataset by using simple regression, as well as these points:

plot(x, y, pch=19, ylim=c(0,6))
xx <- seq(0, 6, length=100)
fit <- lm(y~x)
lines(xx, predict(fit, data.frame(x=xx)))

Now I would like to join the points in the plot to the line as in the following (example) picture, showing the related prediction error:

enter image description here

How can I do?

Upvotes: 4

Views: 1409

Answers (4)

user20650
user20650

Reputation: 25844

Another ggplot2 answer., and similar in spirit to Gregors answer. This makes use of fortify.lm, where you can pass the results from anlm regression to ggplot. To see what fortify does, you can look at the object fortify(fit).

# Your data and linear model
x <- 1:5
y <- c(1, 2, 1.3, 3.75, 2.25)
fit <- lm(y~x)

# Plot
library(ggplot2)    

ggplot(fit, aes(x=x, y=y, xend=x, yend=y, col=factor(x), label=round(.resid, 2))) +
     geom_point() +
     geom_line(aes(x=x, y=.fitted), inherit.aes=FALSE) +
     geom_segment(aes(y=.fitted)) +
     geom_text(aes(vjust=-1*sign(.resid))) +
     theme(legend.position="none")

Upvotes: 0

Heroka
Heroka

Reputation: 13139

Using ggplot:

library(ggplot2)

#ggplot needs a dataframe
dat <- data.frame(x=x,y=y)
fit <- lm(y~x,data=dat)

#add predicted y for each x, to enable segment drawing
dat$pred <- predict(fit, dat)

with thanks to JasonAizkalns: adding labels too
dat$pred <- predict(fit, dat)
dat$pred_error <- dat$y - dat$pred 
dat$vjust <- sign(dat$pred_error)*-1.1 #labels can appear above/below points now

  p1 <- ggplot(dat, aes(x=x,y=y, color=factor(x)))+
  geom_point(size=2) + 
  geom_segment(aes(x=x,xend=x,y=y,yend=pred)) +
  geom_abline(intercept=coefficients(fit)[1],slope=coefficients(fit)[2]) +
  geom_text(aes(label=round(pred_error,2),vjust=vjust))+
  ylim(c(0,5))+
  xlim(c(0,5))+
  theme_bw()+
  theme(legend.position="none")
p1

enter image description here

Upvotes: 0

JasonAizkalns
JasonAizkalns

Reputation: 20463

Using base r you could do the following:

x <- 1:5
y <- c(1, 2, 1.3, 3.75, 2.25)

fit <- lm(y ~ x)
plot(x, y)
abline(fit)
res <- signif(residuals(fit), 5)
pre <- predict(fit)
segments(x, y, x, pre, col = rainbow(length(x)))

plot

Adding labels is easy with calibrate::textxy:

# install.packages("calibrate")
library(calibrate)
textxy(x, y, res)

plot with labels

Upvotes: 4

Gregor Thomas
Gregor Thomas

Reputation: 145745

I like the broom package for generating a nice data frame for things like this:

library(broom)
aug_fit = broom::augment(fit)

with(aug_fit, segments(x0 = x, y0 = y, x1 = x, y1 = .fitted))

Running my with(... segments()) line after your plot yields:

enter image description here

I'll leave adding colors, text labels, etc. to you.

Upvotes: 1

Related Questions