Nothing
# pROC: Tools Receiver operating characteristic (ROC curves) with
# (partial) area under the curve, confidence intervals and comparison.
# Copyright (C) 2010-2014 Xavier Robin, Alexandre Hainard, Natacha Turck,
# Natalia Tiberti, Frédérique Lisacek, Jean-Charles Sanchez
# and Markus Müller
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
plot.roc <- function(x, ...) {
UseMethod("plot.roc")
}
plot.roc.formula <- function(x, data, subset, na.action, ...) {
data.missing <- missing(data)
call <- match.call()
names(call)[2] <- "formula" # forced to be x by definition of plot
roc.data <- roc_utils_extract_formula(formula=x, data, subset, na.action, ...,
data.missing = data.missing,
call = call)
if (length(roc.data$predictor.name) > 1) {
stop("Only one predictor supported in 'plot.roc'.")
}
response <- roc.data$response
predictor <- roc.data$predictors[, 1]
roc <- roc(response, predictor, plot=TRUE, ...)
roc$call <- match.call()
invisible(roc)
}
plot.roc.default <- function(x, predictor, ...) {
roc <- roc(x, predictor, plot=TRUE, ...)
roc$call <- match.call()
invisible(roc)
}
plot.roc.smooth.roc <- plot.smooth.roc <- function(x, ...) {
invisible(plot.roc.roc(x, ...)) # force usage of plot.roc.roc: only print.thres not working
}
plot.roc.roc <- function(x,
add=FALSE,
reuse.auc=TRUE,
axes=TRUE,
legacy.axes=FALSE,
xlim=if(x$percent){c(100, 0)} else{c(1, 0)},
ylim=if(x$percent){c(0, 100)} else{c(0, 1)},
xlab=ifelse(x$percent, ifelse(legacy.axes, "100 - Specificity (%)", "Specificity (%)"), ifelse(legacy.axes, "1 - Specificity", "Specificity")),
ylab=ifelse(x$percent, "Sensitivity (%)", "Sensitivity"),
asp=1,
mar=c(4, 4, 2, 2)+.1,
mgp=c(2.5, 1, 0),
# col, lty and lwd for the ROC line only
col=par("col"),
lty=par("lty"),
lwd=2,
type="l",
# Identity line
identity=!add,
identity.col="darkgrey",
identity.lty=1,
identity.lwd=1,
# Print the thresholds on the plot
print.thres=FALSE,
print.thres.pch=20,
print.thres.adj=c(-.05,1.25),
print.thres.col="black",
print.thres.pattern=ifelse(x$percent, "%.1f (%.1f%%, %.1f%%)", "%.3f (%.3f, %.3f)"),
print.thres.cex=par("cex"),
print.thres.pattern.cex=print.thres.cex,
print.thres.best.method=NULL,
print.thres.best.weights=c(1, 0.5),
# Print the AUC on the plot
print.auc=FALSE,
print.auc.pattern=NULL,
print.auc.x=ifelse(x$percent, 50, .5),
print.auc.y=ifelse(x$percent, 50, .5),
print.auc.adj=c(0,1),
print.auc.col=col,
print.auc.cex=par("cex"),
# Grid
grid=FALSE,
grid.v={
if(is.logical(grid) && grid[1]==TRUE){seq(0, 1, 0.1) * ifelse(x$percent, 100, 1)}
else if(is.numeric(grid)) {seq(0, ifelse(x$percent, 100, 1), grid[1])}
else {NULL}
},
grid.h={
if (length(grid) == 1) {grid.v}
else if (is.logical(grid) && grid[2]==TRUE){seq(0, 1, 0.1) * ifelse(x$percent, 100, 1)}
else if(is.numeric(grid)) {seq(0, ifelse(x$percent, 100, 1), grid[2])}
else {NULL}
},
# for grid.lty, grid.lwd and grid.col, a length 2 value specifies both values for vertical (1) and horizontal (2) grid
grid.lty=3,
grid.lwd=1,
grid.col="#DDDDDD",
# Polygon for the auc
auc.polygon=FALSE,
auc.polygon.col="gainsboro", # Other arguments can be passed to polygon() using "..." (for these two we cannot)
auc.polygon.lty=par("lty"),
auc.polygon.density=NULL,
auc.polygon.angle=45,
auc.polygon.border=NULL,
# Should we show the maximum possible area as another polygon?
max.auc.polygon=FALSE,
max.auc.polygon.col="#EEEEEE", # Other arguments can be passed to polygon() using "..." (for these two we cannot)
max.auc.polygon.lty=par("lty"),
max.auc.polygon.density=NULL,
max.auc.polygon.angle=45,
max.auc.polygon.border=NULL,
# Confidence interval
ci=!is.null(x$ci),
ci.type=c("bars", "shape", "no"),
ci.col=ifelse(ci.type=="bars", par("fg"), "gainsboro"),
...
) {
percent <- x$percent
if (max.auc.polygon | auc.polygon | print.auc) {# we need the auc here
if (is.null(x$auc) | !reuse.auc)
x$auc <- auc(x, ...)
partial.auc <- attr(x$auc, "partial.auc")
partial.auc.focus <- attr(x$auc, "partial.auc.focus")
}
# compute a reasonable default for print.auc.pattern if required
if (print.auc & is.null(print.auc.pattern)) {
print.auc.pattern <- ifelse(identical(partial.auc, FALSE), "AUC: ", "Partial AUC: ")
print.auc.pattern <- paste(print.auc.pattern, ifelse(percent, "%.1f%%", "%.3f"), sep="")
if (ci && methods::is(x$ci, "ci.auc"))
print.auc.pattern <- paste(print.auc.pattern, " (", ifelse(percent, "%.1f%%", "%.3f"), "\u2013", ifelse(percent, "%.1f%%", "%.3f"), ")",sep="")
}
# get and sort the sensitivities and specificities
se <- sort(x$sensitivities, decreasing=TRUE)
sp <- sort(x$specificities, decreasing=FALSE)
if (!add) {
opar <- par(mar=mar, mgp=mgp)
on.exit(par(opar))
# type="n" to plot background lines and polygon shapes first. We will add the line later. axes=FALSE, we'll add them later according to legacy.axis
suppressWarnings(plot(x$specificities, x$sensitivities, xlab=xlab, ylab=ylab, type="n", axes=FALSE, xlim=xlim, ylim=ylim, lwd=lwd, asp=asp, ...))
# As we had axes=FALSE we need to add them again unless axes=FALSE
if (axes) {
box()
# axis behave differently when at and labels are passed (no decimals on 1 and 0),
# so handle each case separately and consistently across axes
if (legacy.axes) {
lab.at <- axTicks(side=1)
lab.labels <- format(ifelse(x$percent, 100, 1) - lab.at)
suppressWarnings(axis(side=1, at=lab.at, labels=lab.labels, ...))
lab.at <- axTicks(side=2)
suppressWarnings(axis(side=2, at=lab.at, labels=format(lab.at), ...))
}
else {
suppressWarnings(axis(side=1, ...))
suppressWarnings(axis(side=2, ...))
}
}
}
# Plot the grid
# make sure grid.lty, grid.lwd and grid.col are at least of length 2
grid.lty <- rep(grid.lty, length.out=2)
grid.lwd <- rep(grid.lwd, length.out=2)
grid.col <- rep(grid.col, length.out=2)
if (!is.null(grid.v)) {
suppressWarnings(abline(v=grid.v, lty=grid.lty[1], col=grid.col[1], lwd=grid.lwd[1], ...))
}
if (!is.null(grid.h)) {
suppressWarnings(abline(h=grid.h, lty=grid.lty[2], col=grid.col[2], lwd=grid.lwd[2], ...))
}
# Plot the polygon displaying the maximal area
if (max.auc.polygon) {
if (identical(partial.auc, FALSE)) {
map.y <- c(0, 1, 1, 0) * ifelse(percent, 100, 1)
map.x <- c(1, 1, 0, 0) * ifelse(percent, 100, 1)
}
else {
if (partial.auc.focus=="sensitivity") {
map.y <- c(partial.auc[2], partial.auc[2], partial.auc[1], partial.auc[1])
map.x <- c(0, 1, 1, 0) * ifelse(percent, 100, 1)
}
else {
map.y <- c(0, 1, 1, 0) * ifelse(percent, 100, 1)
map.x <- c(partial.auc[2], partial.auc[2], partial.auc[1], partial.auc[1])
}
}
suppressWarnings(polygon(map.x, map.y, col=max.auc.polygon.col, lty=max.auc.polygon.lty, border=max.auc.polygon.border, density=max.auc.polygon.density, angle=max.auc.polygon.angle, ...))
}
# Plot the ci shape
if (ci && ! methods::is(x$ci, "ci.auc")) {
ci.type <- match.arg(ci.type)
if (ci.type=="shape")
plot(x$ci, type="shape", col=ci.col, no.roc=TRUE, ...)
}
# Plot the polygon displaying the actual area
if (auc.polygon) {
if (identical(partial.auc, FALSE)) {
suppressWarnings(polygon(c(sp, 0), c(se, 0), col=auc.polygon.col, lty=auc.polygon.lty, border=auc.polygon.border, density=auc.polygon.density, angle=auc.polygon.angle, ...))
}
else {
if (partial.auc.focus == "sensitivity") {
x.all <- rev(se)
y.all <- rev(sp)
}
else {
x.all <- sp
y.all <- se
}
# find the SEs and SPs in the interval
x.int <- x.all[x.all <= partial.auc[1] & x.all >= partial.auc[2]]
y.int <- y.all[x.all <= partial.auc[1] & x.all >= partial.auc[2]]
# if the upper limit is not exactly present in SPs, interpolate
if (!(partial.auc[1] %in% x.int)) {
x.int <- c(x.int, partial.auc[1])
# find the limit indices
idx.out <- match(FALSE, x.all < partial.auc[1])
idx.in <- idx.out - 1
# interpolate y
proportion.start <- (partial.auc[1] - x.all[idx.out]) / (x.all[idx.in] - x.all[idx.out])
y.start <- y.all[idx.out] - proportion.start * (y.all[idx.out] - y.all[idx.in])
y.int <- c(y.int, y.start)
}
# if the lower limit is not exactly present in SPs, interpolate
if (!(partial.auc[2] %in% x.int)) {
x.int <- c(partial.auc[2], x.int)
# find the limit indices
idx.out <- length(x.all) - match(TRUE, rev(x.all) < partial.auc[2]) + 1
idx.in <- idx.out + 1
# interpolate y
proportion.end <- (x.all[idx.in] - partial.auc[2]) / (x.all[idx.in] - x.all[idx.out])
y.end <- y.all[idx.in] + proportion.end * (y.all[idx.out] - y.all[idx.in])
y.int <- c(y.end, y.int)
}
# anchor to baseline
x.int <- c(partial.auc[2], x.int, partial.auc[1])
y.int <- c(0, y.int, 0)
if (partial.auc.focus == "sensitivity") {
# for SE, invert x and y again
suppressWarnings(polygon(y.int, x.int, col=auc.polygon.col, lty=auc.polygon.lty, border=auc.polygon.border, density=auc.polygon.density, angle=auc.polygon.angle, ...))
}
else {
suppressWarnings(polygon(x.int, y.int, col=auc.polygon.col, lty=auc.polygon.lty, border=auc.polygon.border, density=auc.polygon.density, angle=auc.polygon.angle, ...))
}
}
}
# Identity line
if (identity) suppressWarnings(abline(ifelse(percent, 100, 1), -1, col=identity.col, lwd=identity.lwd, lty=identity.lty, ...))
# Actually plot the ROC curve
suppressWarnings(lines(sp, se, type=type, lwd=lwd, col=col, lty=lty, ...))
# Plot the ci bars
if (ci && !methods::is(x$ci, "ci.auc")) {
if (ci.type=="bars")
plot(x$ci, type="bars", col=ci.col, ...)
}
# Print the thresholds on the curve if print.thres is TRUE
if (isTRUE(print.thres))
print.thres <- "best"
if (is.character(print.thres))
print.thres <- match.arg(print.thres, c("no", "all", "local maximas", "best"))
if (methods::is(x, "smooth.roc")) {
if (is.numeric(print.thres))
stop("Numeric 'print.thres' unsupported on a smoothed ROC plot.")
else if (print.thres == "all" || print.thres == "local maximas")
stop("'all' and 'local maximas' 'print.thres' unsupported on a smoothed ROC plot.")
else if (print.thres == "best") {
co <- coords(x, print.thres, best.method=print.thres.best.method, best.weights=print.thres.best.weights, transpose=FALSE)
suppressWarnings(points(co$specificity, co$sensitivity, pch=print.thres.pch, cex=print.thres.cex, col=print.thres.col, ...))
suppressWarnings(text(co$specificity, co$sensitivity, sprintf(print.thres.pattern, NA, co$specificity, co$sensitivity), adj=print.thres.adj, cex=print.thres.pattern.cex, col=print.thres.col, ...))
} # else print.thres == no > do nothing
}
else if (is.numeric(print.thres) || is.character(print.thres)) {
if (is.character(print.thres) && print.thres == "no") {} # do nothing
else {
co <- coords(x, print.thres, best.method=print.thres.best.method, best.weights=print.thres.best.weights, transpose=FALSE)
suppressWarnings(points(co$specificity, co$sensitivity, pch=print.thres.pch, cex=print.thres.cex, col=print.thres.col, ...))
suppressWarnings(text(co$specificity, co$sensitivity, sprintf(print.thres.pattern, co$threshold, co$specificity, co$sensitivity), adj=print.thres.adj, cex=print.thres.pattern.cex, col=print.thres.col, ...))
}
}
# Print the AUC on the plot
if (print.auc) {
if (ci && methods::is(x$ci, "ci.auc")) {
labels <- sprintf(print.auc.pattern, x$auc, x$ci[1], x$ci[3])
suppressWarnings(text(print.auc.x, print.auc.y, labels, adj=print.auc.adj, cex=print.auc.cex, col=print.auc.col, ...))
}
else
labels <- sprintf(print.auc.pattern, x$auc)
suppressWarnings(text(print.auc.x, print.auc.y, labels, adj=print.auc.adj, cex=print.auc.cex, col=print.auc.col, ...))
}
invisible(x)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.