Coverage for plotting/characterisation.py: 64%

47 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-11-16 22:49 +1300

1""" 

2Characterisation Plotting 

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

4 

5Define the characterisation plotting objects. 

6 

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

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

9""" 

10 

11from __future__ import annotations 

12 

13import typing 

14 

15if typing.TYPE_CHECKING: 

16 from matplotlib.figure import Figure 

17 from matplotlib.axes import Axes 

18 

19import numpy as np 

20 

21if typing.TYPE_CHECKING: 

22 from colour.characterisation import ColourChecker 

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

24 

25from colour.models import xyY_to_XYZ 

26from 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) 

36from 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) 

60def 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) 

109def 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)