The ColorManager#

The ColorManager can take care of setting up a colormap, a corresponding normalization, and assists in drawing colorbars. Its aim is to make the matplotlib.colors module accessible via the configuration.

For instance, specifying a colormap, norm and vmin/vmax can be done like this:

cmap:
  name: magma
  under: grey
  over: white
  bad: red
norm:
  name: LogNorm
vmin: 1
vmax: 10

In the corresponding output plot, data points that go beyond vmax are shown in white, and those that cannot be represented with the custom LogNorm are shown as “bad” values in red:

ColorManager output example

Integration#

In order to make full use of the ColorManager’s capabilities, it needs to be integrated in the following way:

  • Depending on your use case, divert the cmap, norm, vmin, vmax and colorbar label arguments to initialize a ColorManager.

  • Where you would typically use the cmap and norm arguments passed through, use the corresponding properties ColorManager.cmap and ColorManager.norm instead.

  • Instead of creating the colorbar yourself, use the ColorManager.create_cbar() method, which knows about the custom colorbar labels.

This may look as follows:

from dantro.plot import ColorManager

def my_scatter_func(
    x,
    y,
    *,
    c,
    ax,
    cmap=None,
    norm=None,
    vmin: float = None,
    vmax: float = None,
    cbar_labels: Union[list, dict] = None,
    cbar_kwargs: dict = {},
    **scatter_kwargs,
):
    """This plot function illustrates ColorManager integration"""

    # Set up the ColorManager
    cm = ColorManager(
        cmap=cmap, norm=norm, vmin=vmin, vmax=vmax, labels=cbar_labels
    )

    # Now plot, passing the corresponding cmap and norm arguments ...
    scatter = ax.scatter(
        x,
        y,
        c=c,
        cmap=cm.cmap,
        norm=cm.norm,
        **scatter_kwargs,
    )

    # ... and let the ColorManager create the colorbar
    cbar = cm.create_cbar(
        scatter,
        **cbar_kwargs,
    )

    return scatter, cbar

Note

If you are not in control of the colorbar — or are not using one — you can also use parse_cmap_and_norm_kwargs(), which will extract the relevant arguments to initialize a ColorManager and return the resolved colormap and norm object.

In that case, the labels argument will not have any effect.

YAML tags#

Furthermore, YAML tags can be used to generate colormaps or norms in places where the ColorManager cannot be integrated but a corresponding matplotlib.colors.Colormap object or norm object is accepted or even required:

cmap: !cmap         # will create a matplotlib.colors.Colormap object
  continuous: true
  from_values:
    0: "#EC7070"
    0.5: "#EC9F7E"
    1: black
  bad: white
norm: !cmap_norm    # will create a matplotlib.colors.Normalize object
  name: Normalize
  vmin: 0
  vmax: 10
  clip: true

Examples#

The following examples use a YAML representation for the parameters.

Specifying colormap and vmin/vmax#

Directly specifying a colormap by name and the boundaries for the norm (falling back to the default Normalize):

cmap:
  name: viridis
  # ... can have more arguments here
vmin: 0
vmax: 10
ColorManager output example

Extreme values#

Can also specify colormap extreme values and a custom norm:

cmap:
  name: magma
  under: grey
  over: white
  bad: red
norm:
  name: LogNorm
vmin: 1
vmax: 10
ColorManager output example

Note how the “bad” values are shown in red while values that go beyond vmax are shown in white. The extend argument for ColorManager.create_cbar() can be used to control whether these colors are shown at the top or bottom of the colorbar. By default, the method inspects whether extreme values are set in the colormap and shows them and selects the fitting visualization automatically.

Custom norm#

The norm argument can be used to select a custom Normalize-derived normalization class. Arguments can simply be passed through.

Available norms are specified in NORMS.

cmap:
  name: coolwarm
  over: red
  under: blue
norm:
  name: TwoSlopeNorm
  vcenter: 0
vmin: -5
vmax: 10
ColorManager output example

Segmented colormaps#

It is easy to specify a ListedColormap using the cmap.from_values argument; the keys of that dictionary specify the positions of the segments.

The segments can either be centered around the values specified as keys or be given explicitly as the left and right edges of the respective segments.

Inferred edges#

