Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make scipy and matplotlib required dependencies (#1159) #1404

Merged
merged 4 commits into from
Jun 22, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ env:
- MAIN_CMD="pytest ${PYTEST_LIST} ${PYTEST_FLAGS}; python ./testsuite/MDAnalysisTests/mda_nosetests ${NOSE_TEST_LIST} ${NOSE_FLAGS}"
- SETUP_CMD=""
- BUILD_CMD="pip install -v package/ && pip install testsuite/"
- CONDA_DEPENDENCIES="mmtf-python nose=1.3.7 mock six biopython networkx cython joblib nose-timer pytest=3.1.2 pytest-cov=2.5.1"
- CONDA_ALL_DEPENDENCIES="mmtf-python nose=1.3.7 mock six biopython networkx cython joblib nose-timer matplotlib netcdf4 scikit-learn scipy seaborn coveralls clustalw=2.1 pytest=3.1.2 pytest-cov=2.5.1"
- CONDA_DEPENDENCIES="mmtf-python nose=1.3.7 mock six biopython networkx cython joblib nose-timer matplotlib scipy griddataformats pytest=3.1.2 pytest-cov=2.5.1"
- CONDA_ALL_DEPENDENCIES="mmtf-python nose=1.3.7 mock six biopython networkx cython joblib nose-timer matplotlib netcdf4 scikit-learn scipy griddataformats seaborn coveralls clustalw=2.1 pytest=3.1.2 pytest-cov=2.5.1"
# Install griddataformats from PIP so that scipy is only installed in the full build (#1147)
- PIP_DEPENDENCIES='griddataformats'
- PIP_DEPENDENCIES=''
- CONDA_CHANNELS='biobuilds conda-forge'
- CONDA_CHANNEL_PRIORITY=True
- NUMPY_VERSION=stable
Expand Down
3 changes: 3 additions & 0 deletions package/CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ Fixes
* Fixed dtype of numpy arrays to accomodate 32 bit architectures (Issue #1362)
* Groups are hashable on python 3 (Issue #1397)

Changes
* scipy and matplotlib are now required dependencies (Issue #1159)


06/03/17 utkbansal, kain88-de, xiki-tempula, kaplajon, wouterboomsma,
richardjgowers, Shtkddud123, QuantumEntangledAndy, orbeckst,
Expand Down
23 changes: 2 additions & 21 deletions package/MDAnalysis/analysis/distances.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
'contact_matrix', 'dist', 'between']

import numpy as np
import scipy.sparse
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not from scipy import sparse?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the full imports much better if we only use a few things. Much easier to grep. And really not much more to write. Why not be explicit with where you get functions from? And it keeps the name space tidier.

(Sidenote: I particular dislike function imports – I think they are really bad because you have no idea where they come from when reading code. )


from MDAnalysis.lib.distances import distance_array, self_distance_array
from MDAnalysis.lib.c_distances import contact_matrix_no_pbc, contact_matrix_pbc
Expand All @@ -51,15 +52,6 @@
import logging
logger = logging.getLogger("MDAnalysis.analysis.distances")

try:
from scipy import sparse
except ImportError:
sparse = None
msg = "scipy.sparse could not be imported: some functionality will " \
"not be available in contact_matrix()"
warnings.warn(msg, category=ImportWarning)
logger.warn(msg)
del msg

def contact_matrix(coord, cutoff=15.0, returntype="numpy", box=None):
'''Calculates a matrix of contacts.
Expand Down Expand Up @@ -93,12 +85,6 @@ def contact_matrix(coord, cutoff=15.0, returntype="numpy", box=None):
The contact matrix is returned in a format determined by the `returntype`
keyword.


Note
----
:mod:`scipy.sparse` is require for using *sparse* matrices; if it cannot
be imported then an `ImportError` is raised.

See Also
--------
:mod:`MDAnalysis.analysis.contacts` for native contact analysis
Expand All @@ -112,14 +98,9 @@ def contact_matrix(coord, cutoff=15.0, returntype="numpy", box=None):
adj = (distance_array(coord, coord, box=box) < cutoff)
return adj
elif returntype == "sparse":
if sparse is None:
# hack: if we are running with minimal dependencies then scipy was
# not imported and we have to bail here (see scipy import at top)
raise ImportError("For sparse matrix functionality you need to "
"import scipy.")
# Initialize square List of Lists matrix of dimensions equal to number
# of coordinates passed
sparse_contacts = sparse.lil_matrix((len(coord), len(coord)), dtype='bool')
sparse_contacts = scipy.sparse.lil_matrix((len(coord), len(coord)), dtype='bool')
if box is not None:
# with PBC
contact_matrix_pbc(coord, sparse_contacts, box, cutoff)
Expand Down
36 changes: 7 additions & 29 deletions package/MDAnalysis/analysis/encore/similarity.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,21 +172,13 @@
from __future__ import print_function, division, absolute_import
from six.moves import range, zip

import MDAnalysis as mda
import numpy as np
import warnings
import logging
try:
from scipy.stats import gaussian_kde
except ImportError:
gaussian_kde = None
msg = "scipy.stats.gaussian_kde could not be imported. " \
"Dimensionality reduction ensemble comparisons will not " \
"be available."
warnings.warn(msg,
category=ImportWarning)
logging.warn(msg)
del msg

import numpy as np
import scipy.stats
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not from scipy.stats import gaussian_kde?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because that is evil.

Honestly, function imports at the module level are bad. See comments above. See PEP something or other IIRC...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PS: Please don't.


import MDAnalysis as mda

from ...coordinates.memory import MemoryReader
from .confdistmatrix import get_distance_matrix
Expand Down Expand Up @@ -460,18 +452,11 @@ def gen_kde_pdfs(embedded_space, ensemble_assignment, nensembles,
embedded_ensembles = []
resamples = []

if gaussian_kde is None:
# hack: if we are running with minimal dependencies then scipy was
# not imported and we have to bail here (see scipy import at top)
raise ImportError("For Kernel Density Estimation functionality you"
"need to import scipy")

for i in range(1, nensembles + 1):
this_embedded = embedded_space.transpose()[
np.where(np.array(ensemble_assignment) == i)].transpose()
embedded_ensembles.append(this_embedded)
kdes.append(gaussian_kde(
this_embedded))
kdes.append(scipy.stats.gaussian_kde(this_embedded))

# # Set number of samples
# if not nsamples:
Expand Down Expand Up @@ -623,12 +608,6 @@ def cumulative_gen_kde_pdfs(embedded_space, ensemble_assignment, nensembles,

"""

if gaussian_kde is None:
# hack: if we are running with minimal dependencies then scipy was
# not imported and we have to bail here (see scipy import at top)
raise ImportError("For Kernel Density Estimation functionality you"
"need to import scipy")

kdes = []
embedded_ensembles = []
resamples = []
Expand All @@ -639,8 +618,7 @@ def cumulative_gen_kde_pdfs(embedded_space, ensemble_assignment, nensembles,
np.logical_and(ensemble_assignment >= ens_id_min,
ensemble_assignment <= i))].transpose()
embedded_ensembles.append(this_embedded)
kdes.append(
gaussian_kde(this_embedded))
kdes.append(scipy.stats.gaussian_kde(this_embedded))

# Resample according to probability distributions
for this_kde in kdes:
Expand Down
26 changes: 14 additions & 12 deletions package/MDAnalysis/analysis/hbonds/hbond_autocorrel.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,14 +155,16 @@
from __future__ import division, absolute_import
from six.moves import zip
import numpy as np
import scipy.optimize
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again why not import the one function we need?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above. Don't.


import warnings

from MDAnalysis.lib.log import ProgressMeter
from MDAnalysis.lib.distances import distance_array, calc_angles, calc_bonds


class HydrogenBondAutoCorrel(object):
"""Perform a time autocorrelation of the hydrogen bonds in the system.
"""Perform a time autocorrelation of the hydrogen bonds in the system.

Parameters
----------
Expand Down Expand Up @@ -421,8 +423,10 @@ def solve(self, p_guess=None):
Initial guess for the leastsq fit, must match the shape of the
expected coefficients

Continuous defition results are fitted to a double exponential,
intermittent definition are fit to a triple exponential.

Continuous defition results are fitted to a double exponential with
:func:`scipy.optimize.leastsq`, intermittent definition are fit to a
triple exponential.

The results of this fitting procedure are saved into the *fit*,
*tau* and *estimate* keywords in the solution dict.
Expand All @@ -434,14 +438,14 @@ def solve(self, p_guess=None):
- *estimate* contains the estimate provided by the fit of the time
autocorrelation function

In addition, the output of the leastsq function is saved into the
solution dict
In addition, the output of the :func:`~scipy.optimize.leastsq` function
is saved into the solution dict

- *infodict*
- *mesg*
- *ier*

"""
from scipy.optimize import leastsq

if self.solution['results'] is None:
raise ValueError(
Expand Down Expand Up @@ -498,9 +502,8 @@ def triple(x, A1, A2, tau1, tau2, tau3):
if p_guess is None:
p_guess = (0.5, 10 * self.sample_time, self.sample_time)

p, cov, infodict, mesg, ier = leastsq(err, p_guess,
args=(time, results),
full_output=True)
p, cov, infodict, mesg, ier = scipy.optimize.leastsq(
err, p_guess, args=(time, results), full_output=True)
self.solution['fit'] = p
A1, tau1, tau2 = p
A2 = 1 - A1
Expand All @@ -512,9 +515,8 @@ def triple(x, A1, A2, tau1, tau2, tau3):
p_guess = (0.33, 0.33, 10 * self.sample_time,
self.sample_time, 0.1 * self.sample_time)

p, cov, infodict, mesg, ier = leastsq(err, p_guess,
args=(time, results),
full_output=True)
p, cov, infodict, mesg, ier = scipy.optimize.leastsq(
err, p_guess, args=(time, results), full_output=True)
self.solution['fit'] = p
A1, A2, tau1, tau2, tau3 = p
A3 = 1 - A1 - A2
Expand Down
16 changes: 6 additions & 10 deletions package/MDAnalysis/analysis/hole.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,6 @@
from six.moves import zip, cPickle
import six

import numpy as np
import glob
import os
import errno
Expand All @@ -258,6 +257,10 @@
import logging
from itertools import cycle

import numpy as np
import matplotlib
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a common idom is import matplotlib as mpl

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, but we don't use it a lot and it's clearer to read and to grep for: if I am looking for matplotlib I use git grep matplotlib.

import matplotlib.pyplot as plt

from MDAnalysis import Universe
from MDAnalysis.exceptions import ApplicationError
from MDAnalysis.lib.util import which, realpath, asiterable
Expand Down Expand Up @@ -370,8 +373,6 @@ def save(self, filename="hole.pickle"):
cPickle.dump(self.profiles, open(filename, "wb"), cPickle.HIGHEST_PROTOCOL)

def _process_plot_kwargs(self, kwargs):
import matplotlib.colors

kw = {}
frames = kwargs.pop('frames', None)
if frames is None:
Expand Down Expand Up @@ -448,9 +449,6 @@ def plot(self, **kwargs):
Returns ``ax``.

"""

import matplotlib.pyplot as plt

kw, kwargs = self._process_plot_kwargs(kwargs)

ax = kwargs.pop('ax', None)
Expand Down Expand Up @@ -517,8 +515,7 @@ def plot3D(self, **kwargs):
Returns ``ax``.

"""

import matplotlib.pyplot as plt
# installed with matplotlib; imported here to enable 3D axes
from mpl_toolkits.mplot3d import Axes3D

kw, kwargs = self._process_plot_kwargs(kwargs)
Expand All @@ -540,8 +537,7 @@ def plot3D(self, **kwargs):
rxncoord = profile.rxncoord
else:
# does not seem to work with masked arrays but with nan hack!
# http://stackoverflow.com/questions/4913306/python-matplotlib-mplot3d-how-do-i-set-a-maximum-value
# -for-the-z-axis
# http://stackoverflow.com/questions/4913306/python-matplotlib-mplot3d-how-do-i-set-a-maximum-value-for-the-z-axis
#radius = np.ma.masked_greater(profile.radius, rmax)
#rxncoord = np.ma.array(profile.rxncoord, mask=radius.mask)
rxncoord = profile.rxncoord
Expand Down
5 changes: 3 additions & 2 deletions package/MDAnalysis/analysis/legacy/x3dna.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,15 @@
import errno
import shutil
import warnings
import numpy as np
import os.path
import subprocess
import tempfile
import textwrap
from collections import OrderedDict

import numpy as np
import matplotlib.pyplot as plt

from MDAnalysis import ApplicationError
from MDAnalysis.lib.util import which, realpath, asiterable

Expand Down Expand Up @@ -413,7 +415,6 @@ def plot(self, **kwargs):
Provide `ax` to have all plots plotted in the same axes.

"""
import matplotlib.pyplot as plt

na_avg, na_std = self.mean_std()
for k in range(len(na_avg[0])):
Expand Down
7 changes: 4 additions & 3 deletions package/MDAnalysis/analysis/pca.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
import warnings

import numpy as np
import scipy.integrate

from MDAnalysis import Universe
from MDAnalysis.analysis.align import _fit_to
Expand Down Expand Up @@ -357,9 +358,9 @@ def cosine_content(pca_space, i):
.. [BerkHess1] Berk Hess. Convergence of sampling in protein simulations.
Phys. Rev. E 65, 031910 (2002).
"""
from scipy.integrate import simps

t = np.arange(len(pca_space))
T = len(pca_space)
cos = np.cos(np.pi * t * (i + 1) / T)
return ((2.0 / T) * (simps(cos*pca_space[:, i])) ** 2 /
simps(pca_space[:, i] ** 2))
return ((2.0 / T) * (scipy.integrate.simps(cos*pca_space[:, i])) ** 2 /
scipy.integrate.simps(pca_space[:, i] ** 2))
7 changes: 3 additions & 4 deletions package/MDAnalysis/analysis/polymer.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
from six.moves import range

import numpy as np
import scipy.optimize

import logging

from .. import NoDataError
Expand Down Expand Up @@ -165,13 +167,10 @@ def fit_exponential_decay(x, y):
-----
This function assumes that data starts at 1.0 and decays to 0.0

Requires scipy
"""
from scipy.optimize import curve_fit

def expfunc(x, a):
return np.exp(-x/a)

a = curve_fit(expfunc, x, y)[0][0]
a = scipy.optimize.curve_fit(expfunc, x, y)[0][0]

return a
Loading