2

Using ggplot I want to plot straight lines of the form ax + by + c = 0, where the three parameters are generated by my code. If neither a nor b are zero, ggplot requires me to use geom_abline but if a = 0 or b = 0, I'd need to use geom_vline or geom_hline respectively.

It is messy to have to test a=0 and b=0 to select the right geom. What I'd really like is a geom like this:

geom_line(x_param = a, y_param = b, const = c)

but it does not seem to exist.

Is there a non-messy solution to my problem?

JeremyC
  • 445
  • 2
  • 14
  • Write your own wrapper function to choose the right geom. It would be easier to help if you provided a [reproducible example](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) with some data and test cases that could be used to test possible solutions. – MrFlick Oct 18 '19 at 15:14
  • 2
    You can use `geom_abline` with `slope=0` (i.e `a=0`), but it certainly objects to `slope=Inf` (`b=0`). An alternative for a general solution would be to use `geom_segment` where you specify the ends of the line. – Andrew Gustar Oct 18 '19 at 15:18
  • @MrFlick The wrapper function option is what I consider to be messy. – JeremyC Oct 18 '19 at 15:36
  • @AndrewGustar I had forgotten that slope = 0 works with abline. That makes the wrapper function a bit less messy. – JeremyC Oct 18 '19 at 15:37
  • What is your definition of "messy". Functions are meant to hide complexity. – MrFlick Oct 18 '19 at 15:37
  • Agreed that is the purpose of functions but the functions themselves can be very complex. Maybe 'inelegant' is the word. – JeremyC Oct 18 '19 at 15:39

2 Answers2

3

It's difficult to help without some example data, but suppose you had parameters in a data frame like this:

df.params <- data.frame(
  a = c(0, 0, 1, .3),
  b = c(1, .27, 0, 0),
  c = c(1, 2, 3, 4)
)

    a    b c
1 0.0 1.00 1
2 0.0 0.27 2
3 1.0 0.00 3
4 0.3 0.00 4

From this, you could use a single call to geom_segment to draw vertical or horizontal lines using Inf values. You can use ifelse to test for zeros in your parameters and swap in either Infs or your intercept values for each line:

ggplot(data = df.params) +
  geom_segment(aes(
    x =    ifelse(a == 0, -Inf, c),
    xend = ifelse(a == 0, Inf, c),
    y =    ifelse(b == 0, -Inf, c),
    yend = ifelse(b == 0, Inf, c)
  )
)

enter image description here

jdobres
  • 11,339
  • 1
  • 17
  • 37
0

For the record, here is the wrapper function that I wrote follwoing the very helpful comments given. In my opinion it is not too inelegant.

line <- function(a, b, c) { 
  if (a == 0 & b == 0) {
    warning('Invalid parameters for line') 
   } else if (b == 0) {
    geom <- geom_vline(xintercept = -c / a) 
   } else {
    geom <- geom_abline(intercept = -c / b, slope = -a / b) 
   }
  return(geom) 
}
JeremyC
  • 445
  • 2
  • 14