commonMain.jetbrains.datalore.plot.base.scale.Mappers.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lets-plot-common Show documentation
Show all versions of lets-plot-common Show documentation
Lets-Plot JVM package without rendering part
/*
* 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.function.Function
import jetbrains.datalore.base.interval.DoubleSpan
import jetbrains.datalore.plot.base.DiscreteTransform
import jetbrains.datalore.plot.base.ScaleMapper
import jetbrains.datalore.plot.base.scale.breaks.QuantizeScale
import jetbrains.datalore.plot.common.data.SeriesUtil
object Mappers {
val IDENTITY = object : ScaleMapper {
override fun invoke(v: Double?): Double? = v
}
val NUMERIC_UNDEFINED: ScaleMapper = undefined()
fun undefined(): ScaleMapper = object : ScaleMapper {
override fun invoke(v: Double?): T? {
throw IllegalStateException("Undefined mapper")
}
}
fun emptyDataMapper(label: String): ScaleMapper {
// mapper for empty data is a special case - should never be used
return object : ScaleMapper {
override fun invoke(v: Double?): T? {
throw throw IllegalStateException("Mapper for empty data series '$label' was invoked with arg " + v)
}
}
}
fun constant(constant: T): ScaleMapper = object : ScaleMapper {
override fun invoke(v: Double?): T? = constant
}
fun mul(domain: DoubleSpan, rangeSpan: Double): ScaleMapper {
val factor = rangeSpan / domain.length
return mul(factor)
}
fun mul(factor: Double): ScaleMapper {
check(factor.isFinite()) { "Can't create mapper with ratio: $factor" }
return object : ScaleMapper {
override fun invoke(v: Double?): Double? {
return if (v != null) factor * v
else null
}
}
}
fun linear(domain: DoubleSpan, range: DoubleSpan, reverse: Boolean = false): ScaleMapper {
return linear(
domain,
rangeLow = if (reverse) range.upperEnd else range.lowerEnd,
rangeHigh = if (reverse) range.lowerEnd else range.upperEnd,
null
)
}
fun linear(domain: DoubleSpan, range: DoubleSpan, defaultValue: Double): ScaleMapper {
return linear(
domain,
range.lowerEnd,
range.upperEnd,
defaultValue
)
}
fun linear(
domain: DoubleSpan,
rangeLow: Double,
rangeHigh: Double,
defaultValue: Double?
): ScaleMapper {
val slop = (rangeHigh - rangeLow) / (domain.upperEnd - domain.lowerEnd)
if (!SeriesUtil.isFinite(slop)) {
// no slop
val v = (rangeHigh - rangeLow) / 2 + rangeLow
return constant(v)
}
val intersect = rangeLow - domain.lowerEnd * slop
return object : ScaleMapper {
override fun invoke(v: Double?): Double? {
return if (v != null && v.isFinite())
v * slop + intersect
else
defaultValue
}
}
}
fun discreteToContinuous(
transformedDomain: List,
outputRange: DoubleSpan,
naValue: Double
): ScaleMapper {
val dataRange = SeriesUtil.range(transformedDomain) ?: return IDENTITY
return linear(dataRange, outputRange, naValue)
}
fun discrete(
discreteTransform: DiscreteTransform,
outputValues: List,
defaultOutputValue: T?
): ScaleMapper {
return object : ScaleMapper {
override fun invoke(v: Double?): T? {
// The input is a transformed domain value.
val domainValue = discreteTransform.applyInverse(v)
val index: Int = domainValue?.let { discreteTransform.indexOf(it) } ?: return defaultOutputValue
return outputValues[index % outputValues.size]
}
}
}
fun quantized(
domain: DoubleSpan?,
outputValues: Collection,
defaultOutputValue: T
): ScaleMapper {
if (domain == null) {
return constant(defaultOutputValue)
}
// todo: extract quantizer
val quantizer = QuantizeScale()
quantizer.domain(domain.lowerEnd, domain.upperEnd)
quantizer.range(outputValues)
val f = QuantizedFun(quantizer, defaultOutputValue)
return object : ScaleMapper {
override fun invoke(v: Double?): T? {
return f.apply(v)
}
}
}
private class QuantizedFun internal constructor(
private val myQuantizer: QuantizeScale,
private val myDefaultOutputValue: T
) : Function {
override fun apply(value: Double?): T {
return if (!SeriesUtil.isFinite(value)) myDefaultOutputValue else myQuantizer.quantize(value!!)
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy