diff --git a/package/AUTHORS b/package/AUTHORS index 35e4029f776..24ab70d0605 100644 --- a/package/AUTHORS +++ b/package/AUTHORS @@ -236,6 +236,7 @@ Chronological list of authors 2024 - Aditya Keshari - Philipp Stärk + - Sampurna Mukherjee External code ------------- diff --git a/package/CHANGELOG b/package/CHANGELOG index 094ec0091ca..bde5de8db78 100644 --- a/package/CHANGELOG +++ b/package/CHANGELOG @@ -16,7 +16,7 @@ The rules for this file: ------------------------------------------------------------------------------- ??/??/?? IAlibay, HeetVekariya, marinegor, lilyminium, RMeli, ljwoods2, aditya292002, pstaerk, PicoCentauri, BFedder, - tyler.je.reddy + tyler.je.reddy, SampurnaM * 2.8.0 @@ -34,6 +34,8 @@ Fixes * Fix deploy action to use the correct version of the pypi upload action. Enhancements + * Added a tqdm progress bar for `MDAnalysis.analysis.pca.PCA.transform()` + (PR #4531) * Improved performance of PDBWriter (Issue #2785, PR #4472) * Added parsing of arbitrary columns of the LAMMPS dump parser. (Issue #3504) * Documented the r0 attribute in the `Contacts` class and added the diff --git a/package/MDAnalysis/analysis/pca.py b/package/MDAnalysis/analysis/pca.py index 4ed5486e4c6..280f7c2a8db 100644 --- a/package/MDAnalysis/analysis/pca.py +++ b/package/MDAnalysis/analysis/pca.py @@ -118,6 +118,7 @@ import numpy as np import scipy.integrate +from tqdm.auto import tqdm from MDAnalysis import Universe from MDAnalysis.analysis.align import _fit_to @@ -355,12 +356,12 @@ def n_components(self, n): n = len(self._variance) self.results.variance = self._variance[:n] self.results.cumulated_variance = (np.cumsum(self._variance) / - np.sum(self._variance))[:n] + np.sum(self._variance))[:n] self.results.p_components = self._p_components[:, :n] self._n_components = n def transform(self, atomgroup, n_components=None, start=None, stop=None, - step=None): + step=None, verbose=False): """Apply the dimensionality reduction on a trajectory Parameters @@ -382,6 +383,11 @@ def transform(self, atomgroup, n_components=None, start=None, stop=None, Include every `step` frames in the PCA transform. If set to ``None`` (the default) then every frame is analyzed (i.e., same as ``step=1``). + verbose : bool, optional + ``verbose = True`` option displays a progress bar for the + iterations of transform. ``verbose = False`` disables the + progress bar, just returns the pca_space array when the + calculations are finished. Returns ------- @@ -391,6 +397,9 @@ def transform(self, atomgroup, n_components=None, start=None, stop=None, .. versionchanged:: 0.19.0 Transform now requires that :meth:`run` has been called before, otherwise a :exc:`ValueError` is raised. + .. versionchanged:: 2.8.0 + Transform now has shows a tqdm progressbar, which can be toggled + on with ``verbose = True``, or off with ``verbose = False`` """ if not self._calculated: raise ValueError('Call run() on the PCA before using transform') @@ -398,7 +407,7 @@ def transform(self, atomgroup, n_components=None, start=None, stop=None, if isinstance(atomgroup, Universe): atomgroup = atomgroup.atoms - if(self._n_atoms != atomgroup.n_atoms): + if self._n_atoms != atomgroup.n_atoms: raise ValueError('PCA has been fit for' '{} atoms. Your atomgroup' 'has {} atoms'.format(self._n_atoms, @@ -415,7 +424,10 @@ def transform(self, atomgroup, n_components=None, start=None, stop=None, dot = np.zeros((n_frames, dim)) - for i, ts in enumerate(traj[start:stop:step]): + for i, ts in tqdm(enumerate(traj[start:stop:step]), disable=not verbose, + total=len(traj[start:stop:step]) + ): + xyz = atomgroup.positions.ravel() - self._xmean dot[i] = np.dot(xyz, self._p_components[:, :dim]) @@ -561,7 +573,7 @@ def project_single_frame(self, components=None, group=None, anchor=None): for res in group.residues: # n_common is the number of pca atoms in a residue n_common = pca_res_counts[np.where( - pca_res_indices == res.resindex)][0] + pca_res_indices == res.resindex)][0] non_pca_atoms = np.append(non_pca_atoms, res.atoms.n_atoms - n_common) # index_extrapolate records the anchor number for each non-PCA atom diff --git a/package/MDAnalysis/lib/log.py b/package/MDAnalysis/lib/log.py index d3a6782aa12..a5cfc2f5018 100644 --- a/package/MDAnalysis/lib/log.py +++ b/package/MDAnalysis/lib/log.py @@ -135,7 +135,8 @@ def create(logger_name="MDAnalysis", logfile="MDAnalysis.log"): # handler that writes to logfile logfile_handler = logging.FileHandler(logfile) - logfile_formatter = logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s') + logfile_formatter = logging.Formatter( + '%(asctime)s %(name)-12s %(levelname)-8s %(message)s') logfile_handler.setFormatter(logfile_formatter) logger.addHandler(logfile_handler) @@ -172,6 +173,7 @@ class NullHandler(logging.Handler): see the advice on logging and libraries in http://docs.python.org/library/logging.html?#configuring-logging-for-a-library """ + def emit(self, record): pass @@ -327,6 +329,7 @@ class ProgressBar(tqdm): .. _`tqdm documentation`: https://tqdm.github.io/ """ + def __init__(self, *args, **kwargs): """""" # ^^^^ keep the empty doc string to avoid Sphinx doc errors with the