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

commonMain.jetbrains.datalore.plot.base.Aes.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

import jetbrains.datalore.base.typedKey.TypedKey
import jetbrains.datalore.base.values.Color
import jetbrains.datalore.plot.base.render.linetype.LineType
import jetbrains.datalore.plot.base.render.point.PointShape

class Aes private constructor(val name: String, val isNumeric: Boolean = true) : TypedKey {

    val isColor: Boolean
        get() = isColor(this)

    init {
        values.add(this)
    }

    override fun toString(): String {
        return "aes '$name'"
    }

    companion object {
        private val values = ArrayList>()

        val X: Aes = Aes("x")
        val Y: Aes = Aes("y")
        val Z: Aes = Aes("z")

        val COLOR: Aes = Aes("color", false)
        val FILL: Aes = Aes("fill", false)
        val ALPHA: Aes = Aes("alpha")
        val SHAPE: Aes = Aes("shape", false)
        val LINETYPE: Aes = Aes("linetype", false)

        val SIZE: Aes = Aes("size")
        val STACKSIZE: Aes = Aes("stacksize")
        val WIDTH: Aes = Aes("width")
        val HEIGHT: Aes = Aes("height")
        val BINWIDTH: Aes = Aes("binwidth")
        val VIOLINWIDTH: Aes = Aes("violinwidth")
        val WEIGHT: Aes = Aes("weight")
        val INTERCEPT: Aes = Aes("intercept")
        val SLOPE: Aes = Aes("slope")
        val XINTERCEPT: Aes = Aes("xintercept")
        val YINTERCEPT: Aes = Aes("yintercept")
        val LOWER: Aes = Aes("lower")
        val MIDDLE: Aes = Aes("middle")
        val UPPER: Aes = Aes("upper")
        val SAMPLE: Aes = Aes("sample")
        val QUANTILE: Aes = Aes("quantile")

        val XMIN: Aes = Aes("xmin")
        val XMAX: Aes = Aes("xmax")
        val YMIN: Aes = Aes("ymin")
        val YMAX: Aes = Aes("ymax")
        val XEND: Aes = Aes("xend")
        val YEND: Aes = Aes("yend")

        val MAP_ID: Aes = Aes("map_id", false)
        val FRAME: Aes = Aes("frame", false)

        val SPEED: Aes = Aes("speed")
        val FLOW: Aes = Aes("flow")

        val LABEL: Aes = Aes("label", false)
        val FAMILY: Aes = Aes("family", false)
        val FONTFACE: Aes = Aes("fontface", false)
        val LINEHEIGHT: Aes = Aes("lineheight")

        // text horizontal justification (numbers [0..1] or predefined strings = new Aes<>(); not positional)
        val HJUST = Aes("hjust", false)

        // text vertical justification (numbers [0..1] or predefined strings, not positional)
        val VJUST = Aes("vjust", false)

        val ANGLE: Aes = Aes("angle")

        // pie geom - defines size of sector
        val SLICE: Aes = Aes("slice")
        // pie geom - to explode sector from center point, detaching it from the main pie
        val EXPLODE: Aes = Aes("explode")

        fun numeric(unfiltered: Iterable>): List> {
            // safe to cast all 'numeric' aesthetics are 'Double'
            @Suppress("UNCHECKED_CAST")
            return unfiltered.filter { aes -> aes.isNumeric } as List>
        }

        fun isPositional(aes: Aes<*>): Boolean {
            return isPositionalXY(aes) ||
                    // SLOPE must be positional or
                    // `geom_abline(slope=number)` will not work.
                    // it should draw the same line as:
                    // `geom_abline(slope=number, intersept=0)`
                    // See: PlotUtil.createLayerAesthetics()
                    aes == SLOPE
        }

        fun isPositionalXY(aes: Aes<*>): Boolean {
            return isPositionalX(aes) ||
                    isPositionalY(aes)
        }

        fun isPositionalX(aes: Aes<*>): Boolean {
            return aes == X ||
                    aes == XINTERCEPT ||
                    aes == XMIN ||
                    aes == XMAX ||
                    aes == XEND
        }

        fun isPositionalY(aes: Aes<*>): Boolean {
            return aes == Y ||
                    aes == YMIN ||
                    aes == YMAX ||
                    aes == INTERCEPT ||
                    aes == YINTERCEPT ||
                    aes == LOWER ||
                    aes == MIDDLE ||
                    aes == UPPER ||
                    aes == SAMPLE ||
                    aes == YEND
        }

        fun toAxisAes(aes: Aes<*>, isYOrientation: Boolean): Aes<*> {
            // Aes like `LOWER` (boxplot) are mapped on either X or Y-axis depending on the geom orientation.
            return when {
                aes == X || aes == Y -> aes
                isPositionalX(aes) -> if (isYOrientation) Y else X
                isPositionalY(aes) -> if (isYOrientation) X else Y
                else -> throw IllegalArgumentException("Expected a positional aes by was $aes")
            }
        }

        fun isColor(aes: Aes<*>): Boolean {
            return aes == COLOR || aes == FILL
        }

        fun affectingScaleX(aes: Aes<*>): Boolean {
            return isPositionalX(aes)
        }

        fun affectingScaleY(aes: Aes<*>): Boolean {
            return isPositionalY(aes) &&
                    // "INTERCEPT" is "positional Y" because it must use the same 'mapper' as other "positional Y"-s,
                    // but its range of values is not taken in account when computing the Y-mapper.
                    aes != INTERCEPT
        }

        fun affectingScaleX(unfiltered: Iterable>): List> {
            val numeric = numeric(unfiltered)
            return numeric.filter { affectingScaleX(it) }
        }

        fun affectingScaleY(unfiltered: Iterable>): List> {
            val numeric = numeric(unfiltered)
            return numeric.filter { affectingScaleY(it) }
        }

        fun noGuideNeeded(aes: Aes<*>): Boolean {
            return aes == MAP_ID ||
                    aes == FRAME ||
                    aes == SPEED ||
                    aes == FLOW ||
                    aes == LABEL ||
                    aes == SLOPE ||
                    aes == STACKSIZE ||
                    aes == WIDTH ||
                    aes == HEIGHT ||
                    aes == BINWIDTH ||
                    aes == VIOLINWIDTH ||
                    aes == QUANTILE ||
                    aes == HJUST ||
                    aes == VJUST ||
                    aes == ANGLE ||
                    aes == FAMILY ||
                    aes == FONTFACE ||
                    aes == LINEHEIGHT ||
                    aes == SLICE ||
                    aes == EXPLODE ||
                    isPositional(aes)
        }

        fun values(): List> {
            return values
        }

        fun allPositional(): List> {
            @Suppress("UNCHECKED_CAST")
            return values.filter { isPositional(it) } as List>
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy