You have at least a couple of options. The first is quite simple, general (in that it is not limited to direct segments) and accurate, but uses base plot , not ggplot . The second one uses ggplot , but a little more complicated and the color transition will not be 100% accurate (but close enough if you specify the appropriate resolution ... read on).
base:
If you want to use the base build functions rather than ggplot , you can crop the build area above the threshold (2.2), and then draw the segments in the preferred color and then copy to the area below the threshold and the graph again in red. While the first clip is completely unnecessary, it prevents you from dragging and dropping different colors, which may look a little annoying.
threshold <- 2.2 set.seed(123) stackOne=data.frame(id=rep(c(1,2,3),each=3), y=rnorm(9,2,1), x=rep(c(1,2,3),3))

ggplot:
If you need or need to use ggplot , you can consider the following ...
One solution is to use geom_line(aes(group=id, color = y < 2.2)) , however this will assign colors based on the y-value of the point at the beginning of each segment. I believe that you want to change the color not only at the nodes, but everywhere where the line crosses your given threshold of 2.2. I'm not so familiar with ggplot, but one way to achieve this is to make a higher resolution version of the data by creating new points along the lines that connect your existing points, and then use the color = y < 2.2 argument to achieve the desired effect.
For instance:
threshold <- 2.2 # set colour-transition threshold yres <- 0.01 # y-resolution (accuracy of colour change location) d <- stackOne # for code simplification # new cols for point coordinates of line end d$y2 <- c(d$y[-1], NA) d$x2 <- c(d$x[-1], NA) d <- d[-findInterval(unique(d$id), d$id), ] # remove last row for each group # new high-resolution y coordinates between each pair within each group y.new <- apply(d, 1, function(x) { seq(x['y'], x['y2'], yres*sign(x['y2'] - x['y'])) }) d$len <- sapply(y.new, length) # length of each series of points # new high-resolution x coordinates corresponding with new y-coords x.new <- apply(d, 1, function(x) { seq(x['x'], x['x2'], length.out=x['len']) }) id <- rep(seq_along(y.new), d$len) # new group id vector y.new <- unlist(y.new) x.new <- unlist(x.new) d.new <- data.frame(id=id, x=x.new, y=y.new) p <- ggplot(d.new, aes(x=x,y=y)) + geom_line(aes(group=d.new$id, color=d.new$y < threshold))+ geom_point(data=stackOne)+ scale_color_discrete(sprintf('Below %s', threshold)) p

There may be a way to do this through ggplot functions, but in the meantime I hope this helps. I could not figure out how to draw ggplotGrob in a cropped viewport (rather, it just scales the graph). If you want the color to be determined by some x-value threshold, this would obviously require some tweaking.