Coverage for nilearn/plotting/surface/tests/test_matplotlib_backend.py: 0%

96 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-20 10:58 +0200

1"""Test nilearn.plotting.surface._matplotlib_backend functions.""" 

2 

3import numpy as np 

4import pytest 

5 

6from nilearn.datasets import fetch_surf_fsaverage 

7from nilearn.plotting.js_plotting_utils import colorscale 

8from nilearn.plotting.surface._matplotlib_backend import ( 

9 MATPLOTLIB_VIEWS, 

10 _compute_facecolors, 

11 _get_bounds, 

12 _get_ticks, 

13 _get_vertexcolor, 

14 _get_view_plot_surf, 

15) 

16from nilearn.surface import ( 

17 load_surf_data, 

18 load_surf_mesh, 

19) 

20 

21pytest.importorskip( 

22 "matplotlib", 

23 reason="Matplotlib is not installed; required to run the tests!", 

24) 

25 

26EXPECTED_VIEW_MATPLOTLIB = { 

27 "left": { 

28 "anterior": (0, 90), 

29 "posterior": (0, 270), 

30 "medial": (0, 0), 

31 "lateral": (0, 180), 

32 "dorsal": (90, 0), 

33 "ventral": (270, 0), 

34 }, 

35 "right": { 

36 "anterior": (0, 90), 

37 "posterior": (0, 270), 

38 "medial": (0, 180), 

39 "lateral": (0, 0), 

40 "dorsal": (90, 0), 

41 "ventral": (270, 0), 

42 }, 

43 "both": { 

44 "right": (0, 0), 

45 "left": (0, 180), 

46 "dorsal": (90, 0), 

47 "ventral": (270, 0), 

48 "anterior": (0, 90), 

49 "posterior": (0, 270), 

50 }, 

51} 

52 

53 

54@pytest.mark.parametrize("hemi, views", MATPLOTLIB_VIEWS.items()) 

55def test_get_view_plot_surf(hemi, views): 

56 """Test if 

57 nilearn.plotting.surface._matplotlib_backend.MatplotlibSurfaceBackend._get_view_plot_surf 

58 returns expected values. 

59 """ 

60 for v in views: 

61 assert ( 

62 _get_view_plot_surf(hemi, v) == EXPECTED_VIEW_MATPLOTLIB[hemi][v] 

63 ) 

64 

65 

66@pytest.mark.parametrize("hemi,view", [("foo", "medial"), ("bar", "anterior")]) 

67def test_get_view_plot_surf_hemisphere_errors(hemi, view): 

68 """Test 

69 nilearn.plotting.surface._matplotlib_backend.MatplotlibSurfaceBackend._get_view_plot_surf 

70 for invalid hemisphere values. 

71 """ 

72 with pytest.raises(ValueError, match="Invalid hemispheres definition"): 

73 _get_view_plot_surf(hemi, view) 

74 

75 

76@pytest.mark.parametrize( 

77 "hemi,view", 

78 [ 

79 ("left", "foo"), 

80 ("right", "bar"), 

81 ("both", "lateral"), 

82 ("both", "medial"), 

83 ("both", "foo"), 

84 ], 

85) 

86def test_get_view_plot_surf_view_errors(hemi, view): 

87 """Test 

88 nilearn.plotting.surface._matplotlib_backend.MatplotlibSurfaceBackend._get_view_plot_surf 

89 for invalid view values. 

90 """ 

91 with pytest.raises(ValueError, match="Invalid view definition"): 

92 _get_view_plot_surf(hemi, view) 

93 

94 

95@pytest.mark.parametrize( 

96 "data,expected", 

97 [ 

98 (np.linspace(0, 1, 100), (0, 1)), 

99 (np.linspace(-0.7, -0.01, 40), (-0.7, -0.01)), 

100 ], 

101) 

102def test_get_bounds(data, expected): 

103 """Test if nilearn.plotting.surface._matplotlib_backend._get_bounds 

104 returns expected values. 

105 """ 

106 assert _get_bounds(data) == expected 

107 assert _get_bounds(data, vmin=0.2) == (0.2, expected[1]) 

108 assert _get_bounds(data, vmax=0.8) == (expected[0], 0.8) 

109 assert _get_bounds(data, vmin=0.1, vmax=0.8) == (0.1, 0.8) 

110 

111 

