log10scaleround = function(x) {
v = log10(c(1, 2, 5, 10))
lx = log10(x)
10^(floor(lx) vapply(lx %% 1, function(r) v[which.min(abs(v - r))], 0))
}
log10scaleround(c(0.2589254, 20.5671765))
[1] 0.2 20.0
The above function can round numbers in log10 scale to numbers like .1, .2, .5, 1, 2, 5, 10, 20, 50, 100.
Given a boundary like 0.2, 20.0, I want to fill in numbers in between like .5, 1, 2, 5, 10.
That is, for input like 0.2589254, 20.5671765, I want the output be c(.2, .5, 1, 2, 5, 10, 20).
I could use a for-loop to solve this problem. But it is not efficient. How to program this efficiently in R?
CodePudding user response:
I think all that was needed was usage of the outer product operator.
log10scaleround <- function(x){
logrange <- floor(log10(x))
fill <- c(c(1,2,5,10) %o% 10^(logrange[1]:logrange[2]))
fill[fill >= x[1] & fill <= x[2]]
}
Which yields:
> log10scaleround(c(0.2589254, 20.5671765))
[1] 0.5 1.0 1.0 2.0 5.0 10.0 10.0 20.0
As previously stated by @jpsmith, the returned vector should not contain 0.2
.
If your use case does not conform to that, then removing the fill >= x[1]
should sort that right out.
CodePudding user response:
Here's something that works. Maybe it could be more efficient.
logSeq <- function(x){
lx1 = floor(log10(min(x)))
lx2 = ceiling(log10(max(x)))
z=rep(10^(lx1:lx2), each=3)*c(1,2,5)
z[z>=log10scaleround(min(x))-0.001 &
z<=log10scaleround(max(x)) 0.001]
}
> logSeq(c(0.2589254, 20.5671765))
[1] 0.2 0.5 1.0 2.0 5.0 10.0 20.0