Plain code version

library(scales)

## log_breaks  is crazy!
log_breaks(n=3)(c(1, 1.2))
## [1]  1 10
log_breaks(n=4)(c(1, 1.2))
## [1] 1.00 1.05 1.10 1.15 1.20
## axisTicks is clunky, and gets carried away!
axisTicks(nint=4, log=TRUE, usr=log(c(1, 20)))
## [1]   1   2   5  10  20  50 100 200 500
## The best I can do for now.

limBreaks <- function(v, n=5){
    b <- axisTicks(nint=n, log=TRUE, usr=range(v))
    upr <- min(b[log(b)>=max(v)])
    lwr <- max(b[log(b)<=min(v)])
    ## print(c(lwr=lwr, upr=upr))
    return(b[(b>=lwr) & (b<=upr)])
}

divmultbreaks <- function(v, n=6, nmin=3, anchor=TRUE){
    if (anchor) v <- unique(c(v, 1))
    v <- log(v)
    neg <- min(v)
    if (neg==0) return(limBreaks(v, n))
    pos <- max(v)
    if (pos==0) return(1/limBreaks(-v, n))

    flip <- -neg
    big <- pmax(pos, flip)
    small <- pmin(pos, flip)
    bigprop <- big/(pos + flip)
    bigticks <- ceiling(n*bigprop)

    main <- limBreaks(c(0, big), bigticks)
    cut <- pmin(bigticks, 1+sum(main<small))
    if(cut<nmin)
        other <- limBreaks(c(0, small), nmin)
    else
        other <- main[1:cut]

    breaks <- c(main, 1/other)
    if (flip > pos) breaks <- 1/breaks
    return(sort(unique(breaks)))
}

divmultbreaks(c(11))
## [1]  1  2  5 10 20
divmultbreaks(c(0.04))
## [1] 1.00 0.20 0.10 0.02
divmultbreaks(c(0.04, 11))
## [1]  0.02  0.10  0.20  1.00  2.00  5.00 10.00 20.00
divmultbreaks(c(0.02, 2))
## [1] 0.02 0.10 0.20 1.00 2.00
divmultbreaks(c(0.8, 20))
## [1]  0.7142857  0.8333333  1.0000000  2.0000000  5.0000000 10.0000000 20.0000000
y <- (exp(seq(-2,5,0.2)))
range(y)
## [1]   0.1353353 148.4131591
divmultbreaks(y)
## [1] 1e-01 2e-01 5e-01 1e+00 1e+01 1e+02 1e+03