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

    override val isContinuous: Boolean = false
    override val isContinuousDomain: Boolean = false

    constructor(
        name: String,
        discreteTransform: DiscreteTransform,
    ) : super(name, breaks = null) {
        this.discreteTransform = discreteTransform

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

    private constructor(b: MyBuilder) : super(b) {
        discreteTransform = b.discreteTransform
    }

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

    override fun hasBreaks(): Boolean {
        // Discrete scale always has breaks: either "defined" or "effective domain".
        return true
    }

    protected override fun getBreaksIntern(): List {
        return if (hasDefinedBreaks()) {
            // Intersect, preserve the order in the 'domain'.
            val breaksSet = super.getBreaksIntern().toSet()
            discreteTransform.effectiveDomain.filter { it in breaksSet }
        } else {
            discreteTransform.effectiveDomain
        }
    }

    protected override fun getLabelsIntern(): List {
        val labels = super.getLabelsIntern()
        return if (!transform.hasDomainLimits() || labels.isEmpty()) {
            labels
        } else if (!hasDefinedBreaks()) {
            labels
        } else {
            // Associate 'defined labels' with 'defined breaks', then re-order according to the domain order.
            val breaks = super.getBreaksIntern()  // Defined breaks!
            val breakLabels = List(breaks.size) { i -> if (i < labels.size) labels[i] else "" }

            // Filter and preserve the order.
            val labelByBreak = breaks.zip(breakLabels).toMap()
            discreteTransform.effectiveDomain
                .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 discreteTransform: DiscreteTransform = scale.discreteTransform

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

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

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




© 2015 - 2025 Weber Informatics LLC | Privacy Policy