Source code for bokeh.models.mappers

#-----------------------------------------------------------------------------
# Copyright (c) 2012 - 2022, Anaconda, Inc., and Bokeh Contributors.
# All rights reserved.
#
# The full license is in the file LICENSE.txt, distributed with this software.
#-----------------------------------------------------------------------------
''' Models for mapping values from one range or space to another in the client.

Mappers (as opposed to scales) are not presumed to be invertible.

'''

#-----------------------------------------------------------------------------
# Boilerplate
#-----------------------------------------------------------------------------
from __future__ import annotations

import logging # isort:skip
log = logging.getLogger(__name__)

#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------

# Bokeh imports
from .. import palettes
from ..core.enums import Palette
from ..core.has_props import abstract
from ..core.properties import (
    Bool,
    Color,
    Either,
    Enum,
    FactorSeq,
    Float,
    HatchPatternType,
    Instance,
    Int,
    List,
    MarkerType,
    Nullable,
    Seq,
    String,
    Tuple,
)
from ..core.validation import warning
from ..core.validation.warnings import PALETTE_LENGTH_FACTORS_MISMATCH
from .transforms import Transform

#-----------------------------------------------------------------------------
# Globals and constants
#-----------------------------------------------------------------------------

__all__ = (
    'Mapper',
    'ColorMapper',
    'CategoricalMapper',
    'CategoricalColorMapper',
    'CategoricalMarkerMapper',
    'CategoricalPatternMapper',
    'ContinuousColorMapper',
    'LinearColorMapper',
    'LogColorMapper',
    'EqHistColorMapper',
)

#-----------------------------------------------------------------------------
# General API
#-----------------------------------------------------------------------------

