Marijn Stevering
Marijn Stevering

Reputation: 1293

Conditional colouring of a geom_smooth

I'm analyzing a series that varies around zero. And to see where there are parts of the series with a tendency to be mostly positive or mostly negative I'm plotting a geom_smooth. I was wondering if it is possible to have the color of the smooth line be dependent on whether or not it is above or below 0. Below is some code that produces a graph much like what I am trying to create.

set.seed(5)
r <- runif(22, max = 5, min = -5)
t <- rep(-5:5,2)
df <- data.frame(r+t,1:22)
colnames(df) <- c("x1","x2")
ggplot(df, aes(x = x2, y = x1)) + geom_hline() + geom_line() + geom_smooth()

I considered calculating the smoothed values, adding them to the df and then using a scale_color_gradient, but I was wondering if there is a way to achieve this in ggplot directly.

Upvotes: 11

Views: 1766

Answers (2)

Henrik
Henrik

Reputation: 67778

You may use the n argument in geom_smooth to increase "number of points to evaluate smoother at" in order to create some more y values close to zero. Then use ggplot_build to grab the smoothed values from the ggplot object. These values are used in a geom_line, which is added on top of the original plot. Last we overplot the y = 0 values with the geom_hline.

# basic plot with a larger number of smoothed values
p <- ggplot(df, aes(x = x2, y = x1)) +
  geom_line() +
  geom_smooth(linetype = "blank", n = 10000)

# grab smoothed values
df2 <- ggplot_build(p)[[1]][[2]][ , c("x", "y")]

# add smoothed values with conditional color
p +
  geom_line(data = df2, aes(x = x, y = y, color = y > 0)) +
  geom_hline(yintercept = 0)

enter image description here

Upvotes: 10

zx8754
zx8754

Reputation: 56159

Something like this:

# loess data
res <- loess.smooth(df$x2, df$x1)
res <- data.frame(do.call(cbind, res))

res$posY <- ifelse(res$y >= 0, res$y, NA)
res$negY <- ifelse(res$y < 0, res$y, NA)

# plot
ggplot(df, aes(x = x2, y = x1)) + 
  geom_hline() + 
  geom_line() + 
  geom_line(data=res, aes(x = x, y = posY, col = "green")) +
  geom_line(data=res, aes(x = x, y = negY, col = "red")) +
  scale_color_identity()

enter image description here

Upvotes: 6

Related Questions