Source code for colour.plotting.characterisation

"""
Characterisation Plotting
=========================

Defines the characterisation plotting objects:

-   :func:`colour.plotting.plot_single_colour_checker`
-   :func:`colour.plotting.plot_multi_colour_checkers`
"""

from __future__ import annotations

import numpy as np
from matplotlib.axes import Axes
from matplotlib.figure import Figure

from colour.characterisation import ColourChecker
from colour.hints import Any, Dict, Sequence, Tuple
from colour.models import xyY_to_XYZ
from colour.plotting import (
    CONSTANTS_COLOUR_STYLE,
    ColourSwatch,
    XYZ_to_plotting_colourspace,
    artist,
    filter_colour_checkers,
    override_style,
    plot_multi_colour_swatches,
    render,
)
from colour.utilities import attest

__author__ = "Colour Developers"
__copyright__ = "Copyright 2013 Colour Developers"
__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
__maintainer__ = "Colour Developers"
__email__ = "colour-developers@colour-science.org"
__status__ = "Production"

__all__ = [
    "plot_single_colour_checker",
    "plot_multi_colour_checkers",
]


[docs] @override_style( **{ "axes.grid": False, "xtick.bottom": False, "ytick.left": False, "xtick.labelbottom": False, "ytick.labelleft": False, } ) def plot_single_colour_checker( colour_checker: (ColourChecker | str) = "ColorChecker24 - After November 2014", **kwargs: Any, ) -> Tuple[Figure, Axes]: """ Plot given colour checker. Parameters ---------- colour_checker Color checker to plot. ``colour_checker`` can be of any type or form supported by the :func:`colour.plotting.common.filter_colour_checkers` definition. Other Parameters ---------------- kwargs {:func:`colour.plotting.artist`, :func:`colour.plotting.plot_multi_colour_swatches`, :func:`colour.plotting.render`}, See the documentation of the previously listed definitions. Returns ------- :class:`tuple` Current figure and axes. Examples -------- >>> plot_single_colour_checker("ColorChecker 2005") # doctest: +ELLIPSIS (<Figure size ... with 1 Axes>, <...Axes...>) .. image:: ../_static/Plotting_Plot_Single_Colour_Checker.png :align: center :alt: plot_single_colour_checker """ return plot_multi_colour_checkers([colour_checker], **kwargs)
[docs] @override_style( **{ "axes.grid": False, "xtick.bottom": False, "ytick.left": False, "xtick.labelbottom": False, "ytick.labelleft": False, } ) def plot_multi_colour_checkers( colour_checkers: ColourChecker | str | Sequence[ColourChecker | str], **kwargs: Any, ) -> Tuple[Figure, Axes]: """ Plot and compares given colour checkers. Parameters ---------- colour_checkers Color checker to plot, count must be less than or equal to 2. ``colour_checkers`` elements can be of any type or form supported by the :func:`colour.plotting.common.filter_colour_checkers` definition. Other Parameters ---------------- kwargs {:func:`colour.plotting.artist`, :func:`colour.plotting.plot_multi_colour_swatches`, :func:`colour.plotting.render`}, See the documentation of the previously listed definitions. Returns ------- :class:`tuple` Current figure and axes. Examples -------- >>> plot_multi_colour_checkers(["ColorChecker 1976", "ColorChecker 2005"]) ... # doctest: +ELLIPSIS (<Figure size ... with 1 Axes>, <...Axes...>) .. image:: ../_static/Plotting_Plot_Multi_Colour_Checkers.png :align: center :alt: plot_multi_colour_checkers """ filtered_colour_checkers = list(filter_colour_checkers(colour_checkers).values()) attest( len(filtered_colour_checkers) <= 2, "Only two colour checkers can be compared at a time!", ) _figure, axes = artist(**kwargs) compare_swatches = len(filtered_colour_checkers) == 2 column_counts = [] colour_swatches = [] colour_checker_names = [] for colour_checker in filtered_colour_checkers: colour_checker_names.append(colour_checker.name) column_counts.append(colour_checker.columns) for label, xyY in colour_checker.data.items(): XYZ = xyY_to_XYZ(xyY) RGB = XYZ_to_plotting_colourspace(XYZ, colour_checker.illuminant) colour_swatches.append( ColourSwatch(np.clip(np.ravel(RGB), 0, 1), label.title()) ) columns = np.unique(column_counts) attest(len(columns) == 1) if compare_swatches: colour_swatches = [ swatch for pairs in zip( colour_swatches[0 : len(colour_swatches) // 2], colour_swatches[len(colour_swatches) // 2 :], ) for swatch in pairs ] background_colour = "0.1" width = height = 1.0 spacing = 0.25 settings: Dict[str, Any] = { "axes": axes, "width": width, "height": height, "spacing": spacing, "columns": columns, "direction": "-y", "text_kwargs": {"size": 8}, "background_colour": background_colour, "compare_swatches": "Stacked" if compare_swatches else None, } settings.update(kwargs) settings["show"] = False plot_multi_colour_swatches(colour_swatches, **settings) axes.text( 0.5, 0.005, ( f"{', '.join(colour_checker_names)} - " f"{CONSTANTS_COLOUR_STYLE.colour.colourspace.name} - " f"Colour Rendition Chart" ), transform=axes.transAxes, color=CONSTANTS_COLOUR_STYLE.colour.bright, ha="center", va="bottom", zorder=CONSTANTS_COLOUR_STYLE.zorder.midground_label, ) settings.update( { "axes": axes, "show": True, "title": ", ".join(colour_checker_names), } ) settings.update(kwargs) return render(**settings)