diff --git a/MANIFEST.in b/MANIFEST.in index 581a8c905d0..1d887d8beca 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -7,12 +7,13 @@ recursive-include mne *.py recursive-include mne/data *.dat recursive-include mne/data *.sel recursive-include mne/data *.fif.gz -recursive-include mne/montages *.elc -recursive-include mne/montages *.txt -recursive-include mne/montages *.csd -recursive-include mne/montages *.sfp -recursive-include mne/layouts *.lout -recursive-include mne/layouts *.lay +recursive-include mne/channels/data/montages *.elc +recursive-include mne/channels/data/montages *.txt +recursive-include mne/channels/data/montages *.csd +recursive-include mne/channels/data/montages *.sfp +recursive-include mne/channels/data/layouts *.lout +recursive-include mne/channels/data/layouts *.lay +recursive-include mne/channels/data/neighbors *.mat recursive-include mne/html *.js recursive-include mne/html *.css recursive-exclude examples/MNE-sample-data * diff --git a/doc/source/python_reference.rst b/doc/source/python_reference.rst index 0eb83843419..26f6b47ec62 100644 --- a/doc/source/python_reference.rst +++ b/doc/source/python_reference.rst @@ -318,9 +318,9 @@ Projections: read_proj write_proj -Set sensors locations for processing and plotting: +Manipulate channels and set sensors locations for processing and plotting: -.. currentmodule:: mne.montages +.. currentmodule:: mne.channels .. autosummary:: :toctree: generated/ @@ -328,17 +328,14 @@ Set sensors locations for processing and plotting: read_montage apply_montage - -.. currentmodule:: mne.layouts - -.. autosummary:: - :toctree: generated/ - :template: function.rst - read_layout find_layout make_eeg_layout make_grid_layout + read_ch_connectivity + equalize_channels + rename_channels + ch_neighbor_connectivity :py:mod:`mne.preprocessing`: diff --git a/doc/source/whats_new.rst b/doc/source/whats_new.rst index f08cdec14cc..35d6a63f158 100644 --- a/doc/source/whats_new.rst +++ b/doc/source/whats_new.rst @@ -31,6 +31,8 @@ Changelog - Add support for montage files by `Denis Engemann`_, `Marijn van Vliet`_ and `Alex Gramfort`_. + - Add support for spatiotemporal permutation clustering on sensors by `Denis Engemann`_ + BUG ~~~ @@ -60,6 +62,9 @@ API - find_events and read_events functions have a new parameter `mask` to set some bits to a don't care state by `Teon Brooks`_ + - New channels module including layouts, electrode montages, and neighbor definitions of sensors which deprecates + ``mne.layouts`` by `Denis Engemann`_ + .. _changes_0_8: diff --git a/examples/stats/plot_spatio_temporal_cluster_stats_sensor.py b/examples/stats/plot_spatio_temporal_cluster_stats_sensor.py index df7f432fd21..e9d7e6f3a6a 100644 --- a/examples/stats/plot_spatio_temporal_cluster_stats_sensor.py +++ b/examples/stats/plot_spatio_temporal_cluster_stats_sensor.py @@ -1,10 +1,14 @@ """ -====================================================== -Spatio-temporal permutation F-test on full sensor data -====================================================== +===================================================== +Spatiotemporal permutation F-test on full sensor data +===================================================== Tests for differential evoked responses in at least -one condition. +one condition using a permutation clustering test. +The the FieldTrip neighbor templates will be used to determine +the adjacency between sensors. This serves as a spatial prior +to the clustering. Significant spatiotemporal clusters will then +visualized using custom matplotlib code. """ # Authors: Denis Engemann @@ -21,6 +25,7 @@ from mne.datasets import sample ############################################################################### + # Set parameters data_path = sample.data_path() raw_fname = data_path + '/MEG/sample/sample_audvis_filt-0-40_raw.fif' @@ -50,16 +55,18 @@ X = [epochs[k].get_data() for k in condition_names] # as 3D matrix X = [np.transpose(x, (0, 2, 1)) for x in X] # transpose for clustering -from mne.channels import read_ch_connectivity -connectivity = read_ch_connectivity('neuromag306mag_neighb.mat') +# load FieldTrip neighbor definition to setup sensor connectivity +from mne.channels import read_ch_connectivity +connectivity = read_ch_connectivity('neuromag306mag_neighb') ############################################################################### # Compute statistic +# set cluster threshold +threshold = 50.0 # very high, but the test is quite sensitive on this data # set family-wise p-value p_accept = 0.001 -threshold = 50.0 # unrealistic high, but the test is sensitive on this data cluster_stats = spatio_temporal_cluster_test(X, n_permutations=1000, threshold=threshold, tail=1, @@ -68,17 +75,13 @@ T_obs, clusters, p_values, _ = cluster_stats good_cluster_inds = np.where(p_values < p_accept)[0] - -# get sensor positions via layout -pos = mne.layouts.find_layout(epochs.info).pos - - ############################################################################### # Visualize clusters -# load viz libraries +# load viz functionality import matplotlib.pyplot as plt from mpl_toolkits.axes_grid1 import make_axes_locatable +from mne.viz import plot_topomap # configure variables for visualization times = epochs.times * 1e3 @@ -88,67 +91,63 @@ # grand average as numpy arrray grand_ave = np.array(X).mean(1) -for i_clu, clu_idx in enumerate(good_cluster_inds): - good_clu = np.squeeze(clusters[clu_idx]) - time_inds, space_inds = good_clu - - title = 'Cluster #{0}'.format(i_clu + 1) +# get sensor positions via layout +pos = mne.layouts.find_layout(epochs.info).pos - # get unique indices from cluster +# loop over significant clusters +for i_clu, clu_idx in enumerate(good_cluster_inds): + # unpack cluster infomation, get unique indices + time_inds, space_inds = np.squeeze(clusters[clu_idx]) ch_inds = np.unique(space_inds) time_inds = np.unique(time_inds) - + # get topography for F stat f_map = T_obs[time_inds, ...].mean(0) - + # get signals at significant sensors signals = grand_ave[..., ch_inds].mean(-1) sig_times = times[time_inds] - + # create spatial mask mask = np.zeros((f_map.shape[0], 1), dtype=bool) mask[ch_inds, :] = True + # initialize figure fig, ax_topo = plt.subplots(1, 1, figsize=(20, 5)) + title = 'Cluster #{0}'.format(i_clu + 1) fig.suptitle(title, fontsize=20) - - # plot topo image - image, _ = mne.viz.plot_topomap(f_map, pos, mask=mask, axis=ax_topo, - cmap='Reds', vmin=np.min, vmax=np.max) - + + # plot average test statistic and mark significant sensors + image, _ = plot_topomap(f_map, pos, mask=mask, axis=ax_topo, + cmap='Reds', vmin=np.min, vmax=np.max) + # advanced matplotlib for showing image with figure and colorbar # in one plot divider = make_axes_locatable(ax_topo) - + # add axes for colorbar ax_colorbar = divider.append_axes('right', size='5%', pad=0.05) plt.colorbar(image, cax=ax_colorbar) - ax_topo.set_xlabel('Averaged F-map ({:0.1f} - {:0.1f} ms)'.format( *sig_times[[0, -1]] )) - - # add new axis for time courses + + # add new axis for time courses and plot time courses ax_signals = divider.append_axes('right', size='300%', pad=1.2) - - # plot time courses - for signal, name, col, ls in zip(signals, - condition_names, - colors, + for signal, name, col, ls in zip(signals, condition_names, colors, linestyles): - ax_signals.plot(times, signal, color=col, - linestyle=ls, label=name) + ax_signals.plot(times, signal, color=col, linestyle=ls, label=name) # add information ax_signals.axvline(0, color='k', linestyle=':', label='stimulus onset') ax_signals.set_xlim(*times[[0, -1]]) ax_signals.set_xlabel('time [ms]') ax_signals.set_ylabel('evoked magnetic fields [fT]') - + + # plot significant time range ymin, ymax = ax_signals.get_ylim() - ax_signals.fill_betweenx((ymin, ymax), sig_times[0], - sig_times[-1], - color='orange', alpha=0.3) + ax_signals.fill_betweenx((ymin, ymax), sig_times[0], sig_times[-1], + color='orange', alpha=0.3) ax_signals.legend(loc='lower right') ax_signals.set_ylim(ymin, ymax) diff --git a/mne/__init__.py b/mne/__init__.py index 55ec018a469..21872d3e592 100644 --- a/mne/__init__.py +++ b/mne/__init__.py @@ -56,9 +56,9 @@ compute_proj_evoked, compute_proj_raw, sensitivity_map) from .selection import read_selection from .dipole import read_dip -from .layouts.layout import find_layout +from . import channels from .channels import (equalize_channels, rename_channels, - read_ch_connectivity) + read_ch_connectivity, find_layout) from . import beamformer from . import commands @@ -80,7 +80,6 @@ from . import viz from . import decoding from . import realtime -from . import montages # initialize logging set_log_level(None, False) diff --git a/mne/channels/__init__.py b/mne/channels/__init__.py new file mode 100644 index 00000000000..57e7a7e3991 --- /dev/null +++ b/mne/channels/__init__.py @@ -0,0 +1,5 @@ +from .layout import (Layout, make_eeg_layout, make_grid_layout, read_layout, + find_layout, read_montage, apply_montage) + +from . channels import (equalize_channels, rename_channels, + read_ch_connectivity, ch_neighbor_connectivity) diff --git a/mne/channels.py b/mne/channels/channels.py similarity index 94% rename from mne/channels.py rename to mne/channels/channels.py index ef939e76c1f..2951005fa3c 100644 --- a/mne/channels.py +++ b/mne/channels/channels.py @@ -12,11 +12,11 @@ from scipy.io import loadmat from scipy import sparse -from .externals.six import string_types +from ..externals.six import string_types -from .utils import verbose, logger -from .io.pick import channel_type, pick_info -from .io.constants import FIFF +from ..utils import verbose, logger +from ..io.pick import channel_type, pick_info +from ..io.constants import FIFF def _get_meg_system(info): @@ -92,10 +92,10 @@ def equalize_channels(candidates, verbose=None): Note. This function operates inplace. """ - from .io.base import _BaseRaw - from .epochs import Epochs - from .evoked import Evoked - from .time_frequency import AverageTFR + from ..io.base import _BaseRaw + from ..epochs import Epochs + from ..evoked import Evoked + from ..time_frequency import AverageTFR if not all([isinstance(c, (_BaseRaw, Epochs, Evoked, AverageTFR)) for c in candidates]): @@ -176,10 +176,10 @@ def drop_channels(self, ch_names, copy=False): def _pick_drop_channels(self, idx): # avoid circular imports - from .io.base import _BaseRaw - from .epochs import Epochs - from .evoked import Evoked - from .time_frequency import AverageTFR + from ..io.base import _BaseRaw + from ..epochs import Epochs + from ..evoked import Evoked + from ..time_frequency import AverageTFR if isinstance(self, (_BaseRaw, Epochs)): if not self.preload: @@ -283,6 +283,10 @@ def _recursive_flatten(cell, dtype): def read_ch_connectivity(fname, picks=None): """Parse FieldTrip neighbors .mat file + More information on these neighbor definitions can be found on the + related FieldTrip documentation pages: + http://fieldtrip.fcdonders.nl/template/neighbours + Parameters ---------- fname : str @@ -298,9 +302,9 @@ def read_ch_connectivity(fname, picks=None): """ if not op.isabs(fname): templates_dir = op.realpath(op.join(op.dirname(__file__), - 'neighbors')) + 'data', 'neighbors')) templates = os.listdir(templates_dir) - if not any(f not in templates for f in (fname, fname + '.mat')): + if not any(f in templates for f in (fname, fname + '.mat')): raise ValueError('I do not know about this neighbor ' 'template: "{}"'.format(fname)) else: diff --git a/mne/layouts/CTF-275.lout b/mne/channels/data/layouts/CTF-275.lout similarity index 100% rename from mne/layouts/CTF-275.lout rename to mne/channels/data/layouts/CTF-275.lout diff --git a/mne/layouts/CTF151.lay b/mne/channels/data/layouts/CTF151.lay similarity index 100% rename from mne/layouts/CTF151.lay rename to mne/channels/data/layouts/CTF151.lay diff --git a/mne/layouts/CTF275.lay b/mne/channels/data/layouts/CTF275.lay similarity index 100% rename from mne/layouts/CTF275.lay rename to mne/channels/data/layouts/CTF275.lay diff --git a/mne/layouts/EEG1005.lay b/mne/channels/data/layouts/EEG1005.lay similarity index 100% rename from mne/layouts/EEG1005.lay rename to mne/channels/data/layouts/EEG1005.lay diff --git a/mne/layouts/EGI256.lout b/mne/channels/data/layouts/EGI256.lout similarity index 100% rename from mne/layouts/EGI256.lout rename to mne/channels/data/layouts/EGI256.lout diff --git a/mne/layouts/KIT-157.lout b/mne/channels/data/layouts/KIT-157.lout similarity index 99% rename from mne/layouts/KIT-157.lout rename to mne/channels/data/layouts/KIT-157.lout index 39d7d6bebc1..2cf5637b843 100644 --- a/mne/layouts/KIT-157.lout +++ b/mne/channels/data/layouts/KIT-157.lout @@ -1,4 +1,4 @@ --42.19 43.52 -41.7 28.71 +-42.19 43.52 -41.7 28.71 001 9.78 -14.18 4.00 3.00 MEG 001 002 3.31 -16.56 4.00 3.00 MEG 002 003 12.02 -19.42 4.00 3.00 MEG 003 diff --git a/mne/layouts/Vectorview-all.lout b/mne/channels/data/layouts/Vectorview-all.lout similarity index 100% rename from mne/layouts/Vectorview-all.lout rename to mne/channels/data/layouts/Vectorview-all.lout diff --git a/mne/layouts/Vectorview-grad.lout b/mne/channels/data/layouts/Vectorview-grad.lout similarity index 100% rename from mne/layouts/Vectorview-grad.lout rename to mne/channels/data/layouts/Vectorview-grad.lout diff --git a/mne/layouts/Vectorview-mag.lout b/mne/channels/data/layouts/Vectorview-mag.lout similarity index 100% rename from mne/layouts/Vectorview-mag.lout rename to mne/channels/data/layouts/Vectorview-mag.lout diff --git a/mne/layouts/biosemi.lay b/mne/channels/data/layouts/biosemi.lay similarity index 100% rename from mne/layouts/biosemi.lay rename to mne/channels/data/layouts/biosemi.lay diff --git a/mne/layouts/magnesWH3600.lout b/mne/channels/data/layouts/magnesWH3600.lout similarity index 100% rename from mne/layouts/magnesWH3600.lout rename to mne/channels/data/layouts/magnesWH3600.lout diff --git a/mne/montages/10-5-System_Mastoids_EGI129.csd b/mne/channels/data/montages/10-5-System_Mastoids_EGI129.csd similarity index 100% rename from mne/montages/10-5-System_Mastoids_EGI129.csd rename to mne/channels/data/montages/10-5-System_Mastoids_EGI129.csd diff --git a/mne/montages/EGI_256.csd b/mne/channels/data/montages/EGI_256.csd similarity index 100% rename from mne/montages/EGI_256.csd rename to mne/channels/data/montages/EGI_256.csd diff --git a/mne/montages/GSN-HydroCel-128.sfp b/mne/channels/data/montages/GSN-HydroCel-128.sfp similarity index 100% rename from mne/montages/GSN-HydroCel-128.sfp rename to mne/channels/data/montages/GSN-HydroCel-128.sfp diff --git a/mne/montages/GSN-HydroCel-129.sfp b/mne/channels/data/montages/GSN-HydroCel-129.sfp similarity index 100% rename from mne/montages/GSN-HydroCel-129.sfp rename to mne/channels/data/montages/GSN-HydroCel-129.sfp diff --git a/mne/montages/GSN-HydroCel-256.sfp b/mne/channels/data/montages/GSN-HydroCel-256.sfp similarity index 100% rename from mne/montages/GSN-HydroCel-256.sfp rename to mne/channels/data/montages/GSN-HydroCel-256.sfp diff --git a/mne/montages/GSN-HydroCel-257.sfp b/mne/channels/data/montages/GSN-HydroCel-257.sfp similarity index 100% rename from mne/montages/GSN-HydroCel-257.sfp rename to mne/channels/data/montages/GSN-HydroCel-257.sfp diff --git a/mne/montages/GSN-HydroCel-32.sfp b/mne/channels/data/montages/GSN-HydroCel-32.sfp similarity index 100% rename from mne/montages/GSN-HydroCel-32.sfp rename to mne/channels/data/montages/GSN-HydroCel-32.sfp diff --git a/mne/montages/GSN-HydroCel-64_1.0.sfp b/mne/channels/data/montages/GSN-HydroCel-64_1.0.sfp similarity index 100% rename from mne/montages/GSN-HydroCel-64_1.0.sfp rename to mne/channels/data/montages/GSN-HydroCel-64_1.0.sfp diff --git a/mne/montages/GSN-HydroCel-65_1.0.sfp b/mne/channels/data/montages/GSN-HydroCel-65_1.0.sfp similarity index 100% rename from mne/montages/GSN-HydroCel-65_1.0.sfp rename to mne/channels/data/montages/GSN-HydroCel-65_1.0.sfp diff --git a/mne/montages/easycap-M1.txt b/mne/channels/data/montages/easycap-M1.txt similarity index 100% rename from mne/montages/easycap-M1.txt rename to mne/channels/data/montages/easycap-M1.txt diff --git a/mne/montages/easycap-M10.txt b/mne/channels/data/montages/easycap-M10.txt similarity index 100% rename from mne/montages/easycap-M10.txt rename to mne/channels/data/montages/easycap-M10.txt diff --git a/mne/montages/standard_1005.elc b/mne/channels/data/montages/standard_1005.elc similarity index 100% rename from mne/montages/standard_1005.elc rename to mne/channels/data/montages/standard_1005.elc diff --git a/mne/montages/standard_1020.elc b/mne/channels/data/montages/standard_1020.elc similarity index 100% rename from mne/montages/standard_1020.elc rename to mne/channels/data/montages/standard_1020.elc diff --git a/mne/montages/standard_alphabetic.elc b/mne/channels/data/montages/standard_alphabetic.elc similarity index 100% rename from mne/montages/standard_alphabetic.elc rename to mne/channels/data/montages/standard_alphabetic.elc diff --git a/mne/montages/standard_postfixed.elc b/mne/channels/data/montages/standard_postfixed.elc similarity index 100% rename from mne/montages/standard_postfixed.elc rename to mne/channels/data/montages/standard_postfixed.elc diff --git a/mne/montages/standard_prefixed.elc b/mne/channels/data/montages/standard_prefixed.elc similarity index 100% rename from mne/montages/standard_prefixed.elc rename to mne/channels/data/montages/standard_prefixed.elc diff --git a/mne/montages/standard_primed.elc b/mne/channels/data/montages/standard_primed.elc similarity index 100% rename from mne/montages/standard_primed.elc rename to mne/channels/data/montages/standard_primed.elc diff --git a/mne/channels/data/neighbors/__init__.py b/mne/channels/data/neighbors/__init__.py new file mode 100644 index 00000000000..2ad72a12320 --- /dev/null +++ b/mne/channels/data/neighbors/__init__.py @@ -0,0 +1,6 @@ +# Neighbor definitions for clustering permutation analysis. +# This is a selection of files from http://fieldtrip.fcdonders.nl/template +# Additional definitions can be obtained through the FieldTrip software. +# For additional information on how these definitions were computed, please +# consider the related fieldtrip documentation: +# http://fieldtrip.fcdonders.nl/template/neighbours. \ No newline at end of file diff --git a/mne/neighbors/biosemi16_neighb.mat b/mne/channels/data/neighbors/biosemi16_neighb.mat similarity index 100% rename from mne/neighbors/biosemi16_neighb.mat rename to mne/channels/data/neighbors/biosemi16_neighb.mat diff --git a/mne/neighbors/biosemi32_neighb.mat b/mne/channels/data/neighbors/biosemi32_neighb.mat similarity index 100% rename from mne/neighbors/biosemi32_neighb.mat rename to mne/channels/data/neighbors/biosemi32_neighb.mat diff --git a/mne/neighbors/biosemi64_neighb.mat b/mne/channels/data/neighbors/biosemi64_neighb.mat similarity index 100% rename from mne/neighbors/biosemi64_neighb.mat rename to mne/channels/data/neighbors/biosemi64_neighb.mat diff --git a/mne/neighbors/bti148_neighb.mat b/mne/channels/data/neighbors/bti148_neighb.mat similarity index 100% rename from mne/neighbors/bti148_neighb.mat rename to mne/channels/data/neighbors/bti148_neighb.mat diff --git a/mne/neighbors/bti248_neighb.mat b/mne/channels/data/neighbors/bti248_neighb.mat similarity index 100% rename from mne/neighbors/bti248_neighb.mat rename to mne/channels/data/neighbors/bti248_neighb.mat diff --git a/mne/neighbors/bti248grad_neighb.mat b/mne/channels/data/neighbors/bti248grad_neighb.mat similarity index 100% rename from mne/neighbors/bti248grad_neighb.mat rename to mne/channels/data/neighbors/bti248grad_neighb.mat diff --git a/mne/neighbors/ctf151_neighb.mat b/mne/channels/data/neighbors/ctf151_neighb.mat similarity index 100% rename from mne/neighbors/ctf151_neighb.mat rename to mne/channels/data/neighbors/ctf151_neighb.mat diff --git a/mne/neighbors/ctf275_neighb.mat b/mne/channels/data/neighbors/ctf275_neighb.mat similarity index 100% rename from mne/neighbors/ctf275_neighb.mat rename to mne/channels/data/neighbors/ctf275_neighb.mat diff --git a/mne/neighbors/ctf64_neighb.mat b/mne/channels/data/neighbors/ctf64_neighb.mat similarity index 100% rename from mne/neighbors/ctf64_neighb.mat rename to mne/channels/data/neighbors/ctf64_neighb.mat diff --git a/mne/neighbors/easycap128ch-avg_neighb.mat b/mne/channels/data/neighbors/easycap128ch-avg_neighb.mat similarity index 100% rename from mne/neighbors/easycap128ch-avg_neighb.mat rename to mne/channels/data/neighbors/easycap128ch-avg_neighb.mat diff --git a/mne/neighbors/easycap32ch-avg_neighb.mat b/mne/channels/data/neighbors/easycap32ch-avg_neighb.mat similarity index 100% rename from mne/neighbors/easycap32ch-avg_neighb.mat rename to mne/channels/data/neighbors/easycap32ch-avg_neighb.mat diff --git a/mne/neighbors/easycap64ch-avg_neighb.mat b/mne/channels/data/neighbors/easycap64ch-avg_neighb.mat similarity index 100% rename from mne/neighbors/easycap64ch-avg_neighb.mat rename to mne/channels/data/neighbors/easycap64ch-avg_neighb.mat diff --git a/mne/neighbors/easycapM11_neighb.mat b/mne/channels/data/neighbors/easycapM11_neighb.mat similarity index 100% rename from mne/neighbors/easycapM11_neighb.mat rename to mne/channels/data/neighbors/easycapM11_neighb.mat diff --git a/mne/neighbors/easycapM14_neighb.mat b/mne/channels/data/neighbors/easycapM14_neighb.mat similarity index 100% rename from mne/neighbors/easycapM14_neighb.mat rename to mne/channels/data/neighbors/easycapM14_neighb.mat diff --git a/mne/neighbors/easycapM15_neighb.mat b/mne/channels/data/neighbors/easycapM15_neighb.mat similarity index 100% rename from mne/neighbors/easycapM15_neighb.mat rename to mne/channels/data/neighbors/easycapM15_neighb.mat diff --git a/mne/neighbors/easycapM1_neighb.mat b/mne/channels/data/neighbors/easycapM1_neighb.mat similarity index 100% rename from mne/neighbors/easycapM1_neighb.mat rename to mne/channels/data/neighbors/easycapM1_neighb.mat diff --git a/mne/neighbors/neuromag122_neighb.mat b/mne/channels/data/neighbors/neuromag122_neighb.mat similarity index 100% rename from mne/neighbors/neuromag122_neighb.mat rename to mne/channels/data/neighbors/neuromag122_neighb.mat diff --git a/mne/neighbors/neuromag306mag_neighb.mat b/mne/channels/data/neighbors/neuromag306mag_neighb.mat similarity index 100% rename from mne/neighbors/neuromag306mag_neighb.mat rename to mne/channels/data/neighbors/neuromag306mag_neighb.mat diff --git a/mne/neighbors/neuromag306planar_neighb.mat b/mne/channels/data/neighbors/neuromag306planar_neighb.mat similarity index 100% rename from mne/neighbors/neuromag306planar_neighb.mat rename to mne/channels/data/neighbors/neuromag306planar_neighb.mat diff --git a/mne/layouts/layout.py b/mne/channels/layout.py similarity index 76% rename from mne/layouts/layout.py rename to mne/channels/layout.py index e812b0fe646..b8b26622814 100644 --- a/mne/layouts/layout.py +++ b/mne/channels/layout.py @@ -2,19 +2,22 @@ # Denis Engemann # Martin Luessi # Eric Larson +# Marijn van Vliet # # License: Simplified BSD from collections import defaultdict from itertools import combinations +import os import os.path as op import numpy as np from scipy.spatial.distance import pdist -from ..preprocessing.maxfilter import fit_sphere_to_headshape -from .. import pick_types +from ..io.pick import pick_types from ..io.constants import FIFF from ..utils import _clean_names from ..externals.six.moves import map +from .channels import _contains_ch_type +from ..viz import plot_montage class Layout(object): @@ -136,7 +139,7 @@ def read_layout(kind, path=None, scale=True): The layout """ if path is None: - path = op.dirname(__file__) + path = op.join(op.dirname(__file__), 'data', 'layouts') if not kind.endswith('.lout') and op.exists(op.join(path, kind + '.lout')): kind += '.lout' @@ -200,7 +203,7 @@ def make_eeg_layout(info, radius=0.5, width=None, height=None): raise RuntimeError('Did not find any digitization points in the info. ' 'Cannot generate layout based on the subject\'s ' 'head shape') - + from ..preprocessing.maxfilter import fit_sphere_to_headshape radius_head, origin_head, origin_device = fit_sphere_to_headshape(info) inds = pick_types(info, meg=False, eeg=True, ref_meg=False, exclude='bads') @@ -678,3 +681,193 @@ def _merge_grad_data(data): data = data.reshape((len(data) // 2, 2, -1)) data = np.sqrt(np.sum(data ** 2, axis=1) / 2) return data + + +class Montage(object): + """Montage for EEG cap + + Montages are typically loaded from a file using read_montage. Only use this + class directly if you're constructing a new montage. + + Parameters + ---------- + pos : array, shape (n_channels, 3) + The positions of the channels in 3d. + ch_names : list + The channel names. + kind : str + The type of montage (e.g. 'standard_1005'). + selection : array of int + The indices of the selected channels in the montage file. + """ + def __init__(self, pos, ch_names, kind, selection): + self.pos = pos + self.ch_names = ch_names + self.kind = kind + self.selection = selection + + def __repr__(self): + s = '' + s %= self.kind, len(self.ch_names), ', '.join(self.ch_names[:3]) + return s + + def plot(self, scale_factor=1.5, show_names=False): + """Plot EEG sensor montage + + Parameters + ---------- + scale_factor : float + Determines the size of the points. Defaults to 1.5 + show_names : bool + Whether to show the channel names. Defaults to False + + Returns + ------- + fig : Instance of matplotlib.figure.Figure + The figure object. + """ + return plot_montage(self, scale_factor=scale_factor, + show_names=show_names) + + +def read_montage(kind, ch_names=None, path=None, scale=True): + """Read montage from a file + + Parameters + ---------- + kind : str + The name of the montage file (e.g. kind='easycap-M10' for + 'easycap-M10.txt'). Files with extensions '.elc', '.txt', '.csd' + or '.sfp' are supported. + ch_names : list of str + The names to read. If None, all names are returned. + path : str | None + The path of the folder containing the montage file + scale : bool + Apply useful scaling for out the box plotting using montage.pos + + Returns + ------- + montage : instance of Montage + The montage. + """ + if path is None: + path = op.join(op.dirname(__file__), 'data', 'montages') + if not op.isabs(kind): + supported = ('.elc', '.txt', '.csd', '.sfp') + montages = [op.splitext(f) for f in os.listdir(path)] + montages = [m for m in montages if m[1] in supported and kind == m[0]] + if len(montages) != 1: + raise ValueError('Could not find the montage. Please provide the ' + 'full path.') + kind, ext = montages[0] + fname = op.join(path, kind + ext) + else: + kind, ext = op.splitext(kind) + fname = op.join(path, kind + ext) + + if ext == '.sfp': + # EGI geodesic + dtype = np.dtype('S4, f8, f8, f8') + data = np.loadtxt(fname, dtype=dtype) + pos = np.c_[data['f1'], data['f2'], data['f3']] + ch_names_ = data['f0'] + elif ext == '.elc': + # 10-5 system + ch_names_ = [] + pos = [] + with open(fname) as fid: + for line in fid: + if 'Positions\n' in line: + break + pos = [] + for line in fid: + if 'Labels\n' in line: + break + pos.append(list(map(float, line.split()))) + for line in fid: + if not line or not set(line) - set([' ']): + break + ch_names_.append(line.strip(' ').strip('\n')) + pos = np.array(pos) + elif ext == '.txt': + # easycap + data = np.genfromtxt(fname, dtype='str', skiprows=1) + ch_names_ = list(data[:, 0]) + theta, phi = data[:, 1].astype(float), data[:, 2].astype(float) + x = 85. * np.cos(np.deg2rad(phi)) * np.sin(np.deg2rad(theta)) + y = 85. * np.sin(np.deg2rad(theta)) * np.sin(np.deg2rad(phi)) + z = 85. * np.cos(np.deg2rad(theta)) + pos = np.c_[x, y, z] + elif ext == '.csd': + # CSD toolbox + dtype = [('label', 'S4'), ('theta', 'f8'), ('phi', 'f8'), + ('radius', 'f8'), ('x', 'f8'), ('y', 'f8'), ('z', 'f8'), + ('off_sph', 'f8')] + table = np.loadtxt(fname, skiprows=2, dtype=dtype) + ch_names_ = table['label'] + theta = (2 * np.pi * table['theta']) / 360. + phi = (2 * np.pi * table['phi']) / 360. + pos = _sphere_to_cartesian(theta, phi, r=1.0) + pos = np.asarray(pos).T + else: + raise ValueError('Currently the "%s" template is not supported.' % + kind) + selection = np.arange(len(pos)) + if ch_names is not None: + sel, ch_names_ = zip(*[(i, e) for i, e in enumerate(ch_names_) + if e in ch_names]) + sel = list(sel) + pos = pos[sel] + selection = selection[sel] + else: + ch_names_ = list(ch_names_) + kind = op.split(kind)[-1] + return Montage(pos=pos, ch_names=ch_names_, kind=kind, selection=selection) + + +def apply_montage(info, montage): + """Apply montage to EEG data. + + This function will replace the EEG channel names and locations with + the values specified for the particular montage. + + Note: You have to rename your object to correclty map + the montage names. + + Note: This function will change the info variable in place. + + Parameters + ---------- + info : instance of Info + The measurement info to update. + montage : instance of Montage + The montage to apply. + """ + if not _contains_ch_type(info, 'eeg'): + raise ValueError('No EEG channels found.') + + sensors_found = False + for pos, ch_name in zip(montage.pos, montage.ch_names): + if ch_name not in info['ch_names']: + continue + + ch_idx = info['ch_names'].index(ch_name) + info['ch_names'][ch_idx] = ch_name + info['chs'][ch_idx]['eeg_loc'] = np.c_[pos, [0.] * 3] + info['chs'][ch_idx]['loc'] = np.r_[pos, [0.] * 9] + sensors_found = True + + if not sensors_found: + raise ValueError('None of the sensors defined in the montage were ' + 'found in the info structure. Check the channel ' + 'names.') + + +def _sphere_to_cartesian(theta, phi, r): + """Transform spherical coordinates to cartesian""" + z = r * np.sin(phi) + rcos_phi = r * np.cos(phi) + x = rcos_phi * np.cos(theta) + y = rcos_phi * np.sin(theta) + return x, y, z diff --git a/mne/layouts/tests/__init__.py b/mne/channels/tests/__init__.py similarity index 100% rename from mne/layouts/tests/__init__.py rename to mne/channels/tests/__init__.py diff --git a/mne/tests/test_channels.py b/mne/channels/tests/test_channels.py similarity index 96% rename from mne/tests/test_channels.py rename to mne/channels/tests/test_channels.py index f9735ecee14..63080938c04 100644 --- a/mne/tests/test_channels.py +++ b/mne/channels/tests/test_channels.py @@ -18,7 +18,7 @@ from mne.fixes import partial from mne.utils import _TempDir -base_dir = op.join(op.dirname(__file__), '..', 'io', 'tests', 'data') +base_dir = op.join(op.dirname(__file__), '..', '..', 'io', 'tests', 'data') raw_fname = op.join(base_dir, 'test_raw.fif') @@ -110,3 +110,5 @@ def test_read_ch_connectivity(): neighbors) neighbors = [['EEG02'], 'EEG01', ['EEG 02']] assert_raises(ValueError, ch_neighbor_connectivity, ch_names, neighbors) + read_ch_connectivity('neuromag306mag_neighb') + assert_raises(ValueError, read_ch_connectivity, 'bananas!') \ No newline at end of file diff --git a/mne/layouts/tests/test_layout.py b/mne/channels/tests/test_layout.py similarity index 97% rename from mne/layouts/tests/test_layout.py rename to mne/channels/tests/test_layout.py index 474122a118a..5d1ea2a4843 100644 --- a/mne/layouts/tests/test_layout.py +++ b/mne/channels/tests/test_layout.py @@ -15,9 +15,9 @@ assert_allclose) from nose.tools import assert_true, assert_raises -from mne.layouts import (make_eeg_layout, make_grid_layout, read_layout, - find_layout) -from mne.layouts.layout import _box_size +from mne.channels import (make_eeg_layout, make_grid_layout, read_layout, + find_layout) +from mne.channels.layout import _box_size from mne import pick_types, pick_info from mne.io import Raw @@ -38,7 +38,7 @@ fname_ctf_raw = op.join(op.dirname(__file__), '..', '..', 'io', 'tests', 'data', 'test_ctf_comp_raw.fif') -fname_kit_157 = op.join(op.dirname(__file__), '..', '..', 'io', 'kit', +fname_kit_157 = op.join(op.dirname(__file__), '..', '..', 'io', 'kit', 'tests', 'data', 'test.sqd') test_info = { diff --git a/mne/montages/tests/test_montage.py b/mne/channels/tests/test_montage.py similarity index 97% rename from mne/montages/tests/test_montage.py rename to mne/channels/tests/test_montage.py index 4c3999dc4f7..622c3ba22d3 100644 --- a/mne/montages/tests/test_montage.py +++ b/mne/channels/tests/test_montage.py @@ -5,7 +5,7 @@ import numpy as np from numpy.testing import assert_array_equal, assert_array_almost_equal -from mne.montages import read_montage, apply_montage +from mne.channels import read_montage, apply_montage from mne.utils import _TempDir from mne import create_info diff --git a/mne/epochs.py b/mne/epochs.py index d26c35945e7..63f3c1fb23f 100644 --- a/mne/epochs.py +++ b/mne/epochs.py @@ -32,7 +32,7 @@ from .baseline import rescale from .utils import (check_random_state, _check_pandas_index_arguments, _check_pandas_installed, object_hash) -from .channels import ContainsMixin, PickDropChannelsMixin +from .channels.channels import ContainsMixin, PickDropChannelsMixin from .filter import resample, detrend from .event import _read_events_fif from .fixes import in1d diff --git a/mne/evoked.py b/mne/evoked.py index 155a36eb7d2..76f33b0380c 100644 --- a/mne/evoked.py +++ b/mne/evoked.py @@ -10,7 +10,7 @@ import warnings from .baseline import rescale -from .channels import ContainsMixin, PickDropChannelsMixin +from .channels.channels import ContainsMixin, PickDropChannelsMixin from .filter import resample, detrend from .fixes import in1d from .utils import (_check_pandas_installed, check_fname, logger, verbose, diff --git a/mne/io/base.py b/mne/io/base.py index 075c8082b01..c8de0fec7c0 100644 --- a/mne/io/base.py +++ b/mne/io/base.py @@ -21,7 +21,7 @@ from .meas_info import write_meas_info from .proj import (setup_proj, activate_proj, proj_equal, ProjMixin, _has_eeg_average_ref_proj, make_eeg_average_ref_proj) -from ..channels import ContainsMixin, PickDropChannelsMixin +from ..channels.channels import ContainsMixin, PickDropChannelsMixin from .compensator import set_current_comp from .write import (start_file, end_file, start_block, end_block, write_dau_pack16, write_float, write_double, diff --git a/mne/layouts/__init__.py b/mne/layouts/__init__.py index 58cbdf459fb..8f91cab67de 100644 --- a/mne/layouts/__init__.py +++ b/mne/layouts/__init__.py @@ -1,2 +1,21 @@ -from .layout import (Layout, make_eeg_layout, make_grid_layout, read_layout, - find_layout) +from ..channels import (make_eeg_layout, make_grid_layout, read_layout, + find_layout) +from ..channels import Layout as _Layout + +from ..utils import deprecated as dep + +msg = ('The module ``mne.layouts`` is deprecated and will be removed in ' + 'MNE-Python 0.10. Please import ``{0}`` from ``mne.templates``') + + +dep(msg.format('Layout')) +class Layout(_Layout): + """""" # needed to inherit doc string + __doc__ += _Layout.__doc__ + pass + + +make_eeg_layout = dep(msg.format('make_eeg_layout'))(make_eeg_layout) +make_grid_layout = dep(msg.format('make_grid_layout'))(make_grid_layout) +read_layout = dep(msg.format('read_layout'))(read_layout) +find_layout = dep(msg.format('find_layout'))(find_layout) diff --git a/mne/montages/__init__.py b/mne/montages/__init__.py deleted file mode 100644 index 3f1283743d6..00000000000 --- a/mne/montages/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -"""Module to handle EEG montages""" - -from .montage import read_montage, apply_montage diff --git a/mne/montages/montage.py b/mne/montages/montage.py deleted file mode 100644 index e739f34c93b..00000000000 --- a/mne/montages/montage.py +++ /dev/null @@ -1,202 +0,0 @@ -# Authors: Denis Engemann -# Marijn van Vliet -# Alexandre Gramfort -# -# License: Simplified BSD - -import os -import os.path as op -import numpy as np - -from ..channels import _contains_ch_type -from ..viz import plot_montage - - -class Montage(object): - """Montage for EEG cap - - Montages are typically loaded from a file using read_montage. Only use this - class directly if you're constructing a new montage. - - Parameters - ---------- - pos : array, shape (n_channels, 3) - The positions of the channels in 3d. - ch_names : list - The channel names. - kind : str - The type of montage (e.g. 'standard_1005'). - selection : array of int - The indices of the selected channels in the montage file. - """ - def __init__(self, pos, ch_names, kind, selection): - self.pos = pos - self.ch_names = ch_names - self.kind = kind - self.selection = selection - - def __repr__(self): - s = '' - s %= self.kind, len(self.ch_names), ', '.join(self.ch_names[:3]) - return s - - def plot(self, scale_factor=1.5, show_names=False): - """Plot EEG sensor montage - - Parameters - ---------- - scale_factor : float - Determines the size of the points. Defaults to 1.5 - show_names : bool - Whether to show the channel names. Defaults to False - - Returns - ------- - fig : Instance of matplotlib.figure.Figure - The figure object. - """ - return plot_montage(self, scale_factor=scale_factor, - show_names=show_names) - - -def read_montage(kind, ch_names=None, path=None, scale=True): - """Read montage from a file - - Parameters - ---------- - kind : str - The name of the montage file (e.g. kind='easycap-M10' for - 'easycap-M10.txt'). Files with extensions '.elc', '.txt', '.csd' - or '.sfp' are supported. - ch_names : list of str - The names to read. If None, all names are returned. - path : str | None - The path of the folder containing the montage file - scale : bool - Apply useful scaling for out the box plotting using montage.pos - - Returns - ------- - montage : instance of Montage - The montage. - """ - if path is None: - path = op.dirname(__file__) - if not op.isabs(kind): - supported = ('.elc', '.txt', '.csd', '.sfp') - montages = [op.splitext(f) for f in os.listdir(path)] - montages = [m for m in montages if m[1] in supported and kind == m[0]] - if len(montages) != 1: - raise ValueError('Could not find the montage. Please provide the ' - 'full path.') - kind, ext = montages[0] - fname = op.join(path, kind + ext) - else: - kind, ext = op.splitext(kind) - fname = op.join(path, kind + ext) - - if ext == '.sfp': - # EGI geodesic - dtype = np.dtype('S4, f8, f8, f8') - data = np.loadtxt(fname, dtype=dtype) - pos = np.c_[data['f1'], data['f2'], data['f3']] - ch_names_ = data['f0'].astype(np.str) - elif ext == '.elc': - # 10-5 system - ch_names_ = [] - pos = [] - with open(fname) as fid: - for line in fid: - if 'Positions\n' in line: - break - pos = [] - for line in fid: - if 'Labels\n' in line: - break - pos.append(list(map(float, line.split()))) - for line in fid: - if not line or not set(line) - set([' ']): - break - ch_names_.append(line.strip(' ').strip('\n')) - pos = np.array(pos) - elif ext == '.txt': - # easycap - data = np.genfromtxt(fname, dtype='str', skiprows=1) - ch_names_ = list(data[:, 0]) - theta, phi = data[:, 1].astype(float), data[:, 2].astype(float) - x = 85. * np.cos(np.deg2rad(phi)) * np.sin(np.deg2rad(theta)) - y = 85. * np.sin(np.deg2rad(theta)) * np.sin(np.deg2rad(phi)) - z = 85. * np.cos(np.deg2rad(theta)) - pos = np.c_[x, y, z] - elif ext == '.csd': - # CSD toolbox - dtype = [('label', 'S4'), ('theta', 'f8'), ('phi', 'f8'), - ('radius', 'f8'), ('x', 'f8'), ('y', 'f8'), ('z', 'f8'), - ('off_sph', 'f8')] - table = np.loadtxt(fname, skiprows=2, dtype=dtype) - ch_names_ = table['label'] - theta = (2 * np.pi * table['theta']) / 360. - phi = (2 * np.pi * table['phi']) / 360. - pos = _sphere_to_cartesian(theta, phi, r=1.0) - pos = np.asarray(pos).T - else: - raise ValueError('Currently the "%s" template is not supported.' % - kind) - selection = np.arange(len(pos)) - if ch_names is not None: - sel, ch_names_ = zip(*[(i, e) for i, e in enumerate(ch_names_) - if e in ch_names]) - sel = list(sel) - pos = pos[sel] - selection = selection[sel] - else: - ch_names_ = list(ch_names_) - kind = op.split(kind)[-1] - return Montage(pos=pos, ch_names=ch_names_, kind=kind, selection=selection) - - -def apply_montage(info, montage): - """Apply montage to EEG data. - - This function will replace the EEG channel names and locations with - the values specified for the particular montage. - - Note: You have to rename your object to correclty map - the montage names. - - Note: This function will change the info variable in place. - - Parameters - ---------- - info : instance of Info - The measurement info to update. - montage : instance of Montage - The montage to apply. - """ - if not _contains_ch_type(info, 'eeg'): - raise ValueError('No EEG channels found.') - - sensors_found = False - for pos, ch_name in zip(montage.pos, montage.ch_names): - if ch_name not in info['ch_names']: - continue - - ch_idx = info['ch_names'].index(ch_name) - info['ch_names'][ch_idx] = ch_name - info['chs'][ch_idx]['eeg_loc'] = np.c_[pos, [0.] * 3] - info['chs'][ch_idx]['loc'] = np.r_[pos, [0.] * 9] - sensors_found = True - - if not sensors_found: - raise ValueError('None of the sensors defined in the montage were ' - 'found in the info structure. Check the channel ' - 'names.') - - -def _sphere_to_cartesian(theta, phi, r): - """Transform spherical coordinates to cartesian""" - z = r * np.sin(phi) - rcos_phi = r * np.cos(phi) - x = rcos_phi * np.cos(theta) - y = rcos_phi * np.sin(theta) - return x, y, z diff --git a/mne/montages/tests/__init__.py b/mne/montages/tests/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/mne/neighbors/__init__.py b/mne/neighbors/__init__.py deleted file mode 100644 index 1cacbfd2ff0..00000000000 --- a/mne/neighbors/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# Neighbor definitions for clustering permutation analysis. -# This is a selection of files from https://github.com/fieldtrip/fieldtrip -# Additional definitions can be obtained through the FieldTrip software. \ No newline at end of file diff --git a/mne/preprocessing/ica.py b/mne/preprocessing/ica.py index 39ff07b289f..4b701ddb4b5 100644 --- a/mne/preprocessing/ica.py +++ b/mne/preprocessing/ica.py @@ -36,7 +36,7 @@ from ..epochs import _BaseEpochs from ..viz import (plot_ica_components, plot_ica_scores, plot_ica_sources, plot_ica_overlay) -from ..channels import _contains_ch_type, ContainsMixin +from ..channels.channels import _contains_ch_type, ContainsMixin from ..io.write import start_file, end_file, write_id from ..utils import (check_sklearn_version, logger, check_fname, verbose, _reject_data_segments) diff --git a/mne/surface.py b/mne/surface.py index 91618973455..76d3b1e0665 100644 --- a/mne/surface.py +++ b/mne/surface.py @@ -23,7 +23,7 @@ write_int_matrix, start_file, end_block, start_block, end_file, write_string, write_float_sparse_rcs) -from .channels import _get_meg_system +from .channels.channels import _get_meg_system from .transforms import transform_surface_to from .utils import logger, verbose, get_subjects_dir diff --git a/mne/time_frequency/tfr.py b/mne/time_frequency/tfr.py index da76452b78d..f543b918e0b 100644 --- a/mne/time_frequency/tfr.py +++ b/mne/time_frequency/tfr.py @@ -18,7 +18,7 @@ from ..baseline import rescale from ..parallel import parallel_func from ..utils import logger, verbose -from ..channels import ContainsMixin, PickDropChannelsMixin +from ..channels.channels import ContainsMixin, PickDropChannelsMixin from ..io.pick import pick_info, pick_types @@ -678,7 +678,7 @@ def plot_topo(self, picks=None, baseline=None, mode='mean', tmin=None, mode, baseline, vmin, vmax, dB) if layout is None: - from mne.layouts.layout import find_layout + from mne import find_layout layout = find_layout(self.info) imshow = partial(_imshow_tfr, tfr=data, freq=freqs, cmap=cmap) diff --git a/mne/viz/tests/test_epochs.py b/mne/viz/tests/test_epochs.py index ae5fa305a43..84a646aa0bc 100644 --- a/mne/viz/tests/test_epochs.py +++ b/mne/viz/tests/test_epochs.py @@ -19,7 +19,7 @@ from mne import io, read_events, Epochs from mne import pick_types from mne.utils import run_tests_if_main -from mne.layouts import read_layout +from mne.channels import read_layout from mne.viz import plot_drop_log, plot_image_epochs, _get_presser diff --git a/mne/viz/tests/test_evoked.py b/mne/viz/tests/test_evoked.py index 89c91623772..1ecb3d95480 100644 --- a/mne/viz/tests/test_evoked.py +++ b/mne/viz/tests/test_evoked.py @@ -20,7 +20,7 @@ from mne import io, read_events, Epochs from mne import pick_types -from mne.layouts import read_layout +from mne.channels import read_layout warnings.simplefilter('always') # enable b/c these tests throw warnings diff --git a/mne/viz/tests/test_montage.py b/mne/viz/tests/test_montage.py index f385bc52257..7e5eddae53b 100644 --- a/mne/viz/tests/test_montage.py +++ b/mne/viz/tests/test_montage.py @@ -7,7 +7,7 @@ import matplotlib matplotlib.use('Agg') # for testing don't use X server -from mne.montages import read_montage +from mne.channels import read_montage def test_plot_montage(): diff --git a/mne/viz/tests/test_topo.py b/mne/viz/tests/test_topo.py index 505e40233a9..a989c9b971a 100644 --- a/mne/viz/tests/test_topo.py +++ b/mne/viz/tests/test_topo.py @@ -19,7 +19,7 @@ from mne import io, read_events, Epochs from mne import pick_channels_evoked -from mne.layouts import read_layout +from mne.channels import read_layout from mne.time_frequency.tfr import AverageTFR from mne.utils import run_tests_if_main diff --git a/mne/viz/tests/test_topomap.py b/mne/viz/tests/test_topomap.py index 1f4561112db..94fc9f9c0d5 100644 --- a/mne/viz/tests/test_topomap.py +++ b/mne/viz/tests/test_topomap.py @@ -21,7 +21,7 @@ from mne import io from mne import read_evokeds, read_proj from mne.io.constants import FIFF -from mne.layouts import read_layout +from mne.channels import read_layout from mne.datasets import testing from mne.time_frequency.tfr import AverageTFR diff --git a/mne/viz/topo.py b/mne/viz/topo.py index 471587eba3b..dd753980c35 100644 --- a/mne/viz/topo.py +++ b/mne/viz/topo.py @@ -79,7 +79,7 @@ def iter_topography(info, layout=None, on_pick=None, fig=None, fig.set_facecolor(fig_facecolor) if layout is None: - from ..layouts import find_layout + from ..channels import find_layout layout = find_layout(info) if on_pick is not None: @@ -317,7 +317,7 @@ def plot_topo(evoked, layout=None, layout_scale=0.945, color=None, ch_names = _clean_names(ch_names) if layout is None: - from ..layouts.layout import find_layout + from ..channels.layout import find_layout layout = find_layout(info) # XXX. at the moment we are committed to 1- / 2-sensor-types layouts @@ -500,7 +500,7 @@ def plot_topo_image_epochs(epochs, layout=None, sigma=0.3, vmin=None, if vmax is None: vmax = data.max() if layout is None: - from ..layouts.layout import find_layout + from ..channels.layout import find_layout layout = find_layout(epochs.info) erf_imshow = partial(_erfimage_imshow, scalings=scalings, order=order, diff --git a/mne/viz/topomap.py b/mne/viz/topomap.py index def9c507979..035140d950b 100644 --- a/mne/viz/topomap.py +++ b/mne/viz/topomap.py @@ -29,7 +29,7 @@ def _prepare_topo_plot(obj, ch_type, layout): """"Aux Function""" info = copy.deepcopy(obj.info) if layout is None and ch_type is not 'eeg': - from ..layouts.layout import find_layout + from ..channels import find_layout layout = find_layout(info) elif layout == 'auto': layout = None @@ -41,7 +41,7 @@ def _prepare_topo_plot(obj, ch_type, layout): # special case for merging grad channels if (ch_type == 'grad' and FIFF.FIFFV_COIL_VV_PLANAR_T1 in np.unique([ch['coil_type'] for ch in info['chs']])): - from ..layouts.layout import _pair_grad_sensors + from ..channels.layout import _pair_grad_sensors picks, pos = _pair_grad_sensors(info, layout) merge_grads = True else: @@ -58,7 +58,7 @@ def _prepare_topo_plot(obj, ch_type, layout): if layout is None: chs = [info['chs'][i] for i in picks] - from ..layouts.layout import _find_topomap_coords + from ..channels.layout import _find_topomap_coords pos = _find_topomap_coords(chs, layout) else: names = [n.upper() for n in layout.names] @@ -88,7 +88,7 @@ def _plot_update_evoked_topomap(params, bools): data = new_evoked.data[np.ix_(params['picks'], params['time_idx'])] * params['scale'] if params['merge_grads']: - from ..layouts.layout import _merge_grad_data + from ..channels.layout import _merge_grad_data data = _merge_grad_data(data) image_mask = params['image_mask'] @@ -154,7 +154,7 @@ def plot_projs_topomap(projs, layout=None, cmap='RdBu_r', sensors=True, import matplotlib.pyplot as plt if layout is None: - from ..layouts import read_layout + from ..channels import read_layout layout = read_layout('Vectorview-all') if not isinstance(layout, list): @@ -175,7 +175,7 @@ def plot_projs_topomap(projs, layout=None, cmap='RdBu_r', sensors=True, for l in layout: is_vv = l.kind.startswith('Vectorview') if is_vv: - from ..layouts.layout import _pair_grad_sensors_from_ch_names + from ..channels.layout import _pair_grad_sensors_from_ch_names grad_pairs = _pair_grad_sensors_from_ch_names(ch_names) if grad_pairs: ch_names = [ch_names[i] for i in grad_pairs] @@ -186,7 +186,7 @@ def plot_projs_topomap(projs, layout=None, cmap='RdBu_r', sensors=True, pos = l.pos[idx] if is_vv and grad_pairs: - from ..layouts.layout import _merge_grad_data + from ..channels.layout import _merge_grad_data shape = (len(idx) / 2, 2, -1) pos = pos.reshape(shape).mean(axis=1) data = _merge_grad_data(data[grad_pairs]).ravel() @@ -644,7 +644,7 @@ def plot_ica_components(ica, picks=None, ch_type='mag', res=64, fig.suptitle(title) if merge_grads: - from ..layouts.layout import _merge_grad_data + from ..channels.layout import _merge_grad_data for ii, data_, ax in zip(picks, data, axes): ax.set_title('IC #%03d' % ii, fontsize=12) data_ = _merge_grad_data(data_) if merge_grads else data_ @@ -793,7 +793,7 @@ def plot_tfr_topomap(tfr, tmin=None, tmax=None, fmin=None, fmax=None, data = np.mean(np.mean(data, axis=2), axis=1)[:, np.newaxis] if merge_grads: - from ..layouts.layout import _merge_grad_data + from ..channels.layout import _merge_grad_data data = _merge_grad_data(data) vmin, vmax = _setup_vmin_vmax(data, vmin, vmax) @@ -998,7 +998,7 @@ def plot_evoked_topomap(evoked, times=None, ch_type='mag', layout=None, data *= scale if merge_grads: - from ..layouts.layout import _merge_grad_data + from ..channels.layout import _merge_grad_data data = _merge_grad_data(data) vmin, vmax = _setup_vmin_vmax(data, vmin, vmax) diff --git a/setup.py b/setup.py index 74632948a81..5f7755f8a08 100755 --- a/setup.py +++ b/setup.py @@ -83,7 +83,6 @@ 'mne.forward', 'mne.forward.tests', 'mne.viz', 'mne.viz.tests', 'mne.gui', 'mne.gui.tests', - 'mne.layouts', 'mne.layouts.tests', 'mne.minimum_norm', 'mne.minimum_norm.tests', 'mne.inverse_sparse', 'mne.inverse_sparse.tests', 'mne.preprocessing', 'mne.preprocessing.tests', @@ -95,18 +94,20 @@ 'mne.decoding', 'mne.decoding.tests', 'mne.commands', 'mne.externals', 'mne.externals.tempita', - 'mne.montages', 'mne.montages.tests', - 'mne.neighbors'], + 'mne.layouts', + 'mne.channels', + 'mne.channels.test'], package_data={'mne': [op.join('data', '*.sel'), op.join('data', 'icos.fif.gz'), op.join('data', 'coil_def.dat'), op.join('data', 'helmets', '*.fif.gz'), op.join('data', 'FreeSurferColorLUT.txt'), - op.join('layouts', '*.lout'), - op.join('layouts', '*.lay'), - op.join('montages', '*.sfp'), - op.join('montages', '*.txt'), - op.join('montages', '*.elc'), + op.join('channels', 'data', 'layouts', '*.lout'), + op.join('channels', 'data', 'layouts', '*.lay'), + op.join('channels', 'data', 'montages', '*.sfp'), + op.join('channels', 'data', 'montages', '*.txt'), + op.join('channels', 'data', 'montages', '*.elc'), + op.join('channels', 'data', 'neighbors', '.mat'), op.join('html', '*.js'), op.join('html', '*.css')]}, scripts=['bin/mne'])