From aa4d672f7adcf30ecbccc103406822261a5527b8 Mon Sep 17 00:00:00 2001 From: Mathieu Scheltienne Date: Wed, 16 Aug 2023 13:03:53 +0200 Subject: [PATCH] shorten strings through 88 character length --- pycrostates/cluster/_base.py | 222 ++++++++---------- pycrostates/cluster/aahc.py | 6 +- pycrostates/cluster/kmeans.py | 32 ++- pycrostates/cluster/utils/utils.py | 12 +- pycrostates/datasets/lemon/lemon.py | 32 ++- pycrostates/io/ch_data.py | 17 +- pycrostates/io/meas_info.py | 137 +++++------ pycrostates/metrics/calinski_harabasz.py | 7 +- pycrostates/metrics/davies_bouldin.py | 13 +- pycrostates/metrics/silhouette.py | 6 +- .../preprocessing/extract_gfp_peaks.py | 45 ++-- pycrostates/preprocessing/resample.py | 16 +- pycrostates/preprocessing/spatial_filter.py | 65 +++-- pycrostates/segmentation/_base.py | 58 +++-- pycrostates/segmentation/segmentation.py | 13 +- pycrostates/segmentation/transitions.py | 16 +- pycrostates/utils/_checks.py | 13 +- pycrostates/utils/_docs.py | 53 ++--- pycrostates/utils/_fixes.py | 4 +- pycrostates/utils/_imports.py | 15 +- pycrostates/utils/utils.py | 11 +- pycrostates/viz/cluster_centers.py | 17 +- pycrostates/viz/segmentation.py | 10 +- 23 files changed, 366 insertions(+), 454 deletions(-) diff --git a/pycrostates/cluster/_base.py b/pycrostates/cluster/_base.py index bfd44f90..1e1cdf7a 100644 --- a/pycrostates/cluster/_base.py +++ b/pycrostates/cluster/_base.py @@ -88,8 +88,7 @@ def __eq__(self, other: Any) -> bool: # check fit if self._fitted + other._fitted == 0: # Both False raise RuntimeError( - "Clustering algorithms must be fitted before using '==' " - "comparison." + "Clustering algorithms must be fitted before using '==' comparison." ) if self._fitted + other._fitted == 1: # One False return False @@ -130,8 +129,7 @@ def __eq__(self, other: Any) -> bool: if self._cluster_names != other._cluster_names: logger.warning( "Cluster names differ between both clustering solution. " - "Consider using '.rename_clusters' to change the cluster " - "names." + "Consider using '.rename_clusters' to change the cluster names." ) return True @@ -205,13 +203,12 @@ def fit( MNE `~mne.io.Raw`, `~mne.Epochs` or `~pycrostates.io.ChData` object from which to extract :term:`cluster centers`. picks : str | list | slice | None - Channels to include. Note that all channels selected must have the - same type. Slices and lists of integers will be interpreted as - channel indices. In lists, channel name strings (e.g. - ``['Fp1', 'Fp2']``) will pick the given channels. Can also be the - string values “all” to pick all channels, or “data” to pick data - channels. ``"eeg"`` (default) will pick all eeg channels. - Note that channels in ``info['bads']`` will be included if their + Channels to include. Note that all channels selected must have the same + type. Slices and lists of integers will be interpreted as channel indices. + In lists, channel name strings (e.g. ``['Fp1', 'Fp2']``) will pick the given + channels. Can also be the string values ``“all”`` to pick all channels, or + ``“data”`` to pick data channels. ``"eeg"`` (default) will pick all eeg + channels. Note that channels in ``info['bads']`` will be included if their names or indices are explicitly provided. %(tmin_raw)s %(tmax_raw)s @@ -235,15 +232,14 @@ def fit( if len(ch_not_used) != 0: if len(ch_not_used) == 1: msg = ( - "The channel %s is set as bad and ignored. To include " - "it, either remove it from inst.info['bads'] or " - "provide it explicitly in the 'picks' argument." + "The channel %s is set as bad and ignored. To include it, either " + "remove it from inst.info['bads'] or provide it explicitly in the " + "'picks' argument." ) else: msg = ( - "The channels %s are set as bads and ignored. To " - "include them, either remove them from " - "inst.info['bads'] or provide them " + "The channels %s are set as bads and ignored. To include them, " + "either remove them from inst.info['bads'] or provide them " "explicitly in the 'picks' argument." ) logger.warning( @@ -289,11 +285,11 @@ def rename_clusters( Parameters ---------- mapping : dict - Mapping from the old names to the new names. The keys are the old - names and the values are the new names. + Mapping from the old names to the new names. The keys are the old names and + the values are the new names. new_names : list | tuple - 1D iterable containing the new cluster names. The length of the - iterable should match the number of clusters. + 1D iterable containing the new cluster names. The length of the iterable + should match the number of clusters. Notes ----- @@ -316,8 +312,7 @@ def rename_clusters( if len(new_names) != self._n_clusters: raise ValueError( "Argument 'new_names' should contain 'n_clusters': " - f"{self._n_clusters} elements. " - f"Provided '{len(new_names)}'." + f"{self._n_clusters} elements. Provided '{len(new_names)}'." ) # sanity-check @@ -330,8 +325,8 @@ def rename_clusters( else: logger.warning( - "Either 'mapping' or 'new_names' should not be 'None' " - "for method 'rename_clusters' to operate." + "Either 'mapping' or 'new_names' should not be 'None' for method " + "'rename_clusters' to operate." ) return @@ -356,11 +351,10 @@ def reorder_clusters( Specify one of the following arguments to change the current order: - * ``mapping``: a dictionary that maps old cluster positions - to new positions, + * ``mapping``: a dictionary that maps old cluster positions to new positions, * ``order``: a 1D iterable containing the new order, - * ``template``: a fitted clustering algorithm used as a reference - to match the order. + * ``template``: a fitted clustering algorithm used as a reference to match the + order. Only one argument can be set at a time. @@ -370,14 +364,11 @@ def reorder_clusters( Mapping from the old order to the new order. key: old position, value: new position. order : list of int | tuple of int | array of int - 1D iterable containing the new order. - Positions are 0-indexed. + 1D iterable containing the new order. Positions are 0-indexed. template : :ref:`cluster` - Fitted clustering algorithm use as template for - ordering optimization. For more details about the - current implementation, check the - :func:`pycrostates.cluster.utils.optimize_order` - documentation. + Fitted clustering algorithm use as template for ordering optimization. For + more details about the current implementation, check the + :func:`pycrostates.cluster.utils.optimize_order` documentation. Notes ----- @@ -408,9 +399,8 @@ def reorder_clusters( for key in mapping: if key in mapping.values(): raise ValueError( - "A position can not be present in both the old and " - f"new order. Position '{key}' is mapped to " - f"'{mapping[key]}' and position " + "A position can not be present in both the old and new order. " + f"Position '{key}' is mapped to '{mapping[key]}' and position " f"'{inverse_mapping[key]}' is mapped to '{key}'." ) @@ -446,8 +436,8 @@ def reorder_clusters( else: logger.warning( - "Either 'mapping', 'order' or 'template' should not be 'None' " - "for method 'reorder_clusters' to operate." + "Either 'mapping', 'order' or 'template' should not be 'None' for " + "method 'reorder_clusters' to operate." ) return @@ -475,16 +465,16 @@ def invert_polarity( invert : bool | list of bool | array of bool List of bool of length ``n_clusters``. True will invert map polarity, while False will have no effect. - If a bool is provided, it is applied to all maps. + If a `bool` is provided, it is applied to all maps. Notes ----- Operates in-place. - Inverting polarities has no effect on the other steps - of the analysis as polarity is ignored in the current methodology. - This function is only used for tuning visualization - (i.e. for visual inspection and/or to generate figure for an article). + Inverting polarities has no effect on the other steps of the analysis as + polarity is ignored in the current methodology. This function is only used for + tuning visualization (i.e. for visual inspection and/or to generate figure for + an article). """ self._check_fit() @@ -507,8 +497,8 @@ def invert_polarity( _check_type(inv, (bool, np.bool_), item_name="invert") if len(invert) != self._n_clusters: raise ValueError( - "Argument 'invert' should be either a bool or a list of bools " - f"of length 'n_clusters' ({self._n_clusters}). The provided " + "Argument 'invert' should be either a bool or a list of bools of " + f"length 'n_clusters' ({self._n_clusters}). The provided " f"'invert' length is '{len(invert)}'." ) @@ -540,17 +530,15 @@ def plot( ---------- %(axes_topo)s show_gradient : bool - If True, plot a line between channel locations - with highest and lowest values. + If True, plot a line between channel locations with highest and lowest + values. gradient_kwargs : dict - Additional keyword arguments passed to - :meth:`matplotlib.axes.Axes.plot` to plot - gradient line. + Additional keyword arguments passed to :meth:`matplotlib.axes.Axes.plot` to + plot gradient line. %(block)s %(verbose)s **kwargs - Additional keyword arguments are passed to - :func:`mne.viz.plot_topomap`. + Additional keyword arguments are passed to :func:`mne.viz.plot_topomap`. Returns ------- @@ -574,8 +562,7 @@ def plot( @abstractmethod def save(self, fname: Union[str, Path]): - """ - Save clustering solution to disk. + """Save clustering solution to disk. Parameters ---------- @@ -602,38 +589,35 @@ def predict( ): r"""Segment `~mne.io.Raw` or `~mne.Epochs` into microstate sequence. - Segment instance into microstate sequence using the segmentation - smoothing algorithm\ :footcite:p:`Marqui1995`. + Segment instance into microstate sequence using the segmentation smoothing + algorithm\ :footcite:p:`Marqui1995`. Parameters ---------- inst : Raw | Epochs - MNE `~mne.io.Raw` or `~mne.Epochs` object containing the data to - use for prediction. + MNE `~mne.io.Raw` or `~mne.Epochs` object containing the data to use for + prediction. picks : str | list | slice | None - Channels to include. Note that all channels selected must have the - same type. Slices and lists of integers will be interpreted as - channel indices. In lists, channel name strings (e.g. - ``['Fp1', 'Fp2']``) will pick the given channels. - Can also be the string values “all” to pick all channels, or “data” - to pick data channels. ``None`` (default) will pick all channels - used during fitting (e.g., ``self.info['ch_names']``). - Note that channels in ``info['bads']`` will be included if their - names or indices are explicitly provided. + Channels to include. Note that all channels selected must have the same + type. Slices and lists of integers will be interpreted as channel indices. + In lists, channel name strings (e.g. ``['Fp1', 'Fp2']``) will pick the given + channels. Can also be the string values ``“all”`` to pick all channels, or + ``“data”`` to pick data channels. ``None`` (default) will pick all channels + used during fitting (e.g., ``self.info['ch_names']``). Note that channels in + ``info['bads']`` will be included if their names or indices are explicitly + provided. factor : int - Factor used for label smoothing. ``0`` means no smoothing. - Default to 0. + Factor used for label smoothing. ``0`` means no smoothing. Default to 0. half_window_size : int - Number of samples used for the half window size while smoothing - labels. The half window size is defined as - ``window_size = 2 * half_window_size + 1``. It has no effect if - ``factor=0`` (default). Default to 1. + Number of samples used for the half window size while smoothing labels. The + half window size is defined as ``window_size = 2 * half_window_size + 1``. + It has no effect if ``factor=0`` (default). Default to 1. tol : float Convergence tolerance. min_segment_length : int - Minimum segment length (in samples). If a segment is shorter than - this value, it will be recursively reasigned to neighbouring - segments based on absolute spatial correlation. + Minimum segment length (in samples). If a segment is shorter than this + value, it will be recursively reasigned to neighbouring segments based on + absolute spatial correlation. reject_edges : bool If ``True``, set first and last segments to unlabeled. %(reject_by_annotation_raw)s @@ -642,10 +626,9 @@ def predict( Returns ------- segmentation : RawSegmentation | EpochsSegmentation - Microstate sequence derivated from instance data. Timepoints are - labeled according to cluster centers number: ``0`` for the first - center, ``1`` for the second, etc.. - ``-1`` is used for unlabeled time points. + Microstate sequence derivated from instance data. Timepoints are labeled + according to cluster centers number: ``0`` for the first center, ``1`` for + the second, etc.. ``-1`` is used for unlabeled time points. References ---------- @@ -670,9 +653,8 @@ def predict( reject_by_annotation = True else: raise ValueError( - "Argument 'reject_by_annotation' can be set to 'True', " - f"'False' or 'omit' (True). '{reject_by_annotation}' is " - "not supported." + "Argument 'reject_by_annotation' can be set to 'True', 'False' or " + f"'omit' (True). '{reject_by_annotation}' is not supported." ) elif reject_by_annotation is None: reject_by_annotation = False @@ -681,13 +663,13 @@ def predict( if self._info["bads"] != []: if len(self._info["bads"]) == 1: msg = ( - "The current fit contains bad channel %s" - + " which will be used for prediction." + "The current fit contains bad channel %s which will be used for " + "prediction." ) else: msg = ( - "The current fit contains bad channels %s" - + " which will be used for prediction." + "The current fit contains bad channels %s which will be used for " + "prediction." ) logger.warning(msg, ", ".join(ch_name for ch_name in self._info["bads"])) del msg @@ -718,8 +700,7 @@ def predict( else: msg = ( f"The channels {missing_non_existing_channel} were used " - "during fitting but are missing from the provided " - "instance." + "during fitting but are missing from the provided instance." ) raise ValueError(msg) @@ -728,20 +709,18 @@ def predict( missing_existing_channel = list(missing_existing_channel) if len(missing_existing_channel) == 1: msg = ( - f"The channel {missing_existing_channel[0]} is required " - "to predict because it was included during fitting. The " - "provided 'picks' argument does not select " - f"{missing_existing_channel[0]}. To include it, either " - "remove it from inst.info['bads'] or provide its name or " - "indice explicitly in the 'picks' argument." + f"The channel {missing_existing_channel[0]} is required to predict " + "because it was included during fitting. The provided 'picks' " + f"argument does not select {missing_existing_channel[0]}. To " + "include it, either remove it from inst.info['bads'] or provide " + "its name or indice explicitly in the 'picks' argument." ) else: msg = ( - f"The channels {missing_existing_channel} are required " - " to predict because they were included during fitting. " - "The provided 'picks' argument does not select " - f"{missing_existing_channel}. To include then, either " - "remove them from inst.info['bads'] or provide their " + f"The channels {missing_existing_channel} are required to predict " + "because they were included during fitting. The provided 'picks' " + f"argument does not select {missing_existing_channel}. To include " + "then, either remove them from inst.info['bads'] or provide their " "names or indices explicitly in the 'picks' argument." ) raise ValueError(msg) @@ -751,15 +730,15 @@ def predict( if len(unused_ch) != 0: if len(unused_ch) == 1: msg = ( - "The provided instance and the 'picks' argument results " - "in the selection of %s which was not used during " - "fitting. Thus, it will not be used for prediction." + "The provided instance and the 'picks' argument results in the " + "selection of %s which was not used during fitting. Thus, it will " + "not be used for prediction." ) else: msg = ( - "The provided instance and the 'picks' argument results " - "in the selection of %s which were not used during " - "fitting. Thus, they will not be used for prediction." + "The provided instance and the 'picks' argument results in the " + "selection of %s which were not used during fitting. Thus, they " + "will not be used for prediction." ) logger.warning(msg, ", ".join(ch_name for ch_name in unused_ch)) del msg @@ -768,13 +747,13 @@ def predict( if len(info["bads"]) != 0: if len(info["bads"]) == 1: msg = ( - "The channel %s is set as bad in the instance but was " - "selected. It will be used for prediction." + "The channel %s is set as bad in the instance but was selected. It " + "will be used for prediction." ) else: msg = ( - "The channels %s are set as bad in the instance but were " - "selected. They will be used for prediction." + "The channels %s are set as bad in the instance but were selected. " + "They will be used for prediction." ) logger.warning(msg, ", ".join(ch_name for ch_name in info["bads"])) del msg @@ -791,8 +770,8 @@ def predict( logger.info("Segmenting data without smoothing.") else: logger.info( - "Segmenting data with factor %s and effective smoothing " - "window size: %.4f (s).", + "Segmenting data with factor %s and effective smoothing window size: " + "%.4f (s).", factor, (2 * half_window_size + 1) / inst.info["sfreq"], ) @@ -1029,8 +1008,8 @@ def _reject_short_segments( ) -> NDArray[int]: """Reject segments that are too short. - Reject segments that are too short by replacing the labels with the - adjacent labels based on data correlation. + Reject segments that are too short by replacing the labels with the adjacent + labels based on data correlation. """ while True: # list all segments @@ -1143,8 +1122,7 @@ def fitted(self, fitted): if fitted and not self._fitted: logger.warning( "The property 'fitted' can not be set to 'True' directly. " - "Please use the .fit() method to fit the clustering " - "algorithm." + "Please use the .fit() method to fit the clustering algorithm." ) elif fitted and self._fitted: logger.warning( @@ -1164,7 +1142,7 @@ def cluster_centers_(self) -> NDArray[float]: Returns None if cluster algorithm has not been fitted. - :type: `~numpy.array` (n_clusters, n_channels) | None + :type: `~numpy.array` of shape (n_clusters, n_channels) | None """ if self._cluster_centers_ is None: assert not self._fitted # sanity-check @@ -1176,7 +1154,7 @@ def cluster_centers_(self) -> NDArray[float]: def fitted_data(self) -> NDArray[float]: """Data array used to fit the clustering algorithm. - :type: `~numpy.array` shape (n_channels, n_samples) | None + :type: `~numpy.array` of shape (n_channels, n_samples) | None """ if self._fitted_data is None: assert not self._fitted # sanity-check @@ -1188,7 +1166,7 @@ def fitted_data(self) -> NDArray[float]: def labels_(self) -> NDArray[int]: """Microstate label attributed to each sample of the fitted data. - :type: `~numpy.array` shape (n_samples, ) | None + :type: `~numpy.array` of shape (n_samples, ) | None """ if self._labels_ is None: assert not self._fitted # sanity-check diff --git a/pycrostates/cluster/aahc.py b/pycrostates/cluster/aahc.py index b9c3558a..2c0642b1 100644 --- a/pycrostates/cluster/aahc.py +++ b/pycrostates/cluster/aahc.py @@ -156,11 +156,10 @@ def fit( @copy_doc(_BaseCluster.save) def save(self, fname: Union[str, Path]): super().save(fname) - # TODO: to be replaced by a general writer than infers the writer from - # the file extension. + # TODO: to be replaced by a general writer than infers the writer from the file + # extension. # pylint: disable=import-outside-toplevel from ..io.fiff import _write_cluster - # pylint: enable=import-outside-toplevel _write_cluster( @@ -250,7 +249,6 @@ def _compute_maps( # pylint: enable=too-many-locals # -------------------------------------------------------------------- - @property def normalize_input(self) -> bool: """If set, the input data is normalized along the channel dimension. diff --git a/pycrostates/cluster/kmeans.py b/pycrostates/cluster/kmeans.py index 22451131..c7de600c 100644 --- a/pycrostates/cluster/kmeans.py +++ b/pycrostates/cluster/kmeans.py @@ -28,14 +28,13 @@ class ModKMeans(_BaseCluster): ---------- %(n_clusters)s n_init : int - Number of time the k-means algorithm is run with different centroid - seeds. The final result will be the run with the highest Global - Explained Variance (GEV). + Number of time the k-means algorithm is run with different centroid seeds. The + final result will be the run with the highest Global Explained Variance (GEV). max_iter : int Maximum number of iterations of the K-means algorithm for a single run. tol : float - Relative tolerance with regards estimate residual noise in the cluster - centers of two consecutive iterations to declare convergence. + Relative tolerance with regards estimate residual noise in the cluster centers + of two consecutive iterations to declare convergence. %(random_state)s References @@ -151,16 +150,15 @@ def fit( Parameters ---------- inst : Raw | Epochs | ChData - MNE `~mne.io.Raw`, `~mne.Epochs` or `~pycrostates.io.ChData` object - from which to extract :term:`cluster centers`. + MNE `~mne.io.Raw`, `~mne.Epochs` or `~pycrostates.io.ChData` object from + which to extract :term:`cluster centers`. picks : str | list | slice | None - Channels to include. Note that all channels selected must have the - same type. Slices and lists of integers will be interpreted as - channel indices. In lists, channel name strings (e.g. - ``['Fp1', 'Fp2']``) will pick the given channels. Can also be the - string values “all” to pick all channels, or “data” to pick data - channels. ``"eeg"`` (default) will pick all eeg channels. - Note that channels in ``info['bads']`` will be included if their + Channels to include. Note that all channels selected must have the same + type. Slices and lists of integers will be interpreted as channel indices. + In lists, channel name strings (e.g. ``['Fp1', 'Fp2']``) will pick the given + channels. Can also be the string values ``“all”`` to pick all channels, or + ``“data”`` to pick data channels. ``"eeg"`` (default) will pick all eeg + channels. Note that channels in ``info['bads']`` will be included if their names or indices are explicitly provided. %(tmin_raw)s %(tmax_raw)s @@ -224,8 +222,8 @@ def fit( ) else: logger.error( - "All the K-means run failed to converge. Please adapt the " - "tolerance and the maximum number of iteration." + "All the K-means run failed to converge. Please adapt the tolerance " + "and the maximum number of iteration." ) self.fitted = False # reset variables related to fit return # break early @@ -427,6 +425,6 @@ def _check_tol(tol: Union[int, float]) -> Union[int, float]: _check_type(tol, ("numeric",), item_name="tol") if tol <= 0: raise ValueError( - "The tolerance must be a positive number. Provided: '{tol}'." + f"The tolerance must be a positive number. Provided: '{tol}'." ) return tol diff --git a/pycrostates/cluster/utils/utils.py b/pycrostates/cluster/utils/utils.py index aad9af75..e50094ed 100644 --- a/pycrostates/cluster/utils/utils.py +++ b/pycrostates/cluster/utils/utils.py @@ -24,11 +24,10 @@ def _optimize_order( def optimize_order(inst: Cluster, template_inst: Cluster): """Optimize the order of cluster centers between two cluster instances. - Optimize the order of cluster centers in an instance of a clustering - algorithm to maximize auto-correlation, based on a template instance - as determined by the Hungarian algorithm. - The two cluster instances must have the same number of cluster centers - and the same polarity setting. + Optimize the order of cluster centers in an instance of a clustering algorithm to + maximize auto-correlation, based on a template instance as determined by the + Hungarian algorithm. The two cluster instances must have the same number of cluster + centers and the same polarity setting. Parameters ---------- @@ -40,8 +39,7 @@ def optimize_order(inst: Cluster, template_inst: Cluster): Returns ------- order : list of int - The new order to apply to inst to maximize auto-correlation - of cluster centers. + The new order to apply to inst to maximize auto-correlation of cluster centers. """ from .._base import _BaseCluster diff --git a/pycrostates/datasets/lemon/lemon.py b/pycrostates/datasets/lemon/lemon.py index 629cd62a..08cca02d 100644 --- a/pycrostates/datasets/lemon/lemon.py +++ b/pycrostates/datasets/lemon/lemon.py @@ -19,22 +19,20 @@ def data_path(subject_id: str, condition: str) -> Path: r"""Get path to a local copy of preprocessed EEG recording from the LEMON dataset. - Get path to a local copy of preprocessed EEG recording from the - mind-brain-body dataset of MRI, EEG, cognition, emotion, and peripheral - physiology in young and old adults\ :footcite:p:`babayan_mind-brain-body_2019`. - If there is no local copy of the recording, this function will fetch it - from the online repository and store it. The default location is - ``~/pycrostates_data``. + Get path to a local copy of preprocessed EEG recording from the mind-brain-body + dataset of MRI, EEG, cognition, emotion, and peripheral physiology in young and old + adults\ :footcite:p:`babayan_mind-brain-body_2019`. If there is no local copy of the + recording, this function will fetch it from the online repository and store it. The + default location is ``~/pycrostates_data``. Parameters ---------- subject_id : str The subject id to use. For example ``'010276'``. - The list of available subjects can be found - on this `FTP server `_. + The list of available subjects can be found on this + `FTP server `_. condition : str - Can be ``'EO'`` for eyes open condition or ``'EC'`` for eyes closed - condition. + Can be ``'EO'`` for eyes open condition or ``'EC'`` for eyes closed condition. Returns ------- @@ -51,8 +49,8 @@ def data_path(subject_id: str, condition: str) -> Path: - ``pip install pymatreader`` - ``conda install -c conda-forge pymatreader`` - Note that an environment created via the MNE installers includes - ``pymatreader`` by default. + Note that an environment created via the MNE installers includes ``pymatreader`` by + default. References ---------- @@ -65,7 +63,7 @@ def data_path(subject_id: str, condition: str) -> Path: config = get_config() fetcher = pooch.create( path=config["PREPROCESSED_LEMON_DATASET_PATH"], - base_url="https://ftp.gwdg.de/pub/misc/MPI-Leipzig_Mind-Brain-Body-LEMON/EEG_MPILMBB_LEMON/EEG_Preprocessed_BIDS_ID/EEG_Preprocessed/", # noqa, + base_url="https://ftp.gwdg.de/pub/misc/MPI-Leipzig_Mind-Brain-Body-LEMON/EEG_MPILMBB_LEMON/EEG_Preprocessed_BIDS_ID/EEG_Preprocessed/", # noqa: E501 version=None, registry=None, ) @@ -86,8 +84,8 @@ def data_path(subject_id: str, condition: str) -> Path: def standardize(raw: BaseRaw): """Standardize :class:`~mne.io.Raw` from the lemon dataset. - This function will interpolate missing channels from the standard setup, - then reorder channels and finally reference to a common average. + This function will interpolate missing channels from the standard setup, then + reorder channels and finally reference to a common average. Parameters ---------- @@ -102,8 +100,8 @@ def standardize(raw: BaseRaw): Notes ----- If you don't want to interpolate missing channels, you can use - :func:`mne.channels.equalize_channels` instead to have the same electrodes - across different recordings. + :func:`mne.channels.equalize_channels` instead to have the same electrodes across + different recordings. """ raw = raw.copy() # fmt: off diff --git a/pycrostates/io/ch_data.py b/pycrostates/io/ch_data.py index 3a3fa715..11009cb2 100644 --- a/pycrostates/io/ch_data.py +++ b/pycrostates/io/ch_data.py @@ -16,8 +16,8 @@ class ChData(CHData, ChannelsMixin, ContainsMixin, MontageMixin): """ChData stores atemporal data with its spatial information. - ChData is similar to a raw instance where temporality has been removed. - Only the spatial information, stored as a `~pycrostates.io.ChInfo` is + `~pycrostates.io.ChData` is similar to a raw instance where temporality has been + removed. Only the spatial information, stored as a `~pycrostates.io.ChInfo` is retained. Parameters @@ -25,8 +25,8 @@ class ChData(CHData, ChannelsMixin, ContainsMixin, MontageMixin): data : array Data array of shape ``(n_channels, n_samples)``. info : mne.Info | ChInfo - Atemporal measurement information. If a `mne.Info` is provided, it is - converted to a `~pycrostates.io.ChInfo`. + Atemporal measurement information. If a `mne.Info` is provided, it is converted + to a `~pycrostates.io.ChInfo`. """ def __init__(self, data: NDArray[float], info: Union[Info, CHInfo]): @@ -36,9 +36,8 @@ def __init__(self, data: NDArray[float], info: Union[Info, CHInfo]): _check_type(info, (Info, ChInfo), "info") if data.ndim != 2: raise ValueError( - "Argument 'data' should be a 2D array " - "(n_channels, n_samples). The provided array " - f"shape is {data.shape} which has {data.ndim} " + "Argument 'data' should be a 2D array (n_channels, n_samples). The " + f"provided array shape is {data.shape} which has {data.ndim} " "dimensions." ) if not len(info["ch_names"]) == data.shape[0]: @@ -118,8 +117,8 @@ def pick(self, picks, exclude="bads"): ---------- %(picks_all)s exclude : list | str - Set of channels to exclude, only used when picking based on - types (e.g., ``exclude="bads"`` when ``picks="meg"``). + Set of channels to exclude, only used when picking based on types (e.g., + ``exclude="bads"`` when ``picks="meg"``). Returns ------- diff --git a/pycrostates/io/meas_info.py b/pycrostates/io/meas_info.py index 639fdf18..e36b55fb 100644 --- a/pycrostates/io/meas_info.py +++ b/pycrostates/io/meas_info.py @@ -28,66 +28,62 @@ class ChInfo(CHInfo, Info): """Atemporal measurement information. Similar to a :class:`mne.Info` class, but without any temporal information. - Only the channel-related information are present. A - :class:`~pycrostates.io.ChInfo` can be created either: + Only the channel-related information are present. A :class:`~pycrostates.io.ChInfo` + can be created either: - - by providing a :class:`~mne.Info` class from which information are - retrieved. - - by providing the ``ch_names`` and the ``ch_types`` to create a new - instance. + - by providing a :class:`~mne.Info` class from which information are retrieved. + - by providing the ``ch_names`` and the ``ch_types`` to create a new instance. Only one of those 2 methods should be used at once. - .. warning:: The only entry that should be manually changed by the user - is ``info['bads']``. All other entries should be - considered read-only, though they can be modified by various - functions or methods (which have safeguards to ensure all - fields remain in sync). + .. warning:: The only entry that should be manually changed by the user is + ``info['bads']``. All other entries should be considered read-only, + though they can be modified by various functions or methods (which have + safeguards to ensure all fields remain in sync). Parameters ---------- info : Info | None - MNE measurement information instance from which channel-related - variables are retrieved. + MNE measurement information instance from which channel-related variables are + retrieved. ch_names : list of str | int | None - Channel names. If an int, a list of channel names will be created - from ``range(ch_names)``. + Channel names. If an int, a list of channel names will be created from + ``range(ch_names)``. ch_types : list of str | str | None Channel types. If str, all channels are assumed to be of the same type. Attributes ---------- bads : list of str - List of bad (noisy/broken) channels, by name. These channels will by - default be ignored by many processing steps. + List of bad (noisy/broken) channels, by name. These channels will by default be + ignored by many processing steps. ch_names : tuple of str The names of the channels. chs : tuple of dict - A list of channel information dictionaries, one per channel. - See Notes for more information. + A list of channel information dictionaries, one per channel. See Notes for more + information. comps : list of dict - CTF software gradient compensation data. - See Notes for more information. + CTF software gradient compensation data. See Notes for more information. ctf_head_t : dict | None - The transformation from 4D/CTF head coordinates to Neuromag head - coordinates. This is only present in 4D/CTF data. + The transformation from 4D/CTF head coordinates to Neuromag head coordinates. + This is only present in 4D/CTF data. custom_ref_applied : int - Whether a custom (=other than average) reference has been applied to - the EEG data. This flag is checked by some algorithms that require an - average reference to be set. + Whether a custom (=other than average) reference has been applied to the EEG + data. This flag is checked by some algorithms that require an average reference + to be set. dev_ctf_t : dict | None - The transformation from device coordinates to 4D/CTF head coordinates. - This is only present in 4D/CTF data. + The transformation from device coordinates to 4D/CTF head coordinates. This is + only present in 4D/CTF data. dev_head_t : dict | None The device to head transformation. dig : tuple of dict | None - The Polhemus digitization data in head coordinates. - See Notes for more information. + The Polhemus digitization data in head coordinates. See Notes for more + information. nchan : int Number of channels. projs : list of Projection - List of SSP operators that operate on the data. - See :class:`mne.Projection` for details. + List of SSP operators that operate on the data. See :class:`mne.Projection` for + details. Notes ----- @@ -96,9 +92,8 @@ class ChInfo(CHInfo, Info): * ``chs`` list of dict: cal : float - The calibration factor to bring the channels to physical - units. Used in product with ``range`` to scale the data read - from disk. + The calibration factor to bring the channels to physical units. Used in + product with ``range`` to scale the data read from disk. ch_name : str The channel name. coil_type : int @@ -108,18 +103,16 @@ class ChInfo(CHInfo, Info): kind : int The kind of channel, e.g. ``FIFFV_EEG_CH``. loc : array, shape (12,) - Channel location. For MEG this is the position plus the - normal given by a 3x3 rotation matrix. For EEG this is the - position followed by reference position (with 6 unused). - The values are specified in device coordinates for MEG and in - head coordinates for EEG channels, respectively. + Channel location. For MEG this is the position plus the normal given by a + 3x3 rotation matrix. For EEG this is the position followed by reference + position (with 6 unused). The values are specified in device coordinates for + MEG and in head coordinates for EEG channels, respectively. logno : int - Logical channel number, conventions in the usage of this - number vary. + Logical channel number, conventions in the usage of this number vary. range : float - The hardware-oriented part of the calibration factor. - This should be only applied to the continuous raw data. - Used in product with ``cal`` to scale data read from disk. + The hardware-oriented part of the calibration factor. This should be only + applied to the continuous raw data. Used in product with ``cal`` to scale + data read from disk. scanno : int Scanning order number, starting from 1. unit : int @@ -144,14 +137,12 @@ class ChInfo(CHInfo, Info): * ``dig`` list of dict: kind : int - The kind of channel, - e.g. ``FIFFV_POINT_EEG``, ``FIFFV_POINT_CARDINAL``. + The kind of channel, e.g. ``FIFFV_POINT_EEG``, ``FIFFV_POINT_CARDINAL``. r : array, shape (3,) 3D position in m. and coord_frame. ident : int - Number specifying the identity of the point. - e.g. ``FIFFV_POINT_NASION`` if kind is ``FIFFV_POINT_CARDINAL``, or - 42 if kind is ``FIFFV_POINT_EEG``. + Number specifying the identity of the point. e.g. ``FIFFV_POINT_NASION`` if + kind is ``FIFFV_POINT_CARDINAL``, or 42 if kind is ``FIFFV_POINT_EEG``. coord_frame : int The coordinate frame used, e.g. ``FIFFV_COORD_HEAD``. """ @@ -160,33 +151,27 @@ class ChInfo(CHInfo, Info): # fmt: off _attributes = { "bads": _check_bads, - "ch_names": "ch_names cannot be set directly. " - "Please use methods inst.add_channels(), " - "inst.drop_channels(), inst.pick_channels(), " - "inst.rename_channels(), inst.reorder_channels() " - "and inst.set_channel_types() instead.", - "chs": "chs cannot be set directly. " - "Please use methods inst.add_channels(), " - "inst.drop_channels(), inst.pick_channels(), " - "inst.rename_channels(), inst.reorder_channels() " - "and inst.set_channel_types() instead.", + "ch_names": "ch_names cannot be set directly. Please use methods " + "inst.add_channels(), inst.drop_channels(), inst.pick_channels(), " + "inst.rename_channels(), inst.reorder_channels() and " + "inst.set_channel_types() instead.", + "chs": "chs cannot be set directly. Please use methods inst.add_channels(), " + "inst.drop_channels(), inst.pick_channels(), inst.rename_channels(), " + "inst.reorder_channels() and inst.set_channel_types() instead.", "comps": "comps cannot be set directly. " - "Please use method Raw.apply_gradient_compensation() " - "instead.", + "Please use method Raw.apply_gradient_compensation() instead.", "ctf_head_t": "ctf_head_t cannot be set directly.", "custom_ref_applied": "custom_ref_applied cannot be set directly. " - "Please use method inst.set_eeg_reference() " - "instead.", + "Please use method inst.set_eeg_reference() instead.", "dev_ctf_t": "dev_ctf_t cannot be set directly.", "dev_head_t": _check_dev_head_t, - "dig": "dig cannot be set directly. " - "Please use method inst.set_montage() instead.", - "nchan": "nchan cannot be set directly. " - "Please use methods inst.add_channels(), " - "inst.drop_channels(), and inst.pick_channels() instead.", - "projs": "projs cannot be set directly. " - "Please use methods inst.add_proj() and inst.del_proj() " + "dig": "dig cannot be set directly. Please use method inst.set_montage() " + "instead.", + "nchan": "nchan cannot be set directly. Please use methods " + "inst.add_channels(), inst.drop_channels(), and inst.pick_channels() " "instead.", + "projs": "projs cannot be set directly. Please use methods inst.add_proj() and " + "inst.del_proj() instead.", } # fmt: on @@ -216,8 +201,7 @@ def __init__( else: raise RuntimeError( "If 'info' is provided, 'ch_names' and 'ch_types' must be " - "None. If 'ch_names' and 'ch_types' are provided, 'info' " - "must be None." + "None. If 'ch_names' and 'ch_types' are provided, 'info' must be None." ) def _init_from_info(self, info: Info): @@ -404,9 +388,8 @@ def __setitem__(self, key, val): val = self._attributes[key](val) # attribute checker function else: raise RuntimeError( - f"Info does not support setting the key {repr(key)}. " - "Supported keys are " - f"{', '.join(repr(k) for k in self._attributes)}" + f"Info does not support setting the key {repr(key)}. Supported keys " + f"are {', '.join(repr(k) for k in self._attributes)}" ) super().__setitem__(key, val) # calls the dict __setitem__ @@ -452,7 +435,7 @@ def _check_consistency(self, prepend_error: str = ""): ): raise RuntimeError( f"{prepend_error}info channel name inconsistency detected, " - "please notify developers." + "please notify the developers." ) for pi, proj in enumerate(self.get("projs", [])): diff --git a/pycrostates/metrics/calinski_harabasz.py b/pycrostates/metrics/calinski_harabasz.py index 1e88a84b..0524ac58 100644 --- a/pycrostates/metrics/calinski_harabasz.py +++ b/pycrostates/metrics/calinski_harabasz.py @@ -12,10 +12,9 @@ def calinski_harabasz_score(cluster): # higher the better r"""Compute the Calinski-Harabasz score. - This function computes the Calinski-Harabasz - score\ :footcite:p:`Calinski-Harabasz` with - :func:`sklearn.metrics.calinski_harabasz_score` from a fitted - :ref:`Clustering` instance. + This function computes the Calinski-Harabasz score\ :footcite:p:`Calinski-Harabasz` + with :func:`sklearn.metrics.calinski_harabasz_score` from a fitted :ref:`Clustering` + instance. Parameters ---------- diff --git a/pycrostates/metrics/davies_bouldin.py b/pycrostates/metrics/davies_bouldin.py index 012ba181..801a0382 100644 --- a/pycrostates/metrics/davies_bouldin.py +++ b/pycrostates/metrics/davies_bouldin.py @@ -14,10 +14,9 @@ def davies_bouldin_score(cluster): # lower the better r"""Compute the Davies-Bouldin score. - This function computes the Davies-Bouldin - score\ :footcite:p:`Davies-Bouldin` with - :func:`sklearn.metrics.davies_bouldin_score` from a fitted - :ref:`Clustering` instance. + This function computes the Davies-Bouldin score\ :footcite:p:`Davies-Bouldin` with + :func:`sklearn.metrics.davies_bouldin_score` from a fitted :ref:`Clustering` + instance. Parameters ---------- @@ -31,9 +30,9 @@ def davies_bouldin_score(cluster): # lower the better Notes ----- For more details regarding the implementation, please refer to - :func:`sklearn.metrics.davies_bouldin_score`. - This function was modified in order to use the absolute spatial correlation - for distance computations instead of the euclidean distance. + :func:`sklearn.metrics.davies_bouldin_score`. This function was modified in order to + use the absolute spatial correlation for distance computations instead of the + euclidean distance. References ---------- diff --git a/pycrostates/metrics/silhouette.py b/pycrostates/metrics/silhouette.py index fd2a91ec..655edf34 100644 --- a/pycrostates/metrics/silhouette.py +++ b/pycrostates/metrics/silhouette.py @@ -13,10 +13,8 @@ def silhouette_score(cluster): # higher the better r"""Compute the mean Silhouette Coefficient. - This function computes the Silhouette - Coefficient\ :footcite:p:`Silhouettes` with - :func:`sklearn.metrics.silhouette_score` from a fitted - :ref:`Clustering` instance. + This function computes the Silhouette Coefficient\ :footcite:p:`Silhouettes` with + :func:`sklearn.metrics.silhouette_score` from a fitted :ref:`Clustering` instance. Parameters ---------- diff --git a/pycrostates/preprocessing/extract_gfp_peaks.py b/pycrostates/preprocessing/extract_gfp_peaks.py index cdcc1ded..f7b17a38 100644 --- a/pycrostates/preprocessing/extract_gfp_peaks.py +++ b/pycrostates/preprocessing/extract_gfp_peaks.py @@ -33,32 +33,29 @@ def extract_gfp_peaks( ) -> CHData: """:term:`Global Field Power` (:term:`GFP`) peaks extraction. - Extract :term:`Global Field Power` (:term:`GFP`) peaks from - :class:`~mne.Epochs` or :class:`~mne.io.Raw`. + Extract :term:`Global Field Power` (:term:`GFP`) peaks from :class:`~mne.Epochs` or + :class:`~mne.io.Raw`. Parameters ---------- inst : Raw | Epochs Instance from which to extract :term:`global field power` (GFP) peaks. picks : str | list | slice | None - Channels to use for GFP computation. - Note that all channels selected must have the - same type. Slices and lists of integers will be interpreted as - channel indices. In lists, channel name strings (e.g. - ``['Fp1', 'Fp2']``) will pick the given channels. Can also be the - string values “all” to pick all channels, or “data” to pick data - channels. ``"eeg"`` (default) will pick all eeg channels. - Note that channels in ``info['bads']`` will be included if their + Channels to use for GFP computation. Note that all channels selected must have + the same type. Slices and lists of integers will be interpreted as channel + indices. In lists, channel name strings (e.g. ``['Fp1', 'Fp2']``) will pick the + given channels. Can also be the string values ``“all”`` to pick all channels, or + ``“data”`` to pick data channels. ``"eeg"`` (default) will pick all eeg + channels. Note that channels in ``info['bads']`` will be included if their names or indices are explicitly provided. return_all : bool - If True, the returned `~pycrostates.io.ChData` instance will - include all channels. - If False (default), the returned `~pycrostates.io.ChData` instance will - only include channels used for GFP computation (i.e ``picks``). + If True, the returned `~pycrostates.io.ChData` instance will include all + channels. If False (default), the returned `~pycrostates.io.ChData` instance + will only include channels used for GFP computation (i.e ``picks``). min_peak_distance : int - Required minimal horizontal distance (``≥ 1`) in samples between - neighboring peaks. Smaller peaks are removed first until the condition - is fulfilled for all remaining peaks. Default to ``1``. + Required minimal horizontal distance (``≥ 1`) in samples between neighboring + peaks. Smaller peaks are removed first until the condition is fulfilled for all + remaining peaks. Default to ``1``. %(tmin_raw)s %(tmax_raw)s %(reject_by_annotation_raw)s @@ -72,9 +69,9 @@ def extract_gfp_peaks( Notes ----- The :term:`Global Field Power` (:term:`GFP`) peaks are extracted with - :func:`scipy.signal.find_peaks`. Only the ``distance`` argument is - filled with the value provided in ``min_peak_distance``. The other - arguments are set to their default values. + :func:`scipy.signal.find_peaks`. Only the ``distance`` argument is filled with the + value provided in ``min_peak_distance``. The other arguments are set to their + default values. """ from ..io import ChData @@ -146,13 +143,13 @@ def _extract_gfp_peaks( data : array of shape (n_channels, n_samples) The data to extract GFP peaks from. min_peak_distance : int - Required minimal horizontal distance (>= 1) in samples between - neighboring peaks. Smaller peaks are removed first until the condition - is fulfilled for all remaining peaks. Default to 2. + Required minimal horizontal distance (>= 1) in samples between neighboring + peaks. Smaller peaks are removed first until the condition is fulfilled for all + remaining peaks. Default to 2. Returns ------- - peaks : array of shape (n_picks) + peaks : array of shape (n_picks,) The indices when peaks occur. """ gfp = np.std(data, axis=0) diff --git a/pycrostates/preprocessing/resample.py b/pycrostates/preprocessing/resample.py index 6eb08d3a..f0a92c25 100644 --- a/pycrostates/preprocessing/resample.py +++ b/pycrostates/preprocessing/resample.py @@ -48,14 +48,13 @@ def resample( %(tmax_raw)s %(reject_by_annotation_raw)s n_resamples : int - Number of resamples to draw. Each epoch can be used to fit a separate - clustering solution. See notes for additional information. + Number of resamples to draw. Each epoch can be used to fit a separate clustering + solution. See notes for additional information. n_samples : int - Length of each epoch (in samples). See notes for additional - information. + Length of each epoch (in samples). See notes for additional information. coverage : float - Strictly positive ratio between resampling data size and size of the - original recording. See notes for additional information. + Strictly positive ratio between resampling data size and size of the original + recording. See notes for additional information. replace : bool Whether or not to allow resampling with replacement. %(random_state)s @@ -68,9 +67,8 @@ def resample( Notes ----- - Only two of ``n_resamples``, ``n_samples`` and ``coverage`` - parameters must be defined, the non-defined one will be - determine at runtime by the 2 other parameters. + Only two of ``n_resamples``, ``n_samples`` and ``coverage`` parameters must be + defined, the non-defined one will be determine at runtime by the 2 other parameters. """ from ..io import ChData diff --git a/pycrostates/preprocessing/spatial_filter.py b/pycrostates/preprocessing/spatial_filter.py index c810769a..e9b2fa07 100644 --- a/pycrostates/preprocessing/spatial_filter.py +++ b/pycrostates/preprocessing/spatial_filter.py @@ -65,50 +65,42 @@ def apply_spatial_filter( ): r"""Apply a spatial filter. - Adapted from \ :footcite:t:`michel2019eeg`. - Apply an instantaneous filter which interpolates channels - with local neighbors while removing outliers. + Adapted from \ :footcite:t:`michel2019eeg`. Apply an instantaneous filter which + interpolates channels with local neighbors while removing outliers. The current implementation proceeds as follows: * An interpolation matrix is computed using - mne.channels.interpolation._make_interpolation_matrix. - * An ajdacency matrix is computed using - `mne.channels.find_ch_adjacency`. - * If ``exclude_bads`` is set to ``True``, - bad channels are removed from the ajdacency matrix. - * For each timepoint and each channel, - a reduced adjacency matrix is built by removing neighbors - with lowest and highest value. - * For each timepoint and each channel, - a reduced interpolation matrix is built by extracting neighbor - weights based on the reduced adjacency matrix. + ``mne.channels.interpolation._make_interpolation_matrix``. + * An ajdacency matrix is computed using `mne.channels.find_ch_adjacency`. + * If ``exclude_bads`` is set to ``True``, bad channels are removed from the + ajdacency matrix. + * For each timepoint and each channel, a reduced adjacency matrix is built by + removing neighbors with lowest and highest value. + * For each timepoint and each channel, a reduced interpolation matrix is built by + extracting neighbor weights based on the reduced adjacency matrix. * The reduced interpolation matrices are normalized. - * The channel's timepoints are interpolated - using their reduced interpolation matrix. + * The channel's timepoints are interpolated using their reduced interpolation + matrix. Parameters ---------- inst : Raw | Epochs | ChData Instance to filter spatially. ch_type : str - The channel type on which to apply the spatial filter. - Currently only supports ``'eeg'``. + The channel type on which to apply the spatial filter. Currently only supports + ``'eeg'``. exclude_bads : bool - If set to ``True``, bad channels will be removed - from the adjacency matrix and therefore not used - to interpolate neighbors. In addition, bad channels - will not be filtered. - If set to ``False``, proceed as if all channels were good. + If set to ``True``, bad channels will be removed from the adjacency matrix and + therefore not used to interpolate neighbors. In addition, bad channels will not + be filtered. If set to ``False``, proceed as if all channels were good. origin : array of shape (3,) | str - Origin of the sphere in the head coordinate frame and in meters. - Can be ``'auto'`` (default), which means a head-digitization-based - origin fit. + Origin of the sphere in the head coordinate frame and in meters. Can be + ``'auto'`` (default), which means a head-digitization-based origin fit. adjacency : array or csr_matrix of shape (n_channels, n_channels) | str - An adjacency matrix. Can be created using - `mne.channels.find_ch_adjacency` and edited with - `mne.viz.plot_ch_adjacency`. - If ``'auto'`` (default), the matrix will be automatically created - using `mne.channels.find_ch_adjacency` and other parameters. + An adjacency matrix. Can be created using `mne.channels.find_ch_adjacency` and + edited with `mne.viz.plot_ch_adjacency`. If ``'auto'`` (default), the matrix + will be automatically created using `mne.channels.find_ch_adjacency` and other + parameters. %(n_jobs)s %(verbose)s @@ -133,10 +125,9 @@ def apply_spatial_filter( _check_preload(inst, "Apply spatial filter") if inst.get_montage() is None: raise ValueError( - "No montage was set on your data, but spatial filter" - "can only work if digitization points for the EEG " - "channels are available. Consider calling inst.set_montage() " - "to apply a montage." + "No montage was set on your data, but spatial filter can only work if " + "digitization points for the EEG channels are available. Consider calling " + "inst.set_montage() to apply a montage." ) # retrieve picks picks = dict(_picks_by_type(inst.info, exclude=[]))[ch_type] @@ -156,8 +147,8 @@ def apply_spatial_filter( distance = np.mean(distance / np.mean(distance)) if np.abs(1.0 - distance) > 0.1: logger.warn( - "Your spherical fit is poor, interpolation results are " - "likely to be inaccurate." + "Your spherical fit is poor, interpolation results are likely to be " + "inaccurate." ) pos = pos - origin interpolate_matrix = _make_interpolation_matrix(pos, pos) diff --git a/pycrostates/segmentation/_base.py b/pycrostates/segmentation/_base.py index ea2d1c2d..9de7d200 100644 --- a/pycrostates/segmentation/_base.py +++ b/pycrostates/segmentation/_base.py @@ -24,7 +24,7 @@ class _BaseSegmentation(ABC): Parameters ---------- - labels : array (n_samples, ) or (n_epochs, n_samples) + labels : array of shape (n_samples, ) or (n_epochs, n_samples) Microstates labels attributed to each sample, i.e. the segmentation. inst : Raw | Epochs MNE instance used to predict the segmentation. @@ -97,34 +97,32 @@ def compute_parameters(self, norm_gfp: bool = True, return_dist: bool = False): Available parameters are listed below: - * ``mean_corr``: Mean correlation value for each time point - assigned to a given state. + * ``mean_corr``: Mean correlation value for each time point assigned to a + given state. * ``gev``: Global explained variance expressed by a given state. - It is the sum of global explained variance values of each - time point assigned to a given state. + It is the sum of global explained variance values of each time point + assigned to a given state. * ``timecov``: Time coverage, the proportion of time during which a given state is active. This metric is expressed as a ratio. * ``meandurs``: Mean durations of segments assigned to a given state. This metric is expressed in seconds (s). * ``occurrences``: Occurrences per second, the mean number of - segment assigned to a given state per second. This metrics is - expressed in segment per second. + segment assigned to a given state per second. This metrics is expressed + in segment per second. * ``dist_corr`` (req. ``return_dist=True``): Distribution of correlations values of each time point assigned to a given state. * ``dist_gev`` (req. ``return_dist=True``): Distribution of global - explained variances values of each time point assigned to a given - state. + explained variances values of each time point assigned to a given state. * ``dist_durs`` (req. ``return_dist=True``): Distribution of - durations of each segments assigned to a given state. Each value - is expressed in seconds (s). + durations of each segments assigned to a given state. Each value is + expressed in seconds (s). Warnings -------- - When working with `~mne.Epochs`, this method will put together - segments of all epochs. This could lead to wrong interpretation - especially on state durations. To avoid this behaviour, - make sure to set the ``reject_edges`` parameter to ``True`` - when creating the segmentation. + When working with `~mne.Epochs`, this method will put together segments of all + epochs. This could lead to wrong interpretation especially on state durations. + To avoid this behaviour, make sure to set the ``reject_edges`` parameter to + ``True`` when creating the segmentation. """ _check_type(norm_gfp, (bool,), "norm_gfp") _check_type(return_dist, (bool,), "return_dist") @@ -133,8 +131,7 @@ def compute_parameters(self, norm_gfp: bool = True, return_dist: bool = False): sfreq = self._inst.info["sfreq"] # don't copy the data/labels array, get_data, swapaxes, reshape are - # returning a new view of the array, which is fine since we do not - # modify it. + # returning a new view of the array, which is fine since we do not modify it. labels = self._labels # same pointer, no memory overhead. if isinstance(self._inst, BaseRaw): data = self._inst.get_data() @@ -208,9 +205,9 @@ def compute_parameters(self, norm_gfp: bool = True, return_dist: bool = False): def compute_transition_matrix(self, stat="probability", ignore_self=True): """Compute the observed transition matrix. - Count the number of transitions from one state to another - and aggregate the result as statistic. - Transition "from" and "to" unlabeled segments ``-1`` are ignored. + Count the number of transitions from one state to another and aggregate the + result as statistic. Transition "from" and "to" unlabeled segments ``-1`` are + ignored. Parameters ---------- @@ -223,11 +220,10 @@ def compute_transition_matrix(self, stat="probability", ignore_self=True): Warnings -------- - When working with `~mne.Epochs`, this method will take into account - transitions that occur between epochs. This could lead to wrong - interpretation when working with discontinuous data. - To avoid this behaviour, make sure to set the ``reject_edges`` - parameter to ``True`` when predicting the segmentation. + When working with `~mne.Epochs`, this method will take into account transitions + that occur between epochs. This could lead to wrong interpretation when working + with discontinuous data. To avoid this behaviour, make sure to set the + ``reject_edges`` parameter to ``True`` when predicting the segmentation. """ return _compute_transition_matrix( self._labels, @@ -240,11 +236,11 @@ def compute_transition_matrix(self, stat="probability", ignore_self=True): def compute_expected_transition_matrix(self, stat="probability", ignore_self=True): """Compute the expected transition matrix. - Compute the theoretical transition matrix as if time course was - ignored, but microstate proportions kept (i.e. shuffled segmentation). - This matrix can be used to quantify/correct the effect of microstate - time coverage on the observed transition matrix obtained with - the method ``compute_expected_transition_matrix``. + Compute the theoretical transition matrix as if time course was ignored, but + microstate proportions kept (i.e. shuffled segmentation). This matrix can be + used to quantify/correct the effect of microstate time coverage on the observed + transition matrix obtained with the method + ``compute_expected_transition_matrix``. Transition "from" and "to" unlabeled segments ``-1`` are ignored. Parameters diff --git a/pycrostates/segmentation/segmentation.py b/pycrostates/segmentation/segmentation.py index 7488035b..951bdfe7 100644 --- a/pycrostates/segmentation/segmentation.py +++ b/pycrostates/segmentation/segmentation.py @@ -32,9 +32,8 @@ def __init__(self, *args, **kwargs): _check_type(self._inst, (BaseRaw,), item_name="raw") if self._labels.ndim != 1: raise ValueError( - "Argument 'labels' should be a 1D array. The provided array " - f"shape is {self._labels.shape} which has {self._labels.ndim} " - "dimensions." + "Argument 'labels' should be a 1D array. The provided array shape " + f"is {self._labels.shape} which has {self._labels.ndim} dimensions." ) if self._inst.times.size != self._labels.shape[-1]: @@ -115,9 +114,8 @@ def __init__(self, *args, **kwargs): if self._labels.ndim != 2: raise ValueError( - "Argument 'labels' should be a 2D array. The provided array " - f"shape is {self._labels.shape} which has {self._labels.ndim} " - "dimensions." + "Argument 'labels' should be a 2D array. The provided array shape " + f"is {self._labels.shape} which has {self._labels.ndim} dimensions." ) if len(self._inst) != self._labels.shape[0]: raise ValueError( @@ -129,8 +127,7 @@ def __init__(self, *args, **kwargs): raise ValueError( "Provided MNE epochs and labels do not have the same number " f"of samples. The 'epochs' have {self._inst.times.size} " - f"samples, while the 'labels' has {self._labels.shape[-1]} " - "samples." + f"samples, while the 'labels' has {self._labels.shape[-1]} samples." ) @fill_doc diff --git a/pycrostates/segmentation/transitions.py b/pycrostates/segmentation/transitions.py index 2ef8de85..b3c36252 100644 --- a/pycrostates/segmentation/transitions.py +++ b/pycrostates/segmentation/transitions.py @@ -16,9 +16,8 @@ def compute_transition_matrix( ) -> NDArray[float]: """Compute the observed transition matrix. - Count the number of transitions from one state to another and aggregate the - result as statistic. Transitions "from" and "to" unlabeled segments ``-1`` - are ignored. + Count the number of transitions from one state to another and aggregate the result + as statistic. Transitions "from" and "to" unlabeled segments ``-1`` are ignored. Parameters ---------- @@ -84,10 +83,10 @@ def compute_expected_transition_matrix( ) -> NDArray[float]: """Compute the expected transition matrix. - Compute the theoretical transition matrix as if time course was - ignored, but microstate proportions was kept (i.e. shuffled segmentation). - This matrix can be used to quantify/correct the effect of microstate - time coverage on the observed transition matrix obtained with the + Compute the theoretical transition matrix as if time course was ignored, but + microstate proportions was kept (i.e. shuffled segmentation). This matrix can be + used to quantify/correct the effect of microstate time coverage on the observed + transition matrix obtained with the :func:`pycrostates.segmentation.compute_transition_matrix`. Transition "from" and "to" unlabeled segments ``-1`` are ignored. @@ -174,8 +173,7 @@ def _check_labels_n_clusters( raise ValueError( "The argument 'labels' must contain the labels of each timepoint " "encoded as consecutive positive integers (0-indexed). Make sure " - f"you are providing an integer array. '{labels.dtype}' is " - "invalid." + f"you are providing an integer array. '{labels.dtype}' is invalid." ) # check for negative integers except -1 if np.any(labels < -1): diff --git a/pycrostates/utils/_checks.py b/pycrostates/utils/_checks.py index 06705532..1394e0c4 100644 --- a/pycrostates/utils/_checks.py +++ b/pycrostates/utils/_checks.py @@ -144,8 +144,7 @@ def _check_value(item, allowed_values, item_name=None, extra=None): item_name : str | None Name of the item to show inside the error message. extra : str | None - Extra string to append to the invalid value sentence, e.g. - "when using ico mode". + Extra string to append to the invalid value sentence, e.g. "with ico mode". Raises ------ @@ -179,11 +178,10 @@ def _check_value(item, allowed_values, item_name=None, extra=None): def _check_n_jobs(n_jobs): - """ - Check n_jobs parameter. + """Check n_jobs parameter. - Check that n_jobs is a positive integer or a negative integer for all - cores. CUDA is not supported. + Check that n_jobs is a positive integer or a negative integer for all cores. CUDA is + not supported. """ _check_type(n_jobs, ("int",), "n_jobs") if n_jobs <= 0: @@ -292,8 +290,7 @@ def _check_picks_uniqueness(info, picks): "%s '%s' channel(s)" % t for t in zip(counts, ch_types) ) raise ValueError( - "Only one datatype can be selected, but 'picks' " - f"results in {channels_msg}." + f"Only one datatype can be selected, but 'picks' results in {channels_msg}." ) diff --git a/pycrostates/utils/_docs.py b/pycrostates/utils/_docs.py index 62b7b9ad..7bf23960 100644 --- a/pycrostates/utils/_docs.py +++ b/pycrostates/utils/_docs.py @@ -34,11 +34,10 @@ "verbose" ] = """ verbose : int | str | bool | None - Sets the verbosity level. The verbosity increases gradually between - ``"CRITICAL"``, ``"ERROR"``, ``"WARNING"``, ``"INFO"`` and ``"DEBUG"``. - If None is provided, the verbosity is set to ``"WARNING"``. - If a bool is provided, the verbosity is set to ``"WARNING"`` for False and - to ``"INFO"`` for True.""" + Sets the verbosity level. The verbosity increases gradually between ``"CRITICAL"``, + ``"ERROR"``, ``"WARNING"``, ``"INFO"`` and ``"DEBUG"``. If None is provided, the + verbosity is set to ``"WARNING"``. If a bool is provided, the verbosity is set to + ``"WARNING"`` for False and to ``"INFO"`` for True.""" # ---- Clusters ---- docdict[ @@ -63,9 +62,9 @@ "cluster" ] = """ cluster : :ref:`cluster` - Fitted clustering algorithm from which to compute score. - For more details about current clustering implementations, - check the :ref:`Clustering` section of the documentation. + Fitted clustering algorithm from which to compute score. For more details about + current clustering implementations, check the :ref:`Clustering` section of the + documentation. """ # ------ I/O ------- @@ -109,33 +108,32 @@ Aggregate statistic to compute transitions. Can be: * ``count``: show the number of observations of each transition. - * ``probability`` or ``proportion``: normalize count such as the - probabilities along the first axis is always equal to ``1``. - * ``percent``: normalize count such as the - probabilities along the first axis is always equal to ``100``.""" + * ``probability`` or ``proportion``: normalize count such as the probabilities along + the first axis is always equal to ``1``. + * ``percent``: normalize count such as the probabilities along the first axis is + always equal to ``100``.""" docdict[ "stat_expected_transitions" ] = """ stat : str Aggregate statistic to compute transitions. Can be: - * ``probability`` or ``proportion``: normalize count such as the - probabilities along the first axis is always equal to ``1``. - * ``percent``: normalize count such as the - probabilities along the first axis is always equal to ``100``.""" + * ``probability`` or ``proportion``: normalize count such as the probabilities along + the first axis is always equal to ``1``. + * ``percent``: normalize count such as the probabilities along the first axis is + always equal to ``100``.""" docdict[ "ignore_self" ] = """ ignore_self : bool - If True, ignores the transition from one state to itself. - This is equivalent to setting the duration of all states to 1 sample.""" + If True, ignores the transition from one state to itself. This is equivalent to + setting the duration of all states to 1 sample.""" docdict[ "transition_matrix" ] = """ T : array of shape ``(n_cluster, n_cluster)`` Array of transition probability values from one label to another. - First axis indicates state ``"from"``. Second axis indicates state - ``"to"``.""" + First axis indicates state ``"from"``. Second axis indicates state ``"to"``.""" # ------ Viz ------- docdict[ @@ -152,22 +150,21 @@ "axes_topo" ] = """ axes : Axes | None - Either ``None`` to create a new figure or axes (or an array of - axes) on which the topographic map should be plotted. If the number of - microstates maps to plot is ``≥ 1``, an array of axes of size - ``n_clusters`` should be provided.""" + Either ``None`` to create a new figure or axes (or an array of axes) on which the + topographic map should be plotted. If the number of microstates maps to plot is + ``≥ 1``, an array of axes of size ``n_clusters`` should be provided.""" docdict[ "axes_seg" ] = """ axes : Axes | None - Either ``None`` to create a new figure or axes on which the - segmentation is plotted.""" + Either ``None`` to create a new figure or axes on which the segmentation is + plotted.""" docdict[ "axes_cbar" ] = """ cbar_axes : Axes | None - Axes on which to draw the colorbar, otherwise the colormap takes - space from the main axes.""" + Axes on which to draw the colorbar, otherwise the colormap takes space from the main + axes.""" # ------------------------- Documentation functions -------------------------- docdict_indented: Dict[int, Dict[str, str]] = {} diff --git a/pycrostates/utils/_fixes.py b/pycrostates/utils/_fixes.py index f81e1404..579aebce 100644 --- a/pycrostates/utils/_fixes.py +++ b/pycrostates/utils/_fixes.py @@ -7,8 +7,8 @@ class _WrapStdOut(object): """Dynamically wrap to sys.stdout. - This makes packages that monkey-patch sys.stdout (e.g.doctest, - sphinx-gallery) work properly. + This makes packages that monkey-patch sys.stdout (e.g.doctest, sphinx-gallery) work + properly. """ def __getattr__(self, name): # noqa: D105 diff --git a/pycrostates/utils/_imports.py b/pycrostates/utils/_imports.py index 2a7a7e50..a60ce880 100644 --- a/pycrostates/utils/_imports.py +++ b/pycrostates/utils/_imports.py @@ -16,8 +16,8 @@ def import_optional_dependency(name: str, extra: str = "", raise_error: bool = T """ Import an optional dependency. - By default, if a dependency is missing an ImportError with a nice message - will be raised. + By default, if a dependency is missing an ImportError with a nice message will be + raised. Parameters ---------- @@ -27,17 +27,16 @@ def import_optional_dependency(name: str, extra: str = "", raise_error: bool = T Additional text to include in the ImportError message. raise_error : bool What to do when a dependency is not found. - * True : If the module is not installed, raise an ImportError, + * True : If the module is not installed, raise an ImportError, otherwise, return + the module. + * False: If the module is not installed, issue a warning and return None, otherwise, return the module. - * False: If the module is not installed, issue a warning and return - None, otherwise, return the module. Returns ------- maybe_module : Optional[ModuleType] The imported module when found. - None is returned when the package is not found and raise_error is - False. + None is returned when the package is not found and raise_error is False. """ package_name = INSTALL_MAPPING.get(name) install_name = package_name if package_name is not None else name @@ -47,7 +46,7 @@ def import_optional_dependency(name: str, extra: str = "", raise_error: bool = T except ImportError: msg = ( f"Missing optional dependency '{install_name}'. {extra} " - + f"Use pip or conda to install '{install_name}'." + f"Use pip or conda to install '{install_name}'." ) if raise_error: raise ImportError(msg) diff --git a/pycrostates/utils/utils.py b/pycrostates/utils/utils.py index 6225801c..1ffac1a3 100644 --- a/pycrostates/utils/utils.py +++ b/pycrostates/utils/utils.py @@ -15,12 +15,11 @@ def _corr_vectors(A, B, axis=0): # written by Marijn van Vliet """Compute pairwise correlation of multiple pairs of vectors. - Fast way to compute correlation of multiple pairs of vectors without - computing all pairs as would with corr(A,B). Borrowed from Oli at - StackOverflow. Note the resulting coefficients vary slightly from the ones - obtained from corr due to differences in the order of the calculations. - (Differences are of a magnitude of 1e-9 to 1e-17 depending on the tested - data). + Fast way to compute correlation of multiple pairs of vectors without computing all + pairs as would with corr(A,B). Borrowed from Oli at StackOverflow. Note the + resulting coefficients vary slightly from the ones obtained from corr due to + differences in the order of the calculations. (Differences are of a magnitude of + 1e-9 to 1e-17 depending on the tested data). Parameters ---------- diff --git a/pycrostates/viz/cluster_centers.py b/pycrostates/viz/cluster_centers.py index 59128379..6fb323bd 100644 --- a/pycrostates/viz/cluster_centers.py +++ b/pycrostates/viz/cluster_centers.py @@ -46,17 +46,14 @@ def plot_cluster_centers( %(cluster_names)s %(axes_topo)s show_gradient : bool - If True, plot a line between channel locations - with highest and lowest values. + If True, plot a line between channel locations with highest and lowest values. gradient_kwargs : dict - Additional keyword arguments passed to - :meth:`matplotlib.axes.Axes.plot` to plot + Additional keyword arguments passed to :meth:`matplotlib.axes.Axes.plot` to plot gradient line. %(block)s %(verbose)s **kwargs - Additional keyword arguments are passed to - :func:`mne.viz.plot_topomap`. + Additional keyword arguments are passed to :func:`mne.viz.plot_topomap`. Returns ------- @@ -78,8 +75,8 @@ def plot_cluster_centers( ) if gradient_kwargs != _GRADIENT_KWARGS_DEFAULTS and not show_gradient: logger.warning( - "The argument 'gradient_kwargs' has not effect when " - "the argument 'show_gradient' is set to False." + "The argument 'gradient_kwargs' has not effect when the argument " + "'show_gradient' is set to False." ) _check_type(block, (bool,), "block") @@ -88,8 +85,8 @@ def plot_cluster_centers( cluster_names = [str(k) for k in range(1, cluster_centers.shape[0] + 1)] if len(cluster_names) != cluster_centers.shape[0]: raise ValueError( - "Argument 'cluster_centers' and 'cluster_names' should have the " - "same number of elements." + "Argument 'cluster_centers' and 'cluster_names' should have the same " + "number of elements." ) # create axes if needed, and retrieve figure diff --git a/pycrostates/viz/segmentation.py b/pycrostates/viz/segmentation.py index 80c8b733..4ff65fd6 100644 --- a/pycrostates/viz/segmentation.py +++ b/pycrostates/viz/segmentation.py @@ -214,8 +214,8 @@ def _plot_segmentation( _check_type(n_clusters, ("int",), "n_clusters") if n_clusters <= 0: raise ValueError( - f"Provided number of clusters {n_clusters} is invalid. The number " - "of clusters must be strictly positive." + f"Provided number of clusters {n_clusters} is invalid. The number of " + "clusters must be strictly positive." ) _check_type(cluster_names, (None, list, tuple), "cluster_names") _check_type(cmap, (None, str, colors.Colormap), "cmap") @@ -270,10 +270,8 @@ def _plot_segmentation( times, gfp, color=color, where=x, step=None, interpolate=False ) logger.info( - "For visualization purposes, " - "the last segment appears truncated by 1 sample. " - "In the case where the last segment is 1 sample long, " - "it does not appear." + "For visualization purposes, the last segment appears truncated by 1 sample. " + "In the case where the last segment is 1 sample long, it does not appear." ) # commonm formatting