Coverage for nilearn/plotting/tests/test_img_plotting/test_plot_connectome.py: 0%

85 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-16 12:32 +0200

1"""Tests for :func:`nilearn.plotting.plot_connectome`.""" 

2 

3import numpy as np 

4import pytest 

5from matplotlib.patches import FancyArrow 

6from scipy import sparse 

7 

8from nilearn.plotting import plot_connectome 

9 

10 

11@pytest.fixture 

12def non_symmetric_matrix(): 

13 """Non symmetric adjacency matrix.""" 

14 return np.array( 

15 [ 

16 [1.0, -2.0, 0.3, 0.2], 

17 [0.1, 1, 1.1, 0.1], 

18 [0.01, 2.3, 1.0, 3.1], 

19 [0.6, 0.03, 1.2, 1.0], 

20 ] 

21 ) 

22 

23 

24def test_plot_connectome_masked_array_sparse_matrix( 

25 node_coords, adjacency, params_plot_connectome 

26): 

27 """Smoke tests for plot_connectome with masked arrays \ 

28 and sparse matrices as inputs. 

29 """ 

30 masked_adjacency_matrix = np.ma.masked_array( 

31 adjacency, np.abs(adjacency) < 0.5 

32 ) 

33 plot_connectome( 

34 masked_adjacency_matrix, node_coords, **params_plot_connectome 

35 ) 

36 sparse_adjacency_matrix = sparse.coo_matrix(adjacency) 

37 plot_connectome( 

38 sparse_adjacency_matrix, node_coords, **params_plot_connectome 

39 ) 

40 

41 

42def test_plot_connectome_with_nans( 

43 adjacency, node_coords, params_plot_connectome 

44): 

45 """Smoke test for plot_connectome with nans in the adjacency matrix.""" 

46 adjacency[0, 1] = np.nan 

47 adjacency[1, 0] = np.nan 

48 params_plot_connectome["node_color"] = np.array( 

49 ["green", "blue", "k", "yellow"] 

50 ) 

51 plot_connectome( 

52 adjacency, node_coords, colorbar=False, **params_plot_connectome 

53 ) 

54 

55 

56def test_plot_connectome_tuple_node_coords( 

57 adjacency, node_coords, params_plot_connectome 

58): 

59 """Smoke test for plot_connectome where node_coords is not provided \ 

60 as an array but as a list of tuples. 

61 """ 

62 plot_connectome( 

63 adjacency, 

64 [tuple(each) for each in node_coords], 

65 display_mode="x", 

66 **params_plot_connectome, 

67 ) 

68 

69 

70def test_plot_connectome_to_file( 

71 adjacency, node_coords, params_plot_connectome, tmp_path 

72): 

73 """Smoke test for plot_connectome and saving to file.""" 

74 params_plot_connectome["display_mode"] = "x" 

75 filename = tmp_path / "temp.png" 

76 display = plot_connectome( 

77 adjacency, node_coords, output_file=filename, **params_plot_connectome 

78 ) 

79 assert display is None 

80 assert filename.is_file() 

81 assert filename.stat().st_size > 0 

82 

83 

84def test_plot_connectome_with_too_high_edge_threshold(adjacency, node_coords): 

85 """Smoke-test where there is no edge to draw, \ 

86 e.g. when edge_threshold is too high. 

87 """ 

88 plot_connectome( 

89 adjacency, node_coords, edge_threshold=1e12, colorbar=False 

90 ) 

91 

92 

93def test_plot_connectome_non_symmetric(node_coords, non_symmetric_matrix): 

94 """Tests for plot_connectome with non symmetric adjacency matrices.""" 

95 ax = plot_connectome( 

96 non_symmetric_matrix, node_coords, display_mode="ortho" 

97 ) 

98 # No thresholding was performed, we should get 

99 # as many arrows as we have edges 

100 for direction in ["x", "y", "z"]: 

101 assert len( 

102 [ 

103 patch 

104 for patch in ax.axes[direction].ax.patches 

105 if isinstance(patch, FancyArrow) 

106 ] 

107 ) == np.prod(non_symmetric_matrix.shape) 

108 

109 # Set a few elements of adjacency matrix to zero 

110 non_symmetric_matrix[1, 0] = 0.0 

111 non_symmetric_matrix[2, 3] = 0.0 

112 # Plot with different display mode 

113 ax = plot_connectome( 

114 non_symmetric_matrix, node_coords, display_mode="lzry" 

115 ) 

116 # No edge in direction 'l' because of node coords 

117 assert not [ 

118 patch 

119 for patch in ax.axes["l"].ax.patches 

120 if isinstance(patch, FancyArrow) 

121 ] 

122 for direction in ["z", "r", "y"]: 

123 assert ( 

124 len( 

125 [ 

126 patch 

127 for patch in ax.axes[direction].ax.patches 

128 if isinstance(patch, FancyArrow) 

129 ] 

130 ) 

131 == np.prod(non_symmetric_matrix.shape) - 2 

132 ) 

133 

134 

135def test_plot_connectome_edge_thresholding(node_coords, non_symmetric_matrix): 

136 """Test for plot_connectome with edge thresholding.""" 

137 # Case 1: Threshold is a number 

138 thresh = 1.1 

139 ax = plot_connectome( 

140 non_symmetric_matrix, node_coords, edge_threshold=thresh 

141 ) 

142 for direction in ["x", "y", "z"]: 

143 assert len( 

144 [ 

145 patch 

146 for patch in ax.axes[direction].ax.patches 

147 if isinstance(patch, FancyArrow) 

148 ] 

149 ) == np.sum(np.abs(non_symmetric_matrix) >= thresh) 

150 # Case 2: Threshold is a percentage 

151 thresh = 80 

152 ax = plot_connectome( 

153 non_symmetric_matrix, node_coords, edge_threshold=f"{thresh}%" 

154 ) 

155 for direction in ["x", "y", "z"]: 

156 assert len( 

157 [ 

158 patch 

159 for patch in ax.axes[direction].ax.patches 

160 if isinstance(patch, FancyArrow) 

161 ] 

162 ) == np.sum( 

163 np.abs(non_symmetric_matrix) 

164 >= np.percentile(np.abs(non_symmetric_matrix.ravel()), thresh) 

165 ) 

166 

167 

168@pytest.mark.parametrize( 

169 "matrix", 

170 [ 

171 np.array([[1.0, 2], [0.4, 1.0]]), 

172 np.ma.masked_array( 

173 np.array([[1.0, 2.0], [2.0, 1.0]]), [[False, True], [False, False]] 

174 ), 

175 ], 

176) 

177def test_plot_connectome_exceptions_non_symmetric_adjacency(matrix): 

178 """Tests that warning messages are given when the adjacency matrix \ 

179 ends up being non symmetric. 

180 """ 

181 node_coords = np.arange(2 * 3).reshape((2, 3)) 

182 with pytest.warns(UserWarning, match="A directed graph will be plotted."): 

183 plot_connectome(matrix, node_coords, display_mode="x") 

184 

185 

186@pytest.mark.parametrize( 

187 "node_color", 

188 [ 

189 ["red", "blue"], 

190 ["red", "blue", "yellow", "cyan", "green"], 

191 np.array(["b", "y", "g", "c", "r"]), 

192 ], 

193) 

194def test_plot_connectome_exceptions_wrong_number_node_colors( 

195 node_color, adjacency, node_coords 

196): 

197 """Tests that a wrong number of node colors raises \ 

198 a ValueError in plot_connectome. 

199 """ 

200 with pytest.raises( 

201 ValueError, match="Mismatch between the number of nodes" 

202 ): 

203 plot_connectome( 

204 adjacency, node_coords, node_color=node_color, display_mode="x" 

205 ) 

206 

207 

208def test_plot_connectome_exception_wrong_edge_threshold( 

209 adjacency, node_coords 

210): 

211 """Tests that a TypeError is raised in plot_connectome \ 

212 when edge threshold is neither a number nor a string. 

213 """ 

214 with pytest.raises( 

215 TypeError, match="should be either a number or a string" 

216 ): 

217 plot_connectome( 

218 adjacency, node_coords, edge_threshold=object(), display_mode="x" 

219 ) 

220 

221 

222@pytest.mark.parametrize("threshold", ["0.1", "10", "10.2.3%", "asdf%"]) 

223def test_plot_connectome_exception_wrong_edge_threshold_format( 

224 threshold, adjacency, node_coords 

225): 

226 """Tests that a ValueError is raised when edge_threshold is \ 

227 an incorrectly formatted string. 

228 """ 

229 with pytest.raises( 

230 ValueError, 

231 match=("should be a number followed by the percent sign"), 

232 ): 

233 plot_connectome( 

234 adjacency, node_coords, edge_threshold=threshold, display_mode="x" 

235 ) 

236 

237 

238def test_plot_connectome_wrong_shapes(): 

239 """Tests that ValueErrors are raised when wrong shapes for node_coords \ 

240 or adjacency_matrix are given. 

241 """ 

242 kwargs = {"display_mode": "x"} 

243 node_coords = np.arange(2 * 3).reshape((2, 3)) 

244 adjacency_matrix = np.array([[1.0, 2.0], [2.0, 1.0]]) 

245 with pytest.raises( 

246 ValueError, match=r"supposed to have shape \(n, n\).+\(1L?, 2L?\)" 

247 ): 

248 plot_connectome(adjacency_matrix[:1, :], node_coords, **kwargs) 

249 

250 with pytest.raises(ValueError, match=r"shape \(2L?, 3L?\).+\(2L?,\)"): 

251 plot_connectome(adjacency_matrix, node_coords[:, 2], **kwargs) 

252 

253 wrong_adjacency_matrix = np.zeros((3, 3)) 

254 with pytest.raises( 

255 ValueError, match=r"Shape mismatch.+\(3L?, 3L?\).+\(2L?, 3L?\)" 

256 ): 

257 plot_connectome(wrong_adjacency_matrix, node_coords, **kwargs) 

258 

259 

260@pytest.fixture 

261def expected_error_node_kwargs(node_kwargs): 

262 """Return the expected error message depending on node_kwargs.""" 

263 if "s" in node_kwargs: 

264 return "Please use 'node_size' and not 'node_kwargs'" 

265 elif "c" in node_kwargs: 

266 return "Please use 'node_color' and not 'node_kwargs'" 

267 

268 

269@pytest.mark.parametrize("node_kwargs", [{"s": 50}, {"c": "blue"}]) 

270def test_plot_connectome_exceptions_providing_node_info_with_kwargs( 

271 node_kwargs, adjacency, node_coords, expected_error_node_kwargs 

272): 

273 """Tests that an error is raised when specifying node parameters \ 

274 via node_kwargs in plot_connectome. 

275 """ 

276 with pytest.raises(ValueError, match=expected_error_node_kwargs): 

277 plot_connectome( 

278 adjacency, node_coords, node_kwargs=node_kwargs, display_mode="x" 

279 )