From 329e80b4db946f7629b6ffe79aba0f3e318378ab Mon Sep 17 00:00:00 2001 From: "Thomas S. Binns" Date: Fri, 21 Jun 2024 18:30:19 +0200 Subject: [PATCH] [MAINT] Clean up string formatting (#205) Co-authored-by: Daniel McCloy --- mne_connectivity/base.py | 80 +++++-------- mne_connectivity/envelope.py | 12 +- mne_connectivity/spectral/epochs.py | 106 ++++++++---------- .../spectral/epochs_multivariate.py | 87 ++++++-------- mne_connectivity/spectral/smooth.py | 2 +- .../spectral/tests/test_spectral.py | 2 +- mne_connectivity/spectral/time.py | 31 +++-- mne_connectivity/tests/test_connectivity.py | 18 ++- mne_connectivity/utils/docs.py | 2 +- mne_connectivity/utils/utils.py | 22 ++-- mne_connectivity/vector_ar/model_selection.py | 5 +- mne_connectivity/vector_ar/var.py | 3 +- mne_connectivity/viz/_3d.py | 5 +- mne_connectivity/viz/circle.py | 7 +- mne_connectivity/viz/tests/test_circle.py | 2 +- 15 files changed, 163 insertions(+), 221 deletions(-) diff --git a/mne_connectivity/base.py b/mne_connectivity/base.py index 9ca9dcbc..74cc1d68 100644 --- a/mne_connectivity/base.py +++ b/mne_connectivity/base.py @@ -64,10 +64,7 @@ def _init_epochs(self, events, event_id, on_missing="warn") -> None: if events is not None: for key, val in self.event_id.items(): if val not in events[:, 2]: - msg = "No matching events found for %s " "(event id %i)" % ( - key, - val, - ) + msg = f"No matching events found for {key} (event id {val})" _on_missing(on_missing, msg) # ensure metadata matches original events size @@ -95,9 +92,8 @@ def append(self, epoch_conn): """ if not isinstance(self, type(epoch_conn)): raise ValueError( - f"The type of the epoch connectivity to append " - f"is {type(epoch_conn)}, which does not match " - f"{type(self)}." + f"The type of the epoch connectivity to append is {type(epoch_conn)}, " + f"which does not match {type(self)}." ) if hasattr(self, "times"): if not np.allclose(self.times, epoch_conn.times): @@ -157,8 +153,8 @@ def combine(self, combine="mean"): if not self.is_epoched: raise RuntimeError( - "Combine only works over Epoched connectivity. " - f"It does not work with {self}" + "Combine only works over Epoched connectivity. It does not work with " + f"{self}" ) fun = _check_combine(combine, valid=("mean", "median")) @@ -247,16 +243,16 @@ def predict(self, data): """ if data.ndim < 2 or data.ndim > 3: raise ValueError( - f"Data passed in must be either 2D or 3D. " - f"The data you passed in has {data.ndim} dims." + "Data passed in must be either 2D or 3D. The data you passed in has " + f"{data.ndim} dims." ) if data.ndim == 2 and self.is_epoched: raise RuntimeError( - "If there is a VAR model over epochs, " "one must pass in a 3D array." + "If there is a VAR model over epochs, one must pass in a 3D array." ) if data.ndim == 3 and not self.is_epoched: raise RuntimeError( - "If there is a single VAR model, " "one must pass in a 2D array." + "If there is a single VAR model, one must pass in a 2D array." ) # make the data 3D @@ -419,9 +415,7 @@ def __init__( ): if isinstance(indices, str) and indices not in ["all", "symmetric"]: raise ValueError( - f"Indices can only be " - f'"all", otherwise ' - f"should be a list of tuples. " + 'Indices can only be "all", "symmetric", or a list of tuples. ' f"It cannot be {indices}." ) @@ -450,12 +444,12 @@ def __repr__(self) -> str: if self.n_epochs is not None: r += f"n_epochs : {self.n_epochs}, " if "freqs" in self.dims: - r += "freq : [%f, %f], " % (self.freqs[0], self.freqs[-1]) # type: ignore + r += f"freq : [{self.freqs[0]}, {self.freqs[-1]}], " # type: ignore if "times" in self.dims: - r += "time : [%f, %f], " % (self.times[0], self.times[-1]) # type: ignore + r += f"time : [{self.times[0]}, {self.times[-1]}], " # type: ignore r += f", nave : {self.n_epochs_used}" r += f", nodes, n_estimated : {self.n_nodes}, " f"{self.n_estimated_nodes}" - r += ", ~%s" % (sizeof_fmt(self._size),) + r += f", ~{sizeof_fmt(self._size)}" r += ">" return r @@ -534,25 +528,21 @@ def _prepare_xarray( def _check_data_consistency(self, data, indices, n_nodes): """Perform data input checks.""" if not isinstance(data, np.ndarray): - raise TypeError("Connectivity data must be passed in as a " "numpy array.") + raise TypeError("Connectivity data must be passed in as a numpy array.") if self.is_epoched: if data.ndim < 2 or data.ndim > 4: raise RuntimeError( - f"Data using an epoched data " - f"structure should have at least " - f"2 dimensions and at most 4 " - f"dimensions. Your data was " - f"{data.shape} shape." + "Data using an epoched data structure should have at least 2 " + f"dimensions and at most 4 dimensions. Your data was {data.shape} " + "shape." ) else: if data.ndim > 3: raise RuntimeError( - f"Data not using an epoched data " - f"structure should have at least " - f"1 dimensions and at most 3 " - f"dimensions. Your data was " - f"{data.shape} shape." + "Data not using an epoched data structure should have at least 1 " + f"dimensions and at most 3 dimensions. Your data was {data.shape} " + "shape." ) # get the number of estimated nodes @@ -566,30 +556,24 @@ def _check_data_consistency(self, data, indices, n_nodes): # check that the indices passed in are of the same length if len(indices[0]) != len(indices[1]): raise ValueError( - f"If indices are passed in " - f"then they must be the same " - f"length. They are right now " - f"{len(indices[0])} and " - f"{len(indices[1])}." + "If indices are passed in then they must be the same length. They " + f"are right now {len(indices[0])} and {len(indices[1])}." ) # indices length should match the data length if len(indices[0]) != data_len: raise ValueError( - f"The number of indices, {len(indices[0])} " - f"should match the raveled data length passed " - f"in of {data_len}." + f"The number of indices, {len(indices[0])} should match the " + f"raveled data length passed in of {data_len}." ) elif indices == "symmetric": expected_len = ((n_nodes + 1) * n_nodes) // 2 if data_len != expected_len: raise ValueError( - f'If "indices" is "symmetric", then ' - f"connectivity data should be the " - f"upper-triangular part of the matrix. There " - f"are {data_len} estimated connections. " - f"But there should be {expected_len} " - f"estimated connections." + 'If "indices" is "symmetric", then ' + f"connectivity data should be the upper-triangular part of the " + f"matrix. There are {data_len} estimated connections. But there " + f"should be {expected_len} estimated connections." ) def copy(self): @@ -731,7 +715,7 @@ def get_data(self, output="compact"): # the matrix, and there could also be cases where multiple # results correspond to the same entries in the matrix. raise ValueError( - "cannot return multivariate connectivity " "data in a dense form" + "cannot return multivariate connectivity data in a dense form" ) # get the new shape of the data array @@ -794,7 +778,7 @@ def rename_nodes(self, mapping): if any(missing): raise ValueError( "Name(s) in mapping missing from info: " - "%s" % np.array(orig_names)[np.array(missing)] + f"{np.array(orig_names)[np.array(missing)]}" ) new_names = [ (names.index(name), new_name) for name, new_name in mapping.items() @@ -802,9 +786,7 @@ def rename_nodes(self, mapping): elif callable(mapping): new_names = [(ci, mapping(name)) for ci, name in enumerate(names)] else: - raise ValueError( - "mapping must be callable or dict, not %s" % (type(mapping),) - ) + raise ValueError(f"mapping must be callable or dict, not {type(mapping)}") # check we got all strings out of the mapping for new_name in new_names: diff --git a/mne_connectivity/envelope.py b/mne_connectivity/envelope.py index 7d2b20df..00f8685e 100644 --- a/mne_connectivity/envelope.py +++ b/mne_connectivity/envelope.py @@ -119,13 +119,13 @@ def envelope_correlation( epoch_data = epoch_data.data if epoch_data.ndim != 2: raise ValueError( - "Each entry in data must be 2D, got shape %s" % (epoch_data.shape,) + f"Each entry in data must be 2D, got shape {epoch_data.shape}" ) n_nodes, n_times = epoch_data.shape if ei > 0 and n_nodes != corrs[0].shape[0]: raise ValueError( - "n_nodes mismatch between data[0] and data[%d], " - "got %s and %s" % (ei, n_nodes, corrs[0].shape[0]) + f"n_nodes mismatch between data[0] and data[{ei}], got {n_nodes} and " + f"{corrs[0].shape[0]}" ) # Get the complex envelope (allowing complex inputs allows people @@ -136,7 +136,7 @@ def envelope_correlation( if not np.iscomplexobj(epoch_data): raise ValueError( - "data.dtype must be float or complex, got %s" % (epoch_data.dtype,) + f"data.dtype must be float or complex, got {epoch_data.dtype}" ) data_mag = np.abs(epoch_data) data_conj_scaled = epoch_data.conj() @@ -280,8 +280,8 @@ def _gen_sym_orth(data, n_iter, tol): n, m = Z.shape if m < n: raise RuntimeError( - f"Symmetric orth requires at least as many time points ({m}) " - f"as the number of time series ({n})" + f"Symmetric orth requires at least as many time points ({m}) as the " + f"number of time series ({n})" ) logger.debug("Symmetric orth") # "starting with D(1) = I_n" diff --git a/mne_connectivity/spectral/epochs.py b/mne_connectivity/spectral/epochs.py index 2745cdc2..af650d48 100644 --- a/mne_connectivity/spectral/epochs.py +++ b/mne_connectivity/spectral/epochs.py @@ -44,12 +44,12 @@ def _compute_freqs(n_times, sfreq, cwt_freqs, mode): elif mode == "cwt_morlet": # cwt_morlet mode if cwt_freqs is None: - raise ValueError("define frequencies of interest using " "cwt_freqs") + raise ValueError("define frequencies of interest using cwt_freqs") else: cwt_freqs = cwt_freqs.astype(np.float64) if any(cwt_freqs > (sfreq / 2.0)): raise ValueError( - "entries in cwt_freqs cannot be " "larger than Nyquist (sfreq / 2)" + "entries in cwt_freqs cannot be larger than Nyquist (sfreq / 2)" ) freqs_all = cwt_freqs else: @@ -98,13 +98,13 @@ def _prepare_connectivity( if tmin is not None and tmin < times_in[0]: warn( - "start time tmin=%0.2f s outside of the time scope of the data " - "[%0.2f s, %0.2f s]" % (tmin, times_in[0], times_in[-1]) + f"start time tmin={tmin:.2f} s outside of the time scope of the data " + f"[{times_in[0]:.2f} s, {times_in[-1]:.2f} s]" ) if tmax is not None and tmax > times_in[-1]: warn( - "stop time tmax=%0.2f s outside of the time scope of the data " - "[%0.2f s, %0.2f s]" % (tmax, times_in[0], times_in[-1]) + f"stop time tmax={tmax:.2f} s outside of the time scope of the data " + f"[{times_in[0]:.2f} s, {times_in[-1]:.2f} s]" ) mask = _time_mask(times_in, tmin, tmax, sfreq=sfreq) @@ -125,8 +125,8 @@ def _prepare_connectivity( if multivariate_con: if any(this_method in _gc_methods for this_method in method): raise ValueError( - "indices must be specified when computing Granger " - "causality, as all-to-all connectivity is not supported" + "indices must be specified when computing Granger causality, as " + "all-to-all connectivity is not supported" ) else: logger.info("using all indices for multivariate connectivity") @@ -151,8 +151,8 @@ def _prepare_connectivity( ) if intersection.size > 0: raise ValueError( - "seed and target indices must not intersect when " - "computing Granger causality" + "seed and target indices must not intersect when computing " + "Granger causality" ) else: indices_use = check_indices(indices) @@ -160,10 +160,10 @@ def _prepare_connectivity( # number of connectivities to compute n_cons = len(indices_use[0]) - logger.info(" computing connectivity for %d connections" % n_cons) + logger.info(f" computing connectivity for {n_cons} connections") logger.info( - " using t=%0.3fs..%0.3fs for estimation (%d points)" - % (tmin_true, tmax_true, n_times) + f" using t={tmin_true:.3f}s..{tmax_true:.3f}s for estimation ({n_times} " + "points)" ) # check that fmin corresponds to at least 5 cycles @@ -175,17 +175,10 @@ def _prepare_connectivity( else: if np.any(fmin < five_cycle_freq): warn( - "fmin=%0.3f Hz corresponds to %0.3f < 5 cycles " - "based on the epoch length %0.3f sec, need at least %0.3f " - "sec epochs or fmin=%0.3f. Spectrum estimate will be " - "unreliable." - % ( - np.min(fmin), - dur * np.min(fmin), - dur, - 5.0 / np.min(fmin), - five_cycle_freq, - ) + f"fmin={np.min(fmin):.3f} Hz corresponds to {dur * np.min(fmin):.3f} < " + f"5 cycles based on the epoch length {dur:.3f} sec, need at least " + f"{5.0 / np.min(fmin):.3f} sec epochs or fmin={five_cycle_freq:.3f}. " + "Spectrum estimate will be unreliable." ) # compute frequencies to analyze based on number of samples, @@ -209,25 +202,24 @@ def _prepare_connectivity( for i, n_f_band in enumerate([len(f) for f in freqs_bands]): if n_f_band == 0: raise ValueError( - "There are no frequency points between " - "%0.1fHz and %0.1fHz. Change the band " - "specification (fmin, fmax) or the " - "frequency resolution." % (fmin[i], fmax[i]) + f"There are no frequency points between {fmin[i]:.1f}Hz and " + f"{fmax[i]:.1f}Hz. Change the band specification (fmin, fmax) or the " + "frequency resolution." ) if n_bands == 1: logger.info( - " frequencies: %0.1fHz..%0.1fHz (%d points)" - % (freqs_bands[0][0], freqs_bands[0][-1], n_freqs) + f" frequencies: {freqs_bands[0][0]:.1f}Hz..{freqs_bands[0][-1]:.1f}Hz " + f"({n_freqs} points)" ) else: logger.info(" computing connectivity for the bands:") for i, bfreqs in enumerate(freqs_bands): logger.info( - " band %d: %0.1fHz..%0.1fHz " - "(%d points)" % (i + 1, bfreqs[0], bfreqs[-1], len(bfreqs)) + f" band {i + 1}: {bfreqs[0]:.1f}Hz..{bfreqs[-1]:.1f}Hz " + f"({len(bfreqs)} points)" ) if faverage: - logger.info(" connectivity scores will be averaged for " "each band") + logger.info(" connectivity scores will be averaged for each band") return ( n_cons, @@ -270,10 +262,10 @@ def _assemble_spectral_params( ) spectral_params.update(window_fun=window_fun, eigvals=eigvals) elif mode == "fourier": - logger.info(" using FFT with a Hanning window to estimate " "spectra") + logger.info(" using FFT with a Hanning window to estimate spectra") spectral_params.update(window_fun=np.hanning(n_times), eigvals=1.0) elif mode == "cwt_morlet": - logger.info(" using CWT with Morlet wavelets to estimate " "spectra") + logger.info(" using CWT with Morlet wavelets to estimate spectra") # reformat cwt_n_cycles if we have removed some frequencies # using fmin, fmax, fskip @@ -281,8 +273,8 @@ def _assemble_spectral_params( if len(cwt_n_cycles) > 1: if len(cwt_n_cycles) != len(cwt_freqs): raise ValueError( - "cwt_n_cycles must be float or an " - "array with the same size as cwt_freqs" + "cwt_n_cycles must be float or an array with the same size as " + "cwt_freqs" ) cwt_n_cycles = cwt_n_cycles[freq_mask] @@ -537,7 +529,7 @@ def _get_and_verify_data_sizes( if n_times is not None: if this_n_times != n_times: raise ValueError( - "all input time series must have the same " "number of time points" + "all input time series must have the same number of time points" ) else: n_times = this_n_times @@ -563,7 +555,7 @@ def _get_and_verify_data_sizes( if n_signals is not None: if n_signals != n_signals_tot: raise ValueError( - "the number of time series has to be the same in " "each epoch" + "the number of time series has to be the same in each epoch" ) n_signals = n_signals_tot @@ -582,14 +574,13 @@ def _check_estimators(method): if this_method in _CON_METHOD_MAP: con_method_types.append(_CON_METHOD_MAP[this_method]) elif isinstance(this_method, str): - raise ValueError("%s is not a valid connectivity method" % this_method) + raise ValueError(f"{this_method} is not a valid connectivity method") else: # support for custom class method_valid, msg = _check_method(this_method) if not method_valid: raise ValueError( - "The supplied connectivity method does " - "not have the method %s" % msg + f"The supplied connectivity method does not have the method {msg}" ) con_method_types.append(this_method) @@ -954,15 +945,15 @@ def spectral_connectivity_epochs( if n_bands != 1 and any(this_method in _gc_methods for this_method in method): raise ValueError( - "computing Granger causality on multiple frequency " - "bands is not yet supported" + "computing Granger causality on multiple frequency bands is not yet " + "supported" ) if any(this_method in _multivariate_methods for this_method in method): if not all(this_method in _multivariate_methods for this_method in method): raise ValueError( - "bivariate and multivariate connectivity methods cannot be " - "used in the same function call" + "bivariate and multivariate connectivity methods cannot be used in the " + "same function call" ) multivariate_con = True else: @@ -998,9 +989,7 @@ def spectral_connectivity_epochs( times_in = None metadata = None if sfreq is None: - raise ValueError( - "Sampling frequency (sfreq) is required with " "array input." - ) + raise ValueError("Sampling frequency (sfreq) is required with array input.") # loop over data; it could be a generator that returns # (n_signals x n_times) arrays or SourceEstimates @@ -1120,7 +1109,7 @@ def spectral_connectivity_epochs( sep = ", " metrics_str = sep.join([meth.name for meth in con_methods]) - logger.info(" the following metrics will be computed: %s" % metrics_str) + logger.info(f" the following metrics will be computed: {metrics_str}") # check dimensions and time scale for this_epoch in epoch_block: @@ -1161,8 +1150,7 @@ def spectral_connectivity_epochs( # no parallel processing for this_epoch in epoch_block: logger.info( - " computing cross-spectral density for epoch %d" - % (epoch_idx + 1) + f" computing cross-spectral density for epoch {epoch_idx + 1}" ) # con methods and psd are updated inplace _epoch_spectral_connectivity(data=this_epoch, **call_params) @@ -1170,8 +1158,8 @@ def spectral_connectivity_epochs( else: # process epochs in parallel logger.info( - " computing cross-spectral density for epochs %d..%d" - % (epoch_idx + 1, epoch_idx + len(epoch_block)) + f" computing cross-spectral density for epochs {epoch_idx + 1}.." + f"{epoch_idx + len(epoch_block)}" ) out = parallel( @@ -1217,16 +1205,14 @@ def spectral_connectivity_epochs( if this_con.shape[0] != n_cons: raise RuntimeError( - "first dimension of connectivity scores does not match the " - "number of connections; please contact the mne-connectivity " - "developers" + "first dimension of connectivity scores does not match the number of " + "connections; please contact the mne-connectivity developers" ) if faverage: if this_con.shape[1] != n_freqs: raise RuntimeError( - "second dimension of connectivity scores does not match " - "the number of frequencies; please contact the " - "mne-connectivity developers" + "second dimension of connectivity scores does not match the number " + "of frequencies; please contact the mne-connectivity developers" ) con_shape = (n_cons, n_bands) + this_con.shape[2:] this_con_bands = np.empty(con_shape, dtype=this_con.dtype) diff --git a/mne_connectivity/spectral/epochs_multivariate.py b/mne_connectivity/spectral/epochs_multivariate.py index 3881e580..e435cfef 100644 --- a/mne_connectivity/spectral/epochs_multivariate.py +++ b/mne_connectivity/spectral/epochs_multivariate.py @@ -44,12 +44,7 @@ def _check_rank_input(rank, data, indices): con_i = 1 for seed_rank, target_rank in zip(rank[0], rank[1]): logger.info( - " connection %i - seeds (%i); targets (%i)" - % ( - con_i, - seed_rank, - target_rank, - ) + f" connection {con_i} - seeds {seed_rank}; targets {target_rank}" ) con_i += 1 rank = tuple((np.array(rank[0]), np.array(rank[1]))) @@ -61,8 +56,8 @@ def _check_rank_input(rank, data, indices): or len(rank[1]) != len(indices[1]) ): raise ValueError( - "rank argument must have shape (2, n_cons), " - "according to n_cons in the indices" + "rank argument must have shape (2, n_cons), according to n_cons in the " + "indices" ) for seed_idcs, target_idcs, seed_rank, target_rank in zip( indices[0], indices[1], rank[0], rank[1] @@ -71,9 +66,9 @@ def _check_rank_input(rank, data, indices): 0 < seed_rank <= len(seed_idcs) and 0 < target_rank <= len(target_idcs) ): raise ValueError( - "ranks for seeds and targets must be > 0 and <= the " - "number of channels in the seeds and targets, " - "respectively, for each connection" + "ranks for seeds and targets must be > 0 and <= the number of " + "channels in the seeds and targets, respectively, for each " + "connection" ) return rank @@ -154,12 +149,7 @@ def _compute_n_progress_bar_steps(self): def _log_connection_number(self, con_i): """Log the number of the connection being computed.""" logger.info( - "Computing %s for connection %i of %i" - % ( - self.name, - con_i + 1, - self.n_cons, - ) + f"Computing {self.name} for connection {con_i + 1} of {self.n_cons}" ) def _get_block_indices(self, block_i, limit): @@ -218,8 +208,8 @@ def __init__( def compute_con(self, indices, ranks, n_epochs=1): """Compute multivariate coherency methods.""" assert self.name in ["CaCoh", "MIC", "MIM"], ( - "the class name is not recognised, please contact the " - "mne-connectivity developers" + "the class name is not recognised, please contact the mne-connectivity " + "developers" ) csd = self.reshape_csd() / n_epochs @@ -322,10 +312,10 @@ def _compute_t(self, C_r, n_seeds): return self._invsqrtm(C_r, n_seeds) except np.linalg.LinAlgError as error: raise RuntimeError( - "the transformation matrix of the data could not be computed " - "from the cross-spectral density; check that you are using " - "full rank data or specify an appropriate rank for the seeds " - "and targets that is less than or equal to their ranks" + "the transformation matrix of the data could not be computed from the " + "cross-spectral density; check that you are using full rank data or " + "specify an appropriate rank for the seeds and targets that is less " + "than or equal to their ranks" ) from error def _invsqrtm(self, C_r, n_seeds): @@ -367,8 +357,8 @@ def _invsqrtm(self, C_r, n_seeds): n_zero = (eigvals == 0).sum() if n_zero: # sign of non-full rank data raise np.linalg.LinAlgError( - "Cannot compute inverse square root of rank-deficient matrix " - f"with {n_zero}/{len(eigvals)} zero eigenvalue(s)" + "Cannot compute inverse square root of rank-deficient matrix with " + f"{n_zero}/{len(eigvals)} zero eigenvalue(s)" ) T[:, :, :n_seeds, :n_seeds] = ( eigvects * np.expand_dims(1.0 / np.sqrt(eigvals), (2)) @@ -379,8 +369,8 @@ def _invsqrtm(self, C_r, n_seeds): n_zero = (eigvals == 0).sum() if n_zero: # sign of non-full rank data raise np.linalg.LinAlgError( - "Cannot compute inverse square root of rank-deficient matrix " - f"with {n_zero}/{len(eigvals)} zero eigenvalue(s)" + "Cannot compute inverse square root of rank-deficient matrix with " + f"{n_zero}/{len(eigvals)} zero eigenvalue(s)" ) T[:, :, n_seeds:, n_seeds:] = ( eigvects * np.expand_dims(1.0 / np.sqrt(eigvals), (2)) @@ -401,8 +391,8 @@ def _compute_con_daughter( ): """Compute multivariate imag. part of coherency for one connection.""" assert self.name in ["MIC", "MIM"], ( - "the class name is not recognised, please contact the " - "mne-connectivity developers" + "the class name is not recognised, please contact the mne-connectivity " + "developers" ) # Eqs. 3 & 4 @@ -531,8 +521,8 @@ def _compute_con_daughter( ): """Compute CaCoh & spatial patterns for one connection.""" assert self.name == "CaCoh", ( - "the class name is not recognised, please contact the " - "mne-connectivity developers" + "the class name is not recognised, please contact the mne-connectivity " + "developers" ) n_seeds = len(seed_idcs) n_targets = len(target_idcs) @@ -698,20 +688,16 @@ def __init__(self, n_signals, n_cons, n_freqs, n_times, n_lags, *, n_jobs=1): self.freq_res = (self.n_freqs - 1) * 2 if n_lags >= self.freq_res: raise ValueError( - "the number of lags (%i) must be less than double the " - "frequency resolution (%i)" - % ( - n_lags, - self.freq_res, - ) + f"the number of lags {n_lags} must be less than double the frequency " + f"resolution {self.freq_res}" ) self.n_lags = n_lags def compute_con(self, indices, ranks, n_epochs=1): """Compute multivariate state-space Granger causality.""" assert self.name in ["GC", "GC time-reversed"], ( - "the class name is not recognised, please contact the " - "mne-connectivity developers" + "the class name is not recognised, please contact the mne-connectivity " + "developers" ) csd = self.reshape_csd() / n_epochs @@ -837,27 +823,26 @@ def _autocov_to_full_var(self, autocov): """Compute full VAR model using Whittle's LWR recursion.""" if np.any(np.linalg.det(autocov) == 0): raise RuntimeError( - "the autocovariance matrix is singular; check if your data is " - "rank deficient and specify an appropriate rank argument <= " - "the rank of the seeds and targets" + "the autocovariance matrix is singular; check if your data is rank " + "deficient and specify an appropriate rank argument <= the rank of the " + "seeds and targets" ) A_f, V = self._whittle_lwr_recursion(autocov) if not np.isfinite(A_f).all(): raise RuntimeError( - "at least one VAR model coefficient is " - "infinite or NaN; check the data you are using" + "at least one VAR model coefficient is infinite or NaN; check the data " + "you are using" ) try: np.linalg.cholesky(V) except np.linalg.LinAlgError as np_error: raise RuntimeError( - "the covariance matrix of the residuals is not " - "positive-definite; check the singular values of your data " - "and specify an appropriate rank argument <= the rank of the " - "seeds and targets" + "the covariance matrix of the residuals is not positive-definite; " + "check the singular values of your data and specify an appropriate " + "rank argument <= the rank of the seeds and targets" ) from np_error return A_f, V @@ -926,9 +911,9 @@ def _whittle_lwr_recursion(self, G): A_b[:, :, k_b] = np.dstack((AA_b, A_b_previous - (AA_b @ A_f_previous))) except np.linalg.LinAlgError as np_error: raise RuntimeError( - "the autocovariance matrix is singular; check if your data is " - "rank deficient and specify an appropriate rank argument <= " - "the rank of the seeds and targets" + "the autocovariance matrix is singular; check if your data is rank " + "deficient and specify an appropriate rank argument <= the rank of the " + "seeds and targets" ) from np_error V = cov - (A_f @ G_f) diff --git a/mne_connectivity/spectral/smooth.py b/mne_connectivity/spectral/smooth.py index 97a1a9de..e67f4ab2 100644 --- a/mne_connectivity/spectral/smooth.py +++ b/mne_connectivity/spectral/smooth.py @@ -26,7 +26,7 @@ def _create_kernel(sm_times, sm_freqs, kernel="hanning"): if scale: # I know this piece of code is terrible ='D - logger.info("For frequency dependent kernel sm_freqs is not used" "") + logger.info("For frequency dependent kernel sm_freqs is not used") # Number of kernels n_kernel = len(sm_times) # Get the size of the biggest kernel diff --git a/mne_connectivity/spectral/tests/test_spectral.py b/mne_connectivity/spectral/tests/test_spectral.py index 0f2e2021..4da3d9d8 100644 --- a/mne_connectivity/spectral/tests/test_spectral.py +++ b/mne_connectivity/spectral/tests/test_spectral.py @@ -1390,7 +1390,7 @@ def test_spectral_connectivity_time_padding(method, mode, padding): # run connectivity estimation if padding == 5: with pytest.raises( - ValueError, match="Padding cannot be larger than " "half of data length" + ValueError, match="Padding cannot be larger than half of data length" ): con = spectral_connectivity_time( data, diff --git a/mne_connectivity/spectral/time.py b/mne_connectivity/spectral/time.py index 9ab86d25..c2db4a97 100644 --- a/mne_connectivity/spectral/time.py +++ b/mne_connectivity/spectral/time.py @@ -392,9 +392,7 @@ def spectral_connectivity_time( names = np.arange(0, n_signals) metadata = None if sfreq is None: - raise ValueError( - "Sampling frequency (sfreq) is required with " "array input." - ) + raise ValueError("Sampling frequency (sfreq) is required with array input.") # check that method is a list if isinstance(method, str): @@ -417,15 +415,15 @@ def spectral_connectivity_time( if len(fmin) != 1 and any(this_method in _gc_methods for this_method in method): raise ValueError( - "computing Granger causality on multiple frequency " - "bands is not yet supported" + "computing Granger causality on multiple frequency bands is not yet " + "supported" ) if any(this_method in _multivariate_methods for this_method in method): if not all(this_method in _multivariate_methods for this_method in method): raise ValueError( - "bivariate and multivariate connectivity methods cannot be " - "used in the same function call" + "bivariate and multivariate connectivity methods cannot be used in the " + "same function call" ) multivariate_con = True else: @@ -452,8 +450,8 @@ def spectral_connectivity_time( if multivariate_con: if any(this_method in _gc_methods for this_method in method): raise ValueError( - "indices must be specified when computing Granger " - "causality, as all-to-all connectivity is not supported" + "indices must be specified when computing Granger causality, as " + "all-to-all connectivity is not supported" ) logger.info("using all indices for multivariate connectivity") # indices expected to be a masked array, even if not ragged @@ -476,8 +474,8 @@ def spectral_connectivity_time( ) if intersection.size > 0: raise ValueError( - "seed and target indices must not intersect when " - "computing Granger causality" + "seed and target indices must not intersect when computing " + "Granger causality" ) # make sure padded indices are stored in the connectivity object # create a copy so that `indices_use` can be modified @@ -527,15 +525,14 @@ def spectral_connectivity_time( cycle_freq = n_cycles / dur if np.any(freqs < cycle_freq): raise ValueError( - "At least one value in n_cycles corresponds to a" - "wavelet longer than the signal. Use less cycles, " - "higher frequencies, or longer epochs." + "At least one value in n_cycles corresponds to a wavelet longer than the " + "signal. Use less cycles, higher frequencies, or longer epochs." ) # check for Nyquist if np.any(freqs > sfreq / 2): raise ValueError( - f"Frequencies {freqs[freqs > sfreq / 2]} Hz are " - f"larger than Nyquist = {sfreq / 2:.2f} Hz" + f"Frequencies {freqs[freqs > sfreq / 2]} Hz are larger than Nyquist = " + f"{sfreq / 2:.2f} Hz" ) # compute frequency mask based on specified min/max and decimation factor @@ -803,7 +800,7 @@ def _spectral_connectivity( raise ValueError(f"Padding cannot be negative, got {padding}.") if padding >= data.shape[-1] / sfreq / 2: raise ValueError( - f"Padding cannot be larger than half of data " f"length, got {padding}." + f"Padding cannot be larger than half of data length, got {padding}." ) pad_idx = int(np.floor(padding * sfreq / decim)) out = out[..., pad_idx:-pad_idx] diff --git a/mne_connectivity/tests/test_connectivity.py b/mne_connectivity/tests/test_connectivity.py index 0f479c60..fe767ee8 100644 --- a/mne_connectivity/tests/test_connectivity.py +++ b/mne_connectivity/tests/test_connectivity.py @@ -128,25 +128,23 @@ def test_connectivity_containers(conn_cls): # test initialization error checks with pytest.raises( - TypeError, match="Connectivity data " "must be passed in as a " "numpy array" + TypeError, match="Connectivity data must be passed in as a numpy array" ): conn_cls(data=data, n_nodes=2, **extra_kwargs) - with pytest.raises(RuntimeError, match="Data*."): + with pytest.raises(RuntimeError, match="Data"): conn_cls(data=bad_numpy_input, n_nodes=2, **extra_kwargs) - with pytest.raises(ValueError, match="If indices are passed*."): + with pytest.raises(ValueError, match="If indices are passed"): conn_cls( data=correct_numpy_input, indices=bad_indices, n_nodes=2, **extra_kwargs ) - with pytest.raises(ValueError, match="Indices can only be*."): + with pytest.raises(ValueError, match="Indices can only be"): conn_cls(data=correct_numpy_input, indices="square", n_nodes=2, **extra_kwargs) indices = ([0, 1], [1, 0]) conn = conn_cls(data=correct_numpy_input, n_nodes=3, **extra_kwargs) # test that get_data works as intended - with pytest.raises( - ValueError, match="Invalid value for the " "'output' parameter*." - ): + with pytest.raises(ValueError, match="Invalid value for the 'output' parameter"): conn.get_data(output="blah") assert conn.shape == tuple(correct_numpy_shape) @@ -154,11 +152,11 @@ def test_connectivity_containers(conn_cls): assert conn.get_data(output="dense").ndim == len(correct_numpy_shape) + 1 # test renaming nodes error checks - with pytest.raises(ValueError, match="Name*."): + with pytest.raises(ValueError, match="Name"): conn.rename_nodes({"100": "new_name"}) - with pytest.raises(ValueError, match="mapping must be*"): + with pytest.raises(ValueError, match="mapping must be"): conn.rename_nodes(["0", "new_name"]) - with pytest.raises(ValueError, match="New channel names*"): + with pytest.raises(ValueError, match="New channel names"): conn.rename_nodes({"0": "1"}) # test renaming nodes diff --git a/mne_connectivity/utils/docs.py b/mne_connectivity/utils/docs.py index a42702cd..b7f0147f 100644 --- a/mne_connectivity/utils/docs.py +++ b/mne_connectivity/utils/docs.py @@ -296,5 +296,5 @@ def fill_doc(f): except (TypeError, ValueError, KeyError) as exp: funcname = f.__name__ funcname = docstring.split("\n")[0] if funcname is None else funcname - raise RuntimeError("Error documenting %s:\n%s" % (funcname, str(exp))) + raise RuntimeError(f"Error documenting {funcname}:\n{str(exp)}") return f diff --git a/mne_connectivity/utils/utils.py b/mne_connectivity/utils/utils.py index a4f3ad50..c996df59 100644 --- a/mne_connectivity/utils/utils.py +++ b/mne_connectivity/utils/utils.py @@ -73,7 +73,7 @@ def check_indices(indices): if len(indices[0]) != len(indices[1]): raise ValueError( - "Index arrays indices[0] and indices[1] must " "have the same length" + "Index arrays indices[0] and indices[1] must have the same length" ) if any( @@ -149,7 +149,7 @@ def _check_multivariate_indices(indices, n_chans): if len(indices[0]) != len(indices[1]): raise ValueError( - "index arrays indices[0] and indices[1] must " "have the same length" + "index arrays indices[0] and indices[1] must have the same length" ) n_cons = len(indices[0]) @@ -160,14 +160,14 @@ def _check_multivariate_indices(indices, n_chans): for con_idx, con in enumerate(group): if not isinstance(con, (np.ndarray, list, tuple)): raise TypeError( - "multivariate indices must contain array-likes of channel " - "indices for each seed and target" + "multivariate indices must contain array-likes of channel indices " + "for each seed and target" ) con = np.array(con) if len(con) != len(np.unique(con)): raise ValueError( - "multivariate indices cannot contain repeated channels " - "within a seed or target" + "multivariate indices cannot contain repeated channels within a " + "seed or target" ) max_n_chans = max(max_n_chans, len(con)) # convert negative to positive indices @@ -175,7 +175,7 @@ def _check_multivariate_indices(indices, n_chans): if chan < 0: if chan * -1 >= n_chans: raise ValueError( - "a negative channel index is not present in the " "data" + "a negative channel index is not present in the data" ) indices[group_idx][con_idx][chan_idx] = chan % n_chans @@ -334,8 +334,8 @@ def degree(connectivity, threshold_prop=0.2): connectivity = np.array(connectivity) if connectivity.ndim != 2 or connectivity.shape[0] != connectivity.shape[1]: raise ValueError( - "connectivity must be have shape (n_nodes, n_nodes), " - "got %s" % (connectivity.shape,) + "connectivity must be have shape (n_nodes, n_nodes), got " + f"{connectivity.shape}" ) n_nodes = len(connectivity) if np.allclose(connectivity, connectivity.T): @@ -345,9 +345,7 @@ def degree(connectivity, threshold_prop=0.2): split = 1.0 threshold_prop = float(threshold_prop) if not 0 < threshold_prop <= 1: - raise ValueError( - "threshold must be 0 <= threshold < 1, got %s" % (threshold_prop,) - ) + raise ValueError(f"threshold must be 0 <= threshold < 1, got {threshold_prop}") degree = connectivity.ravel() # no need to copy because np.array does degree[:: n_nodes + 1] = 0.0 n_keep = int(round((degree.size - len(connectivity)) * threshold_prop / split)) diff --git a/mne_connectivity/vector_ar/model_selection.py b/mne_connectivity/vector_ar/model_selection.py index 5a1b19ca..b507b123 100644 --- a/mne_connectivity/vector_ar/model_selection.py +++ b/mne_connectivity/vector_ar/model_selection.py @@ -49,9 +49,8 @@ def select_order(X, maxlags=None): else: if maxlags > max_estimable: raise ValueError( - "maxlags is too large for the number of observations and " - "the number of equations. The largest model cannot be " - "estimated." + "maxlags is too large for the number of observations and the number of " + "equations. The largest model cannot be estimated." ) # define dictionary of information criterions diff --git a/mne_connectivity/vector_ar/var.py b/mne_connectivity/vector_ar/var.py index c75a1a39..43d46680 100644 --- a/mne_connectivity/vector_ar/var.py +++ b/mne_connectivity/vector_ar/var.py @@ -174,8 +174,7 @@ def vector_auto_regression( if verbose: logger.info( - f"Running {model} vector autoregression with parameters: " - f"\n{model_params}" + f"Running {model} vector autoregression with parameters: \n{model_params}" ) if model == "avg-epochs": diff --git a/mne_connectivity/viz/_3d.py b/mne_connectivity/viz/_3d.py index 3b338cc4..6a2af2e1 100644 --- a/mne_connectivity/viz/_3d.py +++ b/mne_connectivity/viz/_3d.py @@ -60,9 +60,8 @@ def plot_sensors_connectivity( picks = _picks_to_idx(info, picks) if len(picks) != len(con): raise ValueError( - "The number of channels picked (%s) does not " - "correspond to the size of the connectivity data " - "(%s)" % (len(picks), len(con)) + f"The number of channels picked ({len(picks)}) does not correspond to the " + f"size of the connectivity data ({len(con)})" ) # Plot the sensor locations diff --git a/mne_connectivity/viz/circle.py b/mne_connectivity/viz/circle.py index 9b3d4b4a..c39d4e6c 100644 --- a/mne_connectivity/viz/circle.py +++ b/mne_connectivity/viz/circle.py @@ -151,10 +151,9 @@ def plot_connectivity_circle( if fig is not None or subplot is not None: warn( - "Passing a `fig` and `subplot` is deprecated and not be " - "supported after mne-connectivity version 0.4. Please " - "use the `ax` argument and pass a matplotlib axes object " - "with polar coordinates instead", + "Passing a `fig` and `subplot` is deprecated and not supported after " + "mne-connectivity version 0.4. Please use the `ax` argument and pass a " + "matplotlib axes object with polar coordinates instead", DeprecationWarning, ) if ax is None: # don't overwrite ax if passed diff --git a/mne_connectivity/viz/tests/test_circle.py b/mne_connectivity/viz/tests/test_circle.py index 6f36c362..84e52a96 100644 --- a/mne_connectivity/viz/tests/test_circle.py +++ b/mne_connectivity/viz/tests/test_circle.py @@ -171,7 +171,7 @@ def test_plot_connectivity_circle(): fig = plt.figure() with pytest.warns( - DeprecationWarning, match="Passing a `fig` and " "`subplot` is deprecated" + DeprecationWarning, match="Passing a `fig` and `subplot` is deprecated" ): plot_connectivity_circle(con, label_names, fig=fig, subplot=111)