blob: 52644b190a83b14baa8b0eb8af8bcbfd40547764 [file] [log] [blame]
# File src/library/graphics/R/dotchart.R
# Part of the R package, https://www.R-project.org
#
# Copyright (C) 1995-2019 The R Core Team
#
# 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 2 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.
#
# A copy of the GNU General Public License is available at
# https://www.R-project.org/Licenses/
dotchart <-
function(x, labels = NULL, groups = NULL, gdata = NULL,
ann = par("ann"), xaxt = par("xaxt"), frame.plot = TRUE, log = "",
cex = par("cex"), pt.cex = cex,
pch = 21, gpch = 21, bg = par("bg"), color = par("fg"),
gcolor = par("fg"), lcolor = "gray",
xlim = range(x[is.finite(x)]),
main = NULL, xlab = NULL, ylab = NULL, ...)
{
## old-style "graphics" `design-bug: ("mar"), ("mai"), ("mar", "mai")
## all fail, just the following, ("mai", "mar") is ok:
opar <- par("mai", "mar", "cex", "yaxs")
on.exit(par(opar))
par(cex = cex, yaxs = "i")
if(!is.numeric(x))
stop("'x' must be a numeric vector or matrix")
n <- length(x)
if (is.matrix(x)) {
if (is.null(labels))
labels <- rownames(x)
if (is.null(labels))
labels <- as.character(seq_len(nrow(x)))
labels <- rep_len(labels, n)
if (is.null(groups))
groups <- col(x, as.factor = TRUE)
glabels <- levels(groups)
} else {
if (is.null(labels)) labels <- names(x)
glabels <- if(!is.null(groups)) levels(groups)
if (!is.vector(x)) { # e.g. a table
warning("'x' is neither a vector nor a matrix: using as.numeric(x)")
x <- as.numeric(x)
}
}
plot.new() # for strwidth()
linch <-
if(!is.null(labels)) max(strwidth(labels, "inch"), na.rm = TRUE) else 0
if (is.null(glabels)) {
ginch <- 0
goffset <- 0
}
else {
ginch <- max(strwidth(glabels, "inch"), na.rm = TRUE)
goffset <- 0.4
}
if (!(is.null(labels) && is.null(glabels))) {
## The intention seems to be to balance the whitespace
## on each side of the labels+plot.
nmai <- par("mai")
nmai[2L] <- nmai[4L] + max(linch + goffset, ginch) + 0.1
par(mai = nmai)
}
if (is.null(groups)) {
o <- seq_len(n)
y <- o
ylim <- c(0, n + 1)
}
else {
o <- sort.list(as.numeric(groups), decreasing = TRUE)
x <- x[o]
groups <- groups[o]
color <- rep_len(color, length(groups))[o]
lcolor <- rep_len(lcolor, length(groups))[o]
pch <- rep_len(pch, length(groups))[o]
offset <- cumsum(c(0, diff(as.numeric(groups)) != 0))
y <- seq_len(n) + 2 * offset
ylim <- range(0, y + 2)
}
plot.window(xlim = xlim, ylim = ylim, log = log)
# xmin <- par("usr")[1L]
lheight <- par("csi")
if (!is.null(labels)) {
linch <- max(strwidth(labels, "inch"), na.rm = TRUE)
loffset <- (linch + 0.1)/lheight
labs <- labels[o]
mtext(labs, side = 2, line = loffset, at = y, adj = 0,
col = color, las = 2, cex = cex, ...)
}
abline(h = y, lty = "dotted", col = lcolor)
points(x, y, pch = pch, col = color, bg = bg, cex = pt.cex/cex)
if (!is.null(groups)) {
gpos <- rev(cumsum(rev(tapply(groups, groups, length)) + 2) - 1)
ginch <- max(strwidth(glabels, "inch"), na.rm = TRUE)
goffset <- (max(linch+0.2, ginch, na.rm = TRUE) + 0.1)/lheight
mtext(glabels, side = 2, line = goffset, at = gpos,
adj = 0, col = gcolor, las = 2, cex = cex, ...)
if (!is.null(gdata)) {
abline(h = gpos, lty = "dotted")
points(gdata, gpos, pch = gpch, col = gcolor, bg = bg,
cex = pt.cex/cex, ...)
}
}
axis(1, xaxt=xaxt) # FIXME? add '...' or use localAxis() as plot.default()
if(frame.plot)
box()
if(ann)
title(main=main, xlab=xlab, ylab=ylab, ...)
invisible()
}