Coverage for colour/plotting/diagrams.py: 100%
217 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"""
2CIE Chromaticity Diagrams Plotting
3==================================
5Define the *CIE* chromaticity diagrams plotting objects.
7- :func:`colour.plotting.lines_spectral_locus`
8- :func:`colour.plotting.plot_chromaticity_diagram_CIE1931`
9- :func:`colour.plotting.plot_chromaticity_diagram_CIE1960UCS`
10- :func:`colour.plotting.plot_chromaticity_diagram_CIE1976UCS`
11- :func:`colour.plotting.plot_sds_in_chromaticity_diagram_CIE1931`
12- :func:`colour.plotting.plot_sds_in_chromaticity_diagram_CIE1960UCS`
13- :func:`colour.plotting.plot_sds_in_chromaticity_diagram_CIE1976UCS`
14"""
16from __future__ import annotations
18import bisect
19import typing
21import numpy as np
23if typing.TYPE_CHECKING:
24 from collections.abc import ValuesView
26if typing.TYPE_CHECKING:
27 from matplotlib.axes import Axes
29from matplotlib.collections import LineCollection
31if typing.TYPE_CHECKING:
32 from matplotlib.figure import Figure
34from matplotlib.patches import Polygon
36from colour.algebra import normalise_maximum, normalise_vector
37from colour.colorimetry import (
38 SDS_ILLUMINANTS,
39 MultiSpectralDistributions,
40 SpectralDistribution,
41 sd_to_XYZ,
42 sds_and_msds_to_sds,
43)
44from colour.constants import DTYPE_FLOAT_DEFAULT
46if typing.TYPE_CHECKING:
47 from colour.hints import (
48 Any,
49 ArrayLike,
50 Callable,
51 Dict,
52 List,
53 Literal,
54 NDArray,
55 Sequence,
56 )
58from colour.hints import Tuple, cast
59from colour.models import (
60 Luv_to_uv,
61 Luv_uv_to_xy,
62 UCS_to_uv,
63 UCS_uv_to_xy,
64 XYZ_to_Luv,
65 XYZ_to_UCS,
66 XYZ_to_xy,
67 xy_to_Luv_uv,
68 xy_to_UCS_uv,
69 xy_to_XYZ,
70)
71from colour.notation import HEX_to_RGB
72from colour.plotting import (
73 CONSTANTS_ARROW_STYLE,
74 CONSTANTS_COLOUR_STYLE,
75 XYZ_to_plotting_colourspace,
76 artist,
77 filter_cmfs,
78 filter_illuminants,
79 override_style,
80 render,
81 update_settings_collection,
82)
83from colour.utilities import (
84 CanonicalMapping,
85 as_float_array,
86 domain_range_scale,
87 first_item,
88 optional,
89 tsplit,
90 tstack,
91 validate_method,
92 zeros,
93)
95__author__ = "Colour Developers"
96__copyright__ = "Copyright 2013 Colour Developers"
97__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
98__maintainer__ = "Colour Developers"
99__email__ = "colour-developers@colour-science.org"
100__status__ = "Production"
102__all__ = [
103 "METHODS_CHROMATICITY_DIAGRAM",
104 "LABELS_CHROMATICITY_DIAGRAM_DEFAULT",
105 "lines_spectral_locus",
106 "plot_spectral_locus",
107 "plot_chromaticity_diagram_colours",
108 "plot_chromaticity_diagram",
109 "plot_chromaticity_diagram_CIE1931",
110 "plot_chromaticity_diagram_CIE1960UCS",
111 "plot_chromaticity_diagram_CIE1976UCS",
112 "plot_sds_in_chromaticity_diagram",
113 "plot_sds_in_chromaticity_diagram_CIE1931",
114 "plot_sds_in_chromaticity_diagram_CIE1960UCS",
115 "plot_sds_in_chromaticity_diagram_CIE1976UCS",
116]
118METHODS_CHROMATICITY_DIAGRAM: CanonicalMapping = CanonicalMapping(
119 {
120 "CIE 1931": {
121 "XYZ_to_ij": lambda a, *args: XYZ_to_xy(a), # noqa: ARG005
122 "ij_to_XYZ": lambda a, *args: xy_to_XYZ(a), # noqa: ARG005
123 "xy_to_ij": lambda a, *args: a, # noqa: ARG005
124 "uv_to_ij": lambda a, *args: UCS_uv_to_xy(a), # noqa: ARG005
125 },
126 "CIE 1960 UCS": {
127 "XYZ_to_ij": lambda a, *args: UCS_to_uv( # noqa: ARG005
128 XYZ_to_UCS(a)
129 ),
130 "ij_to_XYZ": lambda a, *args: xy_to_XYZ( # noqa: ARG005
131 UCS_uv_to_xy(a)
132 ),
133 "xy_to_ij": lambda a, *args: xy_to_UCS_uv(a), # noqa: ARG005
134 "uv_to_ij": lambda a, *args: a, # noqa: ARG005
135 },
136 "CIE 1976 UCS": {
137 "XYZ_to_ij": lambda a, *args: Luv_to_uv(XYZ_to_Luv(a, *args), *args),
138 "ij_to_XYZ": lambda a, *args: xy_to_XYZ( # noqa: ARG005
139 Luv_uv_to_xy(a)
140 ),
141 "xy_to_ij": lambda a, *args: xy_to_Luv_uv(a), # noqa: ARG005
142 "uv_to_ij": lambda a, *args: xy_to_Luv_uv( # noqa: ARG005
143 UCS_uv_to_xy(a)
144 ),
145 },
146 }
147)
148"""Chromaticity diagram conversion methods."""
150LABELS_CHROMATICITY_DIAGRAM_DEFAULT: CanonicalMapping = CanonicalMapping(
151 {
152 "CIE 1931": (
153 390,
154 460,
155 470,
156 480,
157 490,
158 500,
159 510,
160 520,
161 540,
162 560,
163 580,
164 600,
165 620,
166 700,
167 ),
168 "CIE 1960 UCS": (
169 420,
170 440,
171 450,
172 460,
173 470,
174 480,
175 490,
176 500,
177 510,
178 520,
179 530,
180 540,
181 550,
182 560,
183 570,
184 580,
185 590,
186 600,
187 610,
188 620,
189 630,
190 645,
191 680,
192 ),
193 "CIE 1976 UCS": (
194 420,
195 440,
196 450,
197 460,
198 470,
199 480,
200 490,
201 500,
202 510,
203 520,
204 530,
205 540,
206 550,
207 560,
208 570,
209 580,
210 590,
211 600,
212 610,
213 620,
214 630,
215 645,
216 680,
217 ),
218 }
219)
220"""*Chromaticity Diagram* default labels."""
223def lines_spectral_locus(
224 cmfs: (
225 MultiSpectralDistributions | str | Sequence[MultiSpectralDistributions | str]
226 ) = "CIE 1931 2 Degree Standard Observer",
227 labels: Sequence | None = None,
228 method: (Literal["CIE 1931", "CIE 1960 UCS", "CIE 1976 UCS"] | str) = "CIE 1931",
229) -> Tuple[NDArray, NDArray]:
230 """
231 Return the *Spectral Locus* line vertices, i.e., positions, normals
232 and colours, using the specified method.
234 Parameters
235 ----------
236 cmfs
237 Standard observer colour matching functions used for computing the
238 spectral locus boundaries. ``cmfs`` can be of any type or form
239 supported by the :func:`colour.plotting.common.filter_cmfs`
240 definition.
241 labels
242 Array of wavelength labels used to customise which labels will be
243 drawn around the spectral locus. Passing an empty array will
244 result in no wavelength labels being drawn.
245 method
246 *Chromaticity Diagram* method.
248 Returns
249 -------
250 :class:`tuple`
251 Tuple of *Spectral Locus* vertices and wavelength labels vertices.
253 Examples
254 --------
255 >>> lines = lines_spectral_locus()
256 >>> len(lines)
257 2
258 >>> lines[0].dtype
259 dtype([('position', '<f8', (2,)), ('normal', '<f8', (2,)), \
260('colour', '<f8', (3,))])
261 >>> lines[1].dtype
262 dtype([('position', '<f8', (2,)), ('normal', '<f8', (2,)), \
263('colour', '<f8', (3,))])
264 """
266 cmfs = cast("MultiSpectralDistributions", first_item(filter_cmfs(cmfs).values()))
268 labels = optional(labels, LABELS_CHROMATICITY_DIAGRAM_DEFAULT[method])
270 method = validate_method(method, tuple(METHODS_CHROMATICITY_DIAGRAM))
272 illuminant = CONSTANTS_COLOUR_STYLE.colour.colourspace.whitepoint
274 wavelengths = list(cmfs.wavelengths)
275 equal_energy = np.array([1 / 3] * 2)
277 XYZ_to_ij = METHODS_CHROMATICITY_DIAGRAM[method]["XYZ_to_ij"]
278 ij_to_XYZ = METHODS_CHROMATICITY_DIAGRAM[method]["ij_to_XYZ"]
280 # CMFS
281 ij_cmfs = XYZ_to_ij(cmfs.values, illuminant)
283 # Line of Purples
284 ij_pl = tstack(
285 [
286 np.linspace(ij_cmfs[-1][0], ij_cmfs[0][0], 20),
287 np.linspace(ij_cmfs[-1][1], ij_cmfs[0][1], 20),
288 ]
289 )
291 ij_sl = np.vstack([ij_cmfs, ij_pl])
293 colour_sl = normalise_maximum(
294 XYZ_to_plotting_colourspace(np.reshape(ij_to_XYZ(ij_sl, illuminant), (-1, 3))),
295 axis=-1,
296 )
298 lines_sl = zeros(
299 ij_sl.shape[0],
300 [
301 ("position", DTYPE_FLOAT_DEFAULT, 2),
302 ("normal", DTYPE_FLOAT_DEFAULT, 2),
303 ("colour", DTYPE_FLOAT_DEFAULT, 3),
304 ], # pyright: ignore
305 )
307 lines_sl["position"] = ij_sl
308 lines_sl["colour"] = colour_sl
310 # Labels Normals
311 ij_n, colour_l, normal_l = [], [], []
312 wl_ij_cmfs = dict(zip(wavelengths, ij_cmfs, strict=True))
313 for label in cast("Tuple", labels):
314 ij_l = wl_ij_cmfs.get(label)
316 if ij_l is None:
317 continue
319 i, j = tsplit(ij_l)
321 index = bisect.bisect(wavelengths, label)
322 left = wavelengths[index - 1] if index >= 0 else wavelengths[index]
323 right = wavelengths[index] if index < len(wavelengths) else wavelengths[-1]
325 dx = wl_ij_cmfs[right][0] - wl_ij_cmfs[left][0]
326 dy = wl_ij_cmfs[right][1] - wl_ij_cmfs[left][1]
328 direction = np.array([-dy, dx])
330 normal = (
331 np.array([-dy, dx])
332 if np.dot(
333 normalise_vector(ij_l - equal_energy),
334 normalise_vector(direction),
335 )
336 > 0
337 else np.array([dy, -dx])
338 )
339 normal = normalise_vector(normal)
341 ij_n.append([[i, j], [i + normal[0] / 50, j + normal[1] / 50]])
342 normal_l.append([normal, normal])
343 colour_l.append([ij_l, ij_l])
345 ij_w = np.reshape(as_float_array(ij_n), (-1, 2))
346 normal_w = np.reshape(as_float_array(normal_l), (-1, 2))
347 colours_w = np.reshape(as_float_array(colour_l), (-1, 2))
349 colour_w = normalise_maximum(
350 XYZ_to_plotting_colourspace(
351 np.reshape(ij_to_XYZ(colours_w, illuminant), (-1, 3))
352 ),
353 axis=-1,
354 )
356 lines_w = zeros(
357 ij_w.shape[0],
358 [
359 ("position", DTYPE_FLOAT_DEFAULT, 2),
360 ("normal", DTYPE_FLOAT_DEFAULT, 2),
361 ("colour", DTYPE_FLOAT_DEFAULT, 3),
362 ], # pyright: ignore
363 )
365 lines_w["position"] = ij_w
366 lines_w["normal"] = normal_w
367 lines_w["colour"] = colour_w
369 return lines_sl, lines_w
372@override_style()
373def plot_spectral_locus(
374 cmfs: (
375 MultiSpectralDistributions | str | Sequence[MultiSpectralDistributions | str]
376 ) = "CIE 1931 2 Degree Standard Observer",
377 spectral_locus_colours: ArrayLike | str | None = None,
378 spectral_locus_opacity: float = 1,
379 spectral_locus_labels: Sequence | None = None,
380 method: (Literal["CIE 1931", "CIE 1960 UCS", "CIE 1976 UCS"] | str) = "CIE 1931",
381 **kwargs: Any,
382) -> Tuple[Figure, Axes]:
383 """
384 Plot the *Spectral Locus* using the specified method.
386 Parameters
387 ----------
388 cmfs
389 Standard observer colour matching functions used for computing
390 the spectral locus boundaries. ``cmfs`` can be of any type or
391 form supported by the :func:`colour.plotting.common.filter_cmfs`
392 definition.
393 spectral_locus_colours
394 Colours of the *Spectral Locus*, if ``spectral_locus_colours``
395 is set to *RGB*, the colours will be computed using the
396 corresponding chromaticity coordinates.
397 spectral_locus_opacity
398 Opacity of the *Spectral Locus*.
399 spectral_locus_labels
400 Array of wavelength labels used to customise which labels will
401 be drawn around the spectral locus. Passing an empty array will
402 result in no wavelength labels being drawn.
403 method
404 *Chromaticity Diagram* method.
406 Other Parameters
407 ----------------
408 kwargs
409 {:func:`colour.plotting.artist`,
410 :func:`colour.plotting.render`},
411 See the documentation of the previously listed definitions.
413 Returns
414 -------
415 :class:`tuple`
416 Current figure and axes.
418 Examples
419 --------
420 >>> plot_spectral_locus(spectral_locus_colours="RGB") # doctest: +ELLIPSIS
421 (<Figure size ... with 1 Axes>, <...Axes...>)
423 .. image:: ../_static/Plotting_Plot_Spectral_Locus.png
424 :align: center
425 :alt: plot_spectral_locus
426 """
428 method = validate_method(method, tuple(METHODS_CHROMATICITY_DIAGRAM))
430 spectral_locus_colours = optional(
431 spectral_locus_colours, CONSTANTS_COLOUR_STYLE.colour.dark
432 )
434 labels = optional(
435 spectral_locus_labels, LABELS_CHROMATICITY_DIAGRAM_DEFAULT[method]
436 )
438 use_RGB_colours = str(spectral_locus_colours).upper() == "RGB"
440 settings: Dict[str, Any] = {"uniform": True}
441 settings.update(kwargs)
443 _figure, axes = artist(**settings)
445 cmfs = cast("MultiSpectralDistributions", first_item(filter_cmfs(cmfs).values()))
447 lines_sl, lines_w = lines_spectral_locus(cmfs, spectral_locus_labels, method)
449 axes.add_collection(
450 LineCollection(
451 np.reshape(
452 np.concatenate(
453 [lines_sl["position"][:-1], lines_sl["position"][1:]],
454 axis=1, # pyright: ignore
455 ),
456 (-1, 2, 2),
457 ),
458 colors=(lines_sl["colour"] if use_RGB_colours else spectral_locus_colours),
459 alpha=spectral_locus_opacity,
460 zorder=CONSTANTS_COLOUR_STYLE.zorder.background_line,
461 )
462 )
463 axes.add_collection(
464 LineCollection(
465 np.reshape(lines_w["position"], (-1, 2, 2)), # pyright: ignore
466 colors=(
467 lines_w["colour"][::2] if use_RGB_colours else spectral_locus_colours
468 ),
469 alpha=spectral_locus_opacity,
470 zorder=CONSTANTS_COLOUR_STYLE.zorder.background_line,
471 )
472 )
474 for i, label in enumerate([label for label in labels if label in cmfs.wavelengths]):
475 positions = lines_w["position"][::2]
476 normals = lines_w["normal"][::2]
477 colours = lines_w["colour"][::2]
479 axes.plot(
480 positions[i, 0],
481 positions[i, 1],
482 "o",
483 color=colours[i] if use_RGB_colours else spectral_locus_colours,
484 alpha=spectral_locus_opacity,
485 zorder=CONSTANTS_COLOUR_STYLE.zorder.background_line,
486 )
488 axes.text(
489 positions[i, 0] + normals[i, 0] / 50 * 1.25,
490 positions[i, 1] + normals[i, 1] / 50 * 1.25,
491 label,
492 clip_on=True,
493 ha="left" if lines_w["normal"][::2][i, 0] >= 0 else "right",
494 va="center",
495 fontsize="x-small-colour-science",
496 zorder=CONSTANTS_COLOUR_STYLE.zorder.background_label,
497 )
499 settings = {"axes": axes}
500 settings.update(kwargs)
502 return render(**kwargs)
505@override_style()
506def plot_chromaticity_diagram_colours(
507 samples: int = 256,
508 diagram_colours: ArrayLike | str | None = None,
509 diagram_opacity: float = 1,
510 diagram_clipping_path: ArrayLike | None = None,
511 cmfs: (
512 MultiSpectralDistributions | str | Sequence[MultiSpectralDistributions | str]
513 ) = "CIE 1931 2 Degree Standard Observer",
514 method: (Literal["CIE 1931", "CIE 1960 UCS", "CIE 1976 UCS"] | str) = "CIE 1931",
515 **kwargs: Any,
516) -> Tuple[Figure, Axes]:
517 """
518 Plot the *Chromaticity Diagram* colours using the specified method.
520 Parameters
521 ----------
522 samples
523 Sample count on one axis when computing the *Chromaticity
524 Diagram* colours.
525 diagram_colours
526 Colours of the *Chromaticity Diagram*, if ``diagram_colours``
527 is set to *RGB*, the colours will be computed using the
528 corresponding coordinates.
529 diagram_opacity
530 Opacity of the *Chromaticity Diagram*.
531 diagram_clipping_path
532 Path of points used to clip the *Chromaticity Diagram* colours.
533 cmfs
534 Standard observer colour matching functions used for computing the
535 spectral locus boundaries. ``cmfs`` can be of any type or form
536 supported by the :func:`colour.plotting.common.filter_cmfs`
537 definition.
538 method
539 *Chromaticity Diagram* method.
541 Other Parameters
542 ----------------
543 kwargs
544 {:func:`colour.plotting.artist`,
545 :func:`colour.plotting.render`},
546 See the documentation of the previously listed definitions.
548 Returns
549 -------
550 :class:`tuple`
551 Current figure and axes.
553 Examples
554 --------
555 >>> plot_chromaticity_diagram_colours(diagram_colours="RGB")
556 ... # doctest: +ELLIPSIS
557 (<Figure size ... with 1 Axes>, <...Axes...>)
559 .. image:: ../_static/Plotting_Plot_Chromaticity_Diagram_Colours.png
560 :align: center
561 :alt: plot_chromaticity_diagram_colours
562 """
564 method = validate_method(method, ("CIE 1931", "CIE 1960 UCS", "CIE 1976 UCS"))
566 settings: Dict[str, Any] = {"uniform": True}
567 settings.update(kwargs)
569 _figure, axes = artist(**settings)
571 diagram_colours = optional(
572 diagram_colours, HEX_to_RGB(CONSTANTS_COLOUR_STYLE.colour.average)
573 )
575 cmfs = cast("MultiSpectralDistributions", first_item(filter_cmfs(cmfs).values()))
577 illuminant = CONSTANTS_COLOUR_STYLE.colour.colourspace.whitepoint
579 XYZ_to_ij = METHODS_CHROMATICITY_DIAGRAM[method]["XYZ_to_ij"]
581 spectral_locus = XYZ_to_ij(cmfs.values, illuminant)
583 use_RGB_diagram_colours = str(diagram_colours).upper() == "RGB"
584 if use_RGB_diagram_colours:
585 ii, jj = np.meshgrid(np.linspace(0, 1, samples), np.linspace(1, 0, samples))
586 ij = tstack([ii, jj])
588 ij_to_XYZ = METHODS_CHROMATICITY_DIAGRAM[method]["ij_to_XYZ"]
590 diagram_colours = normalise_maximum(
591 XYZ_to_plotting_colourspace(ij_to_XYZ(ij), illuminant), axis=-1
592 )
594 polygon = Polygon(
595 (spectral_locus if diagram_clipping_path is None else diagram_clipping_path),
596 facecolor=(
597 "none"
598 if use_RGB_diagram_colours
599 else np.hstack([diagram_colours, diagram_opacity])
600 ),
601 edgecolor=(
602 "none"
603 if use_RGB_diagram_colours
604 else np.hstack([diagram_colours, diagram_opacity])
605 ),
606 zorder=CONSTANTS_COLOUR_STYLE.zorder.background_polygon,
607 )
608 axes.add_patch(polygon)
610 if use_RGB_diagram_colours:
611 # Preventing bounding box related issues as per
612 # https://github.com/matplotlib/matplotlib/issues/10529
613 image = axes.imshow(
614 diagram_colours,
615 interpolation="bilinear",
616 extent=(0, 1, 0, 1),
617 clip_path=None,
618 alpha=diagram_opacity,
619 zorder=CONSTANTS_COLOUR_STYLE.zorder.background_polygon,
620 )
621 image.set_clip_path(polygon)
623 settings = {"axes": axes}
624 settings.update(kwargs)
626 return render(**kwargs)
629@override_style()
630def plot_chromaticity_diagram(
631 cmfs: (
632 MultiSpectralDistributions | str | Sequence[MultiSpectralDistributions | str]
633 ) = "CIE 1931 2 Degree Standard Observer",
634 show_diagram_colours: bool = True,
635 show_spectral_locus: bool = True,
636 method: (Literal["CIE 1931", "CIE 1960 UCS", "CIE 1976 UCS"] | str) = "CIE 1931",
637 **kwargs: Any,
638) -> Tuple[Figure, Axes]:
639 """
640 Plot the *Chromaticity Diagram* using the specified method.
642 Parameters
643 ----------
644 cmfs
645 Standard observer colour matching functions used for computing the
646 spectral locus boundaries. ``cmfs`` can be of any type or form
647 supported by the :func:`colour.plotting.common.filter_cmfs`
648 definition.
649 show_diagram_colours
650 Whether to display the *Chromaticity Diagram* background colours.
651 show_spectral_locus
652 Whether to display the *Spectral Locus*.
653 method
654 *Chromaticity Diagram* method.
656 Other Parameters
657 ----------------
658 kwargs
659 {:func:`colour.plotting.artist`,
660 :func:`colour.plotting.diagrams.plot_spectral_locus`,
661 :func:`colour.plotting.diagrams.plot_chromaticity_diagram_colours`,
662 :func:`colour.plotting.render`},
663 See the documentation of the previously listed definitions.
665 Returns
666 -------
667 :class:`tuple`
668 Current figure and axes.
670 Examples
671 --------
672 >>> plot_chromaticity_diagram() # doctest: +ELLIPSIS
673 (<Figure size ... with 1 Axes>, <...Axes...>)
675 .. image:: ../_static/Plotting_Plot_Chromaticity_Diagram.png
676 :align: center
677 :alt: plot_chromaticity_diagram
678 """
680 method = validate_method(method, ("CIE 1931", "CIE 1960 UCS", "CIE 1976 UCS"))
682 settings: Dict[str, Any] = {"uniform": True}
683 settings.update(kwargs)
685 _figure, axes = artist(**settings)
687 cmfs = cast("MultiSpectralDistributions", first_item(filter_cmfs(cmfs).values()))
689 if show_diagram_colours:
690 settings = {"axes": axes, "method": method, "diagram_colours": "RGB"}
691 settings.update(kwargs)
692 settings["show"] = False
693 settings["cmfs"] = cmfs
695 plot_chromaticity_diagram_colours(**settings)
697 if show_spectral_locus:
698 settings = {"axes": axes, "method": method}
699 settings.update(kwargs)
700 settings["show"] = False
701 settings["cmfs"] = cmfs
703 plot_spectral_locus(**settings)
705 if method == "cie 1931":
706 x_label, y_label = "CIE x", "CIE y"
708 elif method == "cie 1960 ucs":
709 x_label, y_label = "CIE u", "CIE v"
711 elif method == "cie 1976 ucs":
712 x_label, y_label = (
713 "CIE u'",
714 "CIE v'",
715 )
717 title = f"{method.upper()} Chromaticity Diagram - {cmfs.display_name}"
719 settings.update(
720 {
721 "axes": axes,
722 "show": True,
723 "bounding_box": (0, 1, 0, 1),
724 "title": title,
725 "x_label": x_label,
726 "y_label": y_label,
727 }
728 )
729 settings.update(kwargs)
731 return render(**settings)
734@override_style()
735def plot_chromaticity_diagram_CIE1931(
736 cmfs: (
737 MultiSpectralDistributions | str | Sequence[MultiSpectralDistributions | str]
738 ) = "CIE 1931 2 Degree Standard Observer",
739 show_diagram_colours: bool = True,
740 show_spectral_locus: bool = True,
741 **kwargs: Any,
742) -> Tuple[Figure, Axes]:
743 """
744 Plot the *CIE 1931 Chromaticity Diagram*.
746 Parameters
747 ----------
748 cmfs
749 Standard observer colour matching functions used for computing the
750 spectral locus boundaries. ``cmfs`` can be of any type or form
751 supported by the :func:`colour.plotting.common.filter_cmfs`
752 definition.
753 show_diagram_colours
754 Whether to display the *Chromaticity Diagram* background colours.
755 show_spectral_locus
756 Whether to display the *Spectral Locus*.
758 Other Parameters
759 ----------------
760 kwargs
761 {:func:`colour.plotting.artist`,
762 :func:`colour.plotting.diagrams.plot_chromaticity_diagram`,
763 :func:`colour.plotting.render`},
764 See the documentation of the previously listed definitions.
766 Returns
767 -------
768 :class:`tuple`
769 Current figure and axes.
771 Examples
772 --------
773 >>> plot_chromaticity_diagram_CIE1931() # doctest: +ELLIPSIS
774 (<Figure size ... with 1 Axes>, <...Axes...>)
776 .. image:: ../_static/Plotting_Plot_Chromaticity_Diagram_CIE1931.png
777 :align: center
778 :alt: plot_chromaticity_diagram_CIE1931
779 """
781 settings = dict(kwargs)
782 settings.update({"method": "CIE 1931"})
784 return plot_chromaticity_diagram(
785 cmfs, show_diagram_colours, show_spectral_locus, **settings
786 )
789@override_style()
790def plot_chromaticity_diagram_CIE1960UCS(
791 cmfs: (
792 MultiSpectralDistributions | str | Sequence[MultiSpectralDistributions | str]
793 ) = "CIE 1931 2 Degree Standard Observer",
794 show_diagram_colours: bool = True,
795 show_spectral_locus: bool = True,
796 **kwargs: Any,
797) -> Tuple[Figure, Axes]:
798 """
799 Plot the *CIE 1960 UCS Chromaticity Diagram*.
801 Parameters
802 ----------
803 cmfs
804 Standard observer colour matching functions used for computing the
805 spectral locus boundaries. ``cmfs`` can be of any type or form
806 supported by the :func:`colour.plotting.common.filter_cmfs`
807 definition.
808 show_diagram_colours
809 Whether to display the *Chromaticity Diagram* background colours.
810 show_spectral_locus
811 Whether to display the *Spectral Locus*.
813 Other Parameters
814 ----------------
815 kwargs
816 {:func:`colour.plotting.artist`,
817 :func:`colour.plotting.diagrams.plot_chromaticity_diagram`,
818 :func:`colour.plotting.render`},
819 See the documentation of the previously listed definitions.
821 Returns
822 -------
823 :class:`tuple`
824 Current figure and axes.
826 Examples
827 --------
828 >>> plot_chromaticity_diagram_CIE1960UCS() # doctest: +ELLIPSIS
829 (<Figure size ... with 1 Axes>, <...Axes...>)
831 .. image:: ../_static/Plotting_Plot_Chromaticity_Diagram_CIE1960UCS.png
832 :align: center
833 :alt: plot_chromaticity_diagram_CIE1960UCS
834 """
836 settings = dict(kwargs)
837 settings.update({"method": "CIE 1960 UCS"})
839 return plot_chromaticity_diagram(
840 cmfs, show_diagram_colours, show_spectral_locus, **settings
841 )
844@override_style()
845def plot_chromaticity_diagram_CIE1976UCS(
846 cmfs: (
847 MultiSpectralDistributions | str | Sequence[MultiSpectralDistributions | str]
848 ) = "CIE 1931 2 Degree Standard Observer",
849 show_diagram_colours: bool = True,
850 show_spectral_locus: bool = True,
851 **kwargs: Any,
852) -> Tuple[Figure, Axes]:
853 """
854 Plot the *CIE 1976 UCS Chromaticity Diagram*.
856 Parameters
857 ----------
858 cmfs
859 Standard observer colour matching functions used for computing the
860 spectral locus boundaries. ``cmfs`` can be of any type or form
861 supported by the :func:`colour.plotting.common.filter_cmfs`
862 definition.
863 show_diagram_colours
864 Whether to display the *Chromaticity Diagram* background colours.
865 show_spectral_locus
866 Whether to display the *Spectral Locus*.
868 Other Parameters
869 ----------------
870 kwargs
871 {:func:`colour.plotting.artist`,
872 :func:`colour.plotting.diagrams.plot_chromaticity_diagram`,
873 :func:`colour.plotting.render`},
874 See the documentation of the previously listed definitions.
876 Returns
877 -------
878 :class:`tuple`
879 Current figure and axes.
881 Examples
882 --------
883 >>> plot_chromaticity_diagram_CIE1976UCS() # doctest: +ELLIPSIS
884 (<Figure size ... with 1 Axes>, <...Axes...>)
886 .. image:: ../_static/Plotting_Plot_Chromaticity_Diagram_CIE1976UCS.png
887 :align: center
888 :alt: plot_chromaticity_diagram_CIE1976UCS
889 """
891 settings = dict(kwargs)
892 settings.update({"method": "CIE 1976 UCS"})
894 return plot_chromaticity_diagram(
895 cmfs, show_diagram_colours, show_spectral_locus, **settings
896 )
899@override_style()
900def plot_sds_in_chromaticity_diagram(
901 sds: (
902 Sequence[SpectralDistribution | MultiSpectralDistributions]
903 | SpectralDistribution
904 | MultiSpectralDistributions
905 | ValuesView
906 ),
907 cmfs: (
908 MultiSpectralDistributions | str | Sequence[MultiSpectralDistributions | str]
909 ) = "CIE 1931 2 Degree Standard Observer",
910 chromaticity_diagram_callable: Callable = plot_chromaticity_diagram,
911 method: (Literal["CIE 1931", "CIE 1960 UCS", "CIE 1976 UCS"] | str) = "CIE 1931",
912 annotate_kwargs: dict | List[dict] | None = None,
913 plot_kwargs: dict | List[dict] | None = None,
914 **kwargs: Any,
915) -> Tuple[Figure, Axes]:
916 """
917 Plot specified spectral distribution chromaticity coordinates into the
918 *Chromaticity Diagram* using the specified method.
920 Parameters
921 ----------
922 sds
923 Spectral distributions or multi-spectral distributions to plot.
924 ``sds`` can be a single :class:`colour.MultiSpectralDistributions`
925 class instance, a list of :class:`colour.MultiSpectralDistributions`
926 class instances or a list of :class:`colour.SpectralDistribution` class
927 instances.
928 cmfs
929 Standard observer colour matching functions used for computing the
930 spectral locus boundaries. ``cmfs`` can be of any type or form
931 supported by the :func:`colour.plotting.common.filter_cmfs`
932 definition.
933 chromaticity_diagram_callable
934 Callable responsible for drawing the *Chromaticity Diagram*.
935 method
936 *Chromaticity Diagram* method.
937 annotate_kwargs
938 Keyword arguments for the :func:`matplotlib.pyplot.annotate`
939 definition, used to annotate the resulting chromaticity coordinates
940 with their respective spectral distribution names.
941 ``annotate_kwargs`` can be either a single dictionary applied to
942 all the arrows with same settings or a sequence of dictionaries
943 with different settings for each spectral distribution. The
944 following special keyword arguments can also be used:
946 - ``annotate`` : Whether to annotate the spectral distributions.
947 plot_kwargs
948 Keyword arguments for the :func:`matplotlib.pyplot.plot`
949 definition, used to control the style of the plotted spectral
950 distributions. ``plot_kwargs`` can be either a single dictionary
951 applied to all the plotted spectral distributions with the same
952 settings or a sequence of dictionaries with different settings for
953 each plotted spectral distribution. The following special keyword
954 arguments can also be used:
956 - ``illuminant`` : The illuminant used to compute the spectral
957 distributions colours. The default is the illuminant
958 associated with the whitepoint of the default plotting
959 colourspace. ``illuminant`` can be of any type or form
960 supported by the :func:`colour.plotting.common.filter_cmfs`
961 definition.
962 - ``cmfs`` : The standard observer colour matching functions
963 used for computing the spectral distributions colours.
964 ``cmfs`` can be of any type or form supported by the
965 :func:`colour.plotting.common.filter_cmfs` definition.
966 - ``normalise_sd_colours`` : Whether to normalise the computed
967 spectral distributions colours. The default is *True*.
968 - ``use_sd_colours`` : Whether to use the computed spectral
969 distributions colours under the plotting colourspace
970 illuminant. Alternatively, it is possible to use the
971 :func:`matplotlib.pyplot.plot` definition ``color`` argument
972 with pre-computed values. The default is *True*.
974 Other Parameters
975 ----------------
976 kwargs
977 {:func:`colour.plotting.artist`,
978 :func:`colour.plotting.diagrams.plot_chromaticity_diagram`,
979 :func:`colour.plotting.render`},
980 See the documentation of the previously listed definitions.
982 Returns
983 -------
984 :class:`tuple`
985 Current figure and axes.
987 Examples
988 --------
989 >>> A = SDS_ILLUMINANTS["A"]
990 >>> D65 = SDS_ILLUMINANTS["D65"]
991 >>> annotate_kwargs = [
992 ... {"xytext": (-25, 15), "arrowprops": {"arrowstyle": "-"}},
993 ... {},
994 ... ]
995 >>> plot_kwargs = [
996 ... {
997 ... "illuminant": SDS_ILLUMINANTS["E"],
998 ... "markersize": 15,
999 ... "normalise_sd_colours": True,
1000 ... "use_sd_colours": True,
1001 ... },
1002 ... {"illuminant": SDS_ILLUMINANTS["E"]},
1003 ... ]
1004 >>> plot_sds_in_chromaticity_diagram(
1005 ... [A, D65], annotate_kwargs=annotate_kwargs, plot_kwargs=plot_kwargs
1006 ... )
1007 ... # doctest: +ELLIPSIS
1008 (<Figure size ... with 1 Axes>, <...Axes...>)
1010 .. image:: ../_static/Plotting_Plot_SDS_In_Chromaticity_Diagram.png
1011 :align: center
1012 :alt: plot_sds_in_chromaticity_diagram
1013 """
1015 method = validate_method(method, ("CIE 1931", "CIE 1960 UCS", "CIE 1976 UCS"))
1017 sds_converted = sds_and_msds_to_sds(sds)
1019 settings: Dict[str, Any] = {"uniform": True}
1020 settings.update(kwargs)
1022 _figure, axes = artist(**settings)
1024 settings.update(
1025 {
1026 "axes": axes,
1027 "show": False,
1028 "method": method,
1029 "cmfs": cmfs,
1030 }
1031 )
1033 chromaticity_diagram_callable(**settings)
1035 XYZ_to_ij = METHODS_CHROMATICITY_DIAGRAM[method]["XYZ_to_ij"]
1037 if method == "cie 1931":
1038 bounding_box = (-0.1, 0.9, -0.1, 0.9)
1040 elif method == "cie 1960 ucs":
1041 bounding_box = (-0.1, 0.7, -0.2, 0.6)
1043 elif method == "cie 1976 ucs":
1044 bounding_box = (-0.1, 0.7, -0.1, 0.7)
1046 annotate_settings_collection = [
1047 {
1048 "annotate": True,
1049 "xytext": (-50, 30),
1050 "textcoords": "offset points",
1051 "arrowprops": CONSTANTS_ARROW_STYLE,
1052 "zorder": CONSTANTS_COLOUR_STYLE.zorder.midground_annotation,
1053 }
1054 for _ in range(len(sds_converted))
1055 ]
1057 if annotate_kwargs is not None:
1058 update_settings_collection(
1059 annotate_settings_collection, annotate_kwargs, len(sds_converted)
1060 )
1062 plot_settings_collection = [
1063 {
1064 "color": CONSTANTS_COLOUR_STYLE.colour.brightest,
1065 "label": f"{sd.display_name}",
1066 "marker": "o",
1067 "markeredgecolor": CONSTANTS_COLOUR_STYLE.colour.dark,
1068 "markeredgewidth": CONSTANTS_COLOUR_STYLE.geometry.short * 0.75,
1069 "markersize": (
1070 CONSTANTS_COLOUR_STYLE.geometry.short * 6
1071 + CONSTANTS_COLOUR_STYLE.geometry.short * 0.75
1072 ),
1073 "zorder": CONSTANTS_COLOUR_STYLE.zorder.midground_line,
1074 "cmfs": cmfs,
1075 "illuminant": SDS_ILLUMINANTS["E"],
1076 "use_sd_colours": False,
1077 "normalise_sd_colours": False,
1078 }
1079 for sd in sds_converted
1080 ]
1082 if plot_kwargs is not None:
1083 update_settings_collection(
1084 plot_settings_collection, plot_kwargs, len(sds_converted)
1085 )
1087 for i, sd in enumerate(sds_converted):
1088 plot_settings = plot_settings_collection[i]
1090 cmfs = cast(
1091 "MultiSpectralDistributions",
1092 first_item(filter_cmfs(plot_settings.pop("cmfs")).values()),
1093 )
1094 illuminant = cast(
1095 "SpectralDistribution",
1096 first_item(filter_illuminants(plot_settings.pop("illuminant")).values()),
1097 )
1098 normalise_sd_colours = plot_settings.pop("normalise_sd_colours")
1099 use_sd_colours = plot_settings.pop("use_sd_colours")
1101 with domain_range_scale("1"):
1102 XYZ = sd_to_XYZ(sd, cmfs, illuminant)
1104 if use_sd_colours:
1105 if normalise_sd_colours:
1106 XYZ /= XYZ[..., 1]
1108 plot_settings["color"] = np.clip(XYZ_to_plotting_colourspace(XYZ), 0, 1)
1110 ij = cast("tuple[float, float]", XYZ_to_ij(XYZ))
1112 axes.plot(ij[0], ij[1], **plot_settings)
1114 if sd.name is not None and annotate_settings_collection[i]["annotate"]:
1115 annotate_settings = annotate_settings_collection[i]
1116 annotate_settings.pop("annotate")
1118 axes.annotate(sd.name, xy=ij, **annotate_settings)
1120 settings.update({"show": True, "bounding_box": bounding_box})
1121 settings.update(kwargs)
1123 return render(**settings)
1126@override_style()
1127def plot_sds_in_chromaticity_diagram_CIE1931(
1128 sds: (
1129 Sequence[SpectralDistribution | MultiSpectralDistributions]
1130 | SpectralDistribution
1131 | MultiSpectralDistributions
1132 | ValuesView
1133 ),
1134 cmfs: (
1135 MultiSpectralDistributions | str | Sequence[MultiSpectralDistributions | str]
1136 ) = "CIE 1931 2 Degree Standard Observer",
1137 chromaticity_diagram_callable_CIE1931: Callable = (
1138 plot_chromaticity_diagram_CIE1931
1139 ),
1140 annotate_kwargs: dict | List[dict] | None = None,
1141 plot_kwargs: dict | List[dict] | None = None,
1142 **kwargs: Any,
1143) -> Tuple[Figure, Axes]:
1144 """
1145 Plot specified spectral distribution chromaticity coordinates in the
1146 *CIE 1931 Chromaticity Diagram*.
1148 Parameters
1149 ----------
1150 sds
1151 Spectral distributions or multi-spectral distributions to plot.
1152 ``sds`` can be a single :class:`colour.MultiSpectralDistributions`
1153 class instance, a list of :class:`colour.MultiSpectralDistributions`
1154 class instances or a list of :class:`colour.SpectralDistribution` class
1155 instances.
1156 cmfs
1157 Standard observer colour matching functions used for computing the
1158 spectral locus boundaries. ``cmfs`` can be of any type or form
1159 supported by the :func:`colour.plotting.common.filter_cmfs`
1160 definition.
1161 chromaticity_diagram_callable_CIE1931
1162 Callable responsible for drawing the *CIE 1931 Chromaticity
1163 Diagram*.
1164 annotate_kwargs
1165 Keyword arguments for the :func:`matplotlib.pyplot.annotate`
1166 definition, used to annotate the resulting chromaticity
1167 coordinates with their respective spectral distribution names.
1168 ``annotate_kwargs`` can be either a single dictionary applied to
1169 all the arrows with same settings or a sequence of dictionaries
1170 with different settings for each spectral distribution. The
1171 following special keyword arguments can also be used:
1173 - ``annotate`` : Whether to annotate the spectral
1174 distributions.
1175 plot_kwargs
1176 Keyword arguments for the :func:`matplotlib.pyplot.plot`
1177 definition, used to control the style of the plotted spectral
1178 distributions. ``plot_kwargs`` can be either a single dictionary
1179 applied to all the plotted spectral distributions with the same
1180 settings or a sequence of dictionaries with different settings for
1181 each plotted spectral distribution. The following special keyword
1182 arguments can also be used:
1184 - ``illuminant`` : The illuminant used to compute the spectral
1185 distributions colours. The default is the illuminant
1186 associated with the whitepoint of the default plotting
1187 colourspace. ``illuminant`` can be of any type or form
1188 supported by the :func:`colour.plotting.common.filter_cmfs`
1189 definition.
1190 - ``cmfs`` : The standard observer colour matching functions
1191 used for computing the spectral distributions colours.
1192 ``cmfs`` can be of any type or form supported by the
1193 :func:`colour.plotting.common.filter_cmfs` definition.
1194 - ``normalise_sd_colours`` : Whether to normalise the computed
1195 spectral distributions colours. The default is *True*.
1196 - ``use_sd_colours`` : Whether to use the computed spectral
1197 distributions colours under the plotting colourspace
1198 illuminant. Alternatively, it is possible to use the
1199 :func:`matplotlib.pyplot.plot` definition ``color`` argument
1200 with pre-computed values. The default is *True*.
1202 Other Parameters
1203 ----------------
1204 kwargs
1205 {:func:`colour.plotting.artist`,
1206 :func:`colour.plotting.diagrams.plot_chromaticity_diagram`,
1207 :func:`colour.plotting.render`},
1208 See the documentation of the previously listed definitions.
1210 Returns
1211 -------
1212 :class:`tuple`
1213 Current figure and axes.
1215 Examples
1216 --------
1217 >>> A = SDS_ILLUMINANTS["A"]
1218 >>> D65 = SDS_ILLUMINANTS["D65"]
1219 >>> plot_sds_in_chromaticity_diagram_CIE1931([A, D65])
1220 ... # doctest: +ELLIPSIS
1221 (<Figure size ... with 1 Axes>, <...Axes...>)
1223 .. image:: ../_static/Plotting_\
1224Plot_SDS_In_Chromaticity_Diagram_CIE1931.png
1225 :align: center
1226 :alt: plot_sds_in_chromaticity_diagram_CIE1931
1227 """
1229 settings = dict(kwargs)
1230 settings.update({"method": "CIE 1931"})
1232 return plot_sds_in_chromaticity_diagram(
1233 sds,
1234 cmfs,
1235 chromaticity_diagram_callable_CIE1931,
1236 annotate_kwargs=annotate_kwargs,
1237 plot_kwargs=plot_kwargs,
1238 **settings,
1239 )
1242@override_style()
1243def plot_sds_in_chromaticity_diagram_CIE1960UCS(
1244 sds: (
1245 Sequence[SpectralDistribution | MultiSpectralDistributions]
1246 | SpectralDistribution
1247 | MultiSpectralDistributions
1248 | ValuesView
1249 ),
1250 cmfs: (
1251 MultiSpectralDistributions | str | Sequence[MultiSpectralDistributions | str]
1252 ) = "CIE 1931 2 Degree Standard Observer",
1253 chromaticity_diagram_callable_CIE1960UCS: Callable = (
1254 plot_chromaticity_diagram_CIE1960UCS
1255 ),
1256 annotate_kwargs: dict | List[dict] | None = None,
1257 plot_kwargs: dict | List[dict] | None = None,
1258 **kwargs: Any,
1259) -> Tuple[Figure, Axes]:
1260 """
1261 Plot spectral distribution chromaticity coordinates in the
1262 *CIE 1960 UCS Chromaticity Diagram*.
1264 Parameters
1265 ----------
1266 sds
1267 Spectral distributions or multi-spectral distributions to plot.
1268 ``sds`` can be a single :class:`colour.MultiSpectralDistributions`
1269 class instance, a list of :class:`colour.MultiSpectralDistributions`
1270 class instances or a list of :class:`colour.SpectralDistribution` class
1271 instances.
1272 cmfs
1273 Standard observer colour matching functions used for computing the
1274 spectral locus boundaries. ``cmfs`` can be of any type or form
1275 supported by the :func:`colour.plotting.common.filter_cmfs`
1276 definition.
1277 chromaticity_diagram_callable_CIE1960UCS
1278 Callable responsible for drawing the
1279 *CIE 1960 UCS Chromaticity Diagram*.
1280 annotate_kwargs
1281 Keyword arguments for the :func:`matplotlib.pyplot.annotate`
1282 definition, used to annotate the resulting chromaticity
1283 coordinates with their respective spectral distribution names.
1284 ``annotate_kwargs`` can be either a single dictionary applied to
1285 all the arrows with same settings or a sequence of dictionaries
1286 with different settings for each spectral distribution. The
1287 following special keyword arguments can also be used:
1289 - ``annotate`` : Whether to annotate the spectral
1290 distributions.
1291 plot_kwargs
1292 Keyword arguments for the :func:`matplotlib.pyplot.plot`
1293 definition, used to control the style of the plotted spectral
1294 distributions. ``plot_kwargs`` can be either a single dictionary
1295 applied to all the plotted spectral distributions with the same
1296 settings or a sequence of dictionaries with different settings for
1297 each plotted spectral distribution. The following special keyword
1298 arguments can also be used:
1300 - ``illuminant`` : The illuminant used to compute the spectral
1301 distributions colours. The default is the illuminant
1302 associated with the whitepoint of the default plotting
1303 colourspace. ``illuminant`` can be of any type or form
1304 supported by the :func:`colour.plotting.common.filter_cmfs`
1305 definition.
1306 - ``cmfs`` : The standard observer colour matching functions
1307 used for computing the spectral distributions colours.
1308 ``cmfs`` can be of any type or form supported by the
1309 :func:`colour.plotting.common.filter_cmfs` definition.
1310 - ``normalise_sd_colours`` : Whether to normalise the computed
1311 spectral distributions colours. The default is *True*.
1312 - ``use_sd_colours`` : Whether to use the computed spectral
1313 distributions colours under the plotting colourspace
1314 illuminant. Alternatively, it is possible to use the
1315 :func:`matplotlib.pyplot.plot` definition ``color`` argument
1316 with pre-computed values. The default is *True*.
1318 Other Parameters
1319 ----------------
1320 kwargs
1321 {:func:`colour.plotting.artist`,
1322 :func:`colour.plotting.diagrams.plot_chromaticity_diagram`,
1323 :func:`colour.plotting.render`},
1324 See the documentation of the previously listed definitions.
1326 Returns
1327 -------
1328 :class:`tuple`
1329 Current figure and axes.
1331 Examples
1332 --------
1333 >>> A = SDS_ILLUMINANTS["A"]
1334 >>> D65 = SDS_ILLUMINANTS["D65"]
1335 >>> plot_sds_in_chromaticity_diagram_CIE1960UCS([A, D65])
1336 ... # doctest: +ELLIPSIS
1337 (<Figure size ... with 1 Axes>, <...Axes...>)
1339 .. image:: ../_static/Plotting_\
1340Plot_SDS_In_Chromaticity_Diagram_CIE1960UCS.png
1341 :align: center
1342 :alt: plot_sds_in_chromaticity_diagram_CIE1960UCS
1343 """
1345 settings = dict(kwargs)
1346 settings.update({"method": "CIE 1960 UCS"})
1348 return plot_sds_in_chromaticity_diagram(
1349 sds,
1350 cmfs,
1351 chromaticity_diagram_callable_CIE1960UCS,
1352 annotate_kwargs=annotate_kwargs,
1353 plot_kwargs=plot_kwargs,
1354 **settings,
1355 )
1358@override_style()
1359def plot_sds_in_chromaticity_diagram_CIE1976UCS(
1360 sds: (
1361 Sequence[SpectralDistribution | MultiSpectralDistributions]
1362 | SpectralDistribution
1363 | MultiSpectralDistributions
1364 | ValuesView
1365 ),
1366 cmfs: (
1367 MultiSpectralDistributions | str | Sequence[MultiSpectralDistributions | str]
1368 ) = "CIE 1931 2 Degree Standard Observer",
1369 chromaticity_diagram_callable_CIE1976UCS: Callable = (
1370 plot_chromaticity_diagram_CIE1976UCS
1371 ),
1372 annotate_kwargs: dict | List[dict] | None = None,
1373 plot_kwargs: dict | List[dict] | None = None,
1374 **kwargs: Any,
1375) -> Tuple[Figure, Axes]:
1376 """
1377 Plot specified spectral distribution chromaticity coordinates in the
1378 *CIE 1976 UCS Chromaticity Diagram*.
1380 Parameters
1381 ----------
1382 sds
1383 Spectral distributions or multi-spectral distributions to plot.
1384 ``sds`` can be a single :class:`colour.MultiSpectralDistributions`
1385 class instance, a list of :class:`colour.MultiSpectralDistributions`
1386 class instances or a list of :class:`colour.SpectralDistribution` class
1387 instances.
1388 cmfs
1389 Standard observer colour matching functions used for computing the
1390 spectral locus boundaries. ``cmfs`` can be of any type or form
1391 supported by the :func:`colour.plotting.common.filter_cmfs`
1392 definition.
1393 chromaticity_diagram_callable_CIE1976UCS
1394 Callable responsible for drawing the
1395 *CIE 1976 UCS Chromaticity Diagram*.
1396 annotate_kwargs
1397 Keyword arguments for the :func:`matplotlib.pyplot.annotate`
1398 definition, used to annotate the resulting chromaticity
1399 coordinates with their respective spectral distribution names.
1400 ``annotate_kwargs`` can be either a single dictionary applied to
1401 all the arrows with same settings or a sequence of dictionaries
1402 with different settings for each spectral distribution. The
1403 following special keyword arguments can also be used:
1405 - ``annotate`` : Whether to annotate the spectral
1406 distributions.
1407 plot_kwargs
1408 Keyword arguments for the :func:`matplotlib.pyplot.plot`
1409 definition, used to control the style of the plotted spectral
1410 distributions. ``plot_kwargs`` can be either a single dictionary
1411 applied to all the plotted spectral distributions with the same
1412 settings or a sequence of dictionaries with different settings for
1413 each plotted spectral distribution. The following special keyword
1414 arguments can also be used:
1416 - ``illuminant`` : The illuminant used to compute the spectral
1417 distributions colours. The default is the illuminant
1418 associated with the whitepoint of the default plotting
1419 colourspace. ``illuminant`` can be of any type or form
1420 supported by the :func:`colour.plotting.common.filter_cmfs`
1421 definition.
1422 - ``cmfs`` : The standard observer colour matching functions
1423 used for computing the spectral distributions colours.
1424 ``cmfs`` can be of any type or form supported by the
1425 :func:`colour.plotting.common.filter_cmfs` definition.
1426 - ``normalise_sd_colours`` : Whether to normalise the computed
1427 spectral distributions colours. The default is *True*.
1428 - ``use_sd_colours`` : Whether to use the computed spectral
1429 distributions colours under the plotting colourspace
1430 illuminant. Alternatively, it is possible to use the
1431 :func:`matplotlib.pyplot.plot` definition ``color`` argument
1432 with pre-computed values. The default is *True*.
1434 Other Parameters
1435 ----------------
1436 kwargs
1437 {:func:`colour.plotting.artist`,
1438 :func:`colour.plotting.diagrams.plot_chromaticity_diagram`,
1439 :func:`colour.plotting.render`},
1440 See the documentation of the previously listed definitions.
1442 Returns
1443 -------
1444 :class:`tuple`
1445 Current figure and axes.
1447 Examples
1448 --------
1449 >>> A = SDS_ILLUMINANTS["A"]
1450 >>> D65 = SDS_ILLUMINANTS["D65"]
1451 >>> plot_sds_in_chromaticity_diagram_CIE1976UCS([A, D65])
1452 ... # doctest: +ELLIPSIS
1453 (<Figure size ... with 1 Axes>, <...Axes...>)
1455 .. image:: ../_static/Plotting_\
1456Plot_SDS_In_Chromaticity_Diagram_CIE1976UCS.png
1457 :align: center
1458 :alt: plot_sds_in_chromaticity_diagram_CIE1976UCS
1459 """
1461 settings = dict(kwargs)
1462 settings.update({"method": "CIE 1976 UCS"})
1464 return plot_sds_in_chromaticity_diagram(
1465 sds,
1466 cmfs,
1467 chromaticity_diagram_callable_CIE1976UCS,
1468 annotate_kwargs=annotate_kwargs,
1469 plot_kwargs=plot_kwargs,
1470 **settings,
1471 )