Repository: mne-tools/mne-python

Issue:
Bug in mne.connectivity.spectral_connectivity()?
Hi all,

I was just trying to use `mne.connectivity.spectral_connectivity()` in the following way:

```python
# perform the connectivity analysis:
conn = mne.connectivity.spectral_connectivity(epochs, method='wpli',
                                              fmin=1, fmax=40, n_jobs=6)
```

I get the following bug:

<details><summary>Error Trace, click to expand</summary>

```
---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
<ipython-input-3-56a8545dd948> in <module>()
     56     # perform the connectivity analysis:
     57     conn = mne.connectivity.spectral_connectivity(epochs, method='wpli',
---> 58                                                   fmin=1, fmax=40, n_jobs=6)
     59 

/Library/anaconda/envs/py36/lib/python3.6/site-packages/mne/connectivity/spectral.py in spectral_connectivity(data, method, indices, sfreq, mode, fmin, fmax, fskip, faverage, tmin, tmax, mt_bandwidth, mt_adaptive, mt_low_bias, cwt_frequencies, cwt_n_cycles, block_size, n_jobs, verbose)

/Library/anaconda/envs/py36/lib/python3.6/site-packages/mne/utils.py in verbose(function, *args, **kwargs)
    724         with use_log_level(verbose_level):
    725             return function(*args, **kwargs)
--> 726     return function(*args, **kwargs)
    727 
    728 

/Library/anaconda/envs/py36/lib/python3.6/site-packages/mne/connectivity/spectral.py in spectral_connectivity(data, method, indices, sfreq, mode, fmin, fmax, fskip, faverage, tmin, tmax, mt_bandwidth, mt_adaptive, mt_low_bias, cwt_frequencies, cwt_n_cycles, block_size, n_jobs, verbose)
    877     # compute final connectivity scores
    878     con = list()
--> 879     for method, n_args in zip(con_methods, n_comp_args):
    880         # future estimators will need to be handled here
    881         if n_args == 3:

UnboundLocalError: local variable 'con_methods' referenced before assignment
```

</details>

&nbsp;

It seemed to me like this is a bug, so I thought I'd report it.

I am using mne 0.15.dev0 (on the latest github commit), but this also occurred with 0.14. I'm on Mac OS Sierra.


Discussion:
Hi @janfreyberg, I looked at the code and it seems that [this line](https://github.com/mne-tools/mne-python/blob/master/mne/connectivity/spectral.py#L785) may be involved, it says:
```python
    for epoch_block in _get_n_epochs(data, n_jobs):
```
`_get_n_epochs` returns epochs packed in lists of `n_jobs` long. It says 'at most' but it actually returns lists exactly `n_jobs` long. This results in:
* `con_methods` not created if `n_epochs` < `n_jobs`
* any leftover epochs (`n_epochs` modulo `n_jobs`) are ignored

Example:
```python
epochs = np.arange(10)
for ep in _get_n_epochs(epochs, 4):
    print(ep)
```
gives:
```python
[(0,), (1,), (2,), (3,)]
[(4,), (5,), (6,), (7,)]
```

while
```python
epochs = np.arange(4)
for ep in _get_n_epochs(epochs, 10):
    print(ep)
```
does nothing.

This definitely looks like a bug.
In short: is `len(epochs) < n_jobs` in your case?
Ok, I just saw in your notebook that you use 4 events that you epochs by. 
It's good you did this because you've uncovered a bug in mne, but if you want to perform connectivity analyses it is recommended to have many more epochs - in your case you would like to cut the basline recording into smaller windows and use these as epochs.

Resolving patch:
diff --git a/mne/connectivity/spectral.py b/mne/connectivity/spectral.py
--- a/mne/connectivity/spectral.py
+++ b/mne/connectivity/spectral.py
@@ -469,6 +469,8 @@ def _get_n_epochs(epochs, n):
         if len(epochs_out) >= n:
             yield epochs_out
             epochs_out = list()
+    if 0 < len(epochs_out) < n:
+        yield epochs_out
 
 
 def _check_method(method):


Test patch:
diff --git a/mne/connectivity/tests/test_spectral.py b/mne/connectivity/tests/test_spectral.py
--- a/mne/connectivity/tests/test_spectral.py
+++ b/mne/connectivity/tests/test_spectral.py
@@ -5,7 +5,7 @@
 from nose.tools import assert_true, assert_raises
 
 from mne.connectivity import spectral_connectivity
-from mne.connectivity.spectral import _CohEst
+from mne.connectivity.spectral import _CohEst, _get_n_epochs
 
 from mne import SourceEstimate
 from mne.utils import run_tests_if_main, slow_test
@@ -215,6 +215,12 @@ def test_spectral_connectivity():
                             freq_idx = np.searchsorted(freqs2, freqs3[i])
                             con2_avg = np.mean(con2[j][:, freq_idx], axis=1)
                             assert_array_almost_equal(con2_avg, con3[j][:, i])
-
+    # test _get_n_epochs
+    full_list = list(range(10))
+    out_lens = np.array([len(x) for x in _get_n_epochs(full_list, 4)])
+    assert_true((out_lens == np.array([4, 4, 2])).all())
+    out_lens = np.array([len(x) for x in _get_n_epochs(full_list, 11)])
+    assert_true(len(out_lens) > 0)
+    assert_true(out_lens[0] == 10)
 
 run_tests_if_main()