in atlas-chart/src/main/scala/com/netflix/atlas/chart/graphics/Ticks.scala [262:306]
def logLinear(v1: Double, v2: Double, n: Int): List[ValueTick] = {
val s = LogLinear.bucketIndex(v1)
val e = LogLinear.bucketIndex(v2)
val posAndNeg = s < 0 && e > 0
val numBuckets = e - s
val majorMod = math.max(1, ((numBuckets / 9) + n - 1) / n * 9)
def idx(i: Int) = if (i < 0) -i - 1 else i
def isMajor(i: Int) = {
if (numBuckets <= n)
true
else
idx(i) % majorMod == 0
}
def includeTick(i: Int) = {
val maxTicks = n * 9
val includeAll = numBuckets < maxTicks
// One third of overall ticks. This will include the powers of 10 and for the linear
// spacing between the 4 and 7 marks.
val includeThird = numBuckets / 3 < maxTicks && idx(i) % 3 == 0
// Only include the powers of 10
val includePow10 = idx(i) % 9 == 0
includeAll || includeThird || includePow10
}
(s to e).toList
.flatMap { i =>
// Rules
// - The associated value is outside the range
// - If the range includes both positive and negative values, then ignore the first
// bucket for both sides and add a tick at zero.
// - Use all buckets if the number is less than requested number of ticks.
// - Otherwise, just include ticks at powers of 10. Major ticks should roughly match
// the requested number.
val b = LogLinear.bucket(i)
if (b < v1 || b > v2)
None
else if (posAndNeg && i == -1)
None
else if (posAndNeg && i == 0)
Some(ValueTick(0.0, 0.0))
else if (includeTick(i))
Some(ValueTick(LogLinear.bucket(i), 0.0, major = isMajor(i)))
else
None
}
}