3

I am trying to plot multiple ROC curves on a single plot with ggplot2. Here is how far I got:

ggroc2 <- function(columns, data = mtcars, classification = "am",
                   interval = 0.2, breaks = seq(0, 1, interval)){
  require(pROC)
  require(ggplot2)

  #The frame for the plot
  g <- ggplot() + geom_segment(aes(x = 0, y = 1, xend = 1,yend = 0)) +
    scale_x_reverse(name = "Specificity",limits = c(1,0), breaks = breaks, 
expand = c(0.001,0.001)) + 
    scale_y_continuous(name = "Sensitivity", limits = c(0,1), breaks = 
breaks, expand = c(0.001, 0.001)) +
    theme_classic() + coord_equal()

  #The loop to calculate ROC's and add them as new layers
  for(i in 1:length(columns)){
    croc <- roc(data[,classification], data[,columns[i]]) 
    plotx <- rev(croc$specificities)
    ploty <- rev(croc$sensitivities)
    g <- g + geom_step(aes(x=plotx, y=ploty))
  }

  g
}



#Sample graph
ggroc2(c("mpg", "disp", "drat", "wt"))

The problem is that only the last parameter in the columns list gets plotted. I identified that the problem must be related to aes() and lazy evaluation after reading the answer to this question. That example used geom_segment(), and the problem is solved after removing aes() altogether. It doesn't work for me, because I need to somehow map the data. When I remove aes() here, nothing gets plotted. How do I work around the lazy evaluation problem in geom_'s that depend on aes()?

naco
  • 373
  • 1
  • 3
  • 14
  • 1
    [This answer](https://stackoverflow.com/a/15988472/2461552) shows using the variable names and `aes_string` as a work-around. – aosmith Jun 29 '17 at 18:28
  • 1
    Regarding the duplicate issue, thanks for pointing out. I am trying to decide whether I should click the "That solved my problem!" button, or "I will edit to explain how". My question really seems to be a duplicate, but I find the answer below to be a much more elegant and efficient workaround than reshaping my data to long format. What should I do? – naco Jun 29 '17 at 19:08
  • 1
    One of the reasons I chose that as the duplicate vs other duplicates is that it shows the `data.frame` work-around. The given answer here is using the same approach. – aosmith Jun 29 '17 at 20:13

1 Answers1

2

Here is a working version of your code.
The final graphical result is not so good and should be improved.

ggroc2 <- function(columns, data = mtcars, classification = "am",
                   interval = 0.2, breaks = seq(0, 1, interval)){
  require(pROC)
  require(ggplot2)

  #The frame for the plot
  g <- ggplot() + geom_segment(aes(x = 0, y = 1, xend = 1,yend = 0)) +
    scale_x_reverse(name = "Specificity",limits = c(1,0), breaks = breaks, 
expand = c(0.001,0.001)) + 
    scale_y_continuous(name = "Sensitivity", limits = c(0,1), breaks = 
breaks, expand = c(0.001, 0.001)) +
    theme_classic() + coord_equal()

  #The loop to calculate ROC's and add them as new layers
  cols <- palette()
  for(i in 1:length(columns)){
    croc <- roc(data[,classification], data[,columns[i]]) 
    sens_spec <- data.frame(spec=rev(croc$specificities),
                            sens=rev(croc$sensitivities))
    g <- g + geom_step(aes(x=spec, y=sens), data=sens_spec, col=cols[i], lwd=1)
  }
  g
}

#Sample graph
ggroc2(c("mpg", "disp", "drat", "wt"))

enter image description here

Marco Sandri
  • 23,289
  • 7
  • 54
  • 58
  • 1
    "The final graphical result is not so good and should be improved." Are you referring to the overlapping lines? Anyhow, very demonstrative answer, thanks. I understand it very clearly. It should be easy to take it further from here. – naco Jun 29 '17 at 19:03
  • 2
    @naco Yes, I don't like overlapping lines. Anyway, I am happy you found my answer helpful! – Marco Sandri Jun 29 '17 at 19:12