I have a function which builds line plots dynamically, hence need to solve my problem with a formula rather than manually setting ranges. (note to experts: I've written this in logical progression for myself & others later - apologies that this means more text; I find R help to be particularly fragmented and unhelpful for plotting, so hopefully this will help others).
The axes for the line plots I've generated have the right kinds of numbers of tick spacings (default, assumedly 'pretty breaks'?) but the axis range doesn't encompass the whole range of the data - some are outside. (you can ignore the rug plot deciles above the axis, though the first & last ones show the data range)
So what I'd like is for the x axis width to encompass all of the data, but retain the pretty breaks, i.e. spread the min/max tick points out to nice values at or past the extreme values... ideally without lots of work! I don't mean to sound lazy, but it feels like something that would be a common desire. I was reading about at
, including pretty
and axTicks
, also xaxt
and xaxs
and xpd
.
In plot
, xaxs
controls the width the actual data line takes up within the plot, "i" extending it to the margins and "r" (or default) squeezing it in a little. Which is cool to know, but arguably isn't the 'axis' as one would expect. (setting here is "r"/default)
Help for xaxt
lets one know that it's what you use to turn axis plotting off, but doesn't say what else it does / what they other types are.
In axis
, at
controls the axis line length, defaulting to axTicks
, which defaults to xaxp
. On the face of it, xaxp
is what I want, allowing one to specify c(x1, x2, n)
, however the default x1
& x2
are inside the data range, rather than encompassing it.
axis
help says:
"The axis line is drawn from the lowest to the highest value of at
, but will be clipped at the plot region. By default, only ticks which are drawn from points within the plot region (up to a tolerance for rounding error) are plotted, but the ticks and their labels may well extend outside the plot region. Use xpd = TRUE
or xpd = NA
to allow axes to extend further"
Neither xpd = TRUE
nor xpd = NA
seem to change anything. xpd help says:
"If FALSE, all plotting is clipped to the plot region, if TRUE, all plotting is clipped to the figure region, and if NA, all plotting is clipped to the device region"
I.e. axis
help says xpd
controls axis extension, xpd
help says xpd
controls plotting clipping.
xaxp
help says "See axTicks()
for a pure R implementation of this"
axTicks
"computes pretty tickmark locations, the same way as R does internally", and defaults to the at
values for the relevant side, i.e. par("xaxp")
.
pretty
seems scarily complex, and may well be what R
uses internally to calculate the default tick spacing when applied to at
; it would be cool to be able to edit the n
argument of that and nothing else, i.e. specify the desired number of intervals given my plotting area size, but I'm happy to leave that if it means spending a day decompiling, understanding, then manually recompiling pretty
! Also I wouldn't know whether the n
of ticks in pretty does the same thing as n
in xaxp
, and which takes priority if so.
So: R help seems to use "axis" to mean both axis (xaxt
, axis
) and plotting (xaxs
, xpd
), there's no indication whether the parameter is controlled by par
, plot
, axis
, or can be controlled by some combination of any of them (as usual). In trying to find the element responsible, axis
says at
which says axTicks
which says xaxp
which says axTicks
which says at
(= loop).
As a secondary, broader, meta question: am I doing something wrong here in terms of trying to find the answer to plotting problems? I read and read and the help is so regularly lacking, confusing, contradictory, and usually leads to an intuition black hole as to whether something should be controlled by par
, plot
or axis
. Thanks in advance guys. Sorry this is long, I genuinely thought this would be a super simple option.
Minimal reproducible example:
png(filename="A.png", width=4*480, height=4*480, units="px", pointsize=80, bg="white", res=NA, family="", type="cairo-png")
par(mar=c(1.32,2,0.4,0.5), fig=c(0,1,0,1), las=1, lwd=8, bty="n", mgp=c(2,0.5,0), xpd=NA)
plot(ChickWeight[,1:2],type="l",xaxs="i",yaxs="i")
dev.off()
The idea is to draw your own axes, not let plot use the default ones. Here's an example that seems to work,
xx <- labeling::extended(min(ChickWeight[,1]), max(ChickWeight[,1]),
3, only.loose=TRUE)
yy <- labeling::extended(min(ChickWeight[,2]), max(ChickWeight[,2]),
3, only.loose=TRUE)
plot(range(xx),range(yy), t="n", xaxt="n", yaxt="n")
points(ChickWeight[,1:2],type="p")
axis(1, at = xx)
axis(2, at = yy)