R语言axis函数在mgp[3]为非整数值时行为异常的技术问询
axis() Function: Unexpected Label Placement When mgp[3] Is Non-Integer Great question—this is one of those subtle R graphics quirks that the documentation doesn't fully spell out. Let's unpack what's happening with the mgp parameter in axis().
First, let's recap the official documentation:
From
?par: Themgp[1:3]vector specifies the margin lines (in mex units) for axis titles, axis labels, and axis lines.mgp[1]affects the title, whilemgp[2:3]affect the axis itself, with a default ofc(3, 1, 0). The?axisdocumentation echoes this, statingmgp[2]controls label position andmgp[3]controls the axis line position.
But as you've discovered, this only holds true when mgp[3] is an integer. When mgp[3] has a fractional component, the axis line still lands exactly where specified, but the axis labels get shifted to mgp[2] + (mgp[3] %% 1)—a detail completely missing from the docs.
Your example perfectly illustrates this discrepancy:
par(mar = c(5, 1, 5, 1)) plot.new() plot.window(xlim = c(0, 1), ylim = c(0, 1)) box(lty = 3) # Integer mgp[3]: labels and axis line match documented positions mgp_bottom <- c(0, 2.5, 1) # mgp[1] value doesn't affect labels/axis here axis(side = 1, mgp = mgp_bottom) mtext(c("labels", "line"), side = 1, line = mgp_bottom[2:3]) # Non-integer mgp[3]: axis line is correct, labels are offset mgp_top <- mgp_bottom - c(0, 0, 1e-3) axis(side = 3, mgp = mgp_top) mtext(c("labels", "line"), side = 3, line = mgp_top[2:3]) mtext("LABELS", side = 3, line = mgp_top[2] + (mgp_top[3] %% 1))
Is this a bug or an undocumented feature?
This is almost certainly an undocumented implementation detail rather than a bug. Digging into the base graphics C code for axis(), the label position calculation combines the fractional part of mgp[3] with mgp[2]—likely as a way to let users fine-tune label placement relative to an axis that's placed on a non-integer margin line. Since this behavior wasn't added to the documentation, it's easy to miss.
Key Takeaways
- When
mgp[3]is an integer:axis()behaves exactly as documented. - When
mgp[3]is non-integer: Labels shift tomgp[2] + (mgp[3] %% 1), while the axis line stays atmgp[3].
If you need precise control over label position regardless of mgp[3], use your manual calculation method (as shown in the example) or place labels independently with mtext().
内容的提问来源于stack exchange,提问作者Mikael Jagan




