0

I am new to R but I am trying to figure out an automated way to determine where a given line between two points crosses the baseline (in this case 75, see dotted line in image link below) in terms of the x-coordinate. Once the x value is found I would like to have it added to the vector of all the x values and the corresponding y value (which would always be the baseline value) in the y value vectors. Basically, have a function look between all points of the input coordinates to see if there are any linear lines between two points that cross the baseline and if there are, to add those new coordinates at the baseline crossing to the output of the x,y vectors. Any help would be most appreciated, especially in terms of automating this between all x,y coordinates.

https://i.stack.imgur.com/UPehz.jpg

baseline = 75
X <- c(1,2,3,4,5,6,7,8,9,10)
y <- c(75,53,37,25,95,35,50,75,75,75)
Natro
  • 3
  • 1
  • 1
    This question and answers look similar, could help: https://stackoverflow.com/questions/20519431/finding-point-of-intersection-in-r – Jon Spring Apr 26 '19 at 23:05
  • This is an **exact duplicate** of my Q & A: [get x-value given y-value: general root finding for linear / non-linear interpolation function](https://stackoverflow.com/a/52655742/4891738). Just use function `RootSpline1` in my answer: `RootSpline1(X, y, baseline)`. – Zheyuan Li Jul 26 '22 at 03:08

1 Answers1

0

Edit: added creation of combined data frame with original data + crossing points.

Adapted from another answer related to two intersecting series with uniform X spacing.

baseline = 75
X <- c(1,2,3,4,5,6,7,8,9,10)
Y1 <- rep(baseline, 10)
Y2 <- c(75,53,37,25,95,35,50,75,75,75)

# Find points where x1 is above x2.
above <- Y1>Y2
# Points always intersect when above=TRUE, then FALSE or reverse
intersect.points<-which(diff(above)!=0)
# Find the slopes for each line segment.
Y2.slopes <- (Y2[intersect.points+1]-Y2[intersect.points]) /
  (X[intersect.points+1]-X[intersect.points])
Y1.slopes <- rep(0,length(Y2.slopes))
# Find the intersection for each segment
X.points <- intersect.points + ((Y2[intersect.points] - Y1[intersect.points]) / (Y1.slopes-Y2.slopes))
Y.points <- Y1[intersect.points] + (Y1.slopes*(X.points-intersect.points))
# Plot.
plot(Y1,type='l')
lines(Y2,type='l',col='red')
points(X.points,Y.points,col='blue')

enter image description here

library(dplyr)
combined <- bind_rows(   # combine rows from...
  tibble(X, Y2),         # table of original, plus
  tibble(X  = X.points, 
         Y2 = Y.points)) %>%  # table of interpolations
  distinct() %>%         # and drop any repeated rows
  arrange(X)             # and sort by X

> combined
# A tibble: 12 x 2
       X    Y2
   <dbl> <dbl>
 1  1       75
 2  2       53
 3  3       37
 4  4       25
 5  4.71    75
 6  5       95
 7  5.33    75
 8  6       35
 9  7       50
10  8       75
11  9       75
12 10       75
Jon Spring
  • 55,165
  • 4
  • 35
  • 53
  • Jon, thank you so much for taking the time to look into this for me. Being still new at R, Is there a way to insert the found points (in blue on the graph) in the correct order with the original set of x and y coordinate vectors? (e.g., newx would have a c(1,2,3,4,4.71,5,5.33,6,7,8,9,10) and newy would have c(75,53,37,25,75,95,75,35,50,75,75,75)) – Natro Apr 27 '19 at 01:27
  • Added to answer, hope that helps. – Jon Spring Apr 27 '19 at 02:59
  • Would it be that difficult to make this code provide output using a 'for' loop for rows of xs and ys? Also, would there be an issue if some rows were uneven in columns, e.g., no new points were identified? Thanks! – Natro Apr 27 '19 at 13:34
  • Is there a way to do this when the xs are not perfectly spaced? Like for instance, if the first x is a zero (c(0,2,3,4,5,6,7,8,9,10)), the function does not seem to return the correct results, it adds a row with "x=1, y=75" – Natro May 02 '19 at 01:16
  • I see there's a problem with returning the right x value for the first element. Hmm. Hacky fix could be to add a dummy first value to throw away, but I'll try to correct that. – Jon Spring May 02 '19 at 01:31
  • I think the function also has trouble if the x-coordinate values are not the same as the column they are in. For instance, if X <- c(0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1) then the function calculates based on position of the numbers in their columns not using the actual numbers. I think this occurs somewhere around the "intersect.points<-which(diff(above)!=0)" statement. I can't figure out how to get it to use the actual x-values and not their positioning. If that makes sense, any help would be great! – Natro May 02 '19 at 02:18
  • I think I figured it out, if you place an 'X' and brackets around intercept points here: X.points <- intersect.points +... = X.points <- X[intersect.points] +... it will insert the right X coordinates. Thanks for all the help! I am a research professor and I am making an R package that needed this code so I will cite you as a contributor if you don't mind. Thanks again. – Natro May 02 '19 at 18:06