Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f678b355f6 | |||
| beedbfbfb2 | |||
| 4393f01728 | |||
| d8e53335bb | |||
| c48657c38b | |||
| 1cfc78f70d | |||
| 0c2785695d | |||
| 32bdb39525 | |||
| 55f8dba526 | |||
| 1956dbb8f7 | |||
| 917447cb6f | |||
| 4ff1f5b7ec | |||
| b73c8310e9 | |||
| 931ae6c54a |
+18
-16
@@ -16,53 +16,55 @@ env:
|
||||
#
|
||||
# Run one test (3.4) with a non-default stim channel to make sure our
|
||||
# tests are explicit about channels.
|
||||
#
|
||||
# Must force libpng version to avoid silly libpng.so.15 error (MPL 1.1 needs it)
|
||||
- PYTHON=2.7 DEPS=full TEST_LOCATION=src
|
||||
- PYTHON=2.7 DEPS=nodata TEST_LOCATION=src MNE_DONTWRITE_HOME=true # also runs flake8
|
||||
- PYTHON=3.4 DEPS=full TEST_LOCATION=install MNE_STIM_CHANNEL=STI101
|
||||
- PYTHON=2.6 DEPS=full TEST_LOCATION=src NUMPY="=1.7" SCIPY="=0.11" MPL="=1.1" SKLEARN="=0.11" PANDAS="=0.8"
|
||||
- PYTHON=2.6 DEPS=full TEST_LOCATION=src NUMPY="=1.7" SCIPY="=0.11" MPL="=1.1" LIBPNG="=1.5" SKLEARN="=0.11" PANDAS="=0.8"
|
||||
- PYTHON=2.7 DEPS=minimal TEST_LOCATION=src
|
||||
|
||||
# Setup anaconda
|
||||
before_install:
|
||||
- wget -q http://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh
|
||||
- chmod +x miniconda.sh
|
||||
- ./miniconda.sh -b &> /dev/null;
|
||||
- ./miniconda.sh -b
|
||||
- export PATH=/home/travis/miniconda/bin:$PATH
|
||||
- conda update --yes --quiet conda &> /dev/null;
|
||||
- conda update --yes --quiet conda
|
||||
# We need to create a (fake) display on Travis (allows Mayavi tests to run)
|
||||
- export DISPLAY=:99.0
|
||||
- /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 1400x900x24 -ac +extension GLX +render -noreset
|
||||
|
||||
install:
|
||||
- conda create -n testenv --yes pip python=$PYTHON &> /dev/null
|
||||
- source activate testenv &> /dev/null
|
||||
- conda install --yes --quiet numpy$NUMPY scipy$SCIPY nose matplotlib$MPL > /dev/null
|
||||
- conda create -n testenv --yes pip python=$PYTHON
|
||||
- source activate testenv
|
||||
- conda install --yes --quiet numpy$NUMPY scipy$SCIPY nose matplotlib$MPL libpng$LIBPNG
|
||||
# We have to replicate e.g. numpy$NUMPY to ensure the recommended (higher) versions
|
||||
# are not automatically installed below with multiple "conda install" calls!
|
||||
- if [ "${DEPS}" == "full" ]; then
|
||||
curl http://lester.ilabs.uw.edu/files/minimal_cmds.tar.gz | tar xz;
|
||||
export MNE_ROOT="${PWD}/minimal_cmds";
|
||||
export NEUROMAG2FT_ROOT="${PWD}/minimal_cmds/bin";
|
||||
source ${MNE_ROOT}/bin/mne_setup_sh > /dev/null;
|
||||
source ${MNE_ROOT}/bin/mne_setup_sh;
|
||||
sudo apt-get update -qq;
|
||||
sudo apt-get install -qq -y libxp6;
|
||||
conda install --yes --quiet pandas$PANDAS scikit-learn$SKLEARN patsy h5py pillow numpy$NUMPY scipy$SCIPY;
|
||||
conda install --yes --quiet pandas$PANDAS scikit-learn$SKLEARN patsy h5py pillow numpy$NUMPY scipy$SCIPY libpng$LIBPNG matplotlib$MPL;
|
||||
pip install -q joblib nibabel;
|
||||
if [ "${PYTHON}" == "3.4" ]; then
|
||||
conda install --yes --quiet ipython > /dev/null;
|
||||
conda install --yes --quiet ipython libpng$LIBPNG matplotlib$MPL;
|
||||
else
|
||||
conda install --yes --quiet ipython==1.1.0 statsmodels numpy$NUMPY scipy$SCIPY pandas$PANDAS > /dev/null;
|
||||
conda install --yes --quiet ipython==1.1.0 statsmodels numpy$NUMPY scipy$SCIPY pandas$PANDAS libpng$LIBPNG matplotlib$MPL;
|
||||
pip install -q nitime;
|
||||
if [ "${PYTHON}" == "2.7" ]; then
|
||||
conda install --yes --quiet mayavi traits > /dev/null;
|
||||
conda install --yes --quiet mayavi traits libpng$LIBPNG matplotlib$MPL;
|
||||
pip install -q pysurfer faulthandler;
|
||||
fi;
|
||||
fi;
|
||||
fi;
|
||||
- if [ "${DEPS}" == "nodata" ]; then
|
||||
pip install -q flake8 > /dev/null;
|
||||
pip install -q flake8;
|
||||
fi;
|
||||
- pip install -q coverage coveralls nose-timer > /dev/null
|
||||
- pip install -q coverage coveralls nose-timer
|
||||
# check our versions for the major packages
|
||||
- NP_VERSION=`python -c 'import numpy; print(numpy.__version__)'`
|
||||
- if [ -n "$NUMPY" ] && [ "${NUMPY:(-3)}" != "${NP_VERSION::3}" ]; then
|
||||
@@ -81,10 +83,10 @@ install:
|
||||
fi;
|
||||
# Suppress the parallel outputs for logging cleanliness
|
||||
- export MNE_LOGGING_LEVEL=warning
|
||||
- python setup.py build > /dev/null
|
||||
- python setup.py install > /dev/null
|
||||
- python setup.py build
|
||||
- python setup.py install
|
||||
- myscripts='browse_raw bti2fiff surf2bem'
|
||||
- for script in $myscripts; do mne $script --help >/dev/null; done;
|
||||
- for script in $myscripts; do mne $script --help; done;
|
||||
- SRC_DIR=$(pwd)
|
||||
- cd ~
|
||||
# Trigger download of testing data. Note that
|
||||
|
||||
+2
-2
@@ -12,8 +12,8 @@
|
||||
.. |Coveralls| image:: https://coveralls.io/repos/mne-tools/mne-python/badge.png?branch=master
|
||||
.. _Coveralls: https://coveralls.io/r/mne-tools/mne-python?branch=master
|
||||
|
||||
.. |Zenodo| image:: https://zenodo.org/badge/doi/10.5281/zenodo.11556.png
|
||||
.. _Zenodo: http://dx.doi.org/10.5281/zenodo.11556
|
||||
.. |Zenodo| image:: https://zenodo.org/badge/5822/mne-tools/mne-python.svg
|
||||
.. _Zenodo: http://dx.doi.org/10.5281/zenodo.17856
|
||||
|
||||
|
||||
`mne-python <http://martinos.org/mne/mne-python.html>`_
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 322 KiB After Width: | Height: | Size: 167 KiB |
+1
-1
@@ -17,7 +17,7 @@
|
||||
# Dev branch marker is: 'X.Y.devN' where N is an integer.
|
||||
#
|
||||
|
||||
__version__ = '0.9.dev0'
|
||||
__version__ = '0.9.0'
|
||||
|
||||
# have to import verbose first since it's needed by many things
|
||||
from .utils import (set_log_level, set_log_file, verbose, set_config,
|
||||
|
||||
+6
-2
@@ -361,7 +361,11 @@ def fft_resample(x, W, new_len, npad, to_remove,
|
||||
def _smart_pad(x, n_pad):
|
||||
"""Pad vector x
|
||||
"""
|
||||
if n_pad == 0:
|
||||
return x
|
||||
elif n_pad < 0:
|
||||
raise RuntimeError('n_pad must be non-negative')
|
||||
# need to pad with zeros if len(x) <= npad
|
||||
z_pad = np.zeros(max(n_pad - len(x) + 1, 0), dtype=x.dtype)
|
||||
return np.r_[z_pad, 2 * x[0] - x[n_pad:0:-1], x,
|
||||
2 * x[-1] - x[-2:-n_pad - 2:-1], z_pad]
|
||||
return np.concatenate([z_pad, 2 * x[0] - x[n_pad:0:-1], x,
|
||||
2 * x[-1] - x[-2:-n_pad - 2:-1], z_pad])
|
||||
|
||||
@@ -9,6 +9,7 @@ import os.path as op
|
||||
|
||||
from nose.tools import assert_equal, assert_true, assert_raises
|
||||
import numpy as np
|
||||
from numpy.testing import assert_array_equal
|
||||
|
||||
from mne import io, Epochs, read_events, pick_types
|
||||
from mne.utils import requires_sklearn, slow_test
|
||||
@@ -180,6 +181,8 @@ def test_generalization_across_time():
|
||||
scores = gat.score()
|
||||
assert_true(scores is gat.scores_)
|
||||
assert_equal(np.shape(gat.scores_), (15, 1))
|
||||
assert_array_equal([tim for ttime in gat.test_times_['times']
|
||||
for tim in ttime], gat.train_times_['times'])
|
||||
|
||||
# Test generalization across conditions
|
||||
gat = GeneralizationAcrossTime(predict_mode='mean-prediction')
|
||||
|
||||
@@ -356,6 +356,7 @@ class GeneralizationAcrossTime(object):
|
||||
if self.test_times == 'diagonal':
|
||||
test_times = _DecodingTime()
|
||||
test_times['slices'] = [[s] for s in self.train_times_['slices']]
|
||||
test_times['times'] = [[s] for s in self.train_times_['times']]
|
||||
elif isinstance(self.test_times, dict):
|
||||
test_times = copy.deepcopy(self.test_times)
|
||||
else:
|
||||
|
||||
+1
-2
@@ -1282,8 +1282,7 @@ class Epochs(_BaseEpochs, ToDataFrameMixin):
|
||||
'event matches all criteria.')
|
||||
select = np.any(np.atleast_2d([epochs._key_match(k)
|
||||
for k in key]), axis=0)
|
||||
epochs.name = ('+'.join(key) if epochs.name == 'Unknown'
|
||||
else 'epochs_%s' % '+'.join(key))
|
||||
epochs.name = '+'.join(key)
|
||||
else:
|
||||
select = key if isinstance(key, slice) else np.atleast_1d(key)
|
||||
|
||||
|
||||
+43
-45
@@ -47,7 +47,7 @@ def _overlap_add_filter(x, h, n_fft=None, zero_phase=True, picks=None,
|
||||
applied in forward and backward direction, resulting in a zero-phase
|
||||
filter.
|
||||
|
||||
WARNING: This operates on the data in-place.
|
||||
.. warning:: This operates on the data in-place.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@@ -77,9 +77,9 @@ def _overlap_add_filter(x, h, n_fft=None, zero_phase=True, picks=None,
|
||||
# Extend the signal by mirroring the edges to reduce transient filter
|
||||
# response
|
||||
n_h = len(h)
|
||||
n_edge = min(n_h, x.shape[1])
|
||||
n_edge = max(min(n_h, x.shape[1]) - 1, 0)
|
||||
|
||||
n_x = x.shape[1] + 2 * n_edge - 2
|
||||
n_x = x.shape[1] + 2 * n_edge
|
||||
|
||||
# Determine FFT length to use
|
||||
if n_fft is None:
|
||||
@@ -112,22 +112,7 @@ def _overlap_add_filter(x, h, n_fft=None, zero_phase=True, picks=None,
|
||||
warnings.warn("FFT length is not a power of 2. Can be slower.")
|
||||
|
||||
# Filter in frequency domain
|
||||
h_fft = fft(np.r_[h, np.zeros(n_fft - n_h, dtype=h.dtype)])
|
||||
|
||||
if zero_phase:
|
||||
# We will apply the filter in forward and backward direction: Scale
|
||||
# frequency response of the filter so that the shape of the amplitude
|
||||
# response stays the same when it is applied twice
|
||||
|
||||
# be careful not to divide by too small numbers
|
||||
idx = np.where(np.abs(h_fft) > 1e-6)
|
||||
h_fft[idx] = h_fft[idx] / np.sqrt(np.abs(h_fft[idx]))
|
||||
|
||||
# Segment length for signal x
|
||||
n_seg = n_fft - n_h + 1
|
||||
|
||||
# Number of segments (including fractional segments)
|
||||
n_segments = int(np.ceil(n_x / float(n_seg)))
|
||||
h_fft = fft(np.concatenate([h, np.zeros(n_fft - n_h, dtype=h.dtype)]))
|
||||
|
||||
# Figure out if we should use CUDA
|
||||
n_jobs, cuda_dict, h_fft = setup_cuda_fft_multiply_repeated(n_jobs, h_fft)
|
||||
@@ -135,12 +120,12 @@ def _overlap_add_filter(x, h, n_fft=None, zero_phase=True, picks=None,
|
||||
# Process each row separately
|
||||
if n_jobs == 1:
|
||||
for p in picks:
|
||||
x[p] = _1d_overlap_filter(x[p], h_fft, n_edge, n_fft, zero_phase,
|
||||
n_segments, n_seg, cuda_dict)
|
||||
x[p] = _1d_overlap_filter(x[p], h_fft, n_h, n_edge, zero_phase,
|
||||
cuda_dict)
|
||||
else:
|
||||
parallel, p_fun, _ = parallel_func(_1d_overlap_filter, n_jobs)
|
||||
data_new = parallel(p_fun(x[p], h_fft, n_edge, n_fft, zero_phase,
|
||||
n_segments, n_seg, cuda_dict)
|
||||
data_new = parallel(p_fun(x[p], h_fft, n_h, n_edge, zero_phase,
|
||||
cuda_dict)
|
||||
for p in picks)
|
||||
for pp, p in enumerate(picks):
|
||||
x[p] = data_new[pp]
|
||||
@@ -148,39 +133,48 @@ def _overlap_add_filter(x, h, n_fft=None, zero_phase=True, picks=None,
|
||||
return x
|
||||
|
||||
|
||||
def _1d_overlap_filter(x, h_fft, n_edge, n_fft, zero_phase, n_segments, n_seg,
|
||||
cuda_dict):
|
||||
def _1d_overlap_filter(x, h_fft, n_h, n_edge, zero_phase, cuda_dict):
|
||||
"""Do one-dimensional overlap-add FFT FIR filtering"""
|
||||
# pad to reduce ringing
|
||||
x_ext = _smart_pad(x, n_edge - 1)
|
||||
if cuda_dict['use_cuda']:
|
||||
n_fft = cuda_dict['x'].size # account for CUDA's modification of h_fft
|
||||
else:
|
||||
n_fft = len(h_fft)
|
||||
x_ext = _smart_pad(x, n_edge)
|
||||
n_x = len(x_ext)
|
||||
filter_input = x_ext
|
||||
x_filtered = np.zeros_like(filter_input)
|
||||
|
||||
for pass_no in list(range(2)) if zero_phase else list(range(1)):
|
||||
# Segment length for signal x
|
||||
n_seg = n_fft - n_h + 1
|
||||
|
||||
# Number of segments (including fractional segments)
|
||||
n_segments = int(np.ceil(n_x / float(n_seg)))
|
||||
|
||||
for pass_no in list(range(2 if zero_phase else 1)):
|
||||
|
||||
if pass_no == 1:
|
||||
# second pass: flip signal
|
||||
filter_input = np.flipud(x_filtered)
|
||||
filter_input = x_filtered[::-1]
|
||||
x_filtered = np.zeros_like(x_ext)
|
||||
|
||||
for seg_idx in range(n_segments):
|
||||
seg = filter_input[seg_idx * n_seg:(seg_idx + 1) * n_seg]
|
||||
seg = np.r_[seg, np.zeros(n_fft - len(seg))]
|
||||
start = seg_idx * n_seg
|
||||
stop = (seg_idx + 1) * n_seg
|
||||
seg = filter_input[start:stop]
|
||||
seg = np.concatenate([seg, np.zeros(n_fft - len(seg))])
|
||||
prod = fft_multiply_repeated(h_fft, seg, cuda_dict)
|
||||
|
||||
if seg_idx * n_seg + n_fft < n_x:
|
||||
x_filtered[seg_idx * n_seg:seg_idx * n_seg + n_fft] += prod
|
||||
x_filtered[start:start + n_fft] += prod
|
||||
else:
|
||||
# Last segment
|
||||
x_filtered[seg_idx * n_seg:] += prod[:n_x - seg_idx * n_seg]
|
||||
|
||||
# Remove mirrored edges that we added
|
||||
x_filtered = x_filtered[n_edge - 1:-n_edge + 1]
|
||||
|
||||
if zero_phase:
|
||||
# flip signal back
|
||||
x_filtered = np.flipud(x_filtered)
|
||||
x_filtered[start:] += prod[:n_x - seg_idx * n_seg]
|
||||
|
||||
# Remove mirrored edges that we added, flip back if necessary, cast
|
||||
if n_edge > 0:
|
||||
x_filtered = x_filtered[n_edge:-n_edge]
|
||||
x_filtered = x_filtered[::-1] if zero_phase else x_filtered
|
||||
x_filtered = x_filtered.astype(x.dtype)
|
||||
return x_filtered
|
||||
|
||||
@@ -307,16 +301,16 @@ def _filter(x, Fs, freq, gain, filter_length='10s', picks=None, n_jobs=1,
|
||||
|
||||
N = x.shape[1] + (extend_x is True)
|
||||
|
||||
H = firwin2(N, freq, gain)[np.newaxis, :]
|
||||
h = firwin2(N, freq, gain)[np.newaxis, :]
|
||||
|
||||
att_db, att_freq = _filter_attenuation(H, freq, gain)
|
||||
att_db, att_freq = _filter_attenuation(h, freq, gain)
|
||||
if att_db < min_att_db:
|
||||
att_freq *= Fs / 2
|
||||
warnings.warn('Attenuation at stop frequency %0.1fHz is only '
|
||||
'%0.1fdB.' % (att_freq, att_db))
|
||||
|
||||
# Make zero-phase filter function
|
||||
B = np.abs(fft(H)).ravel()
|
||||
B = np.abs(fft(h)).ravel()
|
||||
|
||||
# Figure out if we should use CUDA
|
||||
n_jobs, cuda_dict, B = setup_cuda_fft_multiply_repeated(n_jobs, B)
|
||||
@@ -339,9 +333,10 @@ def _filter(x, Fs, freq, gain, filter_length='10s', picks=None, n_jobs=1,
|
||||
# Gain at Nyquist freq: 1: make N EVEN, 0: make N ODD
|
||||
N += 1
|
||||
|
||||
H = firwin2(N, freq, gain)
|
||||
# construct filter with gain resulting from forward-backward filtering
|
||||
h = firwin2(N, freq, gain, window='hann')
|
||||
|
||||
att_db, att_freq = _filter_attenuation(H, freq, gain)
|
||||
att_db, att_freq = _filter_attenuation(h, freq, gain)
|
||||
att_db += 6 # the filter is applied twice (zero phase)
|
||||
if att_db < min_att_db:
|
||||
att_freq *= Fs / 2
|
||||
@@ -349,7 +344,10 @@ def _filter(x, Fs, freq, gain, filter_length='10s', picks=None, n_jobs=1,
|
||||
'%0.1fdB. Increase filter_length for higher '
|
||||
'attenuation.' % (att_freq, att_db))
|
||||
|
||||
x = _overlap_add_filter(x, H, zero_phase=True, picks=picks,
|
||||
# reconstruct filter, this time with appropriate gain for fwd-bkwd
|
||||
gain = np.sqrt(gain)
|
||||
h = firwin2(N, freq, gain, window='hann')
|
||||
x = _overlap_add_filter(x, h, zero_phase=True, picks=picks,
|
||||
n_jobs=n_jobs)
|
||||
|
||||
x.shape = orig_shape
|
||||
|
||||
+1
-1
@@ -978,7 +978,7 @@ class Report(object):
|
||||
html = self._render_bem(subject=subject, subjects_dir=subjects_dir,
|
||||
decim=decim, n_jobs=n_jobs, section=section,
|
||||
caption=caption)
|
||||
html, caption = self._validate_input(html, caption, section)
|
||||
html, caption, _ = self._validate_input(html, caption, section)
|
||||
sectionvar = self._sectionvars[section]
|
||||
|
||||
self.fnames.append('%s-#-%s-#-custom' % (caption[0], sectionvar))
|
||||
|
||||
@@ -144,6 +144,7 @@ def test_epoch_combine_ids():
|
||||
tmin, tmax, picks=picks, preload=False)
|
||||
events_new = merge_events(events, [1, 2], 12)
|
||||
epochs_new = combine_event_ids(epochs, ['a', 'b'], {'ab': 12})
|
||||
assert_equal(epochs_new['ab'].name, 'ab')
|
||||
assert_array_equal(events_new, epochs_new.events)
|
||||
# should probably add test + functionality for non-replacement XXX
|
||||
|
||||
@@ -958,6 +959,10 @@ def test_access_by_name():
|
||||
assert_array_equal(epochs.events, epochs6.events)
|
||||
assert_array_almost_equal(epochs.get_data(), epochs6.get_data(), 20)
|
||||
|
||||
# Make sure we preserve names
|
||||
assert_equal(epochs['a'].name, 'a')
|
||||
assert_equal(epochs[['a', 'b']]['a'].name, 'a')
|
||||
|
||||
|
||||
@requires_pandas
|
||||
def test_to_data_frame():
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import numpy as np
|
||||
from numpy.testing import (assert_array_almost_equal, assert_almost_equal,
|
||||
assert_array_equal)
|
||||
assert_array_equal, assert_allclose)
|
||||
from nose.tools import assert_equal, assert_true, assert_raises
|
||||
import os.path as op
|
||||
import warnings
|
||||
@@ -144,7 +144,11 @@ def test_filters():
|
||||
lp_oa = low_pass_filter(a, sfreq, 8, filter_length)
|
||||
hp_oa = high_pass_filter(lp_oa, sfreq, 4, filter_length)
|
||||
assert_array_almost_equal(hp_oa, bp_oa, 2)
|
||||
assert_array_almost_equal(bp_oa + bs_oa, a, 2)
|
||||
# Our filters are no longer quite complementary with linear rolloffs :(
|
||||
# this is the tradeoff for stability of the filtering
|
||||
# obtained by directly using the result of firwin2 instead of
|
||||
# modifying it...
|
||||
assert_array_almost_equal(bp_oa + bs_oa, a, 1)
|
||||
|
||||
# The two methods should give the same result
|
||||
# As filtering for short signals uses a circular convolution (FFT) and
|
||||
@@ -206,6 +210,19 @@ def test_filters():
|
||||
assert_raises(ValueError, band_pass_filter, a, sfreq, Fp1=4, Fp2=8,
|
||||
picks=np.array([0, 1]))
|
||||
|
||||
# test that our overlap-add filtering doesn't introduce strange
|
||||
# artifacts (from mne_analyze mailing list 2015/06/25)
|
||||
N = 300
|
||||
sfreq = 100.
|
||||
lp = 10.
|
||||
sine_freq = 1.
|
||||
x = np.ones(N)
|
||||
x += np.sin(2 * np.pi * sine_freq * np.arange(N) / sfreq)
|
||||
with warnings.catch_warnings(record=True): # filter attenuation
|
||||
x_filt = low_pass_filter(x, sfreq, lp, '1s')
|
||||
# the firwin2 function gets us this close
|
||||
assert_allclose(x, x_filt, rtol=1e-3, atol=1e-3)
|
||||
|
||||
|
||||
def test_cuda():
|
||||
"""Test CUDA-based filtering
|
||||
|
||||
+7
-4
@@ -152,13 +152,12 @@ def _mouse_click(event, params):
|
||||
"""Vertical select callback"""
|
||||
if event.inaxes is None or event.button != 1:
|
||||
return
|
||||
plot_fun = params['plot_fun']
|
||||
# vertical scrollbar changed
|
||||
if event.inaxes == params['ax_vscroll']:
|
||||
ch_start = max(int(event.ydata) - params['n_channels'] // 2, 0)
|
||||
if params['ch_start'] != ch_start:
|
||||
params['ch_start'] = ch_start
|
||||
plot_fun()
|
||||
params['plot_fun']()
|
||||
# horizontal scrollbar changed
|
||||
elif event.inaxes == params['ax_hscroll']:
|
||||
_plot_raw_time(event.xdata - params['duration'] / 2, params)
|
||||
@@ -315,6 +314,11 @@ def _plot_traces(params, inds, color, bad_color, lines, event_lines,
|
||||
params['ax'].set_yticklabels(tick_list)
|
||||
params['vsel_patch'].set_y(params['ch_start'])
|
||||
params['fig'].canvas.draw()
|
||||
# XXX This is a hack to make sure this figure gets drawn last
|
||||
# so that when matplotlib goes to calculate bounds we don't get a
|
||||
# CGContextRef error on the MacOSX backend :(
|
||||
if params['fig_proj'] is not None:
|
||||
params['fig_proj'].canvas.draw()
|
||||
|
||||
|
||||
def plot_raw(raw, events=None, duration=10.0, start=0.0, n_channels=None,
|
||||
@@ -516,7 +520,7 @@ def plot_raw(raw, events=None, duration=10.0, start=0.0, n_channels=None,
|
||||
info=info, projs=projs, remove_dc=remove_dc, ba=ba,
|
||||
n_channels=n_channels, scalings=scalings, types=types,
|
||||
n_times=n_times, event_times=event_times,
|
||||
event_nums=event_nums, clipping=clipping)
|
||||
event_nums=event_nums, clipping=clipping, fig_proj=None)
|
||||
|
||||
# set up plotting
|
||||
size = get_config('MNE_BROWSE_RAW_SIZE')
|
||||
@@ -623,7 +627,6 @@ def plot_raw(raw, events=None, duration=10.0, start=0.0, n_channels=None,
|
||||
_layout_raw(params)
|
||||
|
||||
# deal with projectors
|
||||
params['fig_opts'] = None
|
||||
if show_options is True:
|
||||
_toggle_options(None, params)
|
||||
|
||||
|
||||
+21
-28
@@ -63,21 +63,19 @@ def tight_layout(pad=1.2, h_pad=None, w_pad=None, fig=None):
|
||||
Figure to apply changes to.
|
||||
"""
|
||||
import matplotlib.pyplot as plt
|
||||
if fig is None:
|
||||
fig = plt.gcf()
|
||||
fig = plt.gcf() if fig is None else fig
|
||||
|
||||
fig.canvas.draw()
|
||||
try: # see https://github.com/matplotlib/matplotlib/issues/2654
|
||||
fig.canvas.draw()
|
||||
fig.tight_layout(pad=pad, h_pad=h_pad, w_pad=w_pad)
|
||||
except:
|
||||
msg = ('Matplotlib function \'tight_layout\'%s.'
|
||||
' Skipping subpplot adjusment.')
|
||||
if not hasattr(plt, 'tight_layout'):
|
||||
case = ' is not available'
|
||||
else:
|
||||
case = (' is not supported by your backend: `%s`'
|
||||
% plt.get_backend())
|
||||
warn(msg % case)
|
||||
except Exception:
|
||||
warn('Matplotlib function \'tight_layout\' is not supported.'
|
||||
' Skipping subplot adjusment.')
|
||||
else:
|
||||
try:
|
||||
fig.set_tight_layout(dict(pad=pad, h_pad=h_pad, w_pad=w_pad))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _check_delayed_ssp(container):
|
||||
@@ -183,13 +181,13 @@ def _toggle_options(event, params):
|
||||
"""Toggle options (projectors) dialog"""
|
||||
import matplotlib.pyplot as plt
|
||||
if len(params['projs']) > 0:
|
||||
if params['fig_opts'] is None:
|
||||
if params['fig_proj'] is None:
|
||||
_draw_proj_checkbox(event, params, draw_current_state=False)
|
||||
else:
|
||||
# turn off options dialog
|
||||
plt.close(params['fig_opts'])
|
||||
plt.close(params['fig_proj'])
|
||||
del params['proj_checks']
|
||||
params['fig_opts'] = None
|
||||
params['fig_proj'] = None
|
||||
|
||||
|
||||
def _toggle_proj(event, params):
|
||||
@@ -235,8 +233,7 @@ def _prepare_trellis(n_cells, max_col):
|
||||
|
||||
def _draw_proj_checkbox(event, params, draw_current_state=True):
|
||||
"""Toggle options (projectors) dialog"""
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib as mpl
|
||||
from matplotlib import widgets
|
||||
projs = params['projs']
|
||||
# turn on options dialog
|
||||
|
||||
@@ -248,13 +245,10 @@ def _draw_proj_checkbox(event, params, draw_current_state=True):
|
||||
height = len(projs) / 6.0 + 0.5
|
||||
fig_proj = figure_nobar(figsize=(width, height))
|
||||
fig_proj.canvas.set_window_title('SSP projection vectors')
|
||||
ax_temp = plt.axes((0, 0, 1, 1))
|
||||
ax_temp.get_yaxis().set_visible(False)
|
||||
ax_temp.get_xaxis().set_visible(False)
|
||||
fig_proj.add_axes(ax_temp)
|
||||
params['fig_proj'] = fig_proj # necessary for proper toggling
|
||||
ax_temp = fig_proj.add_axes((0, 0, 1, 1), frameon=False)
|
||||
|
||||
proj_checks = mpl.widgets.CheckButtons(ax_temp, labels=labels,
|
||||
actives=actives)
|
||||
proj_checks = widgets.CheckButtons(ax_temp, labels=labels, actives=actives)
|
||||
# change already-applied projectors to red
|
||||
for ii, p in enumerate(projs):
|
||||
if p['active'] is True:
|
||||
@@ -326,11 +320,10 @@ def compare_fiff(fname_1, fname_2, fname_out=None, show=True, indent=' ',
|
||||
|
||||
def figure_nobar(*args, **kwargs):
|
||||
"""Make matplotlib figure with no toolbar"""
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib as mpl
|
||||
old_val = mpl.rcParams['toolbar']
|
||||
from matplotlib import rcParams, pyplot as plt
|
||||
old_val = rcParams['toolbar']
|
||||
try:
|
||||
mpl.rcParams['toolbar'] = 'none'
|
||||
rcParams['toolbar'] = 'none'
|
||||
fig = plt.figure(*args, **kwargs)
|
||||
# remove button press catchers (for toolbar)
|
||||
cbs = list(fig.canvas.callbacks.callbacks['key_press_event'].keys())
|
||||
@@ -339,7 +332,7 @@ def figure_nobar(*args, **kwargs):
|
||||
except Exception as ex:
|
||||
raise ex
|
||||
finally:
|
||||
mpl.rcParams['toolbar'] = old_val
|
||||
rcParams['toolbar'] = old_val
|
||||
return fig
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user