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

commonMain.jetbrains.datalore.plot.builder.scale.ScaleProviderBuilder.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.builder.scale

import jetbrains.datalore.base.stringFormat.StringFormat
import jetbrains.datalore.plot.base.*
import jetbrains.datalore.plot.base.scale.BreaksGenerator
import jetbrains.datalore.plot.base.scale.Scales
import jetbrains.datalore.plot.base.scale.transform.Transforms
import jetbrains.datalore.plot.builder.guide.Orientation

class ScaleProviderBuilder constructor(private val aes: Aes) {

    private var _mapperProvider: MapperProvider? = null
    private var myName: String? = null
    private var myBreaks: List? = null
    private var myLabels: List? = null
    private var myLabelFormat: String? = null
    private var myMultiplicativeExpand: Double? = null
    private var myAdditiveExpand: Double? = null
    private var myLimits: List? = null
    private var myContinuousTransform: ContinuousTransform = Transforms.IDENTITY
    private var myBreaksGenerator: BreaksGenerator? = null

    private var myDiscreteDomain = false
    private var myDiscreteDomainReverse = false

    var axisOrientation: Orientation? = when (aes) {
        Aes.X -> Orientation.BOTTOM
        Aes.Y -> Orientation.LEFT
        else -> null
    }

    fun name(name: String): ScaleProviderBuilder {
        myName = name
        return this
    }

    fun breaks(breaks: List): ScaleProviderBuilder {
        myBreaks = breaks
        return this
    }

    @Suppress("FunctionName")
    fun minorBreaks_NI(
        @Suppress("UNUSED_PARAMETER") minorBreaks: List
    ): ScaleProviderBuilder {
        // continuous scale
        throw IllegalStateException("Not implemented")
    }

    fun labels(labels: List): ScaleProviderBuilder {
        myLabels = ArrayList(labels)
        return this
    }

    fun labelFormat(format: String?): ScaleProviderBuilder {
        myLabelFormat = format
        return this
    }

    fun multiplicativeExpand(v: Double): ScaleProviderBuilder {
        myMultiplicativeExpand = v
        return this
    }

    fun additiveExpand(v: Double): ScaleProviderBuilder {
        myAdditiveExpand = v
        return this
    }

    fun limits(v: List<*>): ScaleProviderBuilder {
        // Limits for continuous scale : list(min, max)
        // Limits for discrete scale : list ("a", "b", "c")
        myLimits = v
        return this
    }

    @Suppress("FunctionName")
    fun rescaler_NI(
        @Suppress("UNUSED_PARAMETER") v: Any
    ): ScaleProviderBuilder {
        throw IllegalStateException("Not implemented")
    }

    @Suppress("FunctionName")
    fun oob_NI(
        @Suppress("UNUSED_PARAMETER") v: Any
    ): ScaleProviderBuilder {
        throw IllegalStateException("Not implemented")
    }

    fun continuousTransform(v: ContinuousTransform): ScaleProviderBuilder {
        myContinuousTransform = v
        return this
    }

    fun breaksGenerator(v: BreaksGenerator): ScaleProviderBuilder {
        myBreaksGenerator = v
        return this
    }

    @Suppress("FunctionName")
    fun guide_NI(
        @Suppress("UNUSED_PARAMETER") v: Any
    ): ScaleProviderBuilder {
        // Name of guide object, or object itself.
        throw IllegalStateException("Not implemented")
    }

    fun discreteDomain(b: Boolean): ScaleProviderBuilder {
        myDiscreteDomain = b
        return this
    }

    fun discreteDomainReverse(b: Boolean): ScaleProviderBuilder {
        myDiscreteDomainReverse = b
        return this
    }

    fun build(): ScaleProvider {
        return MyScaleProvider(this)
    }

    private class MyScaleProvider(b: ScaleProviderBuilder) : ScaleProvider {

        private val myName: String? = b.myName

        private val myLabels: List? = b.myLabels?.let { ArrayList(it) }
        private val myLabelFormat: String? = b.myLabelFormat
        private val myMultiplicativeExpand: Double? = b.myMultiplicativeExpand
        private val myAdditiveExpand: Double? = b.myAdditiveExpand
        private val myBreaksGenerator: BreaksGenerator? = b.myBreaksGenerator
        private val myAes: Aes = b.aes

        override val discreteDomain: Boolean = b.myDiscreteDomain
        override val discreteDomainReverse: Boolean = b.myDiscreteDomainReverse

        override val breaks: List? = b.myBreaks?.let { ArrayList(it) }
        override val limits: List? = b.myLimits?.let { ArrayList(it) }

        override val continuousTransform: ContinuousTransform = b.myContinuousTransform
        override val axisOrientation: Orientation? = when (b.aes) {
            Aes.X -> {
                val orientation = b.axisOrientation!!
                require(orientation.isHorizontal) { "Illegal X-axis position: $orientation" }
                orientation
            }

            Aes.Y -> {
                val orientation = b.axisOrientation!!
                require(!orientation.isHorizontal) { "Illegal Y-axis position: $orientation" }
                orientation
            }

            else -> null
        }


        private fun scaleName(variable: DataFrame.Variable): String {
            return myName ?: variable.label
        }

        /**
         * Discrete domain.
         */
        override fun createScale(defaultName: String, discreteTransform: DiscreteTransform): Scale {
            var scale: Scale = Scales.discreteDomain(
                myName ?: defaultName,
                discreteTransform,
            )

            return completeScale(scale)
        }

        override fun createScale(
            defaultName: String,
            continuousTransform: ContinuousTransform,
            continuousRange: Boolean,
            guideBreaks: WithGuideBreaks?
        ): Scale {
            val name = myName ?: defaultName
            var scale: Scale

            // continuous (numeric) domain
            scale = Scales.continuousDomain(
                name,
                continuousRange = continuousRange || myAes.isNumeric
            )

            guideBreaks?.let {
                scale = scale.with()
                    .breaks(it.breaks)
                    .labelFormatter(it.formatter)
                    .build()
            }

            scale = scale.with()
                .continuousTransform(continuousTransform)
                .build()

            if (myBreaksGenerator != null) {
                scale = scale.with()
                    .breaksGenerator(myBreaksGenerator)
                    .build()
            }

            return completeScale(scale)
        }

        private fun completeScale(scale: Scale): Scale {
            val with = scale.with()
            if (breaks != null) {
                with.breaks(breaks)
            }
            if (myLabels != null) {
                with.labels(myLabels)
            }
            if (myLabelFormat != null) {
                with.labelFormatter(StringFormat.forOneArg(myLabelFormat)::format)
            }
            if (myMultiplicativeExpand != null) {
                with.multiplicativeExpand(myMultiplicativeExpand)
            }
            if (myAdditiveExpand != null) {
                with.additiveExpand(myAdditiveExpand)
            }
            return with.build()
        }

        private fun absentMapper(`var`: DataFrame.Variable): ScaleMapper {
            // mapper for empty data is a special case - should never be used
            return object : ScaleMapper {
                override fun invoke(v: Double?): T? {
                    throw IllegalStateException("Mapper for empty data series '" + `var`.name + "' was invoked with arg " + v)
                }
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy