magicaxis provides functions for making pretty, publication-quality scientific plots with base R graphics. It handles minor tick marks, log-scale axes, 2-D density contours, image display, hexagonal binning, and triangle (corner) plots for MCMC chains.
Since version 2.6.0, all internal argument dispatch uses ParmOff instead of
do.call. This lets extra ... arguments be
forwarded flexibly to each sub-function: unrecognised arguments are
silently dropped, so callers no longer need to know exactly which
parameters each inner function accepts.
magaxis() adds nicely formatted tick marks and labels to
an existing plot. It supports log axes, minor ticks, Hershey fonts, and
grid lines.
plot(10^(1:9), 1:9, log = "x", axes = FALSE, xlab = "", ylab = "")
magaxis(side = 1:2, xlab = "x (log scale)", ylab = "y")Styling arguments such as cex.axis and
col.axis are forwarded via ParmOff to the underlying
axis() call, while cex.lab and
col.lab go to mtext():
plot(1:10, (1:10)^2, axes = FALSE, xlab = "", ylab = "")
magaxis(side = 1:2,
xlab = "x", ylab = expression(x^2),
cex.axis = 0.8, col.axis = "steelblue",
cex.lab = 1.1, col.lab = "darkred")Grid lines can be toggled per axis:
plot(1:20, rnorm(20), axes = FALSE, xlab = "", ylab = "")
magaxis(side = 1:2, grid = TRUE, grid.col = "grey80", grid.lty = 2,
xlab = "Index", ylab = "Value")magplot() wraps plot() to produce pretty
axes automatically. For a simple scatter the axis labelling, grid, and
limits are handled internally:
Log axes on both sides:
Sigma-clipping the axis limits to focus on where the data actually are:
temp <- cbind(rt(500, df = 1.5), rt(500, df = 1.5))
magplot(temp, xlim = 2, ylim = 2, xlab = "x", ylab = "y",
main = "2-sigma clipped")When a z vector is supplied, points are coloured by a
colour map and an optional colour bar is added. The magmap
and magbar arguments are filtered via ParmOff, so unknown
args are dropped cleanly:
n <- 300
x <- rnorm(n); y <- rnorm(n); z <- x^2 + y^2
magplot(x, y, z = z, xlab = "x", ylab = "y",
zcol = hcl.colors(21, "YlOrRd"), dobar = TRUE)maghist() prints a summary and draws a styled histogram.
It integrates naturally with magplot() because it returns a
histogram object that magplot() detects:
Log-y histogram:
Pass the returned object back through magplot():
magclip() iteratively removes outliers that are unlikely
given a Normal distribution. It is used internally by
magplot(), maghist(), and
magbin() when a scalar xlim/ylim
is supplied, but it is also useful on its own:
set.seed(42)
x <- c(rnorm(500), runif(30, 5, 10)) # 500 Normal + 30 outliers
result <- magclip(x, sigma = 3)
cat("Before clipping:", length(x), "points\n")
#> Before clipping: 530 points
cat("After clipping:", length(result$x), "points\n")
#> After clipping: 498 points
cat("Clipped range:", round(result$range, 2), "\n")
#> Clipped range: -2.7 2.7The estimate argument controls which tail is used to
estimate the Normal dispersion. Use 'lo' when contamination
is on the high side only:
set.seed(43)
x_hi <- c(rnorm(500), runif(40, 4, 8))
r_both <- magclip(x_hi)
r_lo <- magclip(x_hi, estimate = 'lo')
cat("Both sides kept:", length(r_both$x), "| Low-side only kept:", length(r_lo$x), "\n")
#> Both sides kept: 497 | Low-side only kept: 497magrun() computes running medians (or means/modes) and
scatter measures along a binned axis, ideal for overlaying a trend on
noisy scatter data:
set.seed(44)
n <- 1000
xx <- seq(0, 2, len = n)
yy <- xx + rnorm(n)
magplot(xx, yy, col = "lightgrey", pch = ".", xlab = "x", ylab = "y")
run <- magrun(cbind(xx, yy), bins = 10)
lines(run$x, run$y, col = "red", lwd = 2)
lines(run$x, run$yquan[, 1], lty = 2, col = "red")
lines(run$x, run$yquan[, 2], lty = 2, col = "red")The Nscale = TRUE flag divides the scatter by √N, giving
error-in-the-mean intervals (useful for assessing the significance of a
trend):
set.seed(45)
n <- 500
xx <- seq(0, 1, len = n)
yy <- xx + rnorm(n)
run_sd <- magrun(cbind(xx, yy), bins = 8, Nscale = FALSE, diff = TRUE)
run_sem <- magrun(cbind(xx, yy), bins = 8, Nscale = TRUE, diff = TRUE)
magplot(xx, yy, col = "lightgrey", pch = ".", xlab = "x", ylab = "y")
magerr(run_sd$x, run_sd$y, ylo = run_sd$yquan[, 1], yhi = run_sd$yquan[, 2],
col = "royalblue", length = 0, lty = 2)
magerr(run_sem$x, run_sem$y, ylo = run_sem$yquan[, 1], yhi = run_sem$yquan[, 2],
col = "red")
legend("topleft", legend = c("scatter (1σ)", "SEM (1σ)"),
col = c("royalblue", "red"), lty = c(2, 1), bty = "n")magerr() adds symmetric or asymmetric error bars in x
and/or y to an existing plot. Lower errors are supplied via
xlo/ylo and upper errors via
xhi/yhi (defaulting to the lower value if
omitted):
set.seed(46)
n <- 12
x <- sort(runif(n))
y <- 2 * x + rnorm(n, sd = 0.15)
magplot(x, y, xlab = "x", ylab = "y")
magerr(x, y, xlo = 0.04, ylo = 0.1, yhi = 0.2)Error ellipses are drawn when corxy is supplied:
set.seed(47)
n <- 8
x <- runif(n, 0.1, 0.9)
y <- runif(n, 0.1, 0.9)
sx <- runif(n, 0.03, 0.08)
sy <- runif(n, 0.05, 0.12)
rho <- runif(n, -0.7, 0.7)
magplot(x, y, xlab = "x", ylab = "y", pch = 16)
magerr(x, y, xlo = sx, ylo = sy, corxy = rho)A shaded error polygon is produced with poly = TRUE:
set.seed(48)
x <- seq(0, 2 * pi, len = 30)
y <- sin(x) + rnorm(30, sd = 0.1)
magplot(x, y, type = "l", xlab = "x", ylab = "sin(x)")
magerr(x, y, ylo = 0.15, yhi = 0.15, poly = TRUE, col = adjustcolor("steelblue", 0.3),
border = NA)magcurve() evaluates and plots any R expression over a
range. It is a drop-in replacement for curve() that uses
magplot() for its base plot, giving pretty axes
automatically:
magcurve(sin(x), from = 0, to = 2 * pi, xlab = "x", ylab = "sin(x)")
magcurve(cos(x), add = TRUE, col = "steelblue")
legend("topright", legend = c("sin", "cos"), col = c("black", "steelblue"),
lty = 1, bty = "n")Log axes are supported:
magbar() adds a standalone colour bar to any existing
plot. The position argument accepts compass-style strings
('topright', 'bottomleft', etc.);
orient switches between vertical ('v') and
horizontal ('h'):
n <- 300
set.seed(49)
x <- rnorm(n); y <- rnorm(n); z <- x^2 + y^2
colramp <- hcl.colors(21, "YlOrRd")
colvals <- magmap(z, range = c(1, length(colramp)))$map
magplot(x, y, col = colramp[round(colvals)], pch = 16,
xlab = "x", ylab = "y")
magbar(position = "topright", range = range(z), col = colramp,
orient = "v", title = expression(x^2 + y^2))A horizontal bar at the bottom:
magplot(x, y, col = colramp[round(colvals)], pch = 16,
xlab = "x", ylab = "y")
magbar(position = "bottomleft", range = range(z), col = colramp,
orient = "h", title = "z")magcon() computes a 2-D kernel density estimate and
draws contours at chosen probability levels (default 50%, 68%, 95%)
together with an optional image and colour bar.
x <- rnorm(500); y <- x + rnorm(500, sd = 0.5)
magcon(x, y, h = c(0.2, 0.2), xlab = "x", ylab = "y", barposition = 'topleft',
bartitleshift = 0.5)
#> Warning in rgl.init(initValue, onlyNULL): X11 error: GLXBadContext
#> Warning: 'rgl.init' failed, will use the null device.
#> See '?rgl.useNULL' for ways to avoid this warning.
#> Warning in regularize.values(x, y, ties, missing(ties), na.rm = na.rm):
#> collapsing to unique 'x' valuesContours only (no background image):
magcon(x, y, h = c(0.2, 0.2), doim = FALSE, dobar = FALSE,
xlab = "x", ylab = "y")
#> Warning in regularize.values(x, y, ties, missing(ties), na.rm = na.rm):
#> collapsing to unique 'x' valuesmagbin() bins 2-D data into hexagons, squares, or
triangles and colours them by count or a user-supplied statistic:
Square bins with a z-statistic:
magbin(xy, shape = "square",
z = xy[, 1]^2 - xy[, 2]^2,
colref = "zstat", sizeref = "count",
xlab = "x", ylab = "y")Log-log hexagonal bins:
xylog <- cbind(10^rnorm(2000), 10^rnorm(2000))
magbin(xylog, log = "xy", xlab = "x (log)", ylab = "y (log)")magimage() displays a matrix as an image with a colour
map applied via magmap() and optional axes via
magaxis(). The internal image() call is
dispatched through ParmOff:
z <- outer(seq(-3, 3, len = 50), seq(-3, 3, len = 50),
function(x, y) exp(-(x^2 + y^2)))
magimage(z, xlab = "x", ylab = "y")Asinh stretch to reveal faint structure (the default
stretch = "asinh" is well suited to images with a wide
dynamic range):
z2 <- outer(seq(-3, 3, len = 50), seq(-3, 3, len = 50),
function(x, y) exp(-x^2) + 0.05 * exp(-y^2 / 0.1))
magimage(z2, stretch = "asinh", xlab = "x", ylab = "y")magtri() makes a triangle plot summarising posterior
samples. The diagonal shows marginal densities, the lower triangle shows
2-D density contours (magcon), and the upper triangle shows
scatter plots.
chains <- data.frame(
alpha = rnorm(500, mean = 1, sd = 0.3),
beta = rnorm(500, mean = -0.5, sd = 0.5),
gamma = rnorm(500, mean = 2, sd = 0.8)
)
magtri(chains, samples = 300)Extra ... arguments are now forwarded by ParmOff to
magaxis, magcon, and
points, so you can style each sub-function from the
top-level call. Unrecognised arguments in one sub-function are silently
dropped and not recycled, so there is no risk of “unused argument”
errors:
# cex.axis → magaxis (tick-label size)
# lty → magcon (overrides contour line types)
# col → points (overrides the red mean-marker colour)
magtri(chains,
samples = 300,
cex.axis = 0.7,
lty = c(2, 1, 3),
col = "purple")Supply refvals to mark known true (or reference)
parameter values with a blue vertical line:
Supply majorn to reduce the number of labelled
ticks.