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

io.data2viz.scale.Band.kt Maven / Gradle / Ivy

package io.data2viz.scale

import kotlin.math.floor
import kotlin.math.max


/**
 * Retu
 */
abstract class BandedScale(private val indexableDomain: IndexableDomain = IndexableDomain()) : 
        Scale, 
        DiscreteDomain by indexableDomain, 
        Tickable, 
        StrictlyContinuousRange {

    private val unknown = Double.NaN

    protected var _paddingInner: Double = 0.0
    protected var _paddingOuter: Double = 0.0

    abstract var padding:Double

    override var domain: List
        get() = indexableDomain._domain
        set(value) {
            indexableDomain.domain = value
            rescale()
        }
    override var range: StrictlyContinuous = intervalOf(0.0, 1.0)
        get() = field
        set(value) {
            field = value
            rescale()
        }

    var round: Boolean = false
        set(value) {
            field = value
            rescale()
        }

    var align: Double = 0.5
        set(value) {
            field = value.coerceIn(.0 .. 1.0)
            rescale()
        }

    var step: Double = 1.0
        private set

    var bandwidth: Double = 1.0
        private set

    private var ordinalRange: MutableList = ArrayList()

    override operator fun invoke(domainValue: D): Double {
        val i: Int = indexableDomain.index[domainValue] ?: return unknown
        return if (ordinalRange.isEmpty()) unknown else ordinalRange[i]
    }

    override fun ticks(count: Int): List = domain

    protected fun rescale() {
        val n = indexableDomain._domain.size
        val reverse = range.end < range.start
        var start = if (reverse) range.end else range.start
        val stop = if (reverse) range.start else range.end
        step = (stop - start) / max(1.0, n - _paddingInner + _paddingOuter * 2)
        if (round)
            step = floor(step)

        start += (stop - start - step * (n - _paddingInner)) * align
        bandwidth = step * (1 - _paddingInner)
        if (round) {
            start = kotlin.math.round(start)
            bandwidth = kotlin.math.round(bandwidth)
        }

        val values: Array = Array(n, { start + step * it })
        if (reverse) values.reverse()
        ordinalRange.clear()
        ordinalRange.addAll(values)
    }
}

/**
 * Represents domain as band (for barchart for example).
 * 
 * BandScale.invoke(domain) returns the coordinate of the start of each band.
 * 
 * 
 * [padding]
 * 
 * [paddingInner] representents the size between 
 * 
 * Band scales are like ordinal scales except the output range is continuous and numeric.
 * Discrete output values are automatically computed by the scale by dividing the continuous range into uniform bands.
 * Band scales are typically used for bar charts with an ordinal or categorical dimension.
 * The unknown value of a band scale is always NaN: they do not allow implicit domain construction.
 */
class BandScale : BandedScale() {

    override var padding: Double
        get() = _paddingInner
        set(value) {
            _paddingInner = value
            _paddingOuter = value
            rescale()
        }

    var paddingInner
        get() = _paddingInner
        set(value) {
            _paddingInner = value.coerceIn(.0 .. 1.0)
            rescale()
        }

    var paddingOuter
        get() = _paddingOuter
        set(value) {
            _paddingOuter = value.coerceIn(.0 .. 1.0)
            rescale()
        }
}

/**
 * Point scales are a variant of band scales with the bandwidth fixed to zero.
 * Point scales are typically used for scatterplots with an ordinal or categorical dimension.
 * The unknown value of a point scale is always NaN: they do not allow implicit domain construction.
 */
class PointScale : BandedScale() {

    /**
     * Sets the outer padding to the specified value which must be in the range [0, 1].
     * Returns the current outer padding which defaults to 0.
     * The outer padding determines the ratio of the range that is reserved for blank space before the first
     * point and after the last point. Equivalent to band.paddingOuter.
     */
    override var padding:Double
        get() = _paddingOuter
        set(value) {
            _paddingOuter = value
            rescale()
        }

    init {
        _paddingInner = 1.0
        rescale()
    }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy