Coverage for graph/common.py: 55%
29 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-16 22:49 +1300
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-16 22:49 +1300
1"""
2Graph Common Utilities
3======================
5Defines various common utilities for the graph module.
6"""
8from __future__ import annotations
10import typing
12import numpy as np
14from colour.graph.conversion import conversion_path
15from colour.utilities import as_float_array, get_domain_range_scale_metadata
17if typing.TYPE_CHECKING:
18 from colour.hints import ArrayLike, NDArrayFloat
20__author__ = "Colour Developers"
21__copyright__ = "Copyright 2013 Colour Developers"
22__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
23__maintainer__ = "Colour Developers"
24__email__ = "colour-developers@colour-science.org"
25__status__ = "Production"
27__all__ = [
28 "colourspace_model_to_reference",
29]
32def colourspace_model_to_reference(
33 a: ArrayLike,
34 model: str,
35) -> NDArrayFloat:
36 """
37 Scale given colourspace model array from normalized [0, 1] to the model's
38 reference scale by extracting scale metadata from the conversion function.
40 This function multiplies the input array by the model's reference scale
41 (e.g., [0, 100] for CIE Lab) extracted from the XYZ_to_model conversion
42 function's range annotation.
44 Parameters
45 ----------
46 a
47 Colourspace model array in normalized [0, 1] scale.
48 model
49 Colourspace model name (e.g., "CIE Lab", "CIE XYZ").
51 Returns
52 -------
53 :class:`numpy.ndarray`
54 Colourspace model array scaled to reference scale.
56 Examples
57 --------
58 >>> import numpy as np
59 >>> Lab = np.array([0.41527875, 0.52638583, 0.26923179])
60 >>> colourspace_model_to_reference(Lab, "CIE Lab") # doctest: +ELLIPSIS
61 array([ 41.527875..., 52.638583..., 26.923179...])
62 """
64 import networkx as nx # noqa: PLC0415
66 a = as_float_array(a)
68 try:
69 # Get conversion path from XYZ to model (lowercase for graph)
70 path_functions = conversion_path("cie xyz", model.lower())
72 # Get the last function in the path (final conversion to target model)
73 if path_functions:
74 last_function = path_functions[-1]
75 metadata = get_domain_range_scale_metadata(last_function)
76 range_scale = metadata.get("range")
78 if range_scale is not None:
79 # Handle tuple scales (e.g., (100, 100, 360))
80 if isinstance(range_scale, tuple):
81 scale_factor = np.array(range_scale)
82 else:
83 # Scalar scale applied uniformly
84 scale_factor = range_scale
86 return a * scale_factor
87 except (nx.NodeNotFound, nx.NetworkXNoPath):
88 # Model not in graph or no conversion path exists
89 pass
91 # Fallback: return unchanged if no scale metadata found
92 return a