[docs]@abstract class Mapper(Transform): ''' Base class for mappers. ''' # explicit __init__ to support Init signatures def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs)
[docs]@abstract class ColorMapper(Mapper): ''' Base class for color mapper types. ''' def __init__(self, *args, **kwargs) -> None: if len(args) == 1: kwargs['palette'] = args[0] super().__init__(**kwargs) palette = Seq(Color, help=""" A sequence of colors to use as the target palette for mapping. This property can also be set as a ``String``, to the name of any of the palettes shown in :ref:`bokeh.palettes`. """).accepts(Enum(Palette), lambda pal: getattr(palettes, pal)) nan_color = Color(default="gray", help=""" Color to be used if data is NaN or otherwise not mappable. """)
[docs]@abstract class CategoricalMapper(Mapper): ''' Base class for mappers that map categorical factors to other values. ''' # explicit __init__ to support Init signatures def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) factors = FactorSeq(help=""" A sequence of factors / categories that map to the some target range. For example the following color mapper: .. code-block:: python mapper = CategoricalColorMapper(palette=["red", "blue"], factors=["foo", "bar"]) will map the factor ``"foo"`` to red and the factor ``"bar"`` to blue. """) start = Int(default=0, help=""" A start index to "slice" data factors with before mapping. For example, if the data to color map consists of 2-level factors such as ``["2016", "sales"]`` and ``["2016", "marketing"]``, then setting ``start=1`` will perform color mapping only based on the second sub-factor (i.e. in this case based on the department ``"sales"`` or ``"marketing"``) """) end = Nullable(Int, help=""" A start index to "slice" data factors with before mapping. For example, if the data to color map consists of 2-level factors such as ``["2016", "sales"]`` and ``["2017", "marketing"]``, then setting ``end=1`` will perform color mapping only based on the first sub-factor (i.e. in this case based on the year ``"2016"`` or ``"2017"``) If ``None`` then all sub-factors from ``start`` to the end of the factor will be used for color mapping. """)
[docs]class CategoricalColorMapper(CategoricalMapper, ColorMapper): ''' Map categorical factors to colors. Values that are passed to this mapper that are not in the factors list will be mapped to ``nan_color``. ''' # explicit __init__ to support Init signatures def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) @warning(PALETTE_LENGTH_FACTORS_MISMATCH) def _check_palette_length(self): palette = self.palette factors = self.factors if len(palette) < len(factors): extra_factors = factors[len(palette):] return f"{extra_factors} will be assigned to `nan_color` {self.nan_color}"
[docs]class CategoricalMarkerMapper(CategoricalMapper): ''' Map categorical factors to marker types. Values that are passed to this mapper that are not in the factors list will be mapped to ``default_value``. .. note:: This mappers is primarily only useful with the ``Scatter`` marker glyph that be parameterized by marker type. ''' # explicit __init__ to support Init signatures def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) markers = Seq(MarkerType, help=""" A sequence of marker types to use as the target for mapping. """) default_value = MarkerType(default="circle", help=""" A marker type to use in case an unrecognized factor is passed in to be mapped. """)
[docs]class CategoricalPatternMapper(CategoricalMapper): ''' Map categorical factors to hatch fill patterns. Values that are passed to this mapper that are not in the factors list will be mapped to ``default_value``. Added in version 1.1.1 ''' # explicit __init__ to support Init signatures def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) patterns = Seq(HatchPatternType, help=""" A sequence of marker types to use as the target for mapping. """) default_value = HatchPatternType(default=" ", help=""" A hatch pattern to use in case an unrecognized factor is passed in to be mapped. """)
[docs]@abstract class ContinuousColorMapper(ColorMapper): ''' Base class for continuous color mapper types. ''' # explicit __init__ to support Init signatures def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) domain = List(Tuple(Instance("bokeh.models.renderers.GlyphRenderer"), Either(String, List(String))), default=[], help=""" A collection of glyph renderers to pool data from for establishing data metrics. If empty, mapped data will be used instead. """) low = Nullable(Float, help=""" The minimum value of the range to map into the palette. Values below this are clamped to ``low``. If ``None``, the value is inferred from data. """) high = Nullable(Float, help=""" The maximum value of the range to map into the palette. Values above this are clamped to ``high``. If ``None``, the value is inferred from data. """) low_color = Nullable(Color, help=""" Color to be used if data is lower than ``low`` value. If None, values lower than ``low`` are mapped to the first color in the palette. """) high_color = Nullable(Color, help=""" Color to be used if data is higher than ``high`` value. If None, values higher than ``high`` are mapped to the last color in the palette. """)
[docs]class LinearColorMapper(ContinuousColorMapper): ''' Map numbers in a range [*low*, *high*] linearly into a sequence of colors (a palette). For example, if the range is [0, 99] and the palette is ``['red', 'green', 'blue']``, the values would be mapped as follows:: x < 0 : 'red' # values < low are clamped 0 <= x < 33 : 'red' 33 <= x < 66 : 'green' 66 <= x < 99 : 'blue' 99 <= x : 'blue' # values > high are clamped ''' # explicit __init__ to support Init signatures def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs)
[docs]class LogColorMapper(ContinuousColorMapper): ''' Map numbers in a range [*low*, *high*] into a sequence of colors (a palette) on a natural logarithm scale. For example, if the range is [0, 25] and the palette is ``['red', 'green', 'blue']``, the values would be mapped as follows:: x < 0 : 'red' # values < low are clamped 0 <= x < 2.72 : 'red' # math.e ** 1 2.72 <= x < 7.39 : 'green' # math.e ** 2 7.39 <= x < 20.09 : 'blue' # math.e ** 3 20.09 <= x : 'blue' # values > high are clamped .. warning:: The ``LogColorMapper`` only works for images with scalar values that are non-negative. ''' # explicit __init__ to support Init signatures def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs)
@abstract class ScanningColorMapper(ContinuousColorMapper): # explicit __init__ to support Init signatures def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs)
[docs]class EqHistColorMapper(ScanningColorMapper): ''' ''' # explicit __init__ to support Init signatures def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) bins = Int(default=256*256, help="Number of histogram bins") rescale_discrete_levels = Bool(default=False, help=""" If there are only a few discrete levels in the values that are color mapped then ``rescale_discrete_levels=True`` decreases the lower limit of the span so that the values are rendered towards the top end of the palette. """)
#----------------------------------------------------------------------------- # Dev API #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- # Private API #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- # Code #-----------------------------------------------------------------------------