All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.jetbrains.datalore.plot.base.scale.Mappers.kt Maven / Gradle / Ivy

There is a newer version: 4.5.3-alpha1
Show newest version
/*
 * 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