Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A function to add a colored polygon to a plot for confidence intervals #2

Open
mfidino opened this issue Sep 2, 2021 · 2 comments
Open

Comments

@mfidino
Copy link
Contributor

mfidino commented Sep 2, 2021

The title says it all. The function, which I called ribbon() is a slight modification to polygon() with quality of life improvements to make it easier to add colored confidence intervals to a plot. Default values are taken for all polygon arguments, except for border, which is set to NA. Additionally, an alpha argument has been added to accommodate partially transparent confidence intervals. Any of the input values can be overwritten within this function's call.

A standard workflow would look something like this, which could not add in transparency.

data(cars)
# fit model
m1 <- lm(
  dist ~ speed,
  data = cars
)
# make predictions
preds <- predict(
  m1, 
  newdata = data.frame(speed = 10:25),
  interval = "confidence"
)
# base plot
blank(
  xlim = c(10,25),
  ylim = c(15,120),
  xlab = "Speed",
  ylab = "Stopping distance",
  xaxt = "s",
  yaxt = "s",
  bty = "l",
  las = 1
)
polygon(
  x = c(10:25, rev(10:25)),
  y = c(preds[,2], rev(preds[,3])),
  col = "purple",
  border = NA
)

The function I am suggesting would replace polygon and in this case would look like:

ribbon(
  x=10:25,
  y=preds[,c("lwr","upr")],
  col = "purple",
  alpha = 0.5
)

In this case x does not need to be reversed (i.e., x = c(10:25, rev(10:25))) and you can input a two-column data.frame or matrix into y. Likewise, there is an alpha argument now which uses base R to set the alpha channel & make colors transparent if you want them to be. Code for this function is:

ribbon <- function(x, y, density=NULL, angle=45, border=NA,
                   col=NA, lty= par("lty"),...,fillOddEven=FALSE,
                   alpha = NULL
  ){
  # error checks
  if(!any(is.na(col)) & length(col)>1){
    warning("Two values input to col. Only first element used.")
    col <- col[1]
  }
  # check if y is a matrix
  if(is.matrix(y)|is.data.frame(y)){
    y <- c(y[,1], rev(y[,2]))
    # check if x is half the length of y
    if(length(y)/length(x) == 2){
      x <- c(x, rev(x))
    }
  }
  # evaluate color and alpha channel
  if( is.na(col) ){
    my_col <- NA
  } else { # otherwise go through color process
    # 
    if(
      length(grep("^#", col)) == 1 & # if start with hash
      nchar(col)>7 # & alpha channel is present
      ){
        if(!is.null(alpha)){
          warning("col already has alpha channel, ignoring alpha argument.")
          my_col <- col
        } else {
          my_col <- col
        }
      } else {
      # get rgb
      my_rgbs <- col2rgb(col)
      # set color
      my_col <- rgb(
        my_rgbs[1],my_rgbs[2],my_rgbs[3],max = 255,alpha = 255 * alpha
      )
    } 
  }
  polygon(
    x = x, y = y, density = density, angle = angle,
    border = border, col = my_col, lty = lty,
    fillOddEven = fillOddEven, ...
  )
}

Code, documentation, and tests are written. Happy to submit a PR if you want to check it out!

@juniperlsimonis
Copy link
Collaborator

this was what you put in the PR right?
is there anything else in here that needs to be addressed still?

@mfidino
Copy link
Contributor Author

mfidino commented Jun 6, 2022

Yeah this should be in the PR I did (I just kept adding stuff on top of this) so it should be good to go!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants