user10915156
user10915156

Reputation:

Plot line in different colors above versus below zero

I'd like the plotted line to be blue for values above zero and red for values below zero.

Sample data:

dat <- data.frame(1:10, c(-2, -3, -1, 1, 2, 1, -2, 2, 4, 3))
plot(dat, type = "l", lwd = 2)
abline(h = 0, col = "grey")

Result:

image of resulting plot

Expected result:

image of expected resulting plot

I do not want to use ggplot2 and would prefer a solution in base R.

Upvotes: 3

Views: 1014

Answers (3)

user10915156
user10915156

Reputation:

I am now using clplot() from the plotrix package:

dat <- data.frame(1:10, c(-2, -3, -1, 1, 2, 1, -2, 2, 4, 3))
library(plotrix)
clplot(dat[, 1], dat[, 2], levels = c(0), cols = c("red", "blue"), lwd = 2)

enter image description here

Upvotes: 1

yarnabrina
yarnabrina

Reputation: 1666

Following this answer [as @Sonny suggested in the comment], you can do this using clip:

dat <- data.frame(u = 1:10,
                  v = c(-2, -3, -1, 1, 2, 1, -2, 2, 4, 3))
plot(dat, type = "l", lwd = 2, col = "blue")
clip(x1 = min(dat$u),
     x2 = max(dat$u),
     y1 = min(dat$v),
     y2 = 0)
lines(dat, lwd = 2, col = "red")
abline(h = 0, col = "grey")

Created on 2019-03-24 by the reprex package (v0.2.1)

Upvotes: 1

jay.sf
jay.sf

Reputation: 72919

There is a very flexible solution from @Kohske / @beroe around, which can also be adapted on lines.

The method is that you estimate nullities.

dat.add <- do.call(rbind, 
                 sapply(1:(nrow(dat) - 1), function(i) {
                   f <- lm(x ~ y, dat[i:(i + 1), ])
                   if (f$qr$rank < 2) return(NULL)
                   r <- predict(f, newdata=data.frame(y=0))
                   if(dat[i, ]$x < r & r < dat[i + 1, ]$x)
                     return(data.frame(x=r, y=0))
                   else return(NULL)
                 })
)

Merge the nullites to your original data frame.

dat <- merge(dat, dat.add, all=TRUE)

Then do an empty plot and add segmented lines.

plot(dat, lwd = 2, type="n")
lines(dat[dat$y >= 0, ], col="blue")
lines(dat[dat$y <= 0, ], col="red")
abline(h = 0, col = "grey")

Result

enter image description here

Note, that the lines are not interrupted on the zero line, but abline at 0 hides this fact so we shouldn't care much in this case.

Data

dat <- structure(list(x = 1:10, y = c(-2, -3, -1, 1, 2, 1, -2, 2, 4, 
3)), class = "data.frame", row.names = c(NA, -10L))

Upvotes: 0

Related Questions