Coverage for nilearn/glm/tests/test_paradigm.py: 0%

68 statements  

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

1""" 

2Test the design_matrix utilities. 

3 

4Note that the tests just look whether the data produced has correct dimension, 

5not whether it is exact. 

6""" 

7 

8from pathlib import Path 

9 

10import numpy as np 

11import pandas as pd 

12import pytest 

13from numpy.testing import assert_array_equal 

14 

15from nilearn._utils.data_gen import basic_paradigm 

16from nilearn.glm.first_level.experimental_paradigm import ( 

17 check_events, 

18 handle_modulation_of_duplicate_events, 

19) 

20 

21from ._testing import ( 

22 block_paradigm, 

23 design_with_nan_durations, 

24 design_with_nan_onsets, 

25 design_with_null_durations, 

26 duplicate_events_paradigm, 

27 modulated_block_paradigm, 

28 modulated_event_paradigm, 

29) 

30 

31 

32def test_check_events(): 

33 events = basic_paradigm() 

34 events_copy = check_events(events) 

35 

36 # Check that given trial type is right 

37 assert_array_equal( 

38 events_copy["trial_type"], 

39 ["c0", "c0", "c0", "c1", "c1", "c1", "c2", "c2", "c2"], 

40 ) 

41 

42 # Check that missing modulation yields an array one ones 

43 assert_array_equal(events_copy["modulation"], np.ones(len(events))) 

44 

45 # Modulation is provided 

46 events["modulation"] = np.ones(len(events)) 

47 events_copy = check_events(events) 

48 assert_array_equal(events_copy["modulation"], events["modulation"]) 

49 

50 

51def test_check_events_errors(): 

52 """Test the function which tests that the events \ 

53 data describes a valid experimental paradigm. 

54 """ 

55 events = basic_paradigm() 

56 # Errors checkins 

57 # Wrong type 

58 with pytest.raises( 

59 TypeError, match="Events should be a Pandas DataFrame." 

60 ): 

61 check_events([]) 

62 

63 # Missing onset 

64 missing_onset = events.drop(columns=["onset"]) 

65 with pytest.raises( 

66 ValueError, match="The provided events data has no onset column." 

67 ): 

68 check_events(missing_onset) 

69 

70 # Missing duration 

71 missing_duration = events.drop(columns=["duration"]) 

72 with pytest.raises( 

73 ValueError, match="The provided events data has no duration column." 

74 ): 

75 check_events(missing_duration) 

76 

77 # Duration wrong type 

78 wrong_duration = events.copy() 

79 wrong_duration["duration"] = "foo" 

80 with pytest.raises(ValueError, match="Could not cast duration to float"): 

81 check_events(wrong_duration) 

82 

83 

84def test_check_events_warnings(): 

85 """Test the function which tests that the events \ 

86 data describes a valid experimental paradigm. 

87 """ 

88 events = basic_paradigm() 

89 # Warnings checkins 

90 # Missing trial type 

91 events = events.drop(columns=["trial_type"]) 

92 with pytest.warns(UserWarning, match="'trial_type' column not found"): 

93 events_copy = check_events(events) 

94 

95 # Check that missing trial type yields a 'dummy' array 

96 assert len(np.unique(events_copy["trial_type"])) == 1 

97 assert events_copy["trial_type"][0] == "dummy" 

98 

99 # An unexpected field is provided 

100 events["foo"] = np.zeros(len(events)) 

101 with pytest.warns( 

102 UserWarning, 

103 match=( 

104 "The following unexpected columns " 

105 "in events data will be ignored: foo" 

106 ), 

107 ): 

108 events_copy2 = check_events(events) 

109 

110 assert_array_equal(events_copy["trial_type"], events_copy2["trial_type"]) 

111 assert_array_equal(events_copy["onset"], events_copy2["onset"]) 

112 assert_array_equal(events_copy["duration"], events_copy2["duration"]) 

113 assert_array_equal(events_copy["modulation"], events_copy2["modulation"]) 

114 

115 

116def write_events(events, tmpdir): 

117 """Write events of an experimental paradigm \ 

118 to a file and return the address. 

119 """ 

120 tsvfile = Path(tmpdir, "events.tsv") 

121 events.to_csv(tsvfile, sep="\t") 

122 return tsvfile 

123 

124 

125@pytest.mark.parametrize( 

126 "events", 

127 [ 

128 block_paradigm(), 

129 modulated_event_paradigm(), 

130 modulated_block_paradigm(), 

131 basic_paradigm(), 

132 ], 

133) 

134def test_read_events(events, tmp_path): 

135 """Test that a events for an experimental paradigm are correctly read.""" 

136 csvfile = write_events(events, tmp_path) 

137 read_paradigm = pd.read_table(csvfile) 

138 

139 assert (read_paradigm["onset"] == events["onset"]).all() 

140 

141 

142def test_check_events_warnings_null_duration(): 

143 """Test that events with null duration throw a warning.""" 

144 with pytest.warns( 

145 UserWarning, 

146 match="The following conditions contain events with null duration", 

147 ): 

148 check_events(design_with_null_durations()) 

149 

150 

151@pytest.mark.parametrize( 

152 "design", 

153 [ 

154 design_with_nan_durations, 

155 design_with_nan_onsets, 

156 ], 

157) 

158def test_check_events_nan_designs(design): 

159 """Test that events with nan values.""" 

160 with pytest.raises( 

161 ValueError, match=("The following column must not contain nan values:") 

162 ): 

163 check_events(design()) 

164 

165 

166def test_sum_modulation_of_duplicate_events(): 

167 """Test the function check_events \ 

168 when the paradigm contains duplicate events. 

169 """ 

170 events = duplicate_events_paradigm() 

171 

172 # Check that a warning is given to the user 

173 with pytest.warns(UserWarning, match="Duplicated events were detected."): 

174 events_copy = handle_modulation_of_duplicate_events(events) 

175 assert_array_equal( 

176 events_copy["trial_type"], ["c0", "c0", "c0", "c1", "c1"] 

177 ) 

178 assert_array_equal(events_copy["onset"], [10, 30, 70, 10, 30]) 

179 assert_array_equal(events_copy["duration"], [1.0, 1.0, 1.0, 1.0, 1.0]) 

180 # Modulation was updated 

181 assert_array_equal(events_copy["modulation"], [1, 1, 2, 1, 1])