5

I made a plot with points connected with a line. In this plot I want to draw a vertical line from a point on the x-axis to the intersection with the plot line.And at the intersection, I want to draw a horizontal line to the Y-axis. I have searched several websites, forums and tutorials, but I still can't do it. Any help?

library(ggplot2)

X <- 1:5
Y <- c(2, 6, 4, 7, 12)

DF <- data.frame(X, Y)

ggplot(data = DF,
       aes(x = X,
           y = Y)) +
  geom_point() +
  geom_line() +
  geom_vline(xintercept = 4.5,
             linetype = 2)

Result so far:

enter image description here

Example of desired result:

enter image description here enter image description here

Daniel Valencia C.
  • 2,159
  • 2
  • 19
  • 38
  • 1
    use geom_segment `geom_segment(aes(x=X,xend=X,y=0,yend=Y),linetype=2)+ geom_segment(aes(x=0,xend=X,y=Y,yend=Y),linetype=2)` – Eric Dec 20 '21 at 10:47

3 Answers3

4

Already commented by @Eric but also sort of answered by @akrun in link, by applyng the apply function to the function of @akrun you can also plot all the points of the DF, something like this would work for you:

library(ggplot2)
X <- 1:5
Y <- c(2, 6, 4, 7, 12)
DF <- data.frame(X, Y)

draw_guides<- function(x, y) {
  list(geom_segment(aes(x = -Inf, xend = x, y = y, yend = y), linetype = "dashed"),
       geom_segment(aes(x = x, xend = x, y = y, yend = -Inf), linetype = "dashed"))
}

ggplot(data = DF,
       aes(x = X,
           y = Y)) +
  geom_point() +
  geom_line() +
  apply(DF, 1, function(y) draw_guides(y[1], y[2]))

enter image description here

Tur
  • 604
  • 4
  • 9
3

As already mentioned by @Eric in his comment geom_segment is the way to go to achieve your desired result. Moreover, you have to manually compute the y value where the segments should cut the geom_line which could be achieved using approx. As quick approach may look like so:

library(ggplot2)

X <- 1:5
Y <- c(2, 6, 4, 7, 12)

DF <- data.frame(X, Y)

# vertical line
vsegment <- function(x, X, Y) {
  geom_segment(aes(x = x, xend = x, y = -Inf, yend = approx(X, Y, x)$y),
               linetype = 2)  
}
# horizontal line
hsegment <- function(x, X, Y) {
  geom_segment(aes(x = -Inf, xend = x, y = approx(X, Y, x)$y, yend = approx(X, Y, x)$y),
               linetype = 2)  
}
ggplot(data = DF,
       aes(x = X,
           y = Y)) +
  geom_point() +
  geom_line() +
  vsegment(4.5, X, Y) +
  hsegment(4.5, X, Y)

stefan
  • 90,330
  • 6
  • 25
  • 51
3

You can use geom_path() as well for this

X <- 1:5
Y <- c(2, 6, 4, 7, 12)

DF <- data.frame(X, Y)
          
ggplot(data = DF, aes(x = X, y = Y)) +
  geom_point() +
  geom_line() +
  geom_path(data = data.frame(x = c(-Inf, 4.5, 4.5), y = c(approx(X, Y, 4.5)$y, approx(X, Y, 4.5)$y, -Inf)), aes(x, y), color = "red", linetype = 2)

enter image description here

If you want it more flexible for more intercepts you can use this function. Note the ... part, so you can pass the geom_path arguments along, like color, linetype, size, etc. It supports an intercept based on the x value or based on the y value.

my_intercept <- function(x, y, ...) {
  if (!missing(x)) dt <- data.frame(x = c(-Inf, x, x), y = c(approx(X, Y, x)$y, approx(X, Y, x)$y, -Inf))
  if (!missing(y)) dt <- data.frame(x = c(-Inf, approx(Y, X, y)$y, approx(Y, X, y)$y), y = c(y, y, -Inf))
  geom_path(data = dt, aes(x, y), ...)
}

ggplot(data = DF, aes(x = X, y = Y)) +
  geom_point() +
  geom_line() +
  my_intercept(x = 4.5, color = "blue", linetype = 2) +
  my_intercept(y = 5, color = "red", linetype = 4)

enter image description here

Merijn van Tilborg
  • 5,452
  • 1
  • 7
  • 22