When using scalar keys (0, 1, 4 here), the bin edges are inferred automatically:

cmap:
  from_values:
    0: r
    1: g
    4: b
  bad: w
  over: w
  under: w
labels:
  0: foo
  1: bar
  4: baz
ColorManager output example

Note

If using irregular distances between bins (as done above), the label position will not appear centered. However, the label position can be adjusted separately via the keys of labels.

Custom bin edges#

A segmented colormap with custom bin edges, achieved by passing the boundaries via 2-tuple-like keys:

cmap:
  from_values:
    [-.5, 0.5]: r
    [0.5, 1.5]: ~         # None → will use placeholder color
    [1.5, 4.5]: b
  placeholder_color: w    # default: white
ColorManager output example

Note

If passing labels here as well, they would still need scalar keys for their position.

Labels and colors (shorthand syntax)#

There is a shorthand syntax for specifying labels and the corresponding colors via a single mapping (see the cmap argument labels_and_colors below). Here, the corresponding values are inferred from the size of the mapping and vmin and/or vmax.

There

Implicit syntax#

cmap:
  first: green
  second: blue
  third: red
  fourth: orange

  # can also specify extremes here
  under: k
  over: w
ColorManager output example

Explicit syntax#

To avoid name clashes between labels and valid colormap arguments (those specified in ColorManager._POSSIBLE_CMAP_KWARGS), a more explicit syntax can be used:

cmap:
  labels_and_colors:
    # can use restricted labels here
    name: green
    colors: blue
    reversed: red
    gamma: orange
  under: k
  over: w
ColorManager output example

Custom vmin/vmax#

In cases where the inferred integer range of the labels should not start at zero, simply define vmin and/or vmax.

cmap:
  first: green
  second: blue
  third: red
  fourth: orange

  under: k
  over: w
vmin: 2
vmax: ~
ColorManager output example

Skipping values#

If some values should not be associated with a color, they can be skipped:

cmap:
  first: green
  second: blue
  " ": ~
  fourth: orange
  "  ": ~

  under: k
  over: w
ColorManager output example

Note

In order for the labels to not be shown at all, use spaces as the key of the labels_and_colors mapping. Take care to use unique mapping keys, e.g. by using different numbers of spaces.

Continuous colormaps#

A continous colormap with linearly interpolated colors (LinearSegmentedColormap) can also easily be specified:

cmap:
  continuous: true
  from_values:
    0: '#EC7070'
    0.5: '#EC9F7E'
    1: black
  under: grey
  over: white
vmin: 0
vmax: 10
ColorManager output example

With boundaries#

This can still be combined with the matplotlib.colors.BoundaryNorm:

cmap:
  continuous: true
  from_values:
    0: "#EC7070"
    0.5: "#EC9F7E"
    1: black
  under: grey
  over: white
  bad: red
norm:
  name: BoundaryNorm
  ncolors: 256
  boundaries: [-2, 2, 6, 8, 9, 10]
ColorManager output example

Note

The matplotlib.colors.BoundaryNorm does not include the upper boundary.

Alpha values for extremes#

Specifying color and alpha for the extremes is also possible:

cmap:
  name: viridis
  under:
    color: blue
    alpha: 0.5
  over:
    color: red
    alpha: 0.5
  bad: darkred
ColorManager output example

Seaborn color maps#

It is also possible to use seaborn colormaps, which opens up many new possibilities to define colormaps. These fall into three categories:

The latter two use a prefix syntax for the name argument: To use those modes, use a name argument that starts with color_palette:: or diverging::, respectively, followed by the corresponding arguments. More information and examples below.

Color palettes#

cmap:
  name: color_palette::light:#69d
vmin: 0
vmax: 10
ColorManager output example

More examples:

color_palette::YlOrBr
color_palette::icefire
color_palette::icefire_r          # reversed
color_palette::light:b            # white -> blue
color_palette::dark:b             # black -> blue
color_palette::light:#69d         # custom color
color_palette::light:#69d_r       # custom color reversed
color_palette::dark:salmon_r      # named colormap reversed
color_palette::ch:s=-.2,r=.6      # cubehelix with parameters

Hint

You may have to put these prefixed strings into quotes to avoid YAML interpreting them as mappings.

Diverging palettes#

