As far as I can tell, yes but it's a bit gross.
TLDR::
b <- a +
# reverse ticks
annotation_logticks(short=unit(-0.1, "cm"), mid=unit(-0.2, "cm"), long=unit(-0.3,"cm")) +
# remove clipping
coord_cartesian(clip="off") +
# add space between ticks and labels
theme(axis.text.x=element_text(margin = margin(t = 10)), axis.text.y=element_text(margin = margin(r = 10)))
# get the limits of the panel in data coordinates
bb <- ggplot_build(b)$layout$panel_params[[1]]
# draw a white rectangle to cover up the additional tick marks, gross
# the coordinates are actually in powers of 10 of the data
b +
annotation_custom(
grob=rectGrob(gp=gpar(col=NA)),
# the min values are -100 ie "something very large and negative"
# the max values are the bottom-left corner of the plot plus a tiny
# fudge factor to cover up the stubs of the ticks (gross)
xmin=-100, xmax=min(ab$x.range) + 0.01,
ymax=min(ab$y.range) + 0.01, ymin=-100
)
yields

You have to fudge the 0.01s and -100s in the annotation_custom
.
If you look at annotation_logticks
in the console, it has
layer(data = dumy_data(), # more stuff,
geo = GeomLogticks, # lots more stuff
ggplot2:::GeomLogticks
(it is not an exported function hence the triple :::
to inspect it) shows an object with various functions to draw the ticks. Some trial and error shows that ggplot2:::GeomLogticks$draw_panel
appears to be the function that does all the work. It looks like this function makes a dataframe with coordinates of the xstart, xend, ystart, yend of each individual tick (!).
e.g. a snippet from the body of that function
if (grepl("l", sides)) {
ticks$y_l <- with(data, segmentsGrob(y0 = unit(yticks$y,
"native"), y1 = unit(yticks$y, "native"), x0 = unit(yticks$start,
"cm"), x1 = unit(yticks$end, "cm"), gp = gpar(col = alpha(colour,
alpha), lty = linetype, lwd = size * .pt)))
}
From this, it seems we can just provide negative lengths to annotation_logticks
a2 <- a + annotation_logticks(short=unit(-0.1, "cm"), mid=unit(-0.2, "cm"), long=unit(-0.3,"cm"))
a2

This doesn't really work, you can sort of see the stubs of all the tick marks if you squint hard. It looks like the tick marks are drawing correctly, but they are being clipped by the panel area. (If you temporarily turn off the panel border a2 + theme(panel.border=element_rect(fill=NA, color=NA))
you can see this is the case).
To turn off clipping you can do + coord_cartesian(clip='off')
a3 <- a2 + coord_cartesian(clip='off')
a3

As mentioned in ?coord_cartesian
for the clip
argument, this can lead to "unexpected results" - the ticks are defined for a greater region than the data (I think they do full powers of 10, so if the smallest data point is half-way through a power of 10 it still calculates all the way down to the next lower power) so extend beyond the lower left corner.
A gross way to work around this is to draw a rectangle over the bottom-left part of the graph (outside the panel/in the margin) to cover up the tick marks. annotation_custom
does this but requires coordinates in data coordinates. When using the log scale like this, the coordinates are in powers of 10, so e.g. the "10^-4" is coordinate -4.
So to draw the rectangle to cover up the extra marks, we need to have lower-left corner essentially at negative infinity (bottom left corner of the graph), and the upper-right corner at the minimum values on the X/Y axis.
In annotation_custom
we want a rectGrob
to draw a rectangle. It has a white background by default but a black border which we disable using gpar(col=NA)
. We set the xmin
and ymin
coordinates to -100 (essentially something very large and negative; -Inf
means "the lowest axis value"). We can set the xmax
and ymax
coordinates to the lowest axis values, which -Inf
will do for us.
a3 +
annotation_custom(
grob=rectGrob(gp=gpar(col=NA)),
xmin=-100, xmax=-Inf,
ymax=-Inf, ymin=-100
)
For me this doesn't quite cover up the extra tick marks, leaving annoying little dots.

Really I want the xmax
and ymax
to be -Inf + a little bit
to cover up the entirety of the tick marks. But to do this we can't use -Inf
as a shorthand for "lower limit of the axis" any more, we have to access them explicitly using
bb <- ggplot_build(b)$layout$panel_params[[1]]
# bb$x.range, bb$y.range
Then we modify the above
a4 <- a3 +
annotation_custom(
grob=rectGrob(gp=gpar(col=NA)),
xmin=-100, xmax=min(ab$x.range) + 0.01,
ymax=min(ab$y.range) + 0.01, ymin=-100
)
a4
(I found the 0.01 by trial and error, that's not great).
This is now fine, except that the X and Y axis labels run into the ticks.
To add spacing between the labels and tick marks use
a5 <- a4 + theme(axis.text.x=element_text(margin = margin(t = 10)),
axis.text.y=element_text(margin = margin(r = 10)))
a5
where these are margins in pixels (you can change the units, see ?margin
)
yielding the picture you saw first.
You could make it a function perhaps, allowing the user to modify the various fudge factors (the -100, + 0.01, and margin of 10 pixels).