Repository: mne-tools/mne-python

Issue:
Can't save a slice of a bdf file without preloading full file
Having updated MNE to v0.18.0 via pip, I'm now unable to split a .bdf file into smaller raw.fif files without preloading the full file. This code runs in MNE v0.17.2 without error:
```
In [1]: import mne

In [2]: raw = mne.io.read_raw_edf('./path/to/eeg_file.bdf')
Extracting EDF parameters from ./path/to/eeg_file.bdf...
BDF file detected
Setting channel info structure...
Creating raw.info structure...

In [3]: raw.save('./test-raw.fif', tmin=1.2, tmax=4.0, overwrite=True)
Overwriting existing file.
Writing /home/sam/temp/test-raw.fif
Closing /home/sam/temp/test-raw.fif [done]
```
However, as of 0.18.0, this code returns the following error:
```
~/.pyenv/versions/3.6.8/lib/python3.6/site-packages/mne/io/edf/edf.py in _read_segment_file(data, idx, fi, start, stop, raw
_extras, chs, filenames)
    414
    415     if subtype == 'bdf':
--> 416         cal[0, stim_channel_idx] = 1
    417         offsets[stim_channel_idx, 0] = 0
    418         gains[0, stim_channel_idx] = 1
```
The error occurs as the `stim_channel_idx` variable is set to:
```
ipdb> stim_channel_idx
array([], dtype=float64)
```
which I believe occurs in the block of code on lines 407-413 of `/mne/io/edf/edf.py`. Unfortunately I don't have a good enough understanding of this code block to offer any more information. 

This issue does not occur if the file has been preloaded using `preload=True` in the call to `read_raw_edf`. Unfortunately this is not an option in some cases where the .bdf files are simply too large to load fully in to memory.


Discussion:
I cannot replicate the pb with
https://github.com/mne-tools/mne-testing-data/tree/master/BDF:

In [10]: raw = mne.io.read_raw_bdf('test_generator_2.bdf')

In [11]: raw.save('toto_raw.fif', tmin=1., tmax=2, overwrite=True)

can you share a file?

do I miss something?

>

Unfortunately I cannot share the full files, but will try to generate a small test file that reproduces the issue in the next few days (I don't currently have access to software that can crop BDF data and will need to find a Windows or Matlab install to do this).
you can replicate the pb only with your file? not any of the files from our
testing repo?

>

Sorry for the long delay on getting around to this, but would you be able to point me towards the test files? I cant seem to find them but I'll give them a go and see if it's an issue that only affects my files.
Even if that is the case maybe it would useful just to have a more intuitive error message to suggest what the problem with the file is.
The test files are at the URL @agramfort posted above.
Sorry I missed that link. Ok so I've now run the exact same code using mne 18.2 straight off of pip, on a different, completely clean, brand new machine running Ubuntu 18.04.3 LTS. It appears that the bug occurs for one of the two test stimulus I was linked to ('test_bdf_stim_channel.bdf').

```
import mne

raw = mne.io.read_raw_bdf('test_bdf_stim_channel.bdf')
raw.save('test-raw.fif', tmin=1.2, tmax=4.0, overwrite=True)
```
```
---------------------------------------------------------------------------                                                                                                                                                                                                                                       
IndexError                                Traceback (most recent call last)                                                                                                            
<ipython-input-3-cef6f7eef39b> in <module>                                                                                                                                                                                                                                                                        
----> 1 raw.save('./test-raw.fif', tmin=1.2, tmax=4.0, overwrite=True)                                                                                                                                                               
                                                                                           
</home/bp/.pyenv/versions/anaconda3-2019.03/lib/python3.7/site-packages/mne/externals/decorator.py:decorator-gen-141> in save(self, fname, picks, tmin, tmax, buffer_size_sec, drop_small_buffer, proj, fmt, overwrite, split_size, split_naming, verbose)
                                                                                                                                                                                                                                                                                                                  
~/.pyenv/versions/anaconda3-2019.03/lib/python3.7/site-packages/mne/utils/_logging.py in wrapper(*args, **kwargs)                                                                                                                                                                                                 
     87             with use_log_level(verbose_level):                                                                                                   
     88                 return function(*args, **kwargs)                                                                                                                                                                                                                                                          
---> 89         return function(*args, **kwargs)                                                                                                         
     90     return FunctionMaker.create(                                                                                                                 
     91         function, 'return decfunc(%(signature)s)',                                                                                               
                                                                                                                                                         
~/.pyenv/versions/anaconda3-2019.03/lib/python3.7/site-packages/mne/io/base.py in save(self, fname, picks, tmin, tmax, buffer_size_sec, drop_small_buffer, proj, fmt, overwrite, split_size, split_naming, verbose)                                                                                               
   1595         data_type = type_dict[fmt]                                  
   1596                                                                                                                                                  
-> 1597         data_test = self[0, 0][0]                                   
   1598         if fmt == 'short' and np.iscomplexobj(data_test):                                                                                        
   1599             raise ValueError('Complex data must be saved as "single" or '                                                                        

~/.pyenv/versions/anaconda3-2019.03/lib/python3.7/site-packages/mne/io/base.py in __getitem__(self, item)                                                                                                                                                                                                         
    915             data = self._read_segment(start=start, stop=stop, sel=sel,                                                                           
    916                                       projector=self._projector,                                                                                 
--> 917                                       verbose=self.verbose)                                                                                      
    918         times = self.times[start:stop]                                                                                                           
    919         return data, times                                          

~/.pyenv/versions/anaconda3-2019.03/lib/python3.7/site-packages/mne/io/base.py in _read_segment(self, start, stop, sel, data_buffer, projector, verbose)                                                                                                                                                          
    566             self._read_segment_file(data[:, this_sl], idx, fi,                                                                                   
    567                                     int(start_file), int(stop_file),                                                                             
--> 568                                     cals, mult)                                                                                                  
    569             offset += n_read                                        
    570         return data                                                 

</home/bp/.pyenv/versions/anaconda3-2019.03/lib/python3.7/site-packages/mne/externals/decorator.py:decorator-gen-153> in _read_segment_file(self, data, idx, fi, start, stop, cals, mult)                                                                                                                         

~/.pyenv/versions/anaconda3-2019.03/lib/python3.7/site-packages/mne/utils/_logging.py in wrapper(*args, **kwargs)                                                                                                                                                                                                 
     87             with use_log_level(verbose_level):                                                                                                   
     88                 return function(*args, **kwargs)                                                                                                 
---> 89         return function(*args, **kwargs)                                                                                                         
     90     return FunctionMaker.create(                                    
     91         function, 'return decfunc(%(signature)s)',                                                                                               

~/.pyenv/versions/anaconda3-2019.03/lib/python3.7/site-packages/mne/io/edf/edf.py in _read_segment_file(self, data, idx, fi, start, stop, cals, mult)                                                                                                                                                             
    198         return _read_segment_file(data, idx, fi, start, stop,                                                                                    
    199                                   self._raw_extras[fi], self.info['chs'],                                                                        
--> 200                                   self._filenames[fi])                                                                                           
    201                                                                     
    202     @copy_function_doc_to_method_doc(find_edf_events)                                                                                            

~/.pyenv/versions/anaconda3-2019.03/lib/python3.7/site-packages/mne/io/edf/edf.py in _read_segment_file(data, idx, fi, start, stop, raw_extras, chs, filenames)                                                                                                                                                   
    414                                                                     
    415     if subtype == 'bdf':                                            
--> 416         cal[0, stim_channel_idx] = 1                                
    417         offsets[stim_channel_idx, 0] = 0                                                                                                         
    418         gains[0, stim_channel_idx] = 1                                                                                                           

IndexError: arrays used as indices must be of integer (or boolean) type
```

```
raw = mne.io.read_raw_bdf('test_generator_2.bdf')                 
raw.save('test-raw.fif', tmin=1.2, tmax=4.0, overwrite=True)      
```
@cbrnr shall I let you have a look?
Yes, I can take a look.
The commit that broke it is here:
https://github.com/mne-tools/mne-python/commit/42cf6876414b9b3d1ad97882962110ae5cbd908d#diff-825d45683d0be02fad23614151867e02

This was part of #5841 - @massich can you take over please?

Resolving patch:
diff --git a/mne/io/edf/edf.py b/mne/io/edf/edf.py
--- a/mne/io/edf/edf.py
+++ b/mne/io/edf/edf.py
@@ -395,7 +395,7 @@ def _read_segment_file(data, idx, fi, start, stop, raw_extras, chs, filenames):
                 stim_channel_idx.append(stim_ch_idx)
         stim_channel_idx = np.array(stim_channel_idx).ravel()
 
-    if subtype == 'bdf':
+    if subtype == 'bdf' and len(stim_channel_idx) > 0:
         cal[0, stim_channel_idx] = 1
         offsets[stim_channel_idx, 0] = 0
         gains[0, stim_channel_idx] = 1


Test patch:
diff --git a/mne/io/edf/tests/test_edf.py b/mne/io/edf/tests/test_edf.py
--- a/mne/io/edf/tests/test_edf.py
+++ b/mne/io/edf/tests/test_edf.py
@@ -97,6 +97,13 @@ def test_bdf_data():
     assert (raw_py.info['chs'][63]['loc']).any()
 
 
+@testing.requires_testing_data
+def test_bdf_crop_save_stim_channel(tmpdir):
+    """Test EDF with various sampling rates."""
+    raw = read_raw_bdf(bdf_stim_channel_path)
+    raw.save(tmpdir.join('test-raw.fif'), tmin=1.2, tmax=4.0, overwrite=True)
+
+
 @testing.requires_testing_data
 def test_edf_reduced():
     """Test EDF with various sampling rates."""