Home > Software design >  Is there a way in R and ggplot to create a facet_wrap plot with a conditional geom?
Is there a way in R and ggplot to create a facet_wrap plot with a conditional geom?

Time:02-04

Using R, I want to create a ggplot facet chart that includes a zero line (using geom_hline) in each facet having data that straddles the zero line, while excluding the zero line in each facet having exclusively positive or exclusively negative data. Here is a reprex.

library(ggplot)
dfw <- data.frame(
  date=c(1,2,3,4,5,6),
  A=c(50,53,62,56,54,61),
  B=c(-3,-1,5,7,4,-2),
  C=c(6,4,5,2,3,-2)
)
dfl <- pivot_longer(dfw,2:4,names_to="nms",values_to="val")
# With no zero line: works fine
ggplot(dfl) 
  geom_line(aes(x=date,y=val)) 
  facet_wrap(~nms,scales="free_y")
# With zero line for all facets: works fine
ggplot(dfl) 
  geom_hline(yintercept=0) 
  geom_line(aes(x=date,y=val)) 
  facet_wrap(~nms,scales="free_y")
# With zero line, but only for facets with some data points greater than zero
# and other data points less than zero: Does not work
c0 <- ggplot(dfl) 
  geom_line(aes(x=date,y=val))
if (min(y)>0 | max(y)<0) { # Error: object 'y' not found
  c0 <- c0 geom_hline(yintercept=0) 
} 
c0 <- c0 facet_wrap(~nms,scales="free_y")

CodePudding user response:

You can compute y-intercepts for each facet before plotting, setting to 0 if the data includes 0 and NA otherwise:

library(ggplot2)
library(dplyr)

dfl <- dfl %>% 
  mutate(
    zline = ifelse(min(val) < 0 & max(val > 0), 0, NA),
    .by = nms    # `.by` argument added in dplyr v1.1.0
  )

ggplot(dfl)  
  geom_hline(aes(yintercept = zline), na.rm = TRUE)  
  geom_line(aes(x = date, y = val))  
  facet_wrap(~nms, scales = "free_y")

CodePudding user response:

Here is another solution using a trick:

We say: if all val are > 0 then color our hline white (then it will be invisible). The underlying trick is to use I(). I learned this from @tjebo here enter image description here

  • Related