Coverage for colour/plotting/characterisation.py: 100%
47 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-15 19:01 +1300
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-15 19:01 +1300
1"""
2Characterisation Plotting
3=========================
5Define the characterisation plotting objects.
7- :func:`colour.plotting.plot_single_colour_checker`
8- :func:`colour.plotting.plot_multi_colour_checkers`
9"""
11from __future__ import annotations
13import typing
15if typing.TYPE_CHECKING:
16 from matplotlib.figure import Figure
17 from matplotlib.axes import Axes
19import numpy as np
21if typing.TYPE_CHECKING:
22 from colour.characterisation import ColourChecker
23 from colour.hints import Any, Dict, Sequence, Tuple
25from colour.models import xyY_to_XYZ
26from colour.plotting import (
27 CONSTANTS_COLOUR_STYLE,
28 ColourSwatch,
29 XYZ_to_plotting_colourspace,
30 artist,
31 filter_colour_checkers,
32 override_style,
33 plot_multi_colour_swatches,
34 render,
35)
36from colour.utilities import attest
38__author__ = "Colour Developers"
39__copyright__ = "Copyright 2013 Colour Developers"
40__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
41__maintainer__ = "Colour Developers"
42__email__ = "colour-developers@colour-science.org"
43__status__ = "Production"
45__all__ = [
46 "plot_single_colour_checker",
47 "plot_multi_colour_checkers",
48]
51@override_style(
52 **{
53 "axes.grid": False,
54 "xtick.bottom": False,
55 "ytick.left": False,
56 "xtick.labelbottom": False,
57 "ytick.labelleft": False,
58 }
59)
60def plot_single_colour_checker(
61 colour_checker: (ColourChecker | str) = "ColorChecker24 - After November 2014",
62 **kwargs: Any,
63) -> Tuple[Figure, Axes]:
64 """
65 Plot the specified colour checker.
67 Parameters
68 ----------
69 colour_checker
70 Colour checker to plot. ``colour_checker`` can be of any type or
71 form supported by the
72 :func:`colour.plotting.common.filter_colour_checkers` definition.
74 Other Parameters
75 ----------------
76 kwargs
77 {:func:`colour.plotting.artist`,
78 :func:`colour.plotting.plot_multi_colour_swatches`,
79 :func:`colour.plotting.render`},
80 See the documentation of the previously listed definitions.
82 Returns
83 -------
84 :class:`tuple`
85 Current figure and axes.
87 Examples
88 --------
89 >>> plot_single_colour_checker("ColorChecker 2005") # doctest: +ELLIPSIS
90 (<Figure size ... with 1 Axes>, <...Axes...>)
92 .. image:: ../_static/Plotting_Plot_Single_Colour_Checker.png
93 :align: center
94 :alt: plot_single_colour_checker
95 """
97 return plot_multi_colour_checkers([colour_checker], **kwargs)
100@override_style(
101 **{
102 "axes.grid": False,
103 "xtick.bottom": False,
104 "ytick.left": False,
105 "xtick.labelbottom": False,
106 "ytick.labelleft": False,
107 }
108)
109def plot_multi_colour_checkers(
110 colour_checkers: ColourChecker | str | Sequence[ColourChecker | str],
111 **kwargs: Any,
112) -> Tuple[Figure, Axes]:
113 """
114 Plot and compare the specified colour checkers.
116 Parameters
117 ----------
118 colour_checkers
119 Colour checkers to plot, count must be less than or equal to 2.
120 ``colour_checkers`` elements can be of any type or form supported
121 by the :func:`colour.plotting.common.filter_colour_checkers`
122 definition.
124 Other Parameters
125 ----------------
126 kwargs
127 {:func:`colour.plotting.artist`,
128 :func:`colour.plotting.plot_multi_colour_swatches`,
129 :func:`colour.plotting.render`},
130 See the documentation of the previously listed definitions.
132 Returns
133 -------
134 :class:`tuple`
135 Current figure and axes.
137 Examples
138 --------
139 >>> plot_multi_colour_checkers(["ColorChecker 1976", "ColorChecker 2005"])
140 ... # doctest: +ELLIPSIS
141 (<Figure size ... with 1 Axes>, <...Axes...>)
143 .. image:: ../_static/Plotting_Plot_Multi_Colour_Checkers.png
144 :align: center
145 :alt: plot_multi_colour_checkers
146 """
148 filtered_colour_checkers = list(filter_colour_checkers(colour_checkers).values())
150 attest(
151 len(filtered_colour_checkers) <= 2,
152 "Only two colour checkers can be compared at a time!",
153 )
155 _figure, axes = artist(**kwargs)
157 compare_swatches = len(filtered_colour_checkers) == 2
159 column_counts = []
160 colour_swatches = []
161 colour_checker_names = []
162 for colour_checker in filtered_colour_checkers:
163 colour_checker_names.append(colour_checker.name)
164 column_counts.append(colour_checker.columns)
165 for label, xyY in colour_checker.data.items():
166 XYZ = xyY_to_XYZ(xyY)
167 RGB = XYZ_to_plotting_colourspace(XYZ, colour_checker.illuminant)
168 colour_swatches.append(
169 ColourSwatch(np.clip(np.ravel(RGB), 0, 1), label.title())
170 )
172 columns = np.unique(column_counts)
173 attest(len(columns) == 1)
175 if compare_swatches:
176 colour_swatches = [
177 swatch
178 for pairs in zip(
179 colour_swatches[0 : len(colour_swatches) // 2],
180 colour_swatches[len(colour_swatches) // 2 :],
181 strict=True,
182 )
183 for swatch in pairs
184 ]
186 background_colour = "0.1"
187 width = height = 1.0
188 spacing = 0.25
190 settings: Dict[str, Any] = {
191 "axes": axes,
192 "width": width,
193 "height": height,
194 "spacing": spacing,
195 "columns": columns,
196 "direction": "-y",
197 "text_kwargs": {"size": 8},
198 "background_colour": background_colour,
199 "compare_swatches": "Stacked" if compare_swatches else None,
200 }
201 settings.update(kwargs)
202 settings["show"] = False
204 plot_multi_colour_swatches(colour_swatches, **settings)
206 axes.text(
207 0.5,
208 0.005,
209 (
210 f"{', '.join(colour_checker_names)} - "
211 f"{CONSTANTS_COLOUR_STYLE.colour.colourspace.name} - "
212 f"Colour Rendition Chart"
213 ),
214 transform=axes.transAxes,
215 color=CONSTANTS_COLOUR_STYLE.colour.bright,
216 ha="center",
217 va="bottom",
218 zorder=CONSTANTS_COLOUR_STYLE.zorder.midground_label,
219 )
221 settings.update(
222 {
223 "axes": axes,
224 "show": True,
225 "title": ", ".join(colour_checker_names),
226 }
227 )
228 settings.update(kwargs)
230 return render(**settings)