Repository: mne-tools/mne-python

Issue:
What does set_eeg_reference() do?
Hi all, 

I'm a bit puzzled as to what `set_eeg_reference()` actually does.

Here is a gist where I do `set_eeg_reference(ref_channels=[])` (as my data was already referenced).

https://gist.github.com/nbara/972eefa4a62fd6ef9df308b76ffa2559

Contrary to my expectations, this seems to rereference to the mean, and also appears to include the STIM channel in the mix (visible peaks every .5 seconds)??


Discussion:
Based on the [docstring](https://mne-tools.github.io/dev/generated/mne.set_eeg_reference.html#mne.set_eeg_reference) it seems like doing `[]` should indeed not affect the data, but clearly it did. So I think this is a bug.

Can you take a minute to use `np.random.RandomState(0).randn(...)` as the data to turn this into a minimal example?

Are you up for digging into the code to try to fix it?
Hi Eric,

Here's a minimal example using random data:
https://gist.github.com/nbara/8e6e2a3dbb18675b7b57fca3fbfbc111

Does that work?

I'm afraid I have too much on my plate atm so I won't be able to fix this myself...
What the.... the referencing function should not be doing *that*. ok, I'm looking into it.

Resolving patch:
diff --git a/mne/io/reference.py b/mne/io/reference.py
--- a/mne/io/reference.py
+++ b/mne/io/reference.py
@@ -136,23 +136,23 @@ def _apply_reference(inst, ref_from, ref_to=None):
     inst._projector, _ = \
         setup_proj(inst.info, add_eeg_ref=False, activate=False)
 
-    ref_from = pick_channels(inst.ch_names, ref_from)
-    ref_to = pick_channels(inst.ch_names, ref_to)
-    data = inst._data
-
     # Compute reference
     if len(ref_from) > 0:
+        ref_from = pick_channels(inst.ch_names, ref_from)
+        ref_to = pick_channels(inst.ch_names, ref_to)
+
+        data = inst._data
         ref_data = data[..., ref_from, :].mean(-2, keepdims=True)
         data[..., ref_to, :] -= ref_data
         ref_data = ref_data[..., 0, :]
+
+        # If the reference touches EEG electrodes, note in the info that a
+        # non-CAR has been applied.
+        if len(np.intersect1d(ref_to, eeg_idx)) > 0:
+            inst.info['custom_ref_applied'] = True
     else:
         ref_data = None
 
-    # If the reference touches EEG electrodes, note in the info that a non-CAR
-    # has been applied.
-    if len(np.intersect1d(ref_to, eeg_idx)) > 0:
-        inst.info['custom_ref_applied'] = True
-
     return inst, ref_data
 
 
@@ -385,15 +385,17 @@ def set_eeg_reference(inst, ref_channels=None, copy=True, verbose=None):
 
             return inst, None
 
+    inst = inst.copy() if copy else inst
+
     if ref_channels == []:
         logger.info('EEG data marked as already having the desired reference. '
                     'Preventing automatic future re-referencing to an average '
                     'reference.')
+        inst.info['custom_ref_applied'] = True
+        return inst, None
     else:
         logger.info('Applying a custom EEG reference.')
-
-    inst = inst.copy() if copy else inst
-    return _apply_reference(inst, ref_channels)
+        return _apply_reference(inst, ref_channels)
 
 
 @verbose


Test patch:
diff --git a/mne/io/tests/test_reference.py b/mne/io/tests/test_reference.py
--- a/mne/io/tests/test_reference.py
+++ b/mne/io/tests/test_reference.py
@@ -82,14 +82,14 @@ def test_apply_reference():
     # The CAR reference projection should have been removed by the function
     assert_true(not _has_eeg_average_ref_proj(reref.info['projs']))
 
-    # Test that disabling the reference does not break anything
-    reref, ref_data = _apply_reference(raw, [])
-    assert_array_equal(raw._data, reref._data)
-
     # Test that data is modified in place when copy=False
     reref, ref_data = _apply_reference(raw, ['EEG 001', 'EEG 002'])
     assert_true(raw is reref)
 
+    # Test that disabling the reference does not change anything
+    reref, ref_data = _apply_reference(raw.copy(), [])
+    assert_array_equal(raw._data, reref._data)
+
     # Test re-referencing Epochs object
     raw = read_raw_fif(fif_fname, preload=False)
     events = read_events(eve_fname)
@@ -196,6 +196,10 @@ def test_set_eeg_reference():
     assert_true(not _has_eeg_average_ref_proj(reref.info['projs']))
     assert_equal(reref.info['custom_ref_applied'], True)
 
+    # Test that disabling the reference does not change anything
+    reref, ref_data = set_eeg_reference(raw, [])
+    assert_array_equal(raw._data, reref._data)
+
 
 @testing.requires_testing_data
 def test_set_bipolar_reference():