Coverage for plotting/characterisation.py: 64%

1"""

2 Characterisation Plotting

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

4

5 Define the characterisation plotting objects.

6

7- :func:`colour.plotting.plot_single_colour_checker`

8- :func:`colour.plotting.plot_multi_colour_checkers`

9"""

10

11 from __future__ import annotations

12

13 import typing

14

15 if typing.TYPE_CHECKING:

16 from matplotlib.figure import Figure

17 from matplotlib.axes import Axes

18

19 import numpy as np

20

21 if typing.TYPE_CHECKING:

22 from colour.characterisation import ColourChecker

23 from colour.hints import Any, Dict, Sequence, Tuple

24

25 from colour.models import xyY_to_XYZ

26 from colour.plotting import (

27 CONSTANTS_COLOUR_STYLE,

28 ColourSwatch,

29 XYZ_to_plotting_colourspace,

30 artist,

31 filter_colour_checkers,

32 override_style,

33 plot_multi_colour_swatches,

34 render,

35)

36 from colour.utilities import attest

37

38 __author__ = "Colour Developers"

39 __copyright__ = "Copyright 2013 Colour Developers"

40 __license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"

41 __maintainer__ = "Colour Developers"

42 __email__ = "colour-developers@colour-science.org"

43 __status__ = "Production"

44

45 __all__ = [

46 "plot_single_colour_checker",

47 "plot_multi_colour_checkers",

48]

49

50

51@override_style(

52 **{

53 "axes.grid": False,

54 "xtick.bottom": False,

55 "ytick.left": False,

56 "xtick.labelbottom": False,

57 "ytick.labelleft": False,

58 }

59)

60 def plot_single_colour_checker(

61 colour_checker: (ColourChecker | str) = "ColorChecker24 - After November 2014",

62 **kwargs: Any,

63) -> Tuple[Figure, Axes]:

64 """

65 Plot the specified colour checker.

66

67 Parameters

68 ----------

69 colour_checker

70 Colour checker to plot. ``colour_checker`` can be of any type or

71 form supported by the

72 :func:`colour.plotting.common.filter_colour_checkers` definition.

73

74 Other Parameters

75 ----------------

76 kwargs

77 {:func:`colour.plotting.artist`,

78 :func:`colour.plotting.plot_multi_colour_swatches`,

79 :func:`colour.plotting.render`},

80 See the documentation of the previously listed definitions.

81

82 Returns

83 -------

84 :class:`tuple`

85 Current figure and axes.

86

87 Examples

88 --------

89 >>> plot_single_colour_checker("ColorChecker 2005") # doctest: +ELLIPSIS

90 (<Figure size ... with 1 Axes>, <...Axes...>)

91

92 .. image:: ../_static/Plotting_Plot_Single_Colour_Checker.png

93 :align: center

94 :alt: plot_single_colour_checker

95 """

96

97 return plot_multi_colour_checkers([colour_checker], **kwargs)

98

99

100@override_style(

101 **{

102 "axes.grid": False,

103 "xtick.bottom": False,

104 "ytick.left": False,

105 "xtick.labelbottom": False,

106 "ytick.labelleft": False,

107 }

108)

109 def plot_multi_colour_checkers(

110 colour_checkers: ColourChecker | str | Sequence[ColourChecker | str],

111 **kwargs: Any,

112) -> Tuple[Figure, Axes]:

113 """

114 Plot and compare the specified colour checkers.

115

116 Parameters

117 ----------

118 colour_checkers

119 Colour checkers to plot, count must be less than or equal to 2.

120 ``colour_checkers`` elements can be of any type or form supported

121 by the :func:`colour.plotting.common.filter_colour_checkers`

122 definition.

123

124 Other Parameters

125 ----------------

126 kwargs

127 {:func:`colour.plotting.artist`,

128 :func:`colour.plotting.plot_multi_colour_swatches`,

129 :func:`colour.plotting.render`},

130 See the documentation of the previously listed definitions.

131

132 Returns

133 -------

134 :class:`tuple`

135 Current figure and axes.

136

137 Examples

138 --------

139 >>> plot_multi_colour_checkers(["ColorChecker 1976", "ColorChecker 2005"])

140 ... # doctest: +ELLIPSIS

141 (<Figure size ... with 1 Axes>, <...Axes...>)

142

143 .. image:: ../_static/Plotting_Plot_Multi_Colour_Checkers.png

144 :align: center

145 :alt: plot_multi_colour_checkers

146 """

147

148 filtered_colour_checkers = list(filter_colour_checkers(colour_checkers).values())

149

150 attest(

151 len(filtered_colour_checkers) <= 2,

152 "Only two colour checkers can be compared at a time!",

153 )

154

155 _figure, axes = artist(**kwargs)

156

157 compare_swatches = len(filtered_colour_checkers) == 2

158

159 column_counts = []

160 colour_swatches = []

161 colour_checker_names = []

162 for colour_checker in filtered_colour_checkers:

163 colour_checker_names.append(colour_checker.name)

164 column_counts.append(colour_checker.columns)

165 for label, xyY in colour_checker.data.items():

166 XYZ = xyY_to_XYZ(xyY)

167 RGB = XYZ_to_plotting_colourspace(XYZ, colour_checker.illuminant)

168 colour_swatches.append(

169 ColourSwatch(np.clip(np.ravel(RGB), 0, 1), label.title())

170 )

171

172 columns = np.unique(column_counts)

173 attest(len(columns) == 1)

174

175 if compare_swatches:

176 colour_swatches = [

177 swatch

178 for pairs in zip(

179 colour_swatches[0 : len(colour_swatches) // 2],

180 colour_swatches[len(colour_swatches) // 2 :],

181 strict=True,

182 )

183 for swatch in pairs

184 ]

185

186 background_colour = "0.1"

187 width = height = 1.0

188 spacing = 0.25

189

190 settings: Dict[str, Any] = {

191 "axes": axes,

192 "width": width,

193 "height": height,

194 "spacing": spacing,

195 "columns": columns,

196 "direction": "-y",

197 "text_kwargs": {"size": 8},

198 "background_colour": background_colour,

199 "compare_swatches": "Stacked" if compare_swatches else None,

200 }

201 settings.update(kwargs)

202 settings["show"] = False

203

204 plot_multi_colour_swatches(colour_swatches, **settings)

205

206 axes.text(

207 0.5,

208 0.005,

209 (

210 f"{', '.join(colour_checker_names)} - "

211 f"{CONSTANTS_COLOUR_STYLE.colour.colourspace.name} - "

212 f"Colour Rendition Chart"

213 ),

214 transform=axes.transAxes,

215 color=CONSTANTS_COLOUR_STYLE.colour.bright,

216 ha="center",

217 va="bottom",

218 zorder=CONSTANTS_COLOUR_STYLE.zorder.midground_label,

219 )

220

221 settings.update(

222 {

223 "axes": axes,

224 "show": True,

225 "title": ", ".join(colour_checker_names),

226 }

227 )

228 settings.update(kwargs)

229

230 return render(**settings)