112@pytest.mark.parametrize( 

113 "vmin,vmax,cbar_tick_format,expected", 

114 [ 

115 (0, 0, "%i", [0]), 

116 (0, 3, "%i", [0, 1, 2, 3]), 

117 (0, 4, "%i", [0, 1, 2, 3, 4]), 

118 (1, 5, "%i", [1, 2, 3, 4, 5]), 

119 (0, 5, "%i", [0, 1.25, 2.5, 3.75, 5]), 

120 (0, 10, "%i", [0, 2.5, 5, 7.5, 10]), 

121 (0, 0, "%.1f", [0]), 

122 (0, 1, "%.1f", [0, 0.25, 0.5, 0.75, 1]), 

123 (1, 2, "%.1f", [1, 1.25, 1.5, 1.75, 2]), 

124 (1.1, 1.2, "%.1f", [1.1, 1.125, 1.15, 1.175, 1.2]), 

125 (0, np.nextafter(0, 1), "%.1f", [0.0e000, 5.0e-324]), 

126 ], 

127) 

128def test_get_ticks(vmin, vmax, cbar_tick_format, expected): 

129 """Test if nilearn.plotting.surface._matplotlib_backend._get_ticks 

130 returns expected values. 

131 """ 

132 ticks = _get_ticks(vmin, vmax, cbar_tick_format, threshold=None) 

133 assert 1 <= len(ticks) <= 5 

134 assert ticks[0] == vmin and ticks[-1] == vmax 

135 assert ( 

136 len(np.unique(ticks)) == len(expected) 

137 and (np.unique(ticks) == expected).all() 

138 ) 

139 

140 

141def test_compute_facecolors(): 

142 """Test if nilearn.plotting.surface._matplotlib_backend._compute_facecolors 

143 returns expected values. 

144 """ 

145 fsaverage = fetch_surf_fsaverage() 

146 mesh = load_surf_mesh(fsaverage["pial_left"]) 

147 alpha = "auto" 

148 # Surface map whose value in each vertex is 

149 # 1 if this vertex's curv > 0 

150 # 0 if this vertex's curv is 0 

151 # -1 if this vertex's curv < 0 

152 bg_map = np.sign(load_surf_data(fsaverage["curv_left"])) 

153 bg_min, bg_max = np.min(bg_map), np.max(bg_map) 

154 assert bg_min < 0 or bg_max > 1 

155 

156 facecolors_auto_normalized = _compute_facecolors( 

157 bg_map, 

158 mesh.faces, 

159 len(mesh.coordinates), 

160 None, 

161 alpha, 

162 ) 

163 

164 assert len(facecolors_auto_normalized) == len(mesh.faces) 

165 

166 # Manually set values of background map between 0 and 1 

167 bg_map_normalized = (bg_map - bg_min) / (bg_max - bg_min) 

168 assert np.min(bg_map_normalized) == 0 and np.max(bg_map_normalized) == 1 

169 

170 facecolors_manually_normalized = _compute_facecolors( 

171 bg_map_normalized, 

172 mesh.faces, 

173 len(mesh.coordinates), 

174 None, 

175 alpha, 

176 ) 

177 

178 assert len(facecolors_manually_normalized) == len(mesh.faces) 

179 assert np.allclose( 

180 facecolors_manually_normalized, facecolors_auto_normalized 

181 ) 

182 

183 # Scale background map between 0.25 and 0.75 

184 bg_map_scaled = bg_map_normalized / 2 + 0.25 

185 assert np.min(bg_map_scaled) == 0.25 and np.max(bg_map_scaled) == 0.75 

186 

187 facecolors_manually_rescaled = _compute_facecolors( 

188 bg_map_scaled, 

189 mesh.faces, 

190 len(mesh.coordinates), 

191 None, 

192 alpha, 

193 ) 

194 

195 assert len(facecolors_manually_rescaled) == len(mesh.faces) 

196 assert not np.allclose( 

197 facecolors_manually_rescaled, facecolors_auto_normalized 

198 ) 

199 

200 

201def test_compute_facecolors_deprecation(): 

202 """Test warning deprecation.""" 

203 fsaverage = fetch_surf_fsaverage() 

204 mesh = load_surf_mesh(fsaverage["pial_left"]) 

205 alpha = "auto" 

206 # Surface map whose value in each vertex is 

207 # 1 if this vertex's curv > 0 

208 # 0 if this vertex's curv is 0 

209 # -1 if this vertex's curv < 0 

210 bg_map = np.sign(load_surf_data(fsaverage["curv_left"])) 

211 bg_min, bg_max = np.min(bg_map), np.max(bg_map) 

212 assert bg_min < 0 or bg_max > 1 

213 with pytest.warns( 

214 DeprecationWarning, 

215 match=( 

216 "The `darkness` parameter will be deprecated in release 0.13. " 

217 "We recommend setting `darkness` to None" 

218 ), 

219 ): 

220 _compute_facecolors( 

221 bg_map, 

222 mesh.faces, 

223 len(mesh.coordinates), 

224 0.5, 

225 alpha, 

226 ) 

227 

228 

229def test_get_vertexcolor(): 

230 """Test get_vertexcolor.""" 

231 fsaverage = fetch_surf_fsaverage() 

232 mesh = load_surf_mesh(fsaverage["pial_left"]) 

233 surf_map = np.arange(len(mesh.coordinates)) 

234 colors = colorscale("jet", surf_map, 10) 

235 

236 vertexcolors = _get_vertexcolor( 

237 surf_map, 

238 colors["cmap"], 

239 colors["norm"], 

240 absolute_threshold=colors["abs_threshold"], 

241 bg_map=fsaverage["sulc_left"], 

242 ) 

243 

244 assert len(vertexcolors) == len(mesh.coordinates) 

245 

246 vertexcolors = _get_vertexcolor( 

247 surf_map, 

248 colors["cmap"], 

249 colors["norm"], 

250 absolute_threshold=colors["abs_threshold"], 

251 ) 

252 

253 assert len(vertexcolors) == len(mesh.coordinates) 

254 

255 

256def test_get_vertexcolor_bg_map(): 

257 """Test get_vertexcolor with background map.""" 

258 fsaverage = fetch_surf_fsaverage() 

259 mesh = load_surf_mesh(fsaverage["pial_left"]) 

260 surf_map = np.arange(len(mesh.coordinates)) 

261 colors = colorscale("jet", surf_map, 10) 

262 

263 # Surface map whose value in each vertex is 

264 # 1 if this vertex's curv > 0 

265 # 0 if this vertex's curv is 0 

266 # -1 if this vertex's curv < 0 

267 bg_map = np.sign(load_surf_data(fsaverage["curv_left"])) 

268 bg_min, bg_max = np.min(bg_map), np.max(bg_map) 

269 assert bg_min < 0 or bg_max > 1 

270 

271 vertexcolors_auto_normalized = _get_vertexcolor( 

272 surf_map, 

273 colors["cmap"], 

274 colors["norm"], 

275 absolute_threshold=colors["abs_threshold"], 

276 bg_map=bg_map, 

277 ) 

278 

279 assert len(vertexcolors_auto_normalized) == len(mesh.coordinates) 

280 

281 # Manually set values of background map between 0 and 1 

282 bg_map_normalized = (bg_map - bg_min) / (bg_max - bg_min) 

283 assert np.min(bg_map_normalized) == 0 and np.max(bg_map_normalized) == 1 

284 

285 vertexcolors_manually_normalized = _get_vertexcolor( 

286 surf_map, 

287 colors["cmap"], 

288 colors["norm"], 

289 absolute_threshold=colors["abs_threshold"], 

290 bg_map=bg_map_normalized, 

291 ) 

292 

293 assert len(vertexcolors_manually_normalized) == len(mesh.coordinates) 

294 assert vertexcolors_manually_normalized == vertexcolors_auto_normalized 

295 

296 # Scale background map between 0.25 and 0.75 

297 bg_map_scaled = bg_map_normalized / 2 + 0.25 

298 assert np.min(bg_map_scaled) == 0.25 and np.max(bg_map_scaled) == 0.75 

299 

300 vertexcolors_manually_rescaled = _get_vertexcolor( 

301 surf_map, 

302 colors["cmap"], 

303 colors["norm"], 

304 absolute_threshold=colors["abs_threshold"], 

305 bg_map=bg_map_scaled, 

306 ) 

307 

308 assert len(vertexcolors_manually_rescaled) == len(mesh.coordinates) 

309 assert vertexcolors_manually_rescaled != vertexcolors_auto_normalized 

310 

311 

312def test_get_vertexcolor_deprecation(): 

313 """Check deprecation warning.""" 

314 fsaverage = fetch_surf_fsaverage() 

315 mesh = load_surf_mesh(fsaverage["pial_left"]) 

316 surf_map = np.arange(len(mesh.coordinates)) 

317 colors = colorscale("jet", surf_map, 10) 

318 

319 with pytest.warns( 

320 DeprecationWarning, 

321 match=( 

322 "The `darkness` parameter will be deprecated in release 0.13. " 

323 "We recommend setting `darkness` to None" 

324 ), 

325 ): 

326 _get_vertexcolor( 

327 surf_map, 

328 colors["cmap"], 

329 colors["norm"], 

330 darkness=0.5, 

331 )