Trajectory Clustering, Statistical Analysis, and Visualization Tools - #2264
Trajectory Clustering, Statistical Analysis, and Visualization Tools #2264kontheodosiadis wants to merge 4 commits into
Conversation
jamesmkrieger
left a comment
There was a problem hiding this comment.
I still need to look at the details but in general this seems like a good addition. I have two high-level comments for now.
- move this code into different files instead of interactions.py as it is based on rmsd, not interactions. It may well get split across multiple files, but you will probably have one main one like prody/dynamics/rmsd_ clustering.py
There are currently rmsd clustering and low level plotting tools in prody/utilities/catchall.py, so that could be a possible location for some or all of it, but probably it would be better to have a dedicated file prody/dynamics/rmsd_ clustering.py that could take most of the new code.
Plotting tools could go in either prody/dynamics/plotting.py or prody/utilities/catchall.py depending whether they are high-level (plotting particular dynamics-related features and including the calculations and plotting together) or low-level (just providing plotting utilities like histograms, which could also be quite useful).
prody/utilities/catchall.py has clusterSubfamilies and clusterMatrix that are data agnostic and take a matrix of similarities or distances/rmsds; calcRMSDclusters, which is aliased as calcGromosClusters and calcGromacsClusters, that is based on the method used on Gromacs; and calcKmedoidClusters.
- There is some reinventing of the wheel here that needs to be consolidated with existing functions. I have commented on some examples.
| if reference_coords.shape != aligned_coords.shape[1:]: | ||
| raise ValueError(f"Incompatible shapes: reference is {reference_coords.shape}, but aligned frames have {aligned_coords.shape[1:]}.") | ||
|
|
||
| # Vectorized RMSD calculation |
There was a problem hiding this comment.
prody already has rmsd calculation. Is this version quicker? If so, it should be integrated with what we already have. If not, it should be replaced here with calcRMSD or getRMSD
There was a problem hiding this comment.
James, should we still avoid f-strings (.format() was usually used to support Python 2.7 users)?
If so, we have some in the code (including the one above).
There was a problem hiding this comment.
Probably doesn't matter that much at this point as there won't really be any Python 2.7 users besides the website and we're not rebuilding it at the moment
|
I moved the files to other folders according to your suggestion. I also cleaned things up by removing unnecessary functions and utilizing existing ProDy ones where appropriate. For now, I have kept my clustering functions separately in I have attached the notebooks with the corrected functions. |
Thanks. This looks good now.
Yes, I agree. I suggest making mention of the others in the docstrings to help with users getting confused otherwise.
These notebooks use a filename for a file that I don't have so I won't be able to run them, but I will still glance over them seeing as the outputs are there and see if I have any more comments before finalising my review. Can you put a smaller version of the file in tests/datafiles (maybe with different numbers 1, 2 and 3 frames per cluster for 3 clusters) and make these into unit tests? These would also serve as illustrative examples for users of how to run the code It would also be good to convert some of these into tutorials for the prody website at some point although I don't know whether/when we can actually update it to include them. They also serve as useful findable tutorials on the prody website repo where they also render pretty well |
|
The notebooks generally look great. I have a few comments on them for improvement, but these do not generally impact the integrated code. One that does is that I see that all values in the tables in notebooks 04 and 05 including the part using showClusterStatisticsTable are represented as floats with several decimal places. I'd generally reduce actual floats to have 2 or 3 decimal places and convert those that actually aren't floats at all like Total Frames and Medoid Frame to int.
|
jamesmkrieger
left a comment
There was a problem hiding this comment.
Here are a fair few changes, but it's looking really good now.
|
|
||
| from . import rmsd_clustering | ||
| from .rmsd_clustering import * | ||
| __all__.extend(rmsd_clustering.__all__) No newline at end of file |
|
|
||
| rmsd_array = calcRMSD(ref_coords, target=aligned_coords) | ||
|
|
||
| rmsd_array = np.asarray(rmsd_array) |
There was a problem hiding this comment.
calcRMSD should already return an array from getRMSD
| except ImportError: | ||
| raise ImportError("The 'seaborn' package is required to display the histogram." | ||
| "\nPlease install it using 'pip install seaborn'." | ||
| "\nAlternatively, use standard matplotlib.pyplot.hist() for basic plots.") |
There was a problem hiding this comment.
can the code use matplotlib hist as a fall back rather than raising an error and asking the user to plot it themselves?
| user_label = kwargs.pop('label', None) | ||
|
|
||
| # Seaborn Defaults | ||
| kwargs.setdefault('bins', 50) |
There was a problem hiding this comment.
can the user provide these kwargs to override these defaults e.g. if there are much fewer structures so 50 bins is too many?
|
|
||
| # Proceed with plotting | ||
| plot_barh(result, bond_type, n_per_plot=n_per_plot, min_height=min_height) | ||
|
|
There was a problem hiding this comment.
revert this minimal change so this file doesn't show up as changed
| :arg trajectory: trajectory containing the coordinate sets to align | ||
| :type trajectory: :class:`prody.Trajectory` | ||
|
|
||
| :arg align: atom selection used to calculate the alignment transformation. |
There was a problem hiding this comment.
include selstr or something like that in the variable name so it's immediately obvious what it is without reading the doc string
| atoms.setCoords(orig_coords) | ||
| trajectory.reset() | ||
|
|
||
| return ref_coords, aligned_coords |
There was a problem hiding this comment.
also give an option of returning the aligned trajectory object itself
| return ref_coords, aligned_coords | ||
|
|
||
|
|
||
| def calcPairwiseRMSD(aligned_coords): |
There was a problem hiding this comment.
It would be good to have a method like this for TrajBase like Ensemble has getRMSDs(self, pairwise=False), but I suppose that is a bigger change that we maybe don't want to make right now
|
|
||
| if show: | ||
| kwargs.setdefault('tablefmt', 'fancy_grid') | ||
| kwargs.setdefault('floatfmt', '.4f') |
There was a problem hiding this comment.
This default isn't right for all rows. Some of them are truly ints and most of the others don't deserve so much precision either.
The code was developed under the supervision of Prof. Karolina Mikulska-Ruminska (NCU).
Summary
This pull request introduces a set of tools for clustering and analyzing Molecular Dynamics trajectories. It provides functions for trajectory alignment, RMSD calculations, distance matrix generation, clustering, cluster statistical analysis, visualization, and export of representative structures and clustered trajectories.
Workflow
The functions follow a logical pipline:
.pdbfiles..dcdfiles.Key Features
Clustering Algorithms
Clustering algorithms support multiple backends, where needed. Optimized implementations from scikit-learn (or SciPy, where appropriate) can be used, while dependency-free implementations based on NumPy and the Python standard library are provided whenever practical.
Analysis Utilities
Visualization
@karolamik13 @jamesmkrieger
01_rmsd_frame_to_reference.ipynb
02_rmsd_frame_to_frame.ipynb
03_hierarchical_clustering.ipynb
04_kmedoids_clustering.ipynb
05_density_clustering.ipynb