commonMain.jetbrains.datalore.plot.base.scale.ScaleUtil.kt Maven / Gradle / Ivy
/*
* Copyright (c) 2019. JetBrains s.r.o.
* Use of this source code is governed by the MIT license that can be found in the LICENSE file.
*/
package jetbrains.datalore.plot.base.scale
import jetbrains.datalore.base.gcommon.base.Preconditions.checkState
import jetbrains.datalore.base.gcommon.collect.ClosedRange
import jetbrains.datalore.base.geometry.DoubleVector
import jetbrains.datalore.plot.base.CoordinateSystem
import jetbrains.datalore.plot.base.Scale
import jetbrains.datalore.plot.base.scale.transform.LinearBreaksGen
object ScaleUtil {
fun labels(scale: Scale<*>): List {
if (!scale.hasBreaks()) {
return emptyList()
}
val breaks = scale.breaks
if (scale.hasLabels()) {
val labels = scale.labels
if (breaks.size <= labels.size) {
return labels.subList(0, breaks.size)
}
val result = ArrayList()
for (i in breaks.indices) {
if (labels.isEmpty()) {
result.add("")
} else {
result.add(labels[i % labels.size])
}
}
return result
}
val formatter: (Any) -> String = scale.labelFormatter ?: { v: Any -> v.toString() }
// generate labels
return breaks.map { formatter(it) }
}
fun labelByBreak(scale: Scale<*>): Map {
val result = HashMap()
if (scale.hasBreaks()) {
val breaks = scale.breaks.iterator()
val labels = labels(scale).iterator()
while (breaks.hasNext() && labels.hasNext()) {
result[breaks.next()] = labels.next()
}
}
return result
}
fun breaksAsNumbers(scale: Scale<*>): List {
val breaks = scale.breaks
val numbers = ArrayList()
for (o in breaks) {
numbers.add(scale.asNumber(o)!!)
}
return numbers
}
fun breaksTransformed(scale: Scale<*>): List {
return transform(scale.breaks, scale).map { it!! }
}
fun axisBreaks(scale: Scale, coord: CoordinateSystem, horizontal: Boolean): List {
val scaleBreaks = transformAndMap(scale.breaks, scale)
val axisBreaks = ArrayList()
for (br in scaleBreaks) {
val mappedBrPoint = if (horizontal)
DoubleVector(br!!, 0.0)
else
DoubleVector(0.0, br!!)
val axisBrPoint = coord.toClient(mappedBrPoint)
val axisBr = if (horizontal)
axisBrPoint.x
else
axisBrPoint.y
axisBreaks.add(axisBr)
if (!axisBr.isFinite()) {
throw IllegalStateException(
"Illegal axis '" + scale.name + "' break position " + axisBr +
" at index " + (axisBreaks.size - 1) +
"\nsource breaks : " + scale.breaks +
"\ntranslated breaks: " + scaleBreaks +
"\naxis breaks : " + axisBreaks
)
}
}
return axisBreaks
}
fun breaksAesthetics(scale: Scale): List {
return transformAndMap(scale.breaks, scale)
}
fun map(range: ClosedRange, scale: Scale): ClosedRange {
return MapperUtil.map(range, scale.mapper)
}
fun map(d: Double?, scale: Scale): T? {
return scale.mapper(d)
}
fun map(d: List, scale: Scale): List {
val result = ArrayList()
for (t in d) {
result.add(map(t, scale))
}
return result
}
private fun transformAndMap(l: List<*>, scale: Scale): List {
val tl = transform(l, scale)
return map(tl, scale)
}
fun transform(l: List<*>, scale: Scale<*>): List {
return scale.transform.apply(l)
}
fun inverseTransformToContinuousDomain(l: List, scale: Scale<*>): List {
checkState(scale.isContinuousDomain, "Not continuous numeric domain: $scale")
@Suppress("UNCHECKED_CAST")
return inverseTransform(l, scale) as List
}
fun inverseTransform(l: List, scale: Scale<*>): List<*> {
val transform = scale.transform
val result = ArrayList(l.size)
for (v in l) {
result.add(transform.applyInverse(v))
}
return result
}
fun transformedDefinedLimits(scale: Scale<*>): List {
return if (scale.hasDomainLimits()) {
val l = listOf(scale.domainLimits!!.lowerEnd, scale.domainLimits!!.upperEnd)
transform(l, scale).filterNotNull().filter { it.isFinite() }.toList()
} else {
emptyList()
}
}
fun getBreaksGenerator(scale: Scale<*>): BreaksGenerator {
return when {
scale.hasBreaksGenerator() -> scale.breaksGenerator
else -> LinearBreaksGen(scale.labelFormatter)
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy