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

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

/*
 * 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.gcommon.base.Preconditions.checkState
import jetbrains.datalore.base.gcommon.collect.ClosedRange
import jetbrains.datalore.base.geometry.DoubleVector
import jetbrains.datalore.plot.base.CoordinateSystem
import jetbrains.datalore.plot.base.Scale
import jetbrains.datalore.plot.base.scale.transform.LinearBreaksGen

object ScaleUtil {

    fun labels(scale: Scale<*>): List {
        if (!scale.hasBreaks()) {
            return emptyList()
        }

        val breaks = scale.breaks
        if (scale.hasLabels()) {
            val labels = scale.labels

            if (breaks.size <= labels.size) {
                return labels.subList(0, breaks.size)
            }

            val result = ArrayList()
            for (i in breaks.indices) {
                if (labels.isEmpty()) {
                    result.add("")
                } else {
                    result.add(labels[i % labels.size])
                }
            }
            return result
        }

        val formatter: (Any) -> String = scale.labelFormatter ?: { v: Any -> v.toString() }
        // generate labels
        return breaks.map { formatter(it) }
    }

    fun labelByBreak(scale: Scale<*>): Map {
        val result = HashMap()
        if (scale.hasBreaks()) {
            val breaks = scale.breaks.iterator()
            val labels = labels(scale).iterator()
            while (breaks.hasNext() && labels.hasNext()) {
                result[breaks.next()] = labels.next()
            }
        }
        return result
    }

    fun breaksAsNumbers(scale: Scale<*>): List {
        val breaks = scale.breaks
        val numbers = ArrayList()
        for (o in breaks) {
            numbers.add(scale.asNumber(o)!!)
        }
        return numbers
    }

    fun breaksTransformed(scale: Scale<*>): List {
        return transform(scale.breaks, scale).map { it!! }
    }

    fun axisBreaks(scale: Scale, coord: CoordinateSystem, horizontal: Boolean): List {
        val scaleBreaks = transformAndMap(scale.breaks, scale)
        val axisBreaks = ArrayList()
        for (br in scaleBreaks) {
            val mappedBrPoint = if (horizontal)
                DoubleVector(br!!, 0.0)
            else
                DoubleVector(0.0, br!!)

            val axisBrPoint = coord.toClient(mappedBrPoint)
            val axisBr = if (horizontal)
                axisBrPoint.x
            else
                axisBrPoint.y

            axisBreaks.add(axisBr)
            if (!axisBr.isFinite()) {
                throw IllegalStateException(
                    "Illegal axis '" + scale.name + "' break position " + axisBr +
                            " at index " + (axisBreaks.size - 1) +
                            "\nsource breaks    : " + scale.breaks +
                            "\ntranslated breaks: " + scaleBreaks +
                            "\naxis breaks      : " + axisBreaks
                )
            }
        }
        return axisBreaks
    }

    fun  breaksAesthetics(scale: Scale): List {
        return transformAndMap(scale.breaks, scale)
    }

    fun map(range: ClosedRange, scale: Scale): ClosedRange {
        return MapperUtil.map(range, scale.mapper)
    }

    fun  map(d: Double?, scale: Scale): T? {
        return scale.mapper(d)
    }

    fun  map(d: List, scale: Scale): List {
        val result = ArrayList()
        for (t in d) {
            result.add(map(t, scale))
        }
        return result
    }

    private fun  transformAndMap(l: List<*>, scale: Scale): List {
        val tl = transform(l, scale)
        return map(tl, scale)
    }

    fun transform(l: List<*>, scale: Scale<*>): List {
        return scale.transform.apply(l)
    }

    fun inverseTransformToContinuousDomain(l: List, scale: Scale<*>): List {
        checkState(scale.isContinuousDomain, "Not continuous numeric domain: $scale")
        @Suppress("UNCHECKED_CAST")
        return inverseTransform(l, scale) as List
    }

    fun inverseTransform(l: List, scale: Scale<*>): List<*> {
        val transform = scale.transform
        val result = ArrayList(l.size)
        for (v in l) {
            result.add(transform.applyInverse(v))
        }
        return result
    }

    fun transformedDefinedLimits(scale: Scale<*>): List {
        return if (scale.hasDomainLimits()) {
            val l = listOf(scale.domainLimits!!.lowerEnd, scale.domainLimits!!.upperEnd)
            transform(l, scale).filterNotNull().filter { it.isFinite() }.toList()
        } else {
            emptyList()
        }
    }

    fun getBreaksGenerator(scale: Scale<*>): BreaksGenerator {
        return when {
            scale.hasBreaksGenerator() -> scale.breaksGenerator
            else -> LinearBreaksGen(scale.labelFormatter)
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy