Coverage for graph/common.py: 55%

1"""

2 Graph Common Utilities

3======================

4

5 Defines various common utilities for the graph module.

6"""

7

8 from __future__ import annotations

9

10 import typing

11

12 import numpy as np

13

14 from colour.graph.conversion import conversion_path

15 from colour.utilities import as_float_array, get_domain_range_scale_metadata

16

17 if typing.TYPE_CHECKING:

18 from colour.hints import ArrayLike, NDArrayFloat

19

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"

26

27 __all__ = [

28 "colourspace_model_to_reference",

29]

30

31

32 def 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.

39

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.

43

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").

50

51 Returns

52 -------

53 :class:`numpy.ndarray`

54 Colourspace model array scaled to reference scale.

55

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 """

63

64 import networkx as nx # noqa: PLC0415

65

66 a = as_float_array(a)

67

68 try:

69 # Get conversion path from XYZ to model (lowercase for graph)

70 path_functions = conversion_path("cie xyz", model.lower())

71

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")

77

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

85

86 return a * scale_factor

87 except (nx.NodeNotFound, nx.NetworkXNoPath):

88 # Model not in graph or no conversion path exists

89 pass

90

91 # Fallback: return unchanged if no scale metadata found

92 return a