Search code examples
rggplot2logarithm

calculate intersection on for logarithmic x axis with R


Hey everyone I am trying to show the intersection of a geom_line on a logarithmic x axis. However, I always miss the geom line. Here's what I do:

library(data.table)
library(ggplot2)

x <- c(0.1, 0.2)
y <- c(0.2, 0.4)

dt <- data.table(x = x,
                 y = y)

dt_lm <- lm(y ~ x, data = dt)
dt_slope <- summary(dt_lm)$coefficients[2, 1]
dt_inter <- summary(dt_lm)$coefficients[1, 1]
dt_x <- (0.3 - dt_inter) / dt_slope

ggplot(dt, aes(x, y)) +
  geom_line() +
  geom_segment(aes(x = 0,
                   xend = dt_x,
                   y = 0.3,
                   yend = 0.3),
               color="red") +
  geom_segment(aes(x = dt_x,
                   xend = dt_x,
                   y = 0,
                   yend = 0.3),
               color="red") +
  scale_x_continuous(trans = "log2")

I guess I have to take the log2 into account at the lm, since without trans = "log2" everything looks fine. However, I fail here :D


Solution

  • The problem is that geom_line is simply drawing a straight line segment between the two points defined in dt. With a log transform on the x axis, this "straight" line should actually be a curve, but an axis transformation will not convert a straight line segment between two points to a curve. To do this, you would need to get the correct x and y co-ordinates at all the points along the line and plot these.

    There are a couple of ways to do that. You could get the curve to intersect at the correct point by interpolating many points along the line. This will allow geom_line to draw hundreds of little line segments between the newly created co-ordinates, giving the visual effect of a smooth curve:

    ggplot(as.data.frame(approx(dt$x, dt$y, n = 1000)), aes(x, y)) +
      geom_line() +
      geom_segment(aes(x = 0, xend = dt_x, y = 0.3, yend = 0.3), color = "red") +
      geom_segment(aes(x = dt_x, xend = dt_x, y = 0, yend = 0.3), color = "red") +
      scale_x_continuous(trans = "log2") 
    

    enter image description here

    Perhaps a better approach is to get ggplot to do this for you. Although an axis transformation will not change a straight line to a curve, a coordinate transform will. For this, you need to use coord_trans instead of applying your transformation via scale_x_continuous

    ggplot(dt, aes(x, y)) +
      geom_line() +
      geom_segment(aes(x = 0.1, xend = dt_x, y = 0.3, yend = 0.3), color = "red") +
      geom_segment(aes(x = dt_x, xend = dt_x, y = 0, yend = 0.3), color = "red") +
      coord_trans(x = "log2", xlim = c(0.1, 0.2))
    

    enter image description here

    Note that this gives you the transformed x axis "for free", and has much nicer breaks that emphasize the log scale of the axis.