Repository: nilearn/nilearn

Issue:
FirstLevelModel `signal_scaling` attribute is different type from same-named parameter
<!--Provide a brief description of the bug.-->
The `FirstLevelModel`'s `signal_scaling` parameter is converted to a boolean in the `signal_scaling` _attribute_ and retained as-is in the `scaling_axis` attribute, which causes problems if you want to use `FirstLevelModel.get_params()` without updating the dictionary that's returned.

This stems from https://github.com/nilearn/nilearn/pull/3127#discussion_r783496751

<!--Please fill in the following information, to the best of your ability.-->
Nilearn version: ~0.9.0 (current `main` at e0ec327f3ded6d730a6a60f8043dc8b6f4ee03c1.

### Expected behavior

A FirstLevelModel fitted with the parameters from an existing FirstLevelModel (i.e., using `model.get_params()`) would work in the same manner as the original model.

### Actual behavior

```Python
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-65cf92bf9216> in <module>
     16 # Fit the first GLM
     17 fmri_glm = fmri_glm.fit(fmri_img, design_matrices=design_matrices)
---> 18 test_glm = test_glm.fit(fmri_img, design_matrices=design_matrices)

~/Documents/tsalo/nilearn/nilearn/glm/first_level/first_level.py in fit(self, run_imgs, events, confounds, design_matrices, bins)
    568 
    569             if self.signal_scaling:
--> 570                 Y, _ = mean_scaling(Y, self.scaling_axis)
    571             if self.memory:
    572                 mem_glm = self.memory.cache(run_glm, ignore=['n_jobs'])

~/Documents/tsalo/nilearn/nilearn/glm/first_level/first_level.py in mean_scaling(Y, axis)
     59 
     60     """
---> 61     mean = Y.mean(axis=axis)
     62     if (mean == 0).any():
     63         warn('Mean values of 0 observed.'

/opt/miniconda3/lib/python3.8/site-packages/numpy/core/_methods.py in _mean(a, axis, dtype, out, keepdims, where)
    177             is_float16_result = True
    178 
--> 179     ret = umr_sum(arr, axis, dtype, out, keepdims, where=where)
    180     if isinstance(ret, mu.ndarray):
    181         ret = um.true_divide(

TypeError: an integer is required
```

### Steps and code to reproduce bug

```python
# Adapted from https://nilearn.github.io/stable/auto_examples/04_glm_first_level/plot_fiac_analysis.html#sphx-glr-auto-examples-04-glm-first-level-plot-fiac-analysis-py
import pandas as pd
import numpy as np
from nilearn.datasets import func
from nilearn.glm.first_level import FirstLevelModel

data = func.fetch_fiac_first_level()
fmri_img = [data['func1'], data['func2']]
design_files = [data['design_matrix1'], data['design_matrix2']]
design_matrices = [pd.DataFrame(np.load(df)['X']) for df in design_files]
fmri_glm = FirstLevelModel(mask_img=data['mask'], signal_scaling=0, minimize_memory=True)

# Collect the parameters and use them to create a new GLM
glm_parameters = fmri_glm.get_params()
# Note that glm_parameters["signal_scaling"] is True, 
# even though the parameter we used was the axis (0)
test_glm = FirstLevelModel(**glm_parameters)

# Fit the first GLM
fmri_glm = fmri_glm.fit(fmri_img, design_matrices=design_matrices)
test_glm = test_glm.fit(fmri_img, design_matrices=design_matrices)
```



Discussion:
Thx for opening !
Thanks @tsalo !
Also linking here the related part of the code:

https://github.com/nilearn/nilearn/blob/cc3eafdc3053d07318576cb406ee29439fcff682/nilearn/glm/first_level/first_level.py#L369-L377

Resolving patch:
diff --git a/nilearn/glm/first_level/first_level.py b/nilearn/glm/first_level/first_level.py
--- a/nilearn/glm/first_level/first_level.py
+++ b/nilearn/glm/first_level/first_level.py
@@ -369,8 +369,7 @@ def __init__(self, t_r=None, slice_time_ref=0., hrf_model='glover',
         if signal_scaling is False:
             self.signal_scaling = signal_scaling
         elif signal_scaling in [0, 1, (0, 1)]:
-            self.scaling_axis = signal_scaling
-            self.signal_scaling = True
+            self.signal_scaling = signal_scaling
             self.standardize = False
         else:
             raise ValueError('signal_scaling must be "False", "0", "1"'
@@ -385,6 +384,14 @@ def __init__(self, t_r=None, slice_time_ref=0., hrf_model='glover',
         self.results_ = None
         self.subject_label = subject_label
 
+    @property
+    def scaling_axis(self):
+        warn(DeprecationWarning(
+            "Deprecated. `scaling_axis` will be removed in 0.11.0. "
+            "Please use `signal_scaling` instead."
+        ))
+        return self.signal_scaling
+
     def fit(self, run_imgs, events=None, confounds=None,
             design_matrices=None, bins=100):
         """Fit the GLM
@@ -566,8 +573,8 @@ def fit(self, run_imgs, events=None, confounds=None,
                 sys.stderr.write('Masker took %d seconds       \n'
                                  % t_masking)
 
-            if self.signal_scaling:
-                Y, _ = mean_scaling(Y, self.scaling_axis)
+            if self.signal_scaling is not False:  # noqa
+                Y, _ = mean_scaling(Y, self.signal_scaling)
             if self.memory:
                 mem_glm = self.memory.cache(run_glm, ignore=['n_jobs'])
             else:


Test patch:
diff --git a/nilearn/glm/tests/test_first_level.py b/nilearn/glm/tests/test_first_level.py
--- a/nilearn/glm/tests/test_first_level.py
+++ b/nilearn/glm/tests/test_first_level.py
@@ -711,6 +711,32 @@ def test_first_level_from_bids():
                 bids_path, 'main', 'T1w')  # desc not specified
 
 
+def test_first_level_with_scaling():
+    shapes, rk = [(3, 1, 1, 2)], 1
+    fmri_data = list()
+    fmri_data.append(Nifti1Image(np.zeros((1, 1, 1, 2)) + 6, np.eye(4)))
+    design_matrices = list()
+    design_matrices.append(
+        pd.DataFrame(
+            np.ones((shapes[0][-1], rk)),
+            columns=list('abcdefghijklmnopqrstuvwxyz')[:rk])
+    )
+    fmri_glm = FirstLevelModel(
+        mask_img=False, noise_model='ols', signal_scaling=0,
+        minimize_memory=True
+    )
+    assert fmri_glm.signal_scaling == 0
+    assert not fmri_glm.standardize
+    with pytest.warns(DeprecationWarning,
+                      match="Deprecated. `scaling_axis` will be removed"):
+        assert fmri_glm.scaling_axis == 0
+    glm_parameters = fmri_glm.get_params()
+    test_glm = FirstLevelModel(**glm_parameters)
+    fmri_glm = fmri_glm.fit(fmri_data, design_matrices=design_matrices)
+    test_glm = test_glm.fit(fmri_data, design_matrices=design_matrices)
+    assert glm_parameters['signal_scaling'] == 0
+
+
 def test_first_level_with_no_signal_scaling():
     """
     test to ensure that the FirstLevelModel works correctly with a