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

colour-science / colour / 18370061804

09 Oct 2025 08:19AM UTC coverage: 76.753% (-22.6%) from 99.349%
18370061804

push

github

KelSolaar
Merge branch 'feature/v0.4.7' into develop

32663 of 42556 relevant lines covered (76.75%)

0.77 hits per line

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

72.97
/colour/plotting/tm3018/report.py
1
"""
2
ANSI/IES TM-30-18 Colour Rendition Report
3
=========================================
4

5
Define the *ANSI/IES TM-30-18 Colour Rendition Report* plotting objects:
6

7
-   :func:`colour.plotting.tm3018.plot_single_sd_colour_rendition_report_full`
8
-   :func:`colour.plotting.tm3018.plot_single_sd_colour_rendition_report_intermediate`
9
-   :func:`colour.plotting.tm3018.plot_single_sd_colour_rendition_report_simple`
10
-   :func:`colour.plotting.plot_single_sd_colour_rendition_report`
11
"""
12

13
from __future__ import annotations
×
14

15
import typing
×
16

17
if typing.TYPE_CHECKING:
18
    from matplotlib.figure import Figure
19
    from matplotlib.axes import Axes
20

21
import matplotlib.pyplot as plt
×
22

23
from colour.colorimetry import SpectralDistribution, sd_to_XYZ
×
24

25
if typing.TYPE_CHECKING:
26
    from colour.hints import Any, Dict, Literal, Tuple
27

28
from colour.io import SpectralDistribution_IESTM2714
×
29
from colour.models import Luv_to_uv, XYZ_to_Luv, XYZ_to_xy
×
30
from colour.plotting import CONSTANTS_COLOUR_STYLE, override_style, render
×
31
from colour.plotting.tm3018.components import (
×
32
    plot_colour_fidelity_indexes,
33
    plot_colour_vector_graphic,
34
    plot_local_chroma_shifts,
35
    plot_local_colour_fidelities,
36
    plot_local_hue_shifts,
37
    plot_spectra_ANSIIESTM3018,
38
)
39
from colour.quality import (
×
40
    colour_fidelity_index_ANSIIESTM3018,
41
    colour_rendering_index,
42
)
43
from colour.utilities import (
×
44
    as_float_scalar,
45
    describe_environment,
46
    optional,
47
    validate_method,
48
)
49

50
__author__ = "Colour Developers"
×
51
__copyright__ = "Copyright 2013 Colour Developers"
×
52
__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
×
53
__maintainer__ = "Colour Developers"
×
54
__email__ = "colour-developers@colour-science.org"
×
55
__status__ = "Production"
×
56

57
__all__ = [
×
58
    "CONSTANT_REPORT_SIZE_FULL",
59
    "CONSTANT_REPORT_ROW_HEIGHT_RATIOS_FULL",
60
    "CONSTANT_REPORT_PADDING_FULL",
61
    "CONSTANT_REPORT_SIZE_INTERMEDIATE",
62
    "CONSTANT_REPORT_ROW_HEIGHT_RATIOS_INTERMEDIATE",
63
    "CONSTANT_REPORT_PADDING_INTERMEDIATE",
64
    "CONSTANT_REPORT_SIZE_SIMPLE",
65
    "CONSTANT_REPORT_ROW_HEIGHT_RATIOS_SIMPLE",
66
    "CONSTANT_REPORT_PADDING_SIMPLE",
67
    "CONSTANTS_REPORT_STYLE",
68
    "CONTENT_REPORT_HEADER",
69
    "CONTENT_REPORT_FOOTER",
70
    "plot_single_sd_colour_rendition_report_full",
71
    "plot_single_sd_colour_rendition_report_intermediate",
72
    "plot_single_sd_colour_rendition_report_simple",
73
    "plot_single_sd_colour_rendition_report",
74
]
75

76
# Full Report Size Constants
77
CONSTANT_REPORT_SIZE_FULL: tuple = (8.27, 11.69)
×
78
"""Full report size, default to A4 paper size in inches."""
×
79

80
CONSTANT_REPORT_ROW_HEIGHT_RATIOS_FULL: tuple = (1, 2, 24, 3, 1)
×
81
"""Full report size row height ratios."""
×
82

83
CONSTANT_REPORT_PADDING_FULL: dict = {
×
84
    "w_pad": 20 / 100,
85
    "h_pad": 10 / 100,
86
    "hspace": 0,
87
    "wspace": 0,
88
}
89
"""
×
90
Full report box padding, tries to define the padding around the figure and
91
in-between the axes.
92
"""
93

94
# Intermediate Report Size Constants
95
CONSTANT_REPORT_SIZE_INTERMEDIATE: tuple = (8.27, 11.69 / 2.35)
×
96
"""Intermediate report size, a window into A4 paper size in inches."""
×
97

98
CONSTANT_REPORT_ROW_HEIGHT_RATIOS_INTERMEDIATE: tuple = (1, 8, 1)
×
99
"""Intermediate report size row height ratios."""
×
100

101
CONSTANT_REPORT_PADDING_INTERMEDIATE: dict = {
×
102
    "w_pad": 20 / 100,
103
    "h_pad": 10 / 100,
104
    "hspace": 0,
105
    "wspace": 0,
106
}
107
"""
×
108
Intermediate report box padding, tries to define the padding around the figure
109
and in-between the axes.
110
"""
111

112
# Simple Report Size Constants
113
CONSTANT_REPORT_SIZE_SIMPLE: tuple = (8.27, 8.27)
×
114
"""Simple report size, a window into A4 paper size in inches."""
×
115

116
CONSTANT_REPORT_ROW_HEIGHT_RATIOS_SIMPLE: tuple = (1, 8, 1)
×
117
"""Simple report size row height ratios."""
×
118

119
CONSTANT_REPORT_PADDING_SIMPLE: dict = {
×
120
    "w_pad": 20 / 100,
121
    "h_pad": 10 / 100,
122
    "hspace": 0,
123
    "wspace": 0,
124
}
125
"""
×
126
Simple report box padding, tries to define the padding around the figure
127
and in-between the axes.
128
"""
129

130
CONSTANTS_REPORT_STYLE: dict = {
×
131
    "axes.grid": False,
132
    "axes.labelpad": CONSTANTS_COLOUR_STYLE.geometry.short * 3,
133
    "axes.labelsize": "x-small",
134
    "axes.labelweight": "bold",
135
    "legend.frameon": False,
136
    "xtick.labelsize": "x-small",
137
    "ytick.labelsize": "x-small",
138
    "xtick.direction": "out",
139
    "ytick.direction": "out",
140
    "xtick.major.size": CONSTANTS_COLOUR_STYLE.geometry.long * 0.5,
141
    "ytick.major.size": CONSTANTS_COLOUR_STYLE.geometry.long * 0.5,
142
    "xtick.minor.size": CONSTANTS_COLOUR_STYLE.geometry.long * 0.25,
143
    "ytick.minor.size": CONSTANTS_COLOUR_STYLE.geometry.long * 0.25,
144
    "xtick.minor.visible": False,
145
    "ytick.minor.visible": False,
146
}
147
"""Report style overrides."""
×
148

149
CONTENT_REPORT_HEADER: str = "IES TM-30-18 Colour Rendition Report"
×
150
"""Report header content, i.e., the report title."""
×
151

152
CONTENT_REPORT_FOOTER: str = (
×
153
    "Colours are for visual orientation purposes only. Created with Colour{0}"
154
)
155
"""Report footer content."""
×
156

157
_VALUE_NOT_APPLICABLE: str = "N/A"
×
158

159

160
def _plot_report_header(axes: Axes) -> Axes:
×
161
    """
162
    Plot the report header on the specified axes.
163

164
    Parameters
165
    ----------
166
    axes
167
        Axes to add the report header to.
168

169
    Returns
170
    -------
171
    :class:`matplotlib.axes._axes.Axes`
172
        Axes with the report header added.
173
    """
174

175
    axes.set_axis_off()
1✔
176
    axes.text(
1✔
177
        0.5,
178
        0.5,
179
        CONTENT_REPORT_HEADER,
180
        ha="center",
181
        va="center",
182
        size="x-large",
183
        weight="bold",
184
        zorder=CONSTANTS_COLOUR_STYLE.zorder.foreground_label,
185
    )
186

187
    return axes
1✔
188

189

190
def _plot_report_footer(axes: Axes) -> Axes:
×
191
    """
192
    Plot the report footer on the specified axes.
193

194
    Parameters
195
    ----------
196
    axes
197
        Axes to add the report footer to.
198

199
    Returns
200
    -------
201
    :class:`matplotlib.axes._axes.Axes`
202
        Axes with the report footer added.
203
    """
204

205
    try:
1✔
206
        describe = describe_environment(print_callable=lambda x: x)[
1✔
207
            "colour-science.org"
208
        ]["colour"]
209
        version = f" {describe}."
1✔
210
    except Exception:  # pragma: no cover # noqa: BLE001
211
        version = "."
212

213
    axes.set_axis_off()
1✔
214
    axes.text(
1✔
215
        0.5,
216
        0.5,
217
        CONTENT_REPORT_FOOTER.format(version),
218
        ha="center",
219
        va="center",
220
        size="small",
221
        zorder=CONSTANTS_COLOUR_STYLE.zorder.foreground_label,
222
    )
223

224
    return axes
1✔
225

226

227
@override_style(**CONSTANTS_REPORT_STYLE)
×
228
def plot_single_sd_colour_rendition_report_full(
×
229
    sd: SpectralDistribution,
230
    source: str | None = None,
231
    date: str | None = None,
232
    manufacturer: str | None = None,
233
    model: str | None = None,
234
    notes: str | None = None,
235
    report_size: tuple[float, float] = CONSTANT_REPORT_SIZE_FULL,
236
    report_row_height_ratios: tuple = CONSTANT_REPORT_ROW_HEIGHT_RATIOS_FULL,
237
    report_box_padding: dict | None = None,
238
    **kwargs: Any,
239
) -> Tuple[Figure, Axes]:
240
    """
241
    Generate the full *ANSI/IES TM-30-18 Colour Rendition Report* for the
242
    specified spectral distribution.
243

244
    Parameters
245
    ----------
246
    sd
247
        Spectral distribution of the emission source to generate the report
248
        for.
249
    source
250
        Emission source name, defaults to the
251
        `colour.SpectralDistribution_IESTM2714.header.description` or
252
        `colour.SpectralDistribution_IESTM2714.name` property value.
253
    date
254
        Emission source measurement date, defaults to the
255
        `colour.SpectralDistribution_IESTM2714.header.report_date` property
256
        value.
257
    manufacturer
258
        Emission source manufacturer, defaults to the
259
        `colour.SpectralDistribution_IESTM2714.header.manufacturer` property
260
        value.
261
    model
262
        Emission source model, defaults to the
263
        `colour.SpectralDistribution_IESTM2714.header.catalog_number`
264
        property value.
265
    notes
266
        Notes pertaining to the emission source, defaults to the
267
        `colour.SpectralDistribution_IESTM2714.header.comments` property
268
        value.
269
    report_size
270
        Report size, defaults to A4 paper size in inches.
271
    report_row_height_ratios
272
        Report size row height ratios.
273
    report_box_padding
274
        Report box padding, defines the padding around the figure and
275
        between the axes.
276

277
    Other Parameters
278
    ----------------
279
    kwargs
280
        {:func:`colour.plotting.artist`, :func:`colour.plotting.render`},
281
        See the documentation of the previously listed definitions.
282

283
    Returns
284
    -------
285
    :class:`tuple`
286
        Current figure and axes.
287

288
    Examples
289
    --------
290
    >>> from colour import SDS_ILLUMINANTS
291
    >>> sd = SDS_ILLUMINANTS["FL2"]
292
    >>> plot_single_sd_colour_rendition_report_full(sd)
293
    ... # doctest: +ELLIPSIS
294
    (<Figure size ... with ... Axes>, <...Axes...>)
295

296
    .. image:: ../_static/Plotting_\
297
Plot_Single_SD_Colour_Rendition_Report_Full.png
298
        :align: center
299
        :alt: plot_single_sd_colour_rendition_report_full
300
    """
301

302
    report_box_padding = optional(report_box_padding, CONSTANT_REPORT_PADDING_FULL)
1✔
303

304
    specification = colour_fidelity_index_ANSIIESTM3018(sd, True)
1✔
305

306
    sd = (
1✔
307
        SpectralDistribution_IESTM2714(data=sd, name=sd.name)
308
        if not isinstance(sd, SpectralDistribution_IESTM2714)
309
        else sd
310
    )
311

312
    NA = _VALUE_NOT_APPLICABLE
1✔
313

314
    source = optional(optional(source, sd.header.description), sd.name)
1✔
315
    date = optional(optional(date, sd.header.report_date), NA)
1✔
316
    manufacturer = optional(optional(manufacturer, sd.header.manufacturer), NA)
1✔
317
    model = optional(optional(model, sd.header.catalog_number), NA)
1✔
318
    notes = optional(optional(notes, sd.header.comments), NA)
1✔
319

320
    figure = plt.figure(figsize=report_size, constrained_layout=True)
1✔
321

322
    settings: Dict[str, Any] = dict(kwargs)
1✔
323
    settings["show"] = False
1✔
324
    settings["tight_layout"] = False
1✔
325

326
    gridspec_report = figure.add_gridspec(5, 1, height_ratios=report_row_height_ratios)
1✔
327

328
    # Title Row
329
    gridspec_title = gridspec_report[0].subgridspec(1, 1)
1✔
330
    axes_title = figure.add_subplot(gridspec_title[0])
1✔
331
    _plot_report_header(axes_title)
1✔
332

333
    # Description Rows & Columns
334
    gridspec_description = gridspec_report[1].subgridspec(1, 2)
1✔
335
    # Source & Date Column
336
    axes_source_date = figure.add_subplot(gridspec_description[0])
1✔
337
    axes_source_date.set_axis_off()
1✔
338
    axes_source_date.text(
1✔
339
        0.25,
340
        2 / 3,
341
        "Source: ",
342
        ha="right",
343
        va="center",
344
        size="medium",
345
        weight="bold",
346
    )
347
    axes_source_date.text(0.25, 2 / 3, source, va="center", size="medium")
1✔
348

349
    axes_source_date.text(
1✔
350
        0.25,
351
        1 / 3,
352
        "Date: ",
353
        ha="right",
354
        va="center",
355
        size="medium",
356
        weight="bold",
357
    )
358
    axes_source_date.text(0.25, 1 / 3, date, va="center", size="medium")
1✔
359

360
    # Manufacturer & Model Column
361
    axes_manufacturer_model = figure.add_subplot(gridspec_description[1])
1✔
362
    axes_manufacturer_model.set_axis_off()
1✔
363
    axes_manufacturer_model.text(
1✔
364
        0.25,
365
        2 / 3,
366
        "Manufacturer: ",
367
        ha="right",
368
        va="center",
369
        size="medium",
370
        weight="bold",
371
    )
372
    axes_manufacturer_model.text(0.25, 2 / 3, manufacturer, va="center", size="medium")
1✔
373

374
    axes_manufacturer_model.text(
1✔
375
        0.25,
376
        1 / 3,
377
        "Model: ",
378
        ha="right",
379
        va="center",
380
        size="medium",
381
        weight="bold",
382
    )
383
    axes_manufacturer_model.text(0.25, 1 / 3, model, va="center", size="medium")
1✔
384

385
    # Main Figures Rows & Columns
386
    gridspec_figures = gridspec_report[2].subgridspec(
1✔
387
        4, 2, height_ratios=[1, 1, 1, 1.5]
388
    )
389
    axes_spectra = figure.add_subplot(gridspec_figures[0, 0])
1✔
390
    plot_spectra_ANSIIESTM3018(specification, axes=axes_spectra, **settings)
1✔
391

392
    axes_vector_graphics = figure.add_subplot(gridspec_figures[1:3, 0])
1✔
393
    plot_colour_vector_graphic(specification, axes=axes_vector_graphics, **settings)
1✔
394

395
    axes_chroma_shifts = figure.add_subplot(gridspec_figures[0, 1])
1✔
396
    plot_local_chroma_shifts(specification, axes=axes_chroma_shifts, **settings)
1✔
397

398
    axes_hue_shifts = figure.add_subplot(gridspec_figures[1, 1])
1✔
399
    plot_local_hue_shifts(specification, axes=axes_hue_shifts, **settings)
1✔
400

401
    axes_colour_fidelities = figure.add_subplot(gridspec_figures[2, 1])
1✔
402
    plot_local_colour_fidelities(
1✔
403
        specification, axes=axes_colour_fidelities, x_ticker=True, **settings
404
    )
405

406
    # Colour Fidelity Indexes Row
407
    axes_colour_fidelity_indexes = figure.add_subplot(gridspec_figures[3, :])
1✔
408
    plot_colour_fidelity_indexes(
1✔
409
        specification, axes=axes_colour_fidelity_indexes, **settings
410
    )
411

412
    # Notes & Chromaticities / CRI Row and Columns
413
    gridspec_notes_chromaticities_CRI = gridspec_report[3].subgridspec(1, 2)
1✔
414
    axes_notes = figure.add_subplot(gridspec_notes_chromaticities_CRI[0])
1✔
415
    axes_notes.set_axis_off()
1✔
416
    axes_notes.text(
1✔
417
        0.25,
418
        1,
419
        "Notes: ",
420
        ha="right",
421
        va="center",
422
        size="medium",
423
        weight="bold",
424
    )
425
    axes_notes.text(0.25, 1, notes, va="center", size="medium")
1✔
426
    gridspec_chromaticities_CRI = gridspec_notes_chromaticities_CRI[1].subgridspec(1, 2)
1✔
427

428
    XYZ = sd_to_XYZ(specification.sd_test)
1✔
429
    xy = XYZ_to_xy(XYZ)
1✔
430
    Luv = XYZ_to_Luv(XYZ, xy)
1✔
431
    uv_p = Luv_to_uv(Luv, xy)
1✔
432

433
    gridspec_chromaticities = gridspec_chromaticities_CRI[0].subgridspec(1, 1)
1✔
434
    axes_chromaticities = figure.add_subplot(gridspec_chromaticities[0])
1✔
435
    axes_chromaticities.set_axis_off()
1✔
436
    axes_chromaticities.text(
1✔
437
        0.5,
438
        4 / 5,
439
        f"$x$ {xy[0]:.4f}",
440
        ha="center",
441
        va="center",
442
        size="medium",
443
        weight="bold",
444
    )
445

446
    axes_chromaticities.text(
1✔
447
        0.5,
448
        3 / 5,
449
        f"$y$ {xy[1]:.4f}",
450
        ha="center",
451
        va="center",
452
        size="medium",
453
        weight="bold",
454
    )
455

456
    axes_chromaticities.text(
1✔
457
        0.5,
458
        2 / 5,
459
        f"$u'$ {uv_p[0]:.4f}",
460
        ha="center",
461
        va="center",
462
        size="medium",
463
        weight="bold",
464
    )
465

466
    axes_chromaticities.text(
1✔
467
        0.5,
468
        1 / 5,
469
        f"$v'$ {uv_p[1]:.4f}",
470
        ha="center",
471
        va="center",
472
        size="medium",
473
        weight="bold",
474
    )
475

476
    gridspec_CRI = gridspec_chromaticities_CRI[1].subgridspec(1, 1)
1✔
477

478
    CRI_spec = colour_rendering_index(specification.sd_test, additional_data=True)
1✔
479

480
    axes_CRI = figure.add_subplot(gridspec_CRI[0])
1✔
481
    axes_CRI.set_xticks([])
1✔
482
    axes_CRI.set_yticks([])
1✔
483
    axes_CRI.text(
1✔
484
        0.5,
485
        4 / 5,
486
        "CIE 13.31-1995",
487
        ha="center",
488
        va="center",
489
        size="medium",
490
        weight="bold",
491
    )
492

493
    axes_CRI.text(
1✔
494
        0.5,
495
        3 / 5,
496
        "(CRI)",
497
        ha="center",
498
        va="center",
499
        size="medium",
500
        weight="bold",
501
    )
502

503
    axes_CRI.text(
1✔
504
        0.5,
505
        2 / 5,
506
        f"$R_a$ {as_float_scalar(CRI_spec.Q_a):.0f}",
507
        ha="center",
508
        va="center",
509
        size="medium",
510
        weight="bold",
511
    )
512

513
    axes_CRI.text(
1✔
514
        0.5,
515
        1 / 5,
516
        f"$R_9$ {as_float_scalar(CRI_spec.Q_as[9].Q_a):.0f}",
517
        ha="center",
518
        va="center",
519
        size="medium",
520
        weight="bold",
521
    )
522

523
    gridspec_footer = gridspec_report[4].subgridspec(1, 1)
1✔
524
    axes_footer = figure.add_subplot(gridspec_footer[0])
1✔
525
    _plot_report_footer(axes_footer)
1✔
526

527
    figure.get_layout_engine().set(**report_box_padding)  # pyright: ignore
1✔
528

529
    settings = dict(kwargs)
1✔
530
    settings["tight_layout"] = False
1✔
531

532
    return render(**settings)
1✔
533

534

535
@override_style(**CONSTANTS_REPORT_STYLE)
×
536
def plot_single_sd_colour_rendition_report_intermediate(
×
537
    sd: SpectralDistribution,
538
    report_size: tuple[float, float] = CONSTANT_REPORT_SIZE_INTERMEDIATE,
539
    report_row_height_ratios: tuple = (CONSTANT_REPORT_ROW_HEIGHT_RATIOS_INTERMEDIATE),
540
    report_box_padding: dict | None = None,
541
    **kwargs: Any,
542
) -> Tuple[Figure, Axes]:
543
    """
544
    Generate the intermediate *ANSI/IES TM-30-18 Colour Rendition Report*
545
    for the specified spectral distribution.
546

547
    Parameters
548
    ----------
549
    sd
550
        Spectral distribution of the emission source to generate the report
551
        for.
552
    report_size
553
        Report size, defaults to A4 paper size in inches.
554
    report_row_height_ratios
555
        Report size row height ratios.
556
    report_box_padding
557
        Report box padding, defines the padding around the figure and
558
        between the axes.
559

560
    Other Parameters
561
    ----------------
562
    kwargs
563
        {:func:`colour.plotting.artist`, :func:`colour.plotting.render`},
564
        See the documentation of the previously listed definitions.
565

566
    Returns
567
    -------
568
    :class:`tuple`
569
        Current figure and axes.
570

571
    Examples
572
    --------
573
    >>> from colour import SDS_ILLUMINANTS
574
    >>> sd = SDS_ILLUMINANTS["FL2"]
575
    >>> plot_single_sd_colour_rendition_report_intermediate(sd)
576
    ... # doctest: +ELLIPSIS
577
    (<Figure size ... with ... Axes>, <...Axes...>)
578

579
    .. image:: ../_static/Plotting_\
580
Plot_Single_SD_Colour_Rendition_Report_Intermediate.png
581
        :align: center
582
        :alt: plot_single_sd_colour_rendition_report_intermediate
583
    """
584

585
    report_box_padding = optional(
1✔
586
        report_box_padding, CONSTANT_REPORT_PADDING_INTERMEDIATE
587
    )
588

589
    specification = colour_fidelity_index_ANSIIESTM3018(sd, True)
1✔
590

591
    figure = plt.figure(figsize=report_size, constrained_layout=True)
1✔
592

593
    settings: Dict[str, Any] = dict(kwargs)
1✔
594
    settings["show"] = False
1✔
595
    settings["tight_layout"] = False
1✔
596

597
    gridspec_report = figure.add_gridspec(3, 1, height_ratios=report_row_height_ratios)
1✔
598

599
    # Title Row
600
    gridspec_title = gridspec_report[0].subgridspec(1, 1)
1✔
601
    axes_title = figure.add_subplot(gridspec_title[0])
1✔
602
    _plot_report_header(axes_title)
1✔
603

604
    # Main Figures Rows & Columns
605
    gridspec_figures = gridspec_report[1].subgridspec(2, 2)
1✔
606

607
    axes_vector_graphics = figure.add_subplot(gridspec_figures[0:2, 0])
1✔
608
    plot_colour_vector_graphic(specification, axes=axes_vector_graphics, **settings)
1✔
609

610
    axes_chroma_shifts = figure.add_subplot(gridspec_figures[0, 1])
1✔
611
    plot_local_chroma_shifts(specification, axes=axes_chroma_shifts, **settings)
1✔
612

613
    axes_hue_shifts = figure.add_subplot(gridspec_figures[1, 1])
1✔
614
    plot_local_hue_shifts(
1✔
615
        specification, axes=axes_hue_shifts, x_ticker=True, **settings
616
    )
617

618
    gridspec_footer = gridspec_report[2].subgridspec(1, 1)
1✔
619
    axes_footer = figure.add_subplot(gridspec_footer[0])
1✔
620
    _plot_report_footer(axes_footer)
1✔
621

622
    figure.get_layout_engine().set(**report_box_padding)  # pyright: ignore
1✔
623

624
    settings = dict(kwargs)
1✔
625
    settings["tight_layout"] = False
1✔
626

627
    return render(**settings)
1✔
628

629

630
def plot_single_sd_colour_rendition_report_simple(
×
631
    sd: SpectralDistribution,
632
    report_size: tuple[float, float] = CONSTANT_REPORT_SIZE_SIMPLE,
633
    report_row_height_ratios: tuple = CONSTANT_REPORT_ROW_HEIGHT_RATIOS_SIMPLE,
634
    report_box_padding: dict | None = None,
635
    **kwargs: Any,
636
) -> Tuple[Figure, Axes]:
637
    """
638
    Generate the simple *ANSI/IES TM-30-18 Colour Rendition Report* for the
639
    specified spectral distribution.
640

641
    Parameters
642
    ----------
643
    sd
644
        Spectral distribution of the emission source to generate the report
645
        for.
646
    report_size
647
        Report size, defaults to A4 paper size in inches.
648
    report_row_height_ratios
649
        Report size row height ratios.
650
    report_box_padding
651
        Report box padding, defines the padding around the figure and
652
        between the axes.
653

654
    Other Parameters
655
    ----------------
656
    kwargs
657
        {:func:`colour.plotting.artist`, :func:`colour.plotting.render`},
658
        See the documentation of the previously listed definitions.
659

660
    Returns
661
    -------
662
    :class:`tuple`
663
        Current figure and axes.
664

665
    Examples
666
    --------
667
    >>> from colour import SDS_ILLUMINANTS
668
    >>> sd = SDS_ILLUMINANTS["FL2"]
669
    >>> plot_single_sd_colour_rendition_report_simple(sd)
670
    ... # doctest: +ELLIPSIS
671
    (<Figure size ... with ... Axes>, <...Axes...>)
672

673
    .. image:: ../_static/Plotting_\
674
Plot_Single_SD_Colour_Rendition_Report_Simple.png
675
        :align: center
676
        :alt: plot_single_sd_colour_rendition_report_simple
677
    """
678

679
    report_box_padding = optional(report_box_padding, CONSTANT_REPORT_PADDING_SIMPLE)
1✔
680

681
    specification = colour_fidelity_index_ANSIIESTM3018(sd, True)
1✔
682

683
    figure = plt.figure(figsize=report_size, constrained_layout=True)
1✔
684

685
    settings: Dict[str, Any] = dict(kwargs)
1✔
686
    settings["show"] = False
1✔
687
    settings["tight_layout"] = False
1✔
688

689
    gridspec_report = figure.add_gridspec(3, 1, height_ratios=report_row_height_ratios)
1✔
690

691
    # Title Row
692
    gridspec_title = gridspec_report[0].subgridspec(1, 1)
1✔
693
    axes_title = figure.add_subplot(gridspec_title[0])
1✔
694
    _plot_report_header(axes_title)
1✔
695

696
    # Main Figures Rows & Columns
697
    gridspec_figures = gridspec_report[1].subgridspec(1, 1)
1✔
698

699
    axes_vector_graphics = figure.add_subplot(gridspec_figures[0, 0])
1✔
700
    plot_colour_vector_graphic(specification, axes=axes_vector_graphics, **settings)
1✔
701

702
    gridspec_footer = gridspec_report[2].subgridspec(1, 1)
1✔
703
    axes_footer = figure.add_subplot(gridspec_footer[0])
1✔
704
    _plot_report_footer(axes_footer)
1✔
705

706
    figure.get_layout_engine().set(**report_box_padding)  # pyright: ignore
1✔
707

708
    settings = dict(kwargs)
1✔
709
    settings["tight_layout"] = False
1✔
710

711
    return render(**settings)
1✔
712

713

714
def plot_single_sd_colour_rendition_report(
×
715
    sd: SpectralDistribution,
716
    method: Literal["Full", "Intermediate", "Simple"] | str = "Full",
717
    **kwargs: Any,
718
) -> Tuple[Figure, Axes]:
719
    """
720
    Generate the *ANSI/IES TM-30-18 Colour Rendition Report* for the
721
    specified spectral distribution using the specified method.
722

723
    Parameters
724
    ----------
725
    sd
726
        Spectral distribution of the emission source to generate the
727
        report for.
728
    method
729
        Report plotting method.
730

731
    Other Parameters
732
    ----------------
733
    kwargs
734
        {:func:`colour.plotting.artist`, :func:`colour.plotting.render`,
735
        :func:`colour.plotting.tm3018.\
736
plot_single_sd_colour_rendition_report_full`, :func:`colour.plotting.tm3018.\
737
plot_single_sd_colour_rendition_report_intermediate`, \
738
:func:`colour.plotting.tm3018.plot_single_sd_colour_rendition_report_simple`}
739
        See the documentation of the previously listed definitions.
740

741
    Returns
742
    -------
743
    :class:`tuple`
744
        Current figure and axes.
745

746
    Examples
747
    --------
748
    >>> from colour import SDS_ILLUMINANTS
749
    >>> sd = SDS_ILLUMINANTS["FL2"]
750
    >>> plot_single_sd_colour_rendition_report(sd)
751
    ... # doctest: +ELLIPSIS
752
    (<Figure size ... with ... Axes>, <...Axes...>)
753

754
    .. image:: ../_static/Plotting_\
755
Plot_Single_SD_Colour_Rendition_Report_Full.png
756
        :align: center
757
        :alt: plot_single_sd_colour_rendition_report_full
758

759
    >>> plot_single_sd_colour_rendition_report(sd, "Intermediate")
760
    ... # doctest: +ELLIPSIS
761
    (<Figure size ... with ... Axes>, <...Axes...>)
762

763
    .. image:: ../_static/Plotting_\
764
Plot_Single_SD_Colour_Rendition_Report_Intermediate.png
765
        :align: center
766
        :alt: plot_single_sd_colour_rendition_report_intermediate
767

768
    >>> plot_single_sd_colour_rendition_report(sd, "Simple")
769
    ... # doctest: +ELLIPSIS
770
    (<Figure size ... with ... Axes>, <...Axes...>)
771

772
    .. image:: ../_static/Plotting_\
773
Plot_Single_SD_Colour_Rendition_Report_Simple.png
774
        :align: center
775
        :alt: plot_single_sd_colour_rendition_report_simple
776
    """
777

778
    method = validate_method(method, ("Full", "Intermediate", "Simple"))
1✔
779

780
    if method == "full":
1✔
781
        return plot_single_sd_colour_rendition_report_full(sd, **kwargs)
1✔
782

783
    if method == "intermediate":
1✔
784
        return plot_single_sd_colour_rendition_report_intermediate(sd, **kwargs)
1✔
785

786
    # method == 'simple'
787
    return plot_single_sd_colour_rendition_report_simple(sd, **kwargs)
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