1

I realise lots of questions and answers exists on the use of B-splines in R, but I have yet to find an answer to this (seemingly simple) question.

Given a set of points that describe a control path, how do you fit a B-spline curve to that and extract a given number of points (say 100), along the curve for plotting. The catch is that the path is not monotonous in neither x, nor y.

An example control path:

path <- data.frame(
    x = c(3, 3.5, 4.6875, 9.625, 5.5625, 19.62109375, 33.6796875, 40.546875, 36.59375, 34.5, 33.5, 33),
    y = c(0, 1, 4, 5, 6, 8, 7, 6, 5, 2, 1, 0)
)

I've mainly looked at the splines package but again, most examples has been regarding fitting a smooth curve to data. For context, I'm looking at implementing hierarchical edge bundling in R.

ThomasP85
  • 1,624
  • 2
  • 15
  • 26

1 Answers1

2

The general idea is to predict x and y independently, assuming they are in fact independend:

library(splines)

path <- data.frame(
    x = c(3, 3.5, 4.6875, 9.625, 5.5625, 19.62109375, 33.6796875, 40.546875, 36.59375, 34.5, 33.5, 33),
    y = c(0, 1, 4, 5, 6, 8, 7, 6, 5, 2, 1, 0)
)
# add the time variable
path$time  <- seq(nrow(path))

# fit the models
df  <-  5
lm_x <- lm(x~bs(time,df),path)
lm_y <- lm(y~bs(time,df),path)

# predict the positions and plot them
pred_df  <-  data.frame(x=0,y=0,time=seq(0,nrow(path),length.out=100) )
plot(predict(lm_x,newdata = pred_df),
     predict(lm_y,newdata = pred_df),
     type='l')

you do need to be careful about defining your time variable, since the path is not independent of choice of times (even when they're sequential) since splines are not invariant on the spacing of points in the predictor space. For example:

plotpath  <-  function(...){
    # add the time variable with random spacing
    path$time  <- sort(runif(nrow(path)))

    # fit the models
    df  <-  5
    lm_x <- lm(x~bs(time,df),path)
    lm_y <- lm(y~bs(time,df),path)

    # predict the positions and plot them
    pred_df  <-  data.frame(x=0,y=0,time=seq(min(path$time),max(path$time),length.out=100) )
    plot(predict(lm_x,newdata = pred_df),
         predict(lm_y,newdata = pred_df),
         type='l',...)
}

par(ask=TRUE); # wait until you click on the figure or hit enter to show the next figure
for(i in 1:5)
    plotpath(col='red')
Jthorpe
  • 9,756
  • 2
  • 49
  • 64
  • In terms of "correctness" should the time variable reflect the distance between the points, or does this get evened out? – ThomasP85 Nov 06 '15 at 22:11
  • See http://stackoverflow.com/questions/33609538/specify-clamped-knot-vector-in-bs-call for a follow up... – ThomasP85 Nov 09 '15 at 12:58
  • Looking a bit more into your answer I see that it does not really solve the posed problem. What you propose will fit a spline to the points rather than use the points as control points for the spline. See http://stackoverflow.com/questions/33650171/b-splines-for-drawing-not-predicting-based-on-control-path – ThomasP85 Nov 11 '15 at 12:05