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

commonMain.jetbrains.datalore.plot.base.scale.ContinuousScale.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.plot.base.ContinuousTransform
import jetbrains.datalore.plot.base.Scale
import jetbrains.datalore.plot.base.Transform
import jetbrains.datalore.plot.base.scale.transform.Transforms
import jetbrains.datalore.plot.base.scale.transform.Transforms.createBreaksGeneratorForTransformedDomain
import jetbrains.datalore.plot.common.data.SeriesUtil
import kotlin.math.max
import kotlin.math.min

internal class ContinuousScale : AbstractScale {

    private val continuousTransform: ContinuousTransform
    private val customBreaksGenerator: BreaksGenerator?

    override val isContinuous: Boolean
    override val isContinuousDomain: Boolean = true
    val continuousDomainLimits: Pair

    override val transform: Transform
        get() = continuousTransform

    constructor(
        name: String,
        mapper: ((Double?) -> T?),
        continuousOutput: Boolean
    ) : super(name, mapper) {
        isContinuous = continuousOutput
        continuousDomainLimits = Pair(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY)
        continuousTransform = Transforms.IDENTITY
        customBreaksGenerator = null

        // see: https://ggplot2.tidyverse.org/reference/scale_continuous.html
        // defaults for continuous scale.
        multiplicativeExpand = 0.05
        additiveExpand = 0.0
    }

    private constructor(b: MyBuilder) : super(b) {
        continuousTransform = b.myContinuousTransform
        customBreaksGenerator = b.myCustomBreaksGenerator
        isContinuous = b.myContinuousOutput
        val lower = if (SeriesUtil.isFinite(b.myLowerLimit)) b.myLowerLimit!! else Double.NEGATIVE_INFINITY
        val upper = if (SeriesUtil.isFinite(b.myUpperLimit)) b.myUpperLimit!! else Double.POSITIVE_INFINITY
        continuousDomainLimits = Pair(
            min(lower, upper),
            max(lower, upper)
        )
    }

    override fun getBreaksGenerator(): BreaksGenerator {
        return if (customBreaksGenerator != null) {
            Transforms.BreaksGeneratorForTransformedDomain(continuousTransform, customBreaksGenerator)
        } else {
            createBreaksGeneratorForTransformedDomain(continuousTransform, labelFormatter)
        }
    }

    override fun isInDomainLimits(v: Any): Boolean {
        return if (v is Number) {
            val d = v.toDouble()
            d.isFinite() && d >= continuousDomainLimits.first && d <= continuousDomainLimits.second
        } else {
            false
        }
    }

    override fun hasDomainLimits(): Boolean {
        return continuousDomainLimits.first.isFinite() || continuousDomainLimits.second.isFinite()
    }

    override fun with(): Scale.Builder {
        return MyBuilder(this)
    }


    private class MyBuilder(scale: ContinuousScale) : AbstractBuilder(scale) {
        var myContinuousTransform: ContinuousTransform = scale.continuousTransform
        var myCustomBreaksGenerator: BreaksGenerator? = scale.customBreaksGenerator
        var myLowerLimit: Double? = scale.continuousDomainLimits.first
        var myUpperLimit: Double? = scale.continuousDomainLimits.second

        val myContinuousOutput: Boolean = scale.isContinuous

        override fun lowerLimit(v: Double): Scale.Builder {
            require(v.isFinite()) { "`lower` can't be $v" }
            myLowerLimit = v
            return this
        }

        override fun upperLimit(v: Double): Scale.Builder {
            require(v.isFinite()) { "`upper` can't be $v" }
            myUpperLimit = v
            return this
        }

        override fun limits(domainValues: List): Scale.Builder {
            throw IllegalArgumentException("Can't apply discrete limits to scale with continuous domain")
        }

        override fun continuousTransform(v: ContinuousTransform): Scale.Builder {
            myContinuousTransform = v
            return this
        }

        override fun breaksGenerator(v: BreaksGenerator): Scale.Builder {
            myCustomBreaksGenerator = v
            return this
        }

        override fun build(): Scale {
            return ContinuousScale(this)
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy