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
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-16 12:32 +0200
1"""
2Test the design_matrix utilities.
4Note that the tests just look whether the data produced has correct dimension,
5not whether it is exact.
6"""
8from pathlib import Path
10import numpy as np
11import pandas as pd
12import pytest
13from numpy.testing import assert_array_equal
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)
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)
32def test_check_events():
33 events = basic_paradigm()
34 events_copy = check_events(events)
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 )
42 # Check that missing modulation yields an array one ones
43 assert_array_equal(events_copy["modulation"], np.ones(len(events)))
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"])
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([])
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)
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)
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)
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)
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"
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)
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"])
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
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)
139 assert (read_paradigm["onset"] == events["onset"]).all()
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())
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())
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()
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])