Coverage for nilearn/plotting/matrix/_utils.py: 0%

56 statements  

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

1from warnings import warn 

2 

3import numpy as np 

4from scipy.cluster.hierarchy import leaves_list, linkage, optimal_leaf_ordering 

5 

6from nilearn._utils.logger import find_stack_level 

7from nilearn.glm.contrasts import expression_to_contrast_vector 

8 

9VALID_REORDER_VALUES = (True, False, "single", "complete", "average") 

10VALID_TRI_VALUES = ("full", "lower", "diag") 

11 

12 

13def mask_matrix(mat, tri): 

14 """Help for plot_matrix. 

15 

16 This function masks the matrix depending on the provided 

17 value of ``tri``. 

18 """ 

19 if tri == "lower": 

20 mask = np.tri(mat.shape[0], k=-1, dtype=bool) ^ True 

21 else: 

22 mask = np.tri(mat.shape[0], dtype=bool) ^ True 

23 return np.ma.masked_array(mat, mask) 

24 

25 

26def pad_contrast_matrix(contrast_def, design_matrix): 

27 """Pad contrasts with zeros. 

28 

29 Parameters 

30 ---------- 

31 contrast_def : :class:`numpy.ndarray` 

32 Contrast to be padded 

33 

34 design_matrix : :class:`pandas.DataFrame` 

35 Design matrix to use. 

36 

37 Returns 

38 ------- 

39 axes : :class:`numpy.ndarray` 

40 Padded contrast 

41 

42 """ 

43 design_column_names = design_matrix.columns.tolist() 

44 if isinstance(contrast_def, str): 

45 contrast_def = expression_to_contrast_vector( 

46 contrast_def, design_column_names 

47 ) 

48 n_columns_design_matrix = len(design_column_names) 

49 n_columns_contrast_def = ( 

50 contrast_def.shape[0] 

51 if contrast_def.ndim == 1 

52 else contrast_def.shape[1] 

53 ) 

54 horizontal_padding = n_columns_design_matrix - n_columns_contrast_def 

55 if horizontal_padding == 0: 

56 return contrast_def 

57 warn( 

58 ( 

59 f"Contrasts will be padded with {horizontal_padding} " 

60 "column(s) of zeros." 

61 ), 

62 category=UserWarning, 

63 stacklevel=find_stack_level(), 

64 ) 

65 contrast_def = np.pad( 

66 contrast_def, 

67 ((0, 0), (0, horizontal_padding)), 

68 "constant", 

69 constant_values=(0, 0), 

70 ) 

71 return contrast_def 

72 

73 

74def sanitize_labels(mat_shape, labels): 

75 """Help for plot_matrix.""" 

76 # we need a list so an empty one will be cast to False 

77 if isinstance(labels, np.ndarray): 

78 labels = labels.tolist() 

79 if labels and len(labels) != mat_shape[0]: 

80 raise ValueError( 

81 f"Length of labels ({len(labels)}) " 

82 f"unequal to length of matrix ({mat_shape[0]})." 

83 ) 

84 return labels 

85 

86 

87def sanitize_reorder(reorder): 

88 """Help for plot_matrix.""" 

89 if reorder not in VALID_REORDER_VALUES: 

90 param_to_print = [] 

91 for item in VALID_REORDER_VALUES: 

92 if isinstance(item, str): 

93 param_to_print.append(f'"{item}"') 

94 else: 

95 param_to_print.append(str(item)) 

96 raise ValueError( 

97 "Parameter reorder needs to be one of:" 

98 f"\n{', '.join(param_to_print)}." 

99 ) 

100 reorder = "average" if reorder is True else reorder 

101 return reorder 

102 

103 

104def sanitize_tri(tri, allowed_values=None): 

105 """Help for plot_matrix.""" 

106 if allowed_values is None: 

107 allowed_values = VALID_TRI_VALUES 

108 if tri not in allowed_values: 

109 raise ValueError( 

110 f"Parameter tri needs to be one of: {', '.join(allowed_values)}." 

111 ) 

112 

113 

114def reorder_matrix(mat, labels, reorder): 

115 """Help for plot_matrix. 

116 

117 This function reorders the provided matrix. 

118 """ 

119 if not labels: 

120 raise ValueError("Labels are needed to show the reordering.") 

121 

122 linkage_matrix = linkage(mat, method=reorder) 

123 ordered_linkage = optimal_leaf_ordering(linkage_matrix, mat) 

124 index = leaves_list(ordered_linkage) 

125 # make sure labels is an ndarray and copy it 

126 labels = np.array(labels).copy() 

127 mat = mat.copy() 

128 # and reorder labels and matrix 

129 labels = labels[index].tolist() 

130 mat = mat[index, :][:, index] 

131 return mat, labels