By default, seaborn.diverging_palette() does not offer the expanded string-based syntax that seaborn.color_palette() supports. However, the ColorManager has that functionality.

cmap:
  name: diverging::250, 30, l=65, center=dark
  under: w
  over: w
vmin: -5
vmax: +5
ColorManager output example

More examples:

diverging::220,20
diverging::145,300,s=60
diverging::250, 30, l=65, center=dark

API Reference#

Below, an excerpt from the ColorManager API is shown.

ColorManager.__init__#

ColorManager.__init__(*, cmap: Optional[Union[str, dict, list, Colormap]] = None, norm: Optional[Union[str, dict, Normalize]] = None, labels: Optional[Union[List[str], Dict[float, str]]] = None, vmin: Optional[float] = None, vmax: Optional[float] = None, discretized: Optional[bool] = None)[source]

Initializes a ColorManager by building the colormap, the norm, and the colorbar labels.

Refer to the dedicated documentation page for examples and integration instructions.

Parameters
  • cmap (Union[str, dict, list, Colormap], optional) –

    The colormap specification. If this is not already a matplotlib.colors.Colormap instance, it will be parsed into a dict-like specification, which has the options as shown below.

    • If cmap is a string, it is turned into dict(name=cmap).

    • If cmap is a list (or tuple), it will be converted to dict(from_values=cmap), creating a segmented colormap. See below for more information.

    In dict form, the following arguments are available:

    name (str, optional):

    Name of a registered matplotlib colormap or None to use a default. For available colormap names, see here.

    Also supports seaborn colormaps. If the name starts with the _SNS_COLOR_PALETTE_PREFIX string, seaborn.color_palette() is used to generate the colormap. If starting with _SNS_DIVERGING_PALETTE_PREFIX, seaborn.diverging_palette() is invoked, using argument specified as part of the name.

    This opens many possibilities, as shown in the seaborn documentation. For example:

    color_palette::YlOrBr
    color_palette::icefire
    color_palette::icefire_r          # reversed
    color_palette::light:b            # white -> blue
    color_palette::dark:b             # black -> blue
    color_palette::light:#69d         # custom color
    color_palette::light:#69d_r       # ... reversed
    color_palette::dark:salmon_r      # named, reversed
    color_palette::ch:s=-.2,r=.6      # cubehelix
    
    diverging::220,20
    diverging::145,300,s=60
    diverging::250, 30, l=65, center=dark
    

    Here, the ch:<key>=<val>,<key>=<val> syntax is used to create a seaborn.cubehelix_palette(). The same <arg>,<arg>,<key>=<val>,<key>=<val> syntax is used for the diverging palette.

    Note

    When specifying these via YAML, make sure to put the string into single or double quotes to avoid it being interpreted as a YAML mapping.

    from_values (Union[dict, list], optional):

    Dict of colors keyed by bin-specifier. If given, name is ignored and a discrete colormap is created from the list of specified colors. The norm is then set to matplotlib.colors.BoundaryNorm.

    The bins can be specified either by bin-centers (Scalar) or by bin-intervals (2-tuples). For the former, the deduced bin-edges are assumed halfway between the bin-centers. For the latter, the given intervals must be pairwise connected. In both cases, the bins must monotonically increase.

    If a list of colors is passed they are automatically assigned to the bin-centers [0, 1, 2, ...], potentially shifted depending on vmin and vmax. Inferring these values is done in _infer_pos_map().

    Alternatively, a continuous, linearly interpolated colormap can be generated by setting the continuous flag, see below. This will construct a LinearSegmentedColormap. In such a case, keys in from_values can only be scalar, bin intervals cannot be specified.

    continuous (bool, optional):

    If True, will interpret the from_values data as specifying points between which a linear interpolation is carried out. Will create a LinearSegmentedColormap.

    under (Union[str, dict], optional):

    Passed on to set_under()

    over (Union[str, dict], optional):

    Passed on to set_over()

    bad (Union[str, dict], optional):

    Passed on to set_bad()

    placeholder_color (str, optional):

    None values in from_values are replaced with this color (default: white).

    reversed (bool, optional):

    If True, will reverse the colormap.

    labels_and_colors (dict, optional):

    This is a shorthand syntax for specifying colorbar labels and colors at the same time. Keys refer to labels, values to colors. The label positions and bounds are inferred using _infer_pos_map() and are affected by vmin and vmax. These may also be given implicitly via **kwargs (see below), but not at the same time!

    Effectively, the mapping is unpacked into two parts: The keys are used to specify the values of the labels dict (on the top-level); the values are used to specify the values of the cmap.from_values dict (see above). The keys are inferred from the length of the sequence and vmin and vmax, expecting to map to an integer data positions.

    Example:

    cmap:
      empty: darkkhaki            # -> 0
      susceptible: forestgreen    # -> 1
      exposed: darkorange         # ...
      infected: firebrick
      recovered: slategray
      deceased: black
      source: maroon
      inert: moccasin             # -> 7
    
      # can still set extremes here (should not appear)
      under: red
      over: red
    
    **kwargs (optional):

    Depending on the argument names, these are either passed to colormap instantiation or are used to specify the labels_and_colors mapping. For the latter, labels may not be named after arguments that are relevant for colormap initialization (_POSSIBLE_CMAP_KWARGS).

  • norm (Union[str, dict, Normalize], optional) – The norm that is applied for the color-mapping. If it is a string, the matching norm in matplotlib.colors is created with default values. If it is a dict, the name entry specifies the norm and all further entries are passed to its constructor. Overwritten if a discrete colormap is specified via cmap.from_values.

  • labels (Union[List[str], Dict[float, str]], optional) – Colorbar tick-labels keyed by tick position. If a list of labels is passed they are automatically assigned to the positions [0, 1, 2, ...] (if no vmin and vmax are given) or [vmin, vmin + 1, ..., vmax] otherwise.

  • vmin (float, optional) – The lower bound of the color-mapping. Not passed to matplotlib.colors.BoundaryNorm, which does not support it. If given, this argument in combination with vmax needs to define an integer range that has the same number of values as needed for a colormap constructed from from_values or via the label -> color mapping. If discretized is set, this value will be set to ceil(vmin) - 0.5.

  • vmax (float, optional) – The upper bound of the color-mapping. Not passed to matplotlib.colors.BoundaryNorm, which does not support it. If given, this argument in combination with vmin needs to define an integer range that has the same number of values as needed for a colormap constructed from from_values or via the label -> color mapping. If discretized is set, this value will be set to floor(vmax) + 0.5.

  • discretized (bool, optional) – If True, assumes that the data this colormap is to represent only has integer values and makes a number of changes to improve the overall visualization. For instance, if True, the vmin and vmax values will be set to the appropriate half-integer such that tick positions are centered within the corresponding range. If None (default), will do this automatically if a colormap is constructed via from_values or via label -> color mapping.

ColorManager.create_cbar#

ColorManager.create_cbar(mappable: ScalarMappable, *, fig: Optional[Figure] = None, ax: Optional[Axes] = None, label: Optional[str] = None, label_kwargs: Optional[dict] = None, tick_params: Optional[dict] = None, extend: str = 'auto', **cbar_kwargs) Colorbar[source]

Creates a colorbar of a given mappable

Parameters
Returns

The created colorbar object

Return type

Colorbar

parse_cmap_and_norm_kwargs#

parse_cmap_and_norm_kwargs(*, _key_map: Optional[dict] = None, use_color_manager: bool = True, **kws) dict[source]

A function that parses colormap-related keyword arguments and passes them through the ColorManager, making its functionality available in places that would otherwise not be able to use the expanded syntax of the color manager.

Note

The resulting dict will only have the cmap and cbar kwargs (or their mapped equivalents) set from the color manager, all other arguments are simply passed through.

In particular, this means that the labels feature of the color manager is not supported, because this function has no ability to set the colorbar.

Parameters
  • _key_map (dict, optional) – If custom keyword argument keys are expected as output, e.g. hue_cmap instead of cmap, set the values to these custom names: {"cmap": "hue_cmap"}. Expected keys are cmap, norm, vmin, vmax. If not set or partially not set, will use defaults.

  • use_color_manager (bool, optional) – If false, will simply pass through

  • **kws – Keyword arguments to parse

Returns

The updated keyword arguments with cmap and norm (or equivalent keys according to _key_map).

Return type

dict