Coverage for colour/plotting/temperature.py: 97%
152 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"""
2Colour Temperature & Correlated Colour Temperature Plotting
3===========================================================
5Define the colour temperature and correlated colour temperature plotting
6objects.
8- :func:`colour.plotting.lines_daylight_locus`
9- :func:`colour.plotting.lines_planckian_locus`
10- :func:`colour.plotting.\
11plot_planckian_locus_in_chromaticity_diagram_CIE1931`
12- :func:`colour.plotting.\
13plot_planckian_locus_in_chromaticity_diagram_CIE1960UCS`
14- :func:`colour.plotting.\
15plot_planckian_locus_in_chromaticity_diagram_CIE1976UCS`
16"""
18from __future__ import annotations
20import typing
22import numpy as np
24if typing.TYPE_CHECKING:
25 from matplotlib.axes import Axes
27from matplotlib.collections import LineCollection
29if typing.TYPE_CHECKING:
30 from matplotlib.figure import Figure
32from colour.algebra import normalise_maximum, normalise_vector
33from colour.colorimetry import CCS_ILLUMINANTS, MSDS_CMFS
34from colour.constants import DTYPE_FLOAT_DEFAULT
36if typing.TYPE_CHECKING:
37 from colour.hints import (
38 Any,
39 ArrayLike,
40 Callable,
41 Dict,
42 List,
43 Literal,
44 NDArray,
45 NDArrayFloat,
46 Sequence,
47 Tuple,
48 )
50from colour.hints import cast
51from colour.models import UCS_uv_to_xy, xy_to_XYZ
52from colour.plotting import (
53 CONSTANTS_ARROW_STYLE,
54 CONSTANTS_COLOUR_STYLE,
55 METHODS_CHROMATICITY_DIAGRAM,
56 XYZ_to_plotting_colourspace,
57 artist,
58 filter_passthrough,
59 override_style,
60 plot_chromaticity_diagram_CIE1931,
61 plot_chromaticity_diagram_CIE1960UCS,
62 plot_chromaticity_diagram_CIE1976UCS,
63 render,
64 update_settings_collection,
65)
66from colour.plotting.diagrams import plot_chromaticity_diagram
67from colour.temperature import CCT_to_uv, CCT_to_xy_CIE_D, mired_to_CCT
68from colour.utilities import (
69 CanonicalMapping,
70 as_float_array,
71 as_float_scalar,
72 as_int_scalar,
73 full,
74 optional,
75 tstack,
76 validate_method,
77 zeros,
78)
80__author__ = "Colour Developers"
81__copyright__ = "Copyright 2013 Colour Developers"
82__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
83__maintainer__ = "Colour Developers"
84__email__ = "colour-developers@colour-science.org"
85__status__ = "Production"
87__all__ = [
88 "lines_daylight_locus",
89 "plot_daylight_locus",
90 "LABELS_PLANCKIAN_LOCUS_DEFAULT",
91 "lines_planckian_locus",
92 "plot_planckian_locus",
93 "plot_planckian_locus_in_chromaticity_diagram",
94 "plot_planckian_locus_in_chromaticity_diagram_CIE1931",
95 "plot_planckian_locus_in_chromaticity_diagram_CIE1960UCS",
96 "plot_planckian_locus_in_chromaticity_diagram_CIE1976UCS",
97]
100def lines_daylight_locus(
101 mireds: bool = False,
102 method: (Literal["CIE 1931", "CIE 1960 UCS", "CIE 1976 UCS"] | str) = "CIE 1931",
103) -> Tuple[NDArray]:
104 """
105 Return the *Daylight Locus* line vertices including positions, normals,
106 and colours using the specified chromaticity diagram method.
108 Parameters
109 ----------
110 mireds
111 Whether to use micro reciprocal degrees for the iso-temperature
112 lines.
113 method
114 *Daylight Locus* chromaticity diagram method.
116 Returns
117 -------
118 :class:`tuple`
119 Tuple of *Daylight Locus* line vertices containing position,
120 normal, and colour data.
122 Examples
123 --------
124 >>> lines = lines_daylight_locus()
125 >>> len(lines)
126 1
127 >>> lines[0].dtype
128 dtype([('position', '<f8', (2,)), ('normal', '<f8', (2,)), \
129('colour', '<f8', (3,))])
130 """
132 method = validate_method(method, ("CIE 1931", "CIE 1960 UCS", "CIE 1976 UCS"))
134 xy_to_ij = METHODS_CHROMATICITY_DIAGRAM[method]["xy_to_ij"]
136 def CCT_to_plotting_colourspace(CCT: ArrayLike) -> NDArrayFloat:
137 """
138 Convert specified correlated colour temperature :math:`T_{cp}` to the
139 default plotting colourspace.
140 """
142 return normalise_maximum(
143 XYZ_to_plotting_colourspace(xy_to_XYZ(CCT_to_xy_CIE_D(CCT))),
144 axis=-1,
145 )
147 start, end = (0, 1000) if mireds else (1e6 / 600, 1e6 / 10)
149 CCT = np.arange(start, end + 100, 10) * 1.4388 / 1.4380
150 CCT = mired_to_CCT(CCT) if mireds else CCT
152 ij_sl = np.reshape(xy_to_ij(CCT_to_xy_CIE_D(CCT)), (-1, 2))
153 colour_sl = np.reshape(CCT_to_plotting_colourspace(CCT), (-1, 3))
155 lines_sl = zeros(
156 ij_sl.shape[0],
157 [
158 ("position", DTYPE_FLOAT_DEFAULT, 2),
159 ("normal", DTYPE_FLOAT_DEFAULT, 2),
160 ("colour", DTYPE_FLOAT_DEFAULT, 3),
161 ], # pyright: ignore
162 )
164 lines_sl["position"] = ij_sl
165 lines_sl["colour"] = colour_sl
167 return (lines_sl,)
170@override_style()
171def plot_daylight_locus(
172 daylight_locus_colours: ArrayLike | str | None = None,
173 daylight_locus_opacity: float = 1,
174 daylight_locus_mireds: bool = False,
175 method: (Literal["CIE 1931", "CIE 1960 UCS", "CIE 1976 UCS"] | str) = "CIE 1931",
176 **kwargs: Any,
177) -> Tuple[Figure, Axes]:
178 """
179 Plot the *Daylight Locus* using the specified chromaticity diagram
180 method.
182 Parameters
183 ----------
184 daylight_locus_colours
185 Colours of the *Daylight Locus*. If set to *RGB*, the colours will
186 be computed from the corresponding chromaticity coordinates.
187 daylight_locus_opacity
188 Opacity of the *Daylight Locus*.
189 daylight_locus_mireds
190 Whether to use micro reciprocal degrees for the iso-temperature
191 lines.
192 method
193 *Chromaticity Diagram* method.
195 Other Parameters
196 ----------------
197 kwargs
198 {:func:`colour.plotting.artist`, :func:`colour.plotting.render`},
199 See the documentation of the previously listed definitions.
201 Returns
202 -------
203 :class:`tuple`
204 Current figure and axes.
206 Examples
207 --------
208 >>> plot_daylight_locus(daylight_locus_colours="RGB")
209 ... # doctest: +ELLIPSIS
210 (<Figure size ... with 1 Axes>, <...Axes...>)
212 .. image:: ../_static/Plotting_Plot_Daylight_Locus.png
213 :align: center
214 :alt: plot_daylight_locus
215 """
217 method = validate_method(method, ("CIE 1931", "CIE 1960 UCS", "CIE 1976 UCS"))
219 use_RGB_daylight_locus_colours = str(daylight_locus_colours).upper() == "RGB"
221 daylight_locus_colours = optional(
222 daylight_locus_colours, CONSTANTS_COLOUR_STYLE.colour.dark
223 )
225 settings: Dict[str, Any] = {"uniform": True}
226 settings.update(kwargs)
228 _figure, axes = artist(**settings)
230 lines_sl, *_ = lines_daylight_locus(daylight_locus_mireds, method)
232 line_collection = LineCollection(
233 np.reshape(
234 np.concatenate(
235 [lines_sl["position"][:-1], lines_sl["position"][1:]], axis=1
236 ),
237 (-1, 2, 2),
238 ), # pyright: ignore
239 colors=(
240 lines_sl["colour"]
241 if use_RGB_daylight_locus_colours
242 else daylight_locus_colours
243 ),
244 alpha=daylight_locus_opacity,
245 zorder=CONSTANTS_COLOUR_STYLE.zorder.foreground_line,
246 )
247 axes.add_collection(line_collection)
249 settings = {"axes": axes}
250 settings.update(kwargs)
252 return render(**settings)
255LABELS_PLANCKIAN_LOCUS_DEFAULT: CanonicalMapping = CanonicalMapping(
256 {
257 "Default": (1e6 / 600, 2000, 2500, 3000, 4000, 6000, 1e6 / 100),
258 "Mireds": (0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000),
259 }
260)
261"""*Planckian Locus* default labels."""
264def lines_planckian_locus(
265 labels: Sequence | None = None,
266 mireds: bool = False,
267 iso_temperature_lines_D_uv: float = 0.05,
268 method: (Literal["CIE 1931", "CIE 1960 UCS", "CIE 1976 UCS"] | str) = "CIE 1931",
269) -> Tuple[NDArray, NDArray]:
270 """
271 Return the *Planckian Locus* line vertices with positions, normals, and
272 colours using the specified chromaticity diagram method.
274 Parameters
275 ----------
276 labels
277 Array of labels used to customise which iso-temperature lines will
278 be drawn along the *Planckian Locus*. Passing an empty array will
279 result in no iso-temperature lines being drawn.
280 mireds
281 Whether to use micro reciprocal degrees for the iso-temperature
282 lines.
283 iso_temperature_lines_D_uv
284 Iso-temperature lines :math:`\\Delta_{uv}` length on each side of
285 the *Planckian Locus*.
286 method
287 *Planckian Locus* method.
289 Returns
290 -------
291 :class:`tuple`
292 Tuple of *Planckian Locus* vertices and wavelength labels vertices.
294 Examples
295 --------
296 >>> lines = lines_planckian_locus()
297 >>> len(lines)
298 2
299 >>> lines[0].dtype
300 dtype([('position', '<f8', (2,)), ('normal', '<f8', (2,)), \
301('colour', '<f8', (3,))])
302 >>> lines[1].dtype
303 dtype([('position', '<f8', (2,)), ('normal', '<f8', (2,)), \
304('colour', '<f8', (3,))])
305 """
307 method = validate_method(method, ("CIE 1931", "CIE 1960 UCS", "CIE 1976 UCS"))
309 labels = cast(
310 "tuple",
311 optional(
312 labels,
313 LABELS_PLANCKIAN_LOCUS_DEFAULT["Mireds" if mireds else "Default"],
314 ),
315 )
316 D_uv = iso_temperature_lines_D_uv
318 uv_to_ij = METHODS_CHROMATICITY_DIAGRAM[method]["uv_to_ij"]
320 def CCT_D_uv_to_plotting_colourspace(CCT_D_uv: ArrayLike) -> NDArrayFloat:
321 """
322 Convert specified correlated colour temperature :math:`T_{cp}` and
323 :math:`\\Delta_{uv}` to the default plotting colourspace.
324 """
326 return normalise_maximum(
327 XYZ_to_plotting_colourspace(
328 xy_to_XYZ(UCS_uv_to_xy(CCT_to_uv(CCT_D_uv, "Robertson 1968")))
329 ),
330 axis=-1,
331 )
333 # Planckian Locus
334 start, end = (0, 1000) if mireds else (1e6 / 600, 1e6 / 10)
336 CCT = np.arange(start, end + 100, 100)
337 CCT = mired_to_CCT(CCT) if mireds else CCT
338 CCT_D_uv = tstack([CCT, zeros(CCT.shape)])
340 ij_pl = uv_to_ij(CCT_to_uv(CCT_D_uv, "Robertson 1968"))
341 colour_pl = CCT_D_uv_to_plotting_colourspace(CCT_D_uv)
343 lines_pl = zeros(
344 ij_pl.shape[0],
345 [
346 ("position", DTYPE_FLOAT_DEFAULT, 2),
347 ("normal", DTYPE_FLOAT_DEFAULT, 2),
348 ("colour", DTYPE_FLOAT_DEFAULT, 3),
349 ], # pyright: ignore
350 )
352 lines_pl["position"] = ij_pl
353 lines_pl["colour"] = colour_pl
355 # Labels
356 ij_itl, normal_itl, colour_itl = [], [], []
357 for label in labels:
358 CCT_D_uv = tstack(
359 [
360 full(
361 20,
362 as_float_scalar(mired_to_CCT(label)) if mireds else label,
363 ),
364 np.linspace(-D_uv, D_uv, 20),
365 ]
366 )
368 ij = uv_to_ij(CCT_to_uv(CCT_D_uv, "Robertson 1968"))
369 ij_itl.append(ij)
370 normal_itl.append(np.tile(normalise_vector(ij[-1, ...] - ij[0, ...]), (20, 1)))
371 colour_itl.append(CCT_D_uv_to_plotting_colourspace(CCT_D_uv))
373 ij_l = np.reshape(as_float_array(ij_itl), (-1, 2))
374 normal_l = np.reshape(as_float_array(normal_itl), (-1, 2))
375 colour_l = np.reshape(as_float_array(colour_itl), (-1, 3))
377 lines_l = zeros(
378 ij_l.shape[0],
379 [
380 ("position", DTYPE_FLOAT_DEFAULT, 2),
381 ("normal", DTYPE_FLOAT_DEFAULT, 2),
382 ("colour", DTYPE_FLOAT_DEFAULT, 3),
383 ], # pyright: ignore
384 )
386 lines_l["position"] = ij_l
387 lines_l["normal"] = normal_l
388 lines_l["colour"] = colour_l
390 return lines_pl, lines_l
393@override_style()
394def plot_planckian_locus(
395 planckian_locus_colours: ArrayLike | str | None = None,
396 planckian_locus_opacity: float = 1,
397 planckian_locus_labels: Sequence | None = None,
398 planckian_locus_mireds: bool = False,
399 planckian_locus_iso_temperature_lines_D_uv: float = 0.05,
400 method: (Literal["CIE 1931", "CIE 1960 UCS", "CIE 1976 UCS"] | str) = "CIE 1931",
401 **kwargs: Any,
402) -> Tuple[Figure, Axes]:
403 """
404 Plot the *Planckian Locus* using the specified method.
406 Parameters
407 ----------
408 planckian_locus_colours
409 Colours of the *Planckian Locus*, if ``planckian_locus_colours`` is
410 set to *RGB*, the colours will be computed using the corresponding
411 chromaticity coordinates.
412 planckian_locus_opacity
413 Opacity of the *Planckian Locus*.
414 planckian_locus_labels
415 Array of labels used to customise which iso-temperature lines will
416 be drawn along the *Planckian Locus*. Passing an empty array will
417 result in no iso-temperature lines being drawn.
418 planckian_locus_mireds
419 Whether to use micro reciprocal degrees for the iso-temperature
420 lines.
421 planckian_locus_iso_temperature_lines_D_uv
422 Iso-temperature lines :math:`\\Delta_{uv}` length on each side of
423 the *Planckian Locus*.
424 method
425 *Chromaticity Diagram* method.
427 Other Parameters
428 ----------------
429 kwargs
430 {:func:`colour.plotting.artist`, :func:`colour.plotting.render`},
431 See the documentation of the previously listed definitions.
433 Returns
434 -------
435 :class:`tuple`
436 Current figure and axes.
438 Examples
439 --------
440 >>> plot_planckian_locus(planckian_locus_colours="RGB")
441 ... # doctest: +ELLIPSIS
442 (<Figure size ... with 1 Axes>, <...Axes...>)
444 .. image:: ../_static/Plotting_Plot_Planckian_Locus.png
445 :align: center
446 :alt: plot_planckian_locus
447 """
449 planckian_locus_colours = optional(
450 planckian_locus_colours, CONSTANTS_COLOUR_STYLE.colour.dark
451 )
453 use_RGB_planckian_locus_colours = str(planckian_locus_colours).upper() == "RGB"
455 labels = cast(
456 "tuple",
457 optional(
458 planckian_locus_labels,
459 LABELS_PLANCKIAN_LOCUS_DEFAULT[
460 "Mireds" if planckian_locus_mireds else "Default"
461 ],
462 ),
463 )
465 settings: Dict[str, Any] = {"uniform": True}
466 settings.update(kwargs)
468 _figure, axes = artist(**settings)
470 lines_pl, lines_l = lines_planckian_locus(
471 labels,
472 planckian_locus_mireds,
473 planckian_locus_iso_temperature_lines_D_uv,
474 method,
475 )
477 axes.add_collection(
478 LineCollection(
479 np.reshape(
480 np.concatenate(
481 [lines_pl["position"][:-1], lines_pl["position"][1:]], axis=1
482 ),
483 (-1, 2, 2),
484 ), # pyright: ignore
485 colors=(
486 lines_pl["colour"]
487 if use_RGB_planckian_locus_colours
488 else planckian_locus_colours
489 ),
490 alpha=planckian_locus_opacity,
491 zorder=CONSTANTS_COLOUR_STYLE.zorder.foreground_line,
492 )
493 )
495 lines_itl = np.reshape(lines_l["position"], (len(labels), 20, 2))
496 colours_itl = np.reshape(lines_l["colour"], (len(labels), 20, 3))
497 for i, label in enumerate(labels):
498 axes.add_collection(
499 LineCollection(
500 np.reshape(
501 np.concatenate(
502 [lines_itl[i][:-1], lines_itl[i][1:]], # pyright: ignore
503 axis=1,
504 ),
505 (-1, 2, 2),
506 ),
507 colors=(
508 colours_itl[i]
509 if use_RGB_planckian_locus_colours
510 else planckian_locus_colours
511 ),
512 alpha=planckian_locus_opacity,
513 zorder=CONSTANTS_COLOUR_STYLE.zorder.foreground_line,
514 )
515 )
517 axes.text(
518 lines_itl[i][-1, 0],
519 lines_itl[i][-1, 1],
520 f"{as_int_scalar(label)}{'M' if planckian_locus_mireds else 'K'}",
521 clip_on=True,
522 ha="left",
523 va="bottom",
524 fontsize="x-small-colour-science",
525 zorder=CONSTANTS_COLOUR_STYLE.zorder.foreground_label,
526 )
528 settings = {"axes": axes}
529 settings.update(kwargs)
531 return render(**settings)
534@override_style()
535def plot_planckian_locus_in_chromaticity_diagram(
536 illuminants: str | Sequence[str] | None = None,
537 chromaticity_diagram_callable: Callable = plot_chromaticity_diagram,
538 method: (Literal["CIE 1931", "CIE 1960 UCS", "CIE 1976 UCS"] | str) = "CIE 1931",
539 annotate_kwargs: dict | List[dict] | None = None,
540 plot_kwargs: dict | List[dict] | None = None,
541 **kwargs: Any,
542) -> Tuple[Figure, Axes]:
543 """
544 Plot the *Planckian Locus* and specified illuminants in the
545 *Chromaticity Diagram* using the specified method.
547 Parameters
548 ----------
549 illuminants
550 Illuminants to plot. ``illuminants`` elements can be of any
551 type or form supported by the
552 :func:`colour.plotting.common.filter_passthrough` definition.
553 chromaticity_diagram_callable
554 Callable responsible for drawing the *Chromaticity Diagram*.
555 method
556 *Chromaticity Diagram* method.
557 annotate_kwargs
558 Keyword arguments for the :func:`matplotlib.pyplot.annotate`
559 definition, used to annotate the resulting chromaticity
560 coordinates with their respective spectral distribution names.
561 ``annotate_kwargs`` can be either a single dictionary applied
562 to all the arrows with same settings or a sequence of
563 dictionaries with different settings for each spectral
564 distribution. The following special keyword arguments can also
565 be used:
567 - ``annotate`` : Whether to annotate the spectral distributions.
568 plot_kwargs
569 Keyword arguments for the :func:`matplotlib.pyplot.plot`
570 definition, used to control the style of the plotted
571 illuminants. ``plot_kwargs`` can be either a single dictionary
572 applied to all the plotted illuminants with the same settings
573 or a sequence of dictionaries with different settings for each
574 plotted illuminant.
576 Other Parameters
577 ----------------
578 kwargs
579 {:func:`colour.plotting.artist`,
580 :func:`colour.plotting.diagrams.plot_chromaticity_diagram`,
581 :func:`colour.plotting.temperature.plot_planckian_locus`,
582 :func:`colour.plotting.render`},
583 See the documentation of the previously listed definitions.
585 Returns
586 -------
587 :class:`tuple`
588 Current figure and axes.
590 Examples
591 --------
592 >>> annotate_kwargs = [
593 ... {"xytext": (-25, 15), "arrowprops": {"arrowstyle": "-"}},
594 ... {"arrowprops": {"arrowstyle": "-["}},
595 ... {},
596 ... ]
597 >>> plot_kwargs = [
598 ... {
599 ... "markersize": 15,
600 ... },
601 ... {"color": "r"},
602 ... {},
603 ... ]
604 >>> plot_planckian_locus_in_chromaticity_diagram(
605 ... ["A", "B", "C"],
606 ... annotate_kwargs=annotate_kwargs,
607 ... plot_kwargs=plot_kwargs,
608 ... ) # doctest: +ELLIPSIS
609 (<Figure size ... with 1 Axes>, <...Axes...>)
611 .. image:: ../_static/Plotting_\
612Plot_Planckian_Locus_In_Chromaticity_Diagram.png
613 :align: center
614 :alt: plot_planckian_locus_in_chromaticity_diagram
615 """
617 illuminants = optional(illuminants, [])
619 method = validate_method(method, ("CIE 1931", "CIE 1960 UCS", "CIE 1976 UCS"))
621 cmfs = MSDS_CMFS["CIE 1931 2 Degree Standard Observer"]
623 illuminants_filtered = filter_passthrough(CCS_ILLUMINANTS[cmfs.name], illuminants)
625 settings: Dict[str, Any] = {"uniform": True}
626 settings.update(kwargs)
628 _figure, axes = artist(**settings)
630 method = method.upper()
632 settings = {"axes": axes, "method": method}
633 settings.update(kwargs)
634 settings["show"] = False
636 chromaticity_diagram_callable(**settings)
638 plot_planckian_locus(**settings)
640 xy_to_ij = METHODS_CHROMATICITY_DIAGRAM[method]["xy_to_ij"]
642 if method == "CIE 1931":
643 bounding_box = (-0.1, 0.9, -0.1, 0.9)
645 elif method == "CIE 1960 UCS":
646 bounding_box = (-0.1, 0.7, -0.2, 0.6)
648 elif method == "CIE 1976 UCS":
649 bounding_box = (-0.1, 0.7, -0.1, 0.7)
651 annotate_settings_collection = [
652 {
653 "annotate": True,
654 "xytext": (-50, 30),
655 "textcoords": "offset points",
656 "arrowprops": CONSTANTS_ARROW_STYLE,
657 "zorder": CONSTANTS_COLOUR_STYLE.zorder.foreground_annotation,
658 }
659 for _ in range(len(illuminants_filtered))
660 ]
662 if annotate_kwargs is not None:
663 update_settings_collection(
664 annotate_settings_collection,
665 annotate_kwargs,
666 len(illuminants_filtered),
667 )
669 plot_settings_collection = [
670 {
671 "color": CONSTANTS_COLOUR_STYLE.colour.brightest,
672 "label": f"{illuminant}",
673 "marker": "o",
674 "markeredgecolor": CONSTANTS_COLOUR_STYLE.colour.dark,
675 "markeredgewidth": CONSTANTS_COLOUR_STYLE.geometry.short * 0.75,
676 "markersize": (
677 CONSTANTS_COLOUR_STYLE.geometry.short * 6
678 + CONSTANTS_COLOUR_STYLE.geometry.short * 0.75
679 ),
680 "zorder": CONSTANTS_COLOUR_STYLE.zorder.foreground_line,
681 }
682 for illuminant in illuminants_filtered
683 ]
685 if plot_kwargs is not None:
686 update_settings_collection(
687 plot_settings_collection, plot_kwargs, len(illuminants_filtered)
688 )
690 for i, (illuminant, xy) in enumerate(illuminants_filtered.items()):
691 plot_settings = plot_settings_collection[i]
693 ij = cast("tuple[float, float]", xy_to_ij(xy))
695 axes.plot(ij[0], ij[1], **plot_settings)
697 if annotate_settings_collection[i]["annotate"]:
698 annotate_settings = annotate_settings_collection[i]
699 annotate_settings.pop("annotate")
701 axes.annotate(illuminant, xy=ij, **annotate_settings)
703 title = (
704 (
705 f"{', '.join(illuminants_filtered)} Illuminants - Planckian Locus\n"
706 f"{method.upper()} Chromaticity Diagram - "
707 "CIE 1931 2 Degree Standard Observer"
708 )
709 if illuminants_filtered
710 else (
711 f"Planckian Locus\n{method.upper()} Chromaticity Diagram - "
712 f"CIE 1931 2 Degree Standard Observer"
713 )
714 )
716 settings.update(
717 {
718 "axes": axes,
719 "show": True,
720 "bounding_box": bounding_box,
721 "title": title,
722 }
723 )
724 settings.update(kwargs)
726 return render(**settings)
729@override_style()
730def plot_planckian_locus_in_chromaticity_diagram_CIE1931(
731 illuminants: str | Sequence[str] | None = None,
732 chromaticity_diagram_callable_CIE1931: Callable = (
733 plot_chromaticity_diagram_CIE1931
734 ),
735 annotate_kwargs: dict | List[dict] | None = None,
736 plot_kwargs: dict | List[dict] | None = None,
737 **kwargs: Any,
738) -> Tuple[Figure, Axes]:
739 """
740 Plot the *Planckian Locus* and specified illuminants in the
741 *CIE 1931 Chromaticity Diagram*.
743 Parameters
744 ----------
745 illuminants
746 Illuminants to plot. ``illuminants`` elements can be of any type or
747 form supported by the
748 :func:`colour.plotting.common.filter_passthrough` definition.
749 chromaticity_diagram_callable_CIE1931
750 Callable responsible for drawing the *CIE 1931 Chromaticity Diagram*.
751 annotate_kwargs
752 Keyword arguments for the :func:`matplotlib.pyplot.annotate`
753 definition, used to annotate the resulting chromaticity
754 coordinates with their respective spectral distribution names.
755 ``annotate_kwargs`` can be either a single dictionary applied
756 to all the arrows with same settings or a sequence of
757 dictionaries with different settings for each spectral
758 distribution. The following special keyword arguments can also
759 be used:
761 - ``annotate`` : Whether to annotate the spectral distributions.
762 plot_kwargs
763 Keyword arguments for the :func:`matplotlib.pyplot.plot` definition,
764 used to control the style of the plotted illuminants. ``plot_kwargs``
765 can be either a single dictionary applied to all the plotted
766 illuminants with the same settings or a sequence of dictionaries with
767 different settings for each plotted illuminant.
769 Other Parameters
770 ----------------
771 kwargs
772 {:func:`colour.plotting.artist`,
773 :func:`colour.plotting.diagrams.plot_chromaticity_diagram`,
774 :func:`colour.plotting.temperature.plot_planckian_locus`,
775 :func:`colour.plotting.temperature.\
776plot_planckian_locus_in_chromaticity_diagram`,
777 :func:`colour.plotting.render`},
778 See the documentation of the previously listed definitions.
780 Returns
781 -------
782 :class:`tuple`
783 Current figure and axes.
785 Examples
786 --------
787 >>> plot_planckian_locus_in_chromaticity_diagram_CIE1931(["A", "B", "C"])
788 ... # doctest: +ELLIPSIS
789 (<Figure size ... with 1 Axes>, <...Axes...>)
791 .. image:: ../_static/Plotting_\
792Plot_Planckian_Locus_In_Chromaticity_Diagram_CIE1931.png
793 :align: center
794 :alt: plot_planckian_locus_in_chromaticity_diagram_CIE1931
795 """
797 settings = dict(kwargs)
798 settings.update({"method": "CIE 1931"})
800 return plot_planckian_locus_in_chromaticity_diagram(
801 illuminants,
802 chromaticity_diagram_callable_CIE1931,
803 annotate_kwargs=annotate_kwargs,
804 plot_kwargs=plot_kwargs,
805 **settings,
806 )
809@override_style()
810def plot_planckian_locus_in_chromaticity_diagram_CIE1960UCS(
811 illuminants: str | Sequence[str] | None = None,
812 chromaticity_diagram_callable_CIE1960UCS: Callable = (
813 plot_chromaticity_diagram_CIE1960UCS
814 ),
815 annotate_kwargs: dict | List[dict] | None = None,
816 plot_kwargs: dict | List[dict] | None = None,
817 **kwargs: Any,
818) -> Tuple[Figure, Axes]:
819 """
820 Plot the *Planckian Locus* and specified illuminants in the
821 *CIE 1960 UCS Chromaticity Diagram*.
823 Parameters
824 ----------
825 illuminants
826 Illuminants to plot. ``illuminants`` elements can be of any type or
827 form supported by the
828 :func:`colour.plotting.common.filter_passthrough` definition.
829 chromaticity_diagram_callable_CIE1960UCS
830 Callable responsible for drawing the
831 *CIE 1960 UCS Chromaticity Diagram*.
832 annotate_kwargs
833 Keyword arguments for the :func:`matplotlib.pyplot.annotate`
834 definition, used to annotate the resulting chromaticity
835 coordinates with their respective spectral distribution names.
836 ``annotate_kwargs`` can be either a single dictionary applied
837 to all the arrows with same settings or a sequence of
838 dictionaries with different settings for each spectral
839 distribution. The following special keyword arguments can also
840 be used:
842 - ``annotate`` : Whether to annotate the spectral distributions.
843 plot_kwargs
844 Keyword arguments for the :func:`matplotlib.pyplot.plot`
845 definition, used to control the style of the plotted illuminants.
846 ``plot_kwargs`` can be either a single dictionary applied to all
847 the plotted illuminants with the same settings or a sequence of
848 dictionaries with different settings for each plotted illuminant.
850 Other Parameters
851 ----------------
852 kwargs
853 {:func:`colour.plotting.artist`,
854 :func:`colour.plotting.diagrams.plot_chromaticity_diagram`,
855 :func:`colour.plotting.temperature.plot_planckian_locus`,
856 :func:`colour.plotting.temperature.\
857plot_planckian_locus_in_chromaticity_diagram`,
858 :func:`colour.plotting.render`},
859 See the documentation of the previously listed definitions.
861 Returns
862 -------
863 :class:`tuple`
864 Current figure and axes.
866 Examples
867 --------
868 >>> plot_planckian_locus_in_chromaticity_diagram_CIE1960UCS(
869 ... ["A", "C", "E"]
870 ... ) # doctest: +ELLIPSIS
871 (<Figure size ... with 1 Axes>, <...Axes...>)
873 .. image:: ../_static/Plotting_\
874Plot_Planckian_Locus_In_Chromaticity_Diagram_CIE1960UCS.png
875 :align: center
876 :alt: plot_planckian_locus_in_chromaticity_diagram_CIE1960UCS
877 """
879 settings = dict(kwargs)
880 settings.update({"method": "CIE 1960 UCS"})
882 return plot_planckian_locus_in_chromaticity_diagram(
883 illuminants,
884 chromaticity_diagram_callable_CIE1960UCS,
885 annotate_kwargs=annotate_kwargs,
886 plot_kwargs=plot_kwargs,
887 **settings,
888 )
891@override_style()
892def plot_planckian_locus_in_chromaticity_diagram_CIE1976UCS(
893 illuminants: str | Sequence[str] | None = None,
894 chromaticity_diagram_callable_CIE1976UCS: Callable = (
895 plot_chromaticity_diagram_CIE1976UCS
896 ),
897 annotate_kwargs: dict | List[dict] | None = None,
898 plot_kwargs: dict | List[dict] | None = None,
899 **kwargs: Any,
900) -> Tuple[Figure, Axes]:
901 """
902 Plot the *Planckian Locus* and specified illuminants in the
903 *CIE 1976 UCS Chromaticity Diagram*.
905 Parameters
906 ----------
907 illuminants
908 Illuminants to plot. ``illuminants`` elements can be of any type
909 or form supported by the
910 :func:`colour.plotting.common.filter_passthrough` definition.
911 chromaticity_diagram_callable_CIE1976UCS
912 Callable responsible for drawing the
913 *CIE 1976 UCS Chromaticity Diagram*.
914 annotate_kwargs
915 Keyword arguments for the :func:`matplotlib.pyplot.annotate`
916 definition, used to annotate the resulting chromaticity
917 coordinates with their respective spectral distribution names.
918 ``annotate_kwargs`` can be either a single dictionary applied
919 to all the arrows with same settings or a sequence of
920 dictionaries with different settings for each spectral
921 distribution. The following special keyword arguments can also
922 be used:
924 - ``annotate`` : Whether to annotate the spectral distributions.
925 plot_kwargs
926 Keyword arguments for the :func:`matplotlib.pyplot.plot`
927 definition, used to control the style of the plotted illuminants.
928 ``plot_kwargs`` can be either a single dictionary applied to all
929 the plotted illuminants with the same settings or a sequence of
930 dictionaries with different settings for each plotted illuminant.
932 Other Parameters
933 ----------------
934 kwargs
935 {:func:`colour.plotting.artist`,
936 :func:`colour.plotting.diagrams.plot_chromaticity_diagram`,
937 :func:`colour.plotting.temperature.plot_planckian_locus`,
938 :func:`colour.plotting.temperature.\
939plot_planckian_locus_in_chromaticity_diagram`,
940 :func:`colour.plotting.render`},
941 See the documentation of the previously listed definitions.
943 Returns
944 -------
945 :class:`tuple`
946 Current figure and axes.
948 Examples
949 --------
950 >>> plot_planckian_locus_in_chromaticity_diagram_CIE1976UCS(
951 ... ["A", "C", "E"]
952 ... ) # doctest: +ELLIPSIS
953 (<Figure size ... with 1 Axes>, <...Axes...>)
955 .. image:: ../_static/Plotting_\
956Plot_Planckian_Locus_In_Chromaticity_Diagram_CIE1976UCS.png
957 :align: center
958 :alt: plot_planckian_locus_in_chromaticity_diagram_CIE1976UCS
959 """
961 settings = dict(kwargs)
962 settings.update({"method": "CIE 1976 UCS"})
964 return plot_planckian_locus_in_chromaticity_diagram(
965 illuminants,
966 chromaticity_diagram_callable_CIE1976UCS,
967 annotate_kwargs=annotate_kwargs,
968 plot_kwargs=plot_kwargs,
969 **settings,
970 )