• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

colour-science / colour / 4207404108

pending completion
4207404108

push

github-actions

Thomas Mansencal
Merge branch 'feature/v0.4.3' into develop

4 of 4 new or added lines in 2 files covered. (100.0%)

29816 of 38555 relevant lines covered (77.33%)

0.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.26
/colour/plotting/section.py
1
"""
2
Gamut Section Plotting
3
======================
4

5
Defines the gamut section plotting objects:
6

7
-   :func:`colour.plotting.section.plot_hull_section_colours`
8
-   :func:`colour.plotting.section.plot_hull_section_contour`
9
-   :func:`colour.plotting.plot_visible_spectrum_section`
10
-   :func:`colour.plotting.plot_RGB_colourspace_section`
11
"""
12

13
from __future__ import annotations
×
14

15
import matplotlib.pyplot as plt
×
16
import numpy as np
×
17
from matplotlib.collections import LineCollection
×
18
from matplotlib.patches import Polygon
×
19

20
from colour.colorimetry import (
×
21
    MultiSpectralDistributions,
22
    SpectralDistribution,
23
    SpectralShape,
24
    reshape_msds,
25
)
26
from colour.geometry import hull_section, primitive_cube
×
27
from colour.graph import convert
×
28
from colour.hints import (
×
29
    Any,
30
    ArrayLike,
31
    Dict,
32
    Literal,
33
    Real,
34
    Sequence,
35
    Tuple,
36
    Union,
37
    cast,
38
)
39
from colour.models import (
×
40
    COLOURSPACE_MODELS_AXIS_LABELS,
41
    COLOURSPACE_MODELS_DOMAIN_RANGE_SCALE_1_TO_REFERENCE,
42
    RGB_Colourspace,
43
    RGB_to_XYZ,
44
)
45
from colour.notation import HEX_to_RGB
×
46
from colour.plotting import (
×
47
    CONSTANTS_COLOUR_STYLE,
48
    XYZ_to_plotting_colourspace,
49
    artist,
50
    colourspace_model_axis_reorder,
51
    filter_cmfs,
52
    filter_RGB_colourspaces,
53
    filter_illuminants,
54
    override_style,
55
    render,
56
)
57
from colour.volume import solid_RoschMacAdam
×
58
from colour.utilities import (
×
59
    CanonicalMapping,
60
    as_int_array,
61
    first_item,
62
    full,
63
    optional,
64
    required,
65
    suppress_warnings,
66
    tstack,
67
    validate_method,
68
)
69

70
__author__ = "Colour Developers"
×
71
__copyright__ = "Copyright 2013 Colour Developers"
×
72
__license__ = "New BSD License - https://opensource.org/licenses/BSD-3-Clause"
×
73
__maintainer__ = "Colour Developers"
×
74
__email__ = "colour-developers@colour-science.org"
×
75
__status__ = "Production"
×
76

77
__all__ = [
×
78
    "MAPPING_AXIS_TO_PLANE",
79
    "plot_hull_section_colours",
80
    "plot_hull_section_contour",
81
    "plot_visible_spectrum_section",
82
    "plot_RGB_colourspace_section",
83
]
84

85
MAPPING_AXIS_TO_PLANE: CanonicalMapping = CanonicalMapping(
×
86
    {"+x": (1, 2), "+y": (0, 2), "+z": (0, 1)}
87
)
88
MAPPING_AXIS_TO_PLANE.__doc__ = """Axis to plane mapping."""
×
89

90

91
@required("trimesh")
×
92
@override_style()
×
93
def plot_hull_section_colours(
×
94
    hull: trimesh.Trimesh,  # pyright: ignore  # noqa: F821
95
    model: Literal[
96
        "CAM02LCD",
97
        "CAM02SCD",
98
        "CAM02UCS",
99
        "CAM16LCD",
100
        "CAM16SCD",
101
        "CAM16UCS",
102
        "CIE XYZ",
103
        "CIE xyY",
104
        "CIE Lab",
105
        "CIE Luv",
106
        "CIE UCS",
107
        "CIE UVW",
108
        "DIN99",
109
        "Hunter Lab",
110
        "Hunter Rdab",
111
        "ICaCb",
112
        "ICtCp",
113
        "IPT",
114
        "IgPgTg",
115
        "Jzazbz",
116
        "OSA UCS",
117
        "Oklab",
118
        "hdr-CIELAB",
119
        "hdr-IPT",
120
    ]
121
    | str = "CIE xyY",
122
    axis: Literal["+z", "+x", "+y"] | str = "+z",
123
    origin: float = 0.5,
124
    normalise: bool = True,
125
    section_colours: ArrayLike | str | None = None,
126
    section_opacity: float = 1,
127
    convert_kwargs: dict | None = None,
128
    samples: int = 256,
129
    **kwargs: Any,
130
) -> Tuple[plt.Figure, plt.Axes]:
131
    """
132
    Plot the section colours of given *trimesh* hull along given axis and
133
    origin.
134

135
    Parameters
136
    ----------
137
    hull
138
        *Trimesh* hull.
139
    model
140
        Colourspace model, see :attr:`colour.COLOURSPACE_MODELS` attribute for
141
        the list of supported colourspace models.
142
    axis
143
        Axis the hull section will be normal to.
144
    origin
145
        Coordinate along ``axis`` at which to plot the hull section.
146
    normalise
147
        Whether to normalise ``axis`` to the extent of the hull along it.
148
    section_colours
149
        Colours of the hull section, if ``section_colours`` is set to *RGB*,
150
        the colours will be computed according to the corresponding
151
        coordinates.
152
    section_opacity
153
        Opacity of the hull section colours.
154
    convert_kwargs
155
        Keyword arguments for the :func:`colour.convert` definition.
156
    samples
157
        Samples count on one axis when computing the hull section colours.
158

159
    Other Parameters
160
    ----------------
161
    kwargs
162
        {:func:`colour.plotting.artist`,
163
        :func:`colour.plotting.render`},
164
        See the documentation of the previously listed definitions.
165

166
    Returns
167
    -------
168
    :class:`tuple`
169
        Current figure and axes.
170

171
    Examples
172
    --------
173
    >>> from colour.models import RGB_COLOURSPACE_sRGB
174
    >>> from colour.utilities import is_trimesh_installed
175
    >>> vertices, faces, _outline = primitive_cube(1, 1, 1, 64, 64, 64)
176
    >>> XYZ_vertices = RGB_to_XYZ(
177
    ...     vertices["position"] + 0.5,
178
    ...     RGB_COLOURSPACE_sRGB.whitepoint,
179
    ...     RGB_COLOURSPACE_sRGB.whitepoint,
180
    ...     RGB_COLOURSPACE_sRGB.matrix_RGB_to_XYZ,
181
    ... )
182
    >>> if is_trimesh_installed:
183
    ...     import trimesh
184
    ...
185
    ...     hull = trimesh.Trimesh(XYZ_vertices, faces, process=False)
186
    ...     plot_hull_section_colours(hull, section_colours="RGB")
187
    ...     # doctest: +ELLIPSIS
188
    ...
189
    (<Figure size ... with 1 Axes>, <...Axes...>)
190

191
    .. image:: ../_static/Plotting_Plot_Hull_Section_Colours.png
192
        :align: center
193
        :alt: plot_hull_section_colours
194
    """
195

196
    axis = validate_method(
1✔
197
        axis,
198
        ["+z", "+x", "+y"],
199
        '"{0}" axis is invalid, it must be one of {1}!',
200
    )
201

202
    hull = hull.copy()
1✔
203

204
    settings: Dict[str, Any] = {"uniform": True}
1✔
205
    settings.update(kwargs)
1✔
206

207
    _figure, axes = artist(**settings)
1✔
208

209
    section_colours = cast(
1✔
210
        ArrayLike,
211
        optional(
212
            section_colours, HEX_to_RGB(CONSTANTS_COLOUR_STYLE.colour.average)
213
        ),
214
    )
215

216
    convert_kwargs = optional(convert_kwargs, {})
1✔
217

218
    # Luminance / Lightness reordered along "z" axis.
219
    with suppress_warnings(python_warnings=True):
1✔
220
        ijk_vertices = colourspace_model_axis_reorder(
1✔
221
            convert(hull.vertices, "CIE XYZ", model, **convert_kwargs), model
222
        )
223
        ijk_vertices = np.nan_to_num(ijk_vertices)
1✔
224
        ijk_vertices *= COLOURSPACE_MODELS_DOMAIN_RANGE_SCALE_1_TO_REFERENCE[
1✔
225
            model
226
        ]
227

228
    hull.vertices = ijk_vertices
1✔
229

230
    if axis == "+x":
1✔
231
        index_origin = 0
1✔
232
    elif axis == "+y":
1✔
233
        index_origin = 1
1✔
234
    elif axis == "+z":
1✔
235
        index_origin = 2
1✔
236
    plane = MAPPING_AXIS_TO_PLANE[axis]
1✔
237

238
    section = hull_section(hull, axis, origin, normalise)
1✔
239

240
    padding = 0.1 * np.mean(
1✔
241
        COLOURSPACE_MODELS_DOMAIN_RANGE_SCALE_1_TO_REFERENCE[model]
242
    )
243
    min_x = np.min(ijk_vertices[..., plane[0]]) - padding
1✔
244
    max_x = np.max(ijk_vertices[..., plane[0]]) + padding
1✔
245
    min_y = np.min(ijk_vertices[..., plane[1]]) - padding
1✔
246
    max_y = np.max(ijk_vertices[..., plane[1]]) + padding
1✔
247
    extent = (min_x, max_x, min_y, max_y)
1✔
248

249
    use_RGB_section_colours = str(section_colours).upper() == "RGB"
1✔
250
    if use_RGB_section_colours:
1✔
251
        ii, jj = np.meshgrid(
1✔
252
            np.linspace(min_x, max_x, samples),
253
            np.linspace(max_y, min_y, samples),
254
        )
255
        ij = tstack([ii, jj])
1✔
256
        ijk_section = full(
1✔
257
            (samples, samples, 3),
258
            cast(Real, np.median(section[..., index_origin])),
259
        )
260
        ijk_section[..., plane] = ij
1✔
261
        ijk_section /= COLOURSPACE_MODELS_DOMAIN_RANGE_SCALE_1_TO_REFERENCE[
1✔
262
            model
263
        ]
264
        XYZ_section = convert(
1✔
265
            colourspace_model_axis_reorder(ijk_section, model, "Inverse"),
266
            model,
267
            "CIE XYZ",
268
            **convert_kwargs,
269
        )
270
        RGB_section = XYZ_to_plotting_colourspace(XYZ_section)
1✔
271
    else:
272
        section_colours = np.hstack([section_colours, section_opacity])
1✔
273

274
    facecolor = "none" if use_RGB_section_colours else section_colours
1✔
275
    polygon = Polygon(
1✔
276
        section[..., plane],
277
        facecolor=facecolor,
278
        edgecolor="none",
279
        zorder=CONSTANTS_COLOUR_STYLE.zorder.background_polygon,
280
    )
281
    axes.add_patch(polygon)
1✔
282
    if use_RGB_section_colours:
1✔
283
        image = axes.imshow(
1✔
284
            np.clip(RGB_section, 0, 1),
285
            interpolation="bilinear",
286
            extent=extent,
287
            clip_path=None,
288
            alpha=section_opacity,
289
            zorder=CONSTANTS_COLOUR_STYLE.zorder.background_polygon,
290
        )
291
        image.set_clip_path(polygon)
1✔
292

293
    settings = {
1✔
294
        "axes": axes,
295
        "bounding_box": extent,
296
    }
297
    settings.update(kwargs)
1✔
298

299
    return render(**settings)
1✔
300

301

302
@required("trimesh")
×
303
@override_style()
×
304
def plot_hull_section_contour(
×
305
    hull: trimesh.Trimesh,  # pyright: ignore  # noqa: F821
306
    model: Literal[
307
        "CAM02LCD",
308
        "CAM02SCD",
309
        "CAM02UCS",
310
        "CAM16LCD",
311
        "CAM16SCD",
312
        "CAM16UCS",
313
        "CIE XYZ",
314
        "CIE xyY",
315
        "CIE Lab",
316
        "CIE Luv",
317
        "CIE UCS",
318
        "CIE UVW",
319
        "DIN99",
320
        "Hunter Lab",
321
        "Hunter Rdab",
322
        "ICaCb",
323
        "ICtCp",
324
        "IPT",
325
        "IgPgTg",
326
        "Jzazbz",
327
        "OSA UCS",
328
        "Oklab",
329
        "hdr-CIELAB",
330
        "hdr-IPT",
331
    ]
332
    | str = "CIE xyY",
333
    axis: Literal["+z", "+x", "+y"] | str = "+z",
334
    origin: float = 0.5,
335
    normalise: bool = True,
336
    contour_colours: ArrayLike | str | None = None,
337
    contour_opacity: float = 1,
338
    convert_kwargs: dict | None = None,
339
    **kwargs: Any,
340
) -> Tuple[plt.Figure, plt.Axes]:
341
    """
342
    Plot the section contour of given *trimesh* hull along given axis and
343
    origin.
344

345
    Parameters
346
    ----------
347
    hull
348
        *Trimesh* hull.
349
    model
350
        Colourspace model, see :attr:`colour.COLOURSPACE_MODELS` attribute for
351
        the list of supported colourspace models.
352
    axis
353
        Axis the hull section will be normal to.
354
    origin
355
        Coordinate along ``axis`` at which to plot the hull section.
356
    normalise
357
        Whether to normalise ``axis`` to the extent of the hull along it.
358
    contour_colours
359
        Colours of the hull section contour, if ``contour_colours`` is set to
360
        *RGB*, the colours will be computed according to the corresponding
361
        coordinates.
362
    contour_opacity
363
        Opacity of the hull section contour.
364
    convert_kwargs
365
        Keyword arguments for the :func:`colour.convert` definition.
366

367
    Other Parameters
368
    ----------------
369
    kwargs
370
        {:func:`colour.plotting.artist`,
371
        :func:`colour.plotting.render`},
372
        See the documentation of the previously listed definitions.
373

374
    Returns
375
    -------
376
    :class:`tuple`
377
        Current figure and axes.
378

379
    Examples
380
    --------
381
    >>> from colour.models import RGB_COLOURSPACE_sRGB
382
    >>> from colour.utilities import is_trimesh_installed
383
    >>> vertices, faces, _outline = primitive_cube(1, 1, 1, 64, 64, 64)
384
    >>> XYZ_vertices = RGB_to_XYZ(
385
    ...     vertices["position"] + 0.5,
386
    ...     RGB_COLOURSPACE_sRGB.whitepoint,
387
    ...     RGB_COLOURSPACE_sRGB.whitepoint,
388
    ...     RGB_COLOURSPACE_sRGB.matrix_RGB_to_XYZ,
389
    ... )
390
    >>> if is_trimesh_installed:
391
    ...     import trimesh
392
    ...
393
    ...     hull = trimesh.Trimesh(XYZ_vertices, faces, process=False)
394
    ...     plot_hull_section_contour(hull, contour_colours="RGB")
395
    ...     # doctest: +ELLIPSIS
396
    ...
397
    (<Figure size ... with 1 Axes>, <...Axes...>)
398

399
    .. image:: ../_static/Plotting_Plot_Hull_Section_Contour.png
400
        :align: center
401
        :alt: plot_hull_section_contour
402
    """
403

404
    hull = hull.copy()
1✔
405

406
    contour_colours = cast(
1✔
407
        Union[ArrayLike, str],
408
        optional(contour_colours, CONSTANTS_COLOUR_STYLE.colour.dark),
409
    )
410

411
    settings: Dict[str, Any] = {"uniform": True}
1✔
412
    settings.update(kwargs)
1✔
413

414
    _figure, axes = artist(**settings)
1✔
415

416
    convert_kwargs = optional(convert_kwargs, {})
1✔
417

418
    # Luminance / Lightness is re-ordered along "z-up" axis.
419
    with suppress_warnings(python_warnings=True):
1✔
420
        ijk_vertices = colourspace_model_axis_reorder(
1✔
421
            convert(hull.vertices, "CIE XYZ", model, **convert_kwargs), model
422
        )
423
        ijk_vertices = np.nan_to_num(ijk_vertices)
1✔
424
        ijk_vertices *= COLOURSPACE_MODELS_DOMAIN_RANGE_SCALE_1_TO_REFERENCE[
1✔
425
            model
426
        ]
427

428
    hull.vertices = ijk_vertices
1✔
429

430
    plane = MAPPING_AXIS_TO_PLANE[axis]
1✔
431

432
    padding = 0.1 * np.mean(
1✔
433
        COLOURSPACE_MODELS_DOMAIN_RANGE_SCALE_1_TO_REFERENCE[model]
434
    )
435
    min_x = np.min(ijk_vertices[..., plane[0]]) - padding
1✔
436
    max_x = np.max(ijk_vertices[..., plane[0]]) + padding
1✔
437
    min_y = np.min(ijk_vertices[..., plane[1]]) - padding
1✔
438
    max_y = np.max(ijk_vertices[..., plane[1]]) + padding
1✔
439
    extent = (min_x, max_x, min_y, max_y)
1✔
440

441
    use_RGB_contour_colours = str(contour_colours).upper() == "RGB"
1✔
442
    section = hull_section(hull, axis, origin, normalise)
1✔
443
    if use_RGB_contour_colours:
1✔
444
        ijk_section = section / (
1✔
445
            COLOURSPACE_MODELS_DOMAIN_RANGE_SCALE_1_TO_REFERENCE[model]
446
        )
447
        XYZ_section = convert(
1✔
448
            colourspace_model_axis_reorder(ijk_section, model, "Inverse"),
449
            model,
450
            "CIE XYZ",
451
            **convert_kwargs,
452
        )
453
        contour_colours = np.clip(
1✔
454
            XYZ_to_plotting_colourspace(XYZ_section), 0, 1
455
        )
456

457
    section = np.reshape(section[..., plane], (-1, 1, 2))
1✔
458
    line_collection = LineCollection(
1✔
459
        np.concatenate([section[:-1], section[1:]], axis=1),
460
        colors=contour_colours,
461
        alpha=contour_opacity,
462
        zorder=CONSTANTS_COLOUR_STYLE.zorder.background_line,
463
    )
464
    axes.add_collection(line_collection)
1✔
465

466
    settings = {
1✔
467
        "axes": axes,
468
        "bounding_box": extent,
469
    }
470
    settings.update(kwargs)
1✔
471

472
    return render(**settings)
1✔
473

474

475
@required("trimesh")
×
476
@override_style()
×
477
def plot_visible_spectrum_section(
×
478
    cmfs: MultiSpectralDistributions
479
    | str
480
    | Sequence[
481
        MultiSpectralDistributions | str
482
    ] = "CIE 1931 2 Degree Standard Observer",
483
    illuminant: SpectralDistribution | str = "D65",
484
    model: Literal[
485
        "CAM02LCD",
486
        "CAM02SCD",
487
        "CAM02UCS",
488
        "CAM16LCD",
489
        "CAM16SCD",
490
        "CAM16UCS",
491
        "CIE XYZ",
492
        "CIE xyY",
493
        "CIE Lab",
494
        "CIE Luv",
495
        "CIE UCS",
496
        "CIE UVW",
497
        "DIN99",
498
        "Hunter Lab",
499
        "Hunter Rdab",
500
        "ICaCb",
501
        "ICtCp",
502
        "IPT",
503
        "IgPgTg",
504
        "Jzazbz",
505
        "OSA UCS",
506
        "Oklab",
507
        "hdr-CIELAB",
508
        "hdr-IPT",
509
    ]
510
    | str = "CIE xyY",
511
    axis: Literal["+z", "+x", "+y"] | str = "+z",
512
    origin: float = 0.5,
513
    normalise: bool = True,
514
    show_section_colours: bool = True,
515
    show_section_contour: bool = True,
516
    **kwargs: Any,
517
) -> Tuple[plt.Figure, plt.Axes]:
518
    """
519
    Plot the visible spectrum volume, i.e. *Rösch-MacAdam* colour solid,
520
    section colours along given axis and origin.
521

522
    Parameters
523
    ----------
524
    cmfs
525
        Standard observer colour matching functions, default to the
526
        *CIE 1931 2 Degree Standard Observer*.  ``cmfs`` can be of any type or
527
        form supported by the :func:`colour.plotting.common.filter_cmfs`
528
        definition.
529
    illuminant
530
        Illuminant spectral distribution, default to *CIE Illuminant D65*.
531
        ``illuminant`` can be of any type or form supported by the
532
        :func:`colour.plotting.common.filter_illuminants` definition.
533
    model
534
        Colourspace model, see :attr:`colour.COLOURSPACE_MODELS` attribute for
535
        the list of supported colourspace models.
536
    axis
537
        Axis the hull section will be normal to.
538
    origin
539
        Coordinate along ``axis`` at which to plot the hull section.
540
    normalise
541
        Whether to normalise ``axis`` to the extent of the hull along it.
542
    show_section_colours
543
        Whether to show the hull section colours.
544
    show_section_contour
545
        Whether to show the hull section contour.
546

547
    Other Parameters
548
    ----------------
549
    kwargs
550
        {:func:`colour.plotting.artist`,
551
        :func:`colour.plotting.render`,
552
        :func:`colour.plotting.section.plot_hull_section_colours`
553
        :func:`colour.plotting.section.plot_hull_section_contour`},
554
        See the documentation of the previously listed definitions.
555

556
    Returns
557
    -------
558
    :class:`tuple`
559
        Current figure and axes.
560

561
    Examples
562
    --------
563
    >>> from colour.utilities import is_trimesh_installed
564
    >>> if is_trimesh_installed:
565
    ...     plot_visible_spectrum_section(
566
    ...         section_colours="RGB", section_opacity=0.15
567
    ...     )
568
    ...     # doctest: +ELLIPSIS
569
    ...
570
    (<Figure size ... with 1 Axes>, <...Axes...>)
571

572
    .. image:: ../_static/Plotting_Plot_Visible_Spectrum_Section.png
573
        :align: center
574
        :alt: plot_visible_spectrum_section
575
    """
576

577
    import trimesh
1✔
578

579
    settings: Dict[str, Any] = {"uniform": True}
1✔
580
    settings.update(kwargs)
1✔
581

582
    _figure, axes = artist(**settings)
1✔
583

584
    # pylint: disable=E1102
585
    cmfs = cast(
1✔
586
        MultiSpectralDistributions,
587
        reshape_msds(
588
            first_item(filter_cmfs(cmfs).values()), SpectralShape(360, 780, 1)
589
        ),
590
    )
591
    illuminant = cast(
1✔
592
        SpectralDistribution,
593
        first_item(filter_illuminants(illuminant).values()),
594
    )
595

596
    vertices = solid_RoschMacAdam(
1✔
597
        cmfs,
598
        illuminant,
599
        point_order="Pulse Wave Width",
600
        filter_jagged_points=True,
601
    )
602
    mesh = trimesh.Trimesh(vertices)
1✔
603
    hull = trimesh.convex.convex_hull(mesh)
1✔
604

605
    if show_section_colours:
1✔
606
        settings = {"axes": axes}
1✔
607
        settings.update(kwargs)
1✔
608
        settings["standalone"] = False
1✔
609

610
        plot_hull_section_colours(
1✔
611
            hull, model, axis, origin, normalise, **settings
612
        )
613

614
    if show_section_contour:
1✔
615
        settings = {"axes": axes}
1✔
616
        settings.update(kwargs)
1✔
617
        settings["standalone"] = False
1✔
618

619
        plot_hull_section_contour(
1✔
620
            hull, model, axis, origin, normalise, **settings
621
        )
622

623
    title = (
1✔
624
        f"Visible Spectrum Section - "
625
        f"{f'{origin * 100}%' if normalise else origin} - "
626
        f"{model} - "
627
        f"{cmfs.display_name}"
628
    )
629

630
    plane = MAPPING_AXIS_TO_PLANE[axis]
1✔
631

632
    labels = np.array(COLOURSPACE_MODELS_AXIS_LABELS[model])[
1✔
633
        as_int_array(colourspace_model_axis_reorder([0, 1, 2], model))
634
    ]
635
    x_label, y_label = labels[plane[0]], labels[plane[1]]
1✔
636

637
    settings.update(
1✔
638
        {
639
            "axes": axes,
640
            "standalone": True,
641
            "title": title,
642
            "x_label": x_label,
643
            "y_label": y_label,
644
        }
645
    )
646
    settings.update(kwargs)
1✔
647

648
    return render(**settings)
1✔
649

650

651
@required("trimesh")
×
652
@override_style()
×
653
def plot_RGB_colourspace_section(
×
654
    colourspace: RGB_Colourspace | str | Sequence[RGB_Colourspace | str],
655
    model: Literal[
656
        "CAM02LCD",
657
        "CAM02SCD",
658
        "CAM02UCS",
659
        "CAM16LCD",
660
        "CAM16SCD",
661
        "CAM16UCS",
662
        "CIE XYZ",
663
        "CIE xyY",
664
        "CIE Lab",
665
        "CIE Luv",
666
        "CIE UCS",
667
        "CIE UVW",
668
        "DIN99",
669
        "Hunter Lab",
670
        "Hunter Rdab",
671
        "ICaCb",
672
        "ICtCp",
673
        "IPT",
674
        "IgPgTg",
675
        "Jzazbz",
676
        "OSA UCS",
677
        "Oklab",
678
        "hdr-CIELAB",
679
        "hdr-IPT",
680
    ]
681
    | str = "CIE xyY",
682
    axis: Literal["+z", "+x", "+y"] | str = "+z",
683
    origin: float = 0.5,
684
    normalise: bool = True,
685
    show_section_colours: bool = True,
686
    show_section_contour: bool = True,
687
    **kwargs: Any,
688
) -> Tuple[plt.Figure, plt.Axes]:
689
    """
690
    Plot given *RGB* colourspace section colours along given axis and origin.
691

692
    Parameters
693
    ----------
694
    colourspace
695
        *RGB* colourspace of the *RGB* array. ``colourspace`` can be of any
696
        type or form supported by the
697
        :func:`colour.plotting.common.filter_RGB_colourspaces` definition.
698
    model
699
        Colourspace model, see :attr:`colour.COLOURSPACE_MODELS` attribute for
700
        the list of supported colourspace models.
701
    axis
702
        Axis the hull section will be normal to.
703
    origin
704
        Coordinate along ``axis`` at which to plot the hull section.
705
    normalise
706
        Whether to normalise ``axis`` to the extent of the hull along it.
707
    show_section_colours
708
        Whether to show the hull section colours.
709
    show_section_contour
710
        Whether to show the hull section contour.
711

712
    Other Parameters
713
    ----------------
714
    kwargs
715
        {:func:`colour.plotting.artist`,
716
        :func:`colour.plotting.render`,
717
        :func:`colour.plotting.section.plot_hull_section_colours`
718
        :func:`colour.plotting.section.plot_hull_section_contour`},
719
        See the documentation of the previously listed definitions.
720

721
    Returns
722
    -------
723
    :class:`tuple`
724
        Current figure and axes.
725

726
    Examples
727
    --------
728
    >>> from colour.utilities import is_trimesh_installed
729
    >>> if is_trimesh_installed:
730
    ...     plot_RGB_colourspace_section(
731
    ...         "sRGB", section_colours="RGB", section_opacity=0.15
732
    ...     )
733
    ...     # doctest: +ELLIPSIS
734
    ...
735
    (<Figure size ... with 1 Axes>, <...Axes...>)
736

737
    .. image:: ../_static/Plotting_Plot_RGB_Colourspace_Section.png
738
        :align: center
739
        :alt: plot_RGB_colourspace_section
740
    """
741

742
    import trimesh
1✔
743

744
    settings: Dict[str, Any] = {"uniform": True}
1✔
745
    settings.update(kwargs)
1✔
746

747
    _figure, axes = artist(**settings)
1✔
748

749
    colourspace = cast(
1✔
750
        RGB_Colourspace,
751
        first_item(filter_RGB_colourspaces(colourspace).values()),
752
    )
753

754
    vertices, faces, _outline = primitive_cube(1, 1, 1, 64, 64, 64)
1✔
755
    XYZ_vertices = RGB_to_XYZ(
1✔
756
        vertices["position"] + 0.5,
757
        colourspace.whitepoint,
758
        colourspace.whitepoint,
759
        colourspace.matrix_RGB_to_XYZ,
760
    )
761
    hull = trimesh.Trimesh(XYZ_vertices, faces, process=False)
1✔
762

763
    if show_section_colours:
1✔
764
        settings = {"axes": axes}
1✔
765
        settings.update(kwargs)
1✔
766
        settings["standalone"] = False
1✔
767

768
        plot_hull_section_colours(
1✔
769
            hull, model, axis, origin, normalise, **settings
770
        )
771

772
    if show_section_contour:
1✔
773
        settings = {"axes": axes}
1✔
774
        settings.update(kwargs)
1✔
775
        settings["standalone"] = False
1✔
776

777
        plot_hull_section_contour(
1✔
778
            hull, model, axis, origin, normalise, **settings
779
        )
780

781
    title = (
1✔
782
        f"{colourspace.name} Section - "
783
        f"{f'{origin * 100}%' if normalise else origin} - "
784
        f"{model}"
785
    )
786

787
    plane = MAPPING_AXIS_TO_PLANE[axis]
1✔
788

789
    labels = np.array(COLOURSPACE_MODELS_AXIS_LABELS[model])[
1✔
790
        as_int_array(colourspace_model_axis_reorder([0, 1, 2], model))
791
    ]
792
    x_label, y_label = labels[plane[0]], labels[plane[1]]
1✔
793

794
    settings.update(
1✔
795
        {
796
            "axes": axes,
797
            "standalone": True,
798
            "title": title,
799
            "x_label": x_label,
800
            "y_label": y_label,
801
        }
802
    )
803
    settings.update(kwargs)
1✔
804

805
    return render(**settings)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc