Skip to content

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

Open
@mfidino

Description

@mfidino

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!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions