Repository: nilearn/nilearn

Issue:
Method generate_report raises TypeError when mask_img of FirstLevelModel is NiftiMasker
<!--Provide a brief description of the bug.-->
`FirstLevelModel` accepts `mask_img` to be a `NiftiMasker`. However, calling `generate_report()` on such an instance will raise a `TypeError`, due to the fact that `_mask_to_svg()` calls `plot_roi()` on attribute `mask_img` (`plot_roi()` would need `mask_img` to be a `NiftiImage`, not a `NiftiMasker`).

<!--Please fill in the following information, to the best of your ability.-->
Nilearn version: 0.8.2.dev

### Expected behavior
The report should be generated flawlessly.

### Actual behavior
An explicit `TypeError` is raised, but users can't easily fix this bug as it lies in unexposed methods.

### Steps and code to reproduce bug
Here is an incomplete code snippet leading to this bug:

```python
masker = NiftiMasker()
masker.fit(anatomical_img)

glm = FirstLevelModel(t_r=t_r, mask_img=masker)
glm.fit(functional_imgs, events)
glm.generate_report(["condition_name"])
```

### Fix
A simple fix would be to call `_mask_to_svg()` with `NiftiImage` parameters only. One simply need to modify the following lines to do a proper type check: https://github.com/nilearn/nilearn/blob/80c55fc43d614c4edf35c42186ac414ac3b770e3/nilearn/reporting/glm_reporter.py#L217-L220

I can take care of this soon!


Discussion:

Resolving patch:
diff --git a/nilearn/reporting/glm_reporter.py b/nilearn/reporting/glm_reporter.py
--- a/nilearn/reporting/glm_reporter.py
+++ b/nilearn/reporting/glm_reporter.py
@@ -40,6 +40,8 @@
 
 from nilearn.reporting._get_clusters_table import get_clusters_table
 from nilearn.reporting.utils import figure_to_svg_quoted
+from nilearn.input_data import NiftiMasker
+from nilearn._utils import check_niimg
 
 
 HTML_TEMPLATE_ROOT_PATH = os.path.join(os.path.dirname(__file__),
@@ -214,7 +216,18 @@ def make_glm_report(model,
                                                    )
     statistical_maps = _make_stat_maps(model, contrasts)
     html_design_matrices = _dmtx_to_svg_url(design_matrices)
-    mask_img = model.mask_img or model.masker_.mask_img_
+
+    # Select mask_img to use for plotting
+    if isinstance(model.mask_img, NiftiMasker):
+        mask_img = model.masker_.mask_img_
+    else:
+        try:
+            # check that mask_img is a niiimg-like object
+            check_niimg(model.mask_img)
+            mask_img = model.mask_img
+        except Exception:
+            mask_img = model.masker_.mask_img_
+
     mask_plot_html_code = _mask_to_svg(mask_img=mask_img,
                                        bg_img=bg_img,
                                        )


Test patch:
diff --git a/nilearn/reporting/tests/test_glm_reporter.py b/nilearn/reporting/tests/test_glm_reporter.py
--- a/nilearn/reporting/tests/test_glm_reporter.py
+++ b/nilearn/reporting/tests/test_glm_reporter.py
@@ -16,6 +16,7 @@
 from nilearn.glm.first_level import FirstLevelModel
 from nilearn.reporting import glm_reporter as glmr
 from nilearn.glm.second_level import SecondLevelModel
+from nilearn.input_data import NiftiMasker
 
 try:
     import matplotlib as mpl  # noqa: F841
@@ -289,3 +290,32 @@ def test_plot_contrasts():
     contrast_plots = glmr._plot_contrasts(contrast,  # noqa: F841
                                           [dmtx],
                                           )
+
+
+def test_masking_first_level_model():
+    """
+    Checks that using NiftiMasker when instantiating
+    FirstLevelModel doesn't raise Error when calling
+    generate_report().
+    """
+    with InTemporaryDirectory():
+        shapes, rk = ((7, 8, 7, 15), (7, 8, 7, 16)), 3
+        mask, fmri_data, design_matrices =\
+            write_fake_fmri_data_and_design(shapes, rk)
+        masker = NiftiMasker(mask_img=mask)
+        masker.fit(fmri_data)
+        flm = FirstLevelModel(mask_img=masker).fit(
+            fmri_data, design_matrices=design_matrices
+        )
+        contrast = np.eye(3)[1]
+
+        report_flm = flm.generate_report(
+            contrast, plot_type='glass', height_control=None,
+            min_distance=15, alpha=0.001, threshold=2.78
+        )
+
+        report_iframe = report_flm.get_iframe()
+        # So flake8 doesn't complain about not using variable (F841)
+        report_iframe
+
+        del mask, flm, fmri_data, masker