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

commonMain.jetbrains.datalore.plot.base.scale.DiscreteScale.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.DiscreteTransform
import jetbrains.datalore.plot.base.Scale
import jetbrains.datalore.plot.base.Transform

internal class DiscreteScale : AbstractScale {

    private val discreteTransform: DiscreteTransform

    override val transform: Transform
        get() = discreteTransform

    constructor(
        name: String,
        domainValues: Collection,
        mapper: ((Double?) -> T?)
    ) : super(name, mapper, breaks = domainValues.toList()) {
        discreteTransform = DiscreteTransform(domainValues, emptyList())

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

    private constructor(b: MyBuilder) : super(b) {
        discreteTransform = DiscreteTransform(b.myDomainValues, b.myDomainLimits)
    }

    override fun getBreaksGenerator(): BreaksGenerator {
        throw IllegalStateException("No breaks generator for discrete scale '$name'")
    }

    override fun hasDomainLimits(): Boolean {
        return discreteTransform.hasDomainLimits()
    }

    override fun isInDomainLimits(v: Any): Boolean {
        return discreteTransform.isInDomain(v)
    }

    protected override fun getBreaksIntern(): List {
        return if (!hasDomainLimits()) {
            super.getBreaksIntern()
        } else {
            // Filter and preserve the order defined by limits.
            val breaksSet = super.getBreaksIntern().toSet()
            discreteTransform.domainLimits.filter { it in breaksSet }
        }
    }

    override fun getLabelsIntern(): List {
        val labels = super.getLabelsIntern()
        return if (!hasDomainLimits() || labels.isEmpty()) {
            labels
        } else {
            val breaks = super.getBreaksIntern()
            val breakLabels = breaks.mapIndexed { i, _ -> labels[i % labels.size] }

            // Filter and preserve the order defined by limits.
            val labelByBreak = breaks.zip(breakLabels).toMap()
            discreteTransform.domainLimits
                .filter { labelByBreak.containsKey(it) }
                .map { labelByBreak.getValue(it) }
        }
    }

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

    private class MyBuilder(scale: DiscreteScale) : AbstractBuilder(scale) {
        internal val myDomainValues: Collection = scale.discreteTransform.domainValues
        internal var myDomainLimits: List = scale.discreteTransform.domainLimits

        override fun breaksGenerator(v: BreaksGenerator): Scale.Builder {
            throw IllegalStateException("Not applicable to scale with discrete domain")
        }

        override fun lowerLimit(v: Double): Scale.Builder {
            throw IllegalStateException("Not applicable to scale with discrete domain")
        }

        override fun upperLimit(v: Double): Scale.Builder {
            throw IllegalStateException("Not applicable to scale with discrete domain")
        }

        override fun limits(domainValues: List): Scale.Builder {
            myDomainLimits = domainValues
            return this
        }

        override fun continuousTransform(v: ContinuousTransform): Scale.Builder {
            // ignore
            return this
        }

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




© 2015 - 2025 Weber Informatics LLC | Privacy Policy