Reputation:
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:
Expected result:
I do not want to use ggplot2 and would prefer a solution in base R.
Upvotes: 3
Views: 1014
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)
Upvotes: 1
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
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
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