# -*- coding: utf-8 -*-
"""This module defines plotting functions for protein dynamics analysis.
Plotting functions are called by the name of the plotted data/property
and are prefixed with ``show``. Function documentations refers to the
:mod:`matplotlib.pyplot` function utilized for actual plotting. Arguments
and keyword arguments are passed to the Matplotlib functions."""
from collections import defaultdict
import numpy as np
from prody import LOGGER, SETTINGS
from prody.utilities import showFigure
from .nma import NMA
from .gnm import GNMBase
from .mode import Mode, VectorBase, Vector
from .modeset import ModeSet
from .analysis import calcSqFlucts, calcProjection, calcCrossCorr
from .analysis import calcFractVariance, calcCrossProjection
from .compare import calcOverlap
__all__ = ['showContactMap', 'showCrossCorr',
'showCumulOverlap', 'showFractVars',
'showCumulFractVars', 'showMode',
'showOverlap', 'showOverlapTable', 'showProjection',
'showCrossProjection', 'showEllipsoid', 'showSqFlucts',
'showScaledSqFlucts', 'showNormedSqFlucts', 'resetTicks',
'showDiffMatrix', ]
[docs]def showEllipsoid(modes, onto=None, n_std=2, scale=1., *args, **kwargs):
"""Show an ellipsoid using :meth:`~mpl_toolkits.mplot3d.Axes3D
.plot_wireframe`.
Ellipsoid volume gives an analytical view of the conformational space that
given modes describe.
:arg modes: 3 modes for which ellipsoid will be drawn.
:type modes: :class:`.ModeSet`, :class:`.PCA`, :class:`.ANM`, :class:`.NMA`
:arg onto: 3 modes onto which ellipsoid will be projected.
:type modes: :class:`.ModeSet`, :class:`.PCA`, :class:`.ANM`, :class:`.NMA`
:arg n_std: Number of standard deviations to scale the ellipsoid.
:type n_std: float
:arg scale: Used for scaling the volume of ellipsoid. This can be
obtained from :func:`.sampleModes`.
:type scale: float"""
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
if not isinstance(modes, (NMA, ModeSet)):
raise TypeError('modes must be a NMA or ModeSet instance, '
'not {0}'.format(type(modes)))
if not modes.is3d():
raise ValueError('modes must be from a 3-dimensional model')
if len(modes) != 3:
raise ValueError('length of modes is not equal to 3')
if onto is not None:
if not isinstance(onto, (NMA, ModeSet)):
raise TypeError('onto must be a NMA or ModeSet instance, '
'not {0}'.format(type(onto)))
if not onto.is3d():
raise ValueError('onto must be from a 3-dimensional model')
if len(onto) != 3:
raise ValueError('length of onto is not equal to 3')
if onto.numAtoms() != modes.numAtoms():
raise ValueError('modes and onto must have same number of atoms')
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
var = modes.getVariances()
#randn = np.random.standard_normal((1000, 3))
#coef = ((randn ** 2 * var).sum(1) ** 0.5).mean()
#scale=float(n_std)*modes.numAtoms()**.5 * float(rmsd) / coef * var **.5
scale = float(n_std) * scale * var ** 0.5
#scale=float(n_std)*modes.numAtoms()**.5*float(rmsd)/var.sum()**.5*var**.5
x = scale[0] * np.outer(np.cos(u), np.sin(v))
y = scale[1] * np.outer(np.sin(u), np.sin(v))
z = scale[2] * np.outer(np.ones(np.size(u)), np.cos(v))
if onto is not None:
change_of_basis = np.dot(modes._getArray().T, onto._getArray())
xyz = np.array([x.flatten(), y.flatten(), z.flatten()])
xyz = np.dot(xyz.T, change_of_basis)
x = xyz[:,0].reshape((100,100))
y = xyz[:,1].reshape((100,100))
z = xyz[:,2].reshape((100,100))
cf = plt.gcf()
show = None
for child in cf.get_children():
if isinstance(child, Axes3D):
show = child
break
if show is None:
show = Axes3D(cf)
show.plot_wireframe(x, y, z, rstride=6, cstride=6, *args, **kwargs)
if onto is not None:
onto = list(onto)
show.set_xlabel('Mode {0} coordinate'.format(int(onto[0])+1))
show.set_ylabel('Mode {0} coordinate'.format(int(onto[1])+1))
show.set_zlabel('Mode {0} coordinate'.format(int(onto[2])+1))
else:
modes = list(modes)
show.set_xlabel('Mode {0} coordinate'.format(int(modes[0])+1))
show.set_ylabel('Mode {0} coordinate'.format(int(modes[1])+1))
show.set_zlabel('Mode {0} coordinate'.format(int(modes[2])+1))
if SETTINGS['auto_show']:
showFigure()
return show
[docs]def showFractVars(modes, *args, **kwargs):
"""Show fraction of variances using :func:`~matplotlib.pyplot.bar`. Note
that mode indices are incremented by 1."""
import matplotlib.pyplot as plt
if not isinstance(modes, (ModeSet, NMA)):
raise TypeError('modes must be NMA, or ModeSet, not {0}'
.format(type(modes)))
fracts = calcFractVariance(modes)
fracts = [(int(mode), fract) for mode, fract in zip(modes, fracts)]
fracts = np.array(fracts)
show = plt.bar(fracts[:,0]+0.5, fracts[:,1], *args, **kwargs)
axis = list(plt.axis())
axis[0] = 0.5
axis[2] = 0
axis[3] = 1
plt.axis(axis)
plt.xlabel('Mode index')
plt.ylabel('Fraction of variance')
if SETTINGS['auto_show']:
showFigure()
return show
[docs]def showCumulFractVars(modes, *args, **kwargs):
"""Show fraction of variances of *modes* using :func:`~matplotlib.pyplot.
plot`. Note that mode indices are incremented by 1. See also
:func:`.showFractVars` function."""
import matplotlib.pyplot as plt
if not isinstance(modes, (Mode, NMA, ModeSet)):
raise TypeError('modes must be a Mode, NMA, or ModeSet instance, '
'not {0}'.format(type(modes)))
if isinstance(modes, Mode):
indices = modes.getIndices() + 0.5
modes = [modes]
elif isinstance(modes, ModeSet):
indices = modes.getIndices() + 0.5
else:
indices = np.arange(len(modes)) + 0.5
fracts = calcFractVariance(modes).cumsum()
show = plt.plot(indices, fracts, *args, **kwargs)
axis = list(plt.axis())
axis[0] = 0.5
axis[2] = 0
axis[3] = 1
plt.axis(axis)
plt.xlabel('Mode index')
plt.ylabel('Fraction of variance')
if SETTINGS['auto_show']:
showFigure()
return show
[docs]def showProjection(ensemble, modes, *args, **kwargs):
"""Show a projection of conformational deviations onto up to three normal
modes from the same model.
:arg ensemble: an ensemble, trajectory or a conformation for which
deviation(s) will be projected, or a deformation vector
:type ensemble: :class:`.Ensemble`, :class:`.Conformation`,
:class:`.Vector`, :class:`.Trajectory`
:arg modes: up to three normal modes
:type modes: :class:`.Mode`, :class:`.ModeSet`, :class:`.NMA`
:arg color: a color name or a list of color name, default is ``'blue'``
:type color: str, list
:arg label: label or a list of labels
:type label: str, list
:arg marker: a marker or a list of markers, default is ``'o'``
:type marker: str, list
:arg linestyle: line style, default is ``'None'``
:type linestyle: str
:arg text: list of text labels, one for each conformation
:type text: list
:arg fontsize: font size for text labels
:type fontsize: int
The projected values are by default converted to RMSD. Pass ``rmsd=False``
to use projection itself.
Matplotlib function used for plotting depends on the number of modes:
* 1 mode: :func:`~matplotlib.pyplot.hist`
* 2 modes: :func:`~matplotlib.pyplot.plot`
* 3 modes: :meth:`~mpl_toolkits.mplot3d.Axes3D.plot`"""
import matplotlib.pyplot as plt
projection = calcProjection(ensemble, modes, kwargs.pop('rmsd', True))
if projection.ndim == 1 or projection.shape[1] == 1:
show = plt.hist(projection.flatten(), *args, **kwargs)
plt.xlabel('{0} coordinate'.format(str(modes)))
plt.ylabel('Number of conformations')
return show
elif projection.shape[1] > 3:
raise ValueError('Projection onto up to 3 modes can be shown. '
'You have given {0} mode.'.format(len(modes)))
num = projection.shape[0]
markers = kwargs.pop('marker', 'o')
if isinstance(markers, str) or markers is None:
markers = [markers] * num
elif isinstance(markers, list):
if len(markers) != num:
raise ValueError('length of marker must be {0}'.format(num))
else:
raise TypeError('marker must be a string or a list')
colors = kwargs.pop('color', 'blue')
if isinstance(colors, str) or colors is None:
colors = [colors] * num
elif isinstance(colors, list):
if len(colors) != num:
raise ValueError('length of color must be {0}'.format(num))
else:
raise TypeError('color must be a string or a list')
labels = kwargs.pop('label', None)
if isinstance(labels, str) or labels is None:
labels = [labels] * num
elif isinstance(labels, list):
if len(labels) != num:
raise ValueError('length of label must be {0}'.format(num))
elif labels is not None:
raise TypeError('label must be a string or a list')
kwargs['ls'] = kwargs.pop('linestyle', None) or kwargs.pop('ls', 'None')
texts = kwargs.pop('text', None)
if texts:
if not isinstance(texts, list):
raise TypeError('text must be a list')
elif len(texts) != num:
raise TypeError('length of text must be {0}'.format(num))
size = kwargs.pop('fontsize', None) or kwargs.pop('size', None)
modes = [m for m in modes]
if len(modes) == 2:
plot = plt.plot
show = plt.gcf()
text = plt.text
else:
from mpl_toolkits.mplot3d import Axes3D
cf = plt.gcf()
show = None
for child in cf.get_children():
if isinstance(child, Axes3D):
show = child
break
if show is None:
show = Axes3D(cf)
plot = show.plot
text = show.text
indict = defaultdict(list)
for i, opts in enumerate(zip(markers, colors, labels)): # PY3K: OK
indict[opts].append(i)
args = list(args)
for opts, indices in indict.items(): # PY3K: OK
marker, color, label = opts
kwargs['marker'] = marker
kwargs['color'] = color
if label:
kwargs['label'] = label
else:
kwargs.pop('label', None)
plot(*(list(projection[indices].T) + args), **kwargs)
if texts:
kwargs = {}
if size:
kwargs['size'] = size
for args in zip(*(list(projection.T) + [texts])):
text(*args, **kwargs)
if len(modes) == 2:
plt.xlabel('{0} coordinate'.format(int(modes[0])+1))
plt.ylabel('{0} coordinate'.format(int(modes[1])+1))
elif len(modes) == 3:
show.set_xlabel('Mode {0} coordinate'.format(int(modes[0])+1))
show.set_ylabel('Mode {0} coordinate'.format(int(modes[1])+1))
show.set_zlabel('Mode {0} coordinate'.format(int(modes[2])+1))
if SETTINGS['auto_show']:
showFigure()
return show
[docs]def showCrossProjection(ensemble, mode_x, mode_y, scale=None, *args, **kwargs):
"""Show a projection of conformational deviations onto modes from
different models using :func:`~matplotlib.pyplot.plot`. This function
differs from :func:`.showProjection` by accepting modes from two different
models.
:arg ensemble: an ensemble or a conformation for which deviation(s) will be
projected, or a deformation vector
:type ensemble: :class:`.Ensemble`, :class:`.Conformation`,
:class:`.Vector`, :class:`.Trajectory`
:arg mode_x: projection onto this mode will be shown along x-axis
:type mode_x: :class:`.Mode`, :class:`.Vector`
:arg mode_y: projection onto this mode will be shown along y-axis
:type mode_y: :class:`.Mode`, :class:`.Vector`
:arg scale: scale width of the projection onto mode ``x`` or ``y``,
best scaling factor will be calculated and printed on the console,
absolute value of scalar makes the with of two projection same,
sign of scalar makes the projections yield a positive correlation
:type scale: str
:arg scalar: scalar factor for projection onto selected mode
:type scalar: float
:arg color: a color name or a list of color name, default is ``'blue'``
:type color: str, list
:arg label: label or a list of labels
:type label: str, list
:arg marker: a marker or a list of markers, default is ``'o'``
:type marker: str, list
:arg linestyle: line style, default is ``'None'``
:type linestyle: str
:arg text: list of text labels, one for each conformation
:type text: list
:arg fontsize: font size for text labels
:type fontsize: int
The projected values are by default converted to RMSD. Pass ``rmsd=False``
to calculate raw projection values. See :ref:`pca-xray-plotting` for a
more elaborate example."""
import matplotlib.pyplot as plt
xcoords, ycoords = calcCrossProjection(ensemble, mode_x, mode_y,
scale=scale, **kwargs)
num = len(xcoords)
markers = kwargs.pop('marker', 'o')
if isinstance(markers, str) or markers is None:
markers = [markers] * num
elif isinstance(markers, list):
if len(markers) != num:
raise ValueError('length of marker must be {0}'.format(num))
else:
raise TypeError('marker must be a string or a list')
colors = kwargs.pop('color', 'blue')
if isinstance(colors, str) or colors is None:
colors = [colors] * num
elif isinstance(colors, list):
if len(colors) != num:
raise ValueError('length of color must be {0}'.format(num))
else:
raise TypeError('color must be a string or a list')
labels = kwargs.pop('label', None)
if isinstance(labels, str) or labels is None:
labels = [labels] * num
elif isinstance(labels, list):
if len(labels) != num:
raise ValueError('length of label must be {0}'.format(num))
elif labels is not None:
raise TypeError('label must be a string or a list')
kwargs['ls'] = kwargs.pop('linestyle', None) or kwargs.pop('ls', 'None')
texts = kwargs.pop('text', None)
if texts:
if not isinstance(texts, list):
raise TypeError('text must be a list')
elif len(texts) != num:
raise TypeError('length of text must be {0}'.format(num))
size = kwargs.pop('fontsize', None) or kwargs.pop('size', None)
indict = defaultdict(list)
for i, opts in enumerate(zip(markers, colors, labels)): # PY3K: OK
indict[opts].append(i)
for opts, indices in indict.items(): # PY3K: OK
marker, color, label = opts
kwargs['marker'] = marker
kwargs['color'] = color
if label:
kwargs['label'] = label
else:
kwargs.pop('label', None)
show = plt.plot(xcoords[indices], ycoords[indices], *args, **kwargs)
if texts:
kwargs = {}
if size:
kwargs['size'] = size
for x, y, t in zip(xcoords, ycoords, texts):
plt.text(x, y, t, **kwargs)
plt.xlabel('{0} coordinate'.format(mode_x))
plt.ylabel('{0} coordinate'.format(mode_y))
if SETTINGS['auto_show']:
showFigure()
return show
[docs]def showOverlapTable(modes_x, modes_y, **kwargs):
"""Show overlap table using :func:`~matplotlib.pyplot.pcolor`. *modes_x*
and *modes_y* are sets of normal modes, and correspond to x and y axes of
the plot. Note that mode indices are incremented by 1. List of modes
is assumed to contain a set of contiguous modes from the same model.
Default arguments for :func:`~matplotlib.pyplot.pcolor`:
* ``cmap=plt.cm.jet``
* ``norm=plt.normalize(0, 1)``"""
import matplotlib.pyplot as plt
overlap = abs(calcOverlap(modes_y, modes_x))
if overlap.ndim == 0:
overlap = np.array([[overlap]])
elif overlap.ndim == 1:
overlap = overlap.reshape((modes_y.numModes(), modes_x.numModes()))
cmap = kwargs.pop('cmap', plt.cm.jet)
norm = kwargs.pop('norm', plt.normalize(0, 1))
show = (plt.pcolor(overlap, cmap=cmap, norm=norm, **kwargs),
plt.colorbar())
x_range = np.arange(1, modes_x.numModes() + 1)
plt.xticks(x_range-0.5, x_range)
plt.xlabel(str(modes_x))
y_range = np.arange(1, modes_y.numModes() + 1)
plt.yticks(y_range-0.5, y_range)
plt.ylabel(str(modes_y))
plt.axis([0, modes_x.numModes(), 0, modes_y.numModes()])
if SETTINGS['auto_show']:
showFigure()
return show
[docs]def showCrossCorr(modes, *args, **kwargs):
"""Show cross-correlations using :func:`~matplotlib.pyplot.imshow`. By
default, *origin=lower* and *interpolation=bilinear* keyword arguments
are passed to this function, but user can overwrite these parameters.
See also :func:`.calcCrossCorr`."""
import matplotlib.pyplot as plt
arange = np.arange(modes.numAtoms())
cross_correlations = np.zeros((arange[-1]+2, arange[-1]+2))
cross_correlations[arange[0]+1:,
arange[0]+1:] = calcCrossCorr(modes)
if not 'interpolation' in kwargs:
kwargs['interpolation'] = 'bilinear'
if not 'origin' in kwargs:
kwargs['origin'] = 'lower'
show = plt.imshow(cross_correlations, *args, **kwargs), plt.colorbar()
plt.axis([arange[0]+0.5, arange[-1]+1.5, arange[0]+0.5, arange[-1]+1.5])
plt.title('Cross-correlations for {0}'.format(str(modes)))
plt.xlabel('Indices')
plt.ylabel('Indices')
if SETTINGS['auto_show']:
showFigure()
return show
[docs]def showMode(mode, *args, **kwargs):
"""Show mode array using :func:`~matplotlib.pyplot.plot`."""
import matplotlib.pyplot as plt
if not isinstance(mode, Mode):
raise TypeError('mode must be a Mode instance, '
'not {0}'.format(type(mode)))
if mode.is3d():
a3d = mode.getArrayNx3()
show = plt.plot(a3d[:, 0], *args, label='x-component', **kwargs)
plt.plot(a3d[:, 1], *args, label='y-component', **kwargs)
plt.plot(a3d[:, 2], *args, label='z-component', **kwargs)
else:
show = plt.plot(mode._getArray(), *args, **kwargs)
plt.title(str(mode))
plt.xlabel('Indices')
if SETTINGS['auto_show']:
showFigure()
return show
[docs]def showSqFlucts(modes, *args, **kwargs):
"""Show square fluctuations using :func:`~matplotlib.pyplot.plot`. See
also :func:`.calcSqFlucts`."""
import matplotlib.pyplot as plt
sqf = calcSqFlucts(modes)
if not 'label' in kwargs:
kwargs['label'] = str(modes)
show = plt.plot(sqf, *args, **kwargs)
plt.xlabel('Indices')
plt.ylabel('Square fluctuations')
plt.title(str(modes))
if SETTINGS['auto_show']:
showFigure()
return show
[docs]def showScaledSqFlucts(modes, *args, **kwargs):
"""Show scaled square fluctuations using :func:`~matplotlib.pyplot.plot`.
Modes or mode sets given as additional arguments will be scaled to have
the same mean squared fluctuations as *modes*."""
import matplotlib.pyplot as plt
sqf = calcSqFlucts(modes)
mean = sqf.mean()
args = list(args)
modesarg = []
i = 0
while i < len(args):
if isinstance(args[i], (VectorBase, ModeSet, NMA)):
modesarg.append(args.pop(i))
else:
i += 1
show = [plt.plot(sqf, *args, label=str(modes), **kwargs)]
plt.xlabel('Indices')
plt.ylabel('Square fluctuations')
for modes in modesarg:
sqf = calcSqFlucts(modes)
scalar = mean / sqf.mean()
show.append(plt.plot(sqf * scalar, *args,
label='{0} (x{1:.2f})'.format(str(modes), scalar),
**kwargs))
if SETTINGS['auto_show']:
showFigure()
return show
[docs]def showNormedSqFlucts(modes, *args, **kwargs):
"""Show normalized square fluctuations via :func:`~matplotlib.pyplot.plot`.
"""
import matplotlib.pyplot as plt
sqf = calcSqFlucts(modes)
args = list(args)
modesarg = []
i = 0
while i < len(args):
if isinstance(args[i], (VectorBase, ModeSet, NMA)):
modesarg.append(args.pop(i))
else:
i += 1
show = [plt.plot(sqf/(sqf**2).sum()**0.5, *args,
label='{0}'.format(str(modes)), **kwargs)]
plt.xlabel('Indices')
plt.ylabel('Square fluctuations')
for modes in modesarg:
sqf = calcSqFlucts(modes)
show.append(plt.plot(sqf/(sqf**2).sum()**0.5, *args,
label='{0}'.format(str(modes)), **kwargs))
if SETTINGS['auto_show']:
showFigure()
return show
[docs]def showOverlap(mode, modes, *args, **kwargs):
"""Show overlap :func:`~matplotlib.pyplot.bar`.
:arg mode: a single mode/vector
:type mode: :class:`.Mode`, :class:`.Vector`
:arg modes: multiple modes
:type modes: :class:`.ModeSet`, :class:`.ANM`, :class:`.GNM`, :class:`.PCA`
"""
import matplotlib.pyplot as plt
if not isinstance(mode, (Mode, Vector)):
raise TypeError('mode must be Mode or Vector, not {0}'
.format(type(mode)))
if not isinstance(modes, (NMA, ModeSet)):
raise TypeError('modes must be NMA or ModeSet, not {0}'
.format(type(modes)))
overlap = abs(calcOverlap(mode, modes))
if isinstance(modes, NMA):
arange = np.arange(0.5, len(modes)+0.5)
else:
arange = modes.getIndices() + 0.5
show = plt.bar(arange, overlap, *args, **kwargs)
plt.title('Overlap with {0}'.format(str(mode)))
plt.xlabel('{0} mode index'.format(modes))
plt.ylabel('Overlap')
if SETTINGS['auto_show']:
showFigure()
return show
[docs]def showCumulOverlap(mode, modes, *args, **kwargs):
"""Show cumulative overlap using :func:`~matplotlib.pyplot.plot`.
:type mode: :class:`.Mode`, :class:`.Vector`
:arg modes: multiple modes
:type modes: :class:`.ModeSet`, :class:`.ANM`, :class:`.GNM`, :class:`.PCA`
"""
import matplotlib.pyplot as plt
if not isinstance(mode, (Mode, Vector)):
raise TypeError('mode must be NMA, ModeSet, Mode or Vector, not {0}'
.format(type(mode)))
if not isinstance(modes, (NMA, ModeSet)):
raise TypeError('modes must be NMA, ModeSet, or Mode, not {0}'
.format(type(modes)))
cumov = (calcOverlap(mode, modes) ** 2).cumsum() ** 0.5
if isinstance(modes, NMA):
arange = np.arange(0.5, len(modes)+0.5)
else:
arange = modes.getIndices() + 0.5
show = plt.plot(arange, cumov, *args, **kwargs)
plt.title('Cumulative overlap with {0}'.format(str(mode)))
plt.xlabel('{0} mode index'.format(modes))
plt.ylabel('Cumulative overlap')
plt.axis((arange[0]-0.5, arange[-1]+0.5, 0, 1))
if SETTINGS['auto_show']:
showFigure()
return show
[docs]def resetTicks(x, y=None):
"""Reset X (and Y) axis ticks using values in given *array*. Ticks in the
current figure should not be fractional values for this function to work as
expected."""
import matplotlib.pyplot as plt
if x is not None:
try:
xticks = plt.xticks()[0]
xlist = list(xticks.astype(int))
if xlist[-1] > len(x):
xlist.pop()
if xlist:
xlist = list(x[xlist])
plt.xticks(xticks, xlist + [''] * (len(xticks) - len(xlist)))
except:
LOGGER.warning('xticks could not be reset.')
if y is not None:
try:
yticks = plt.yticks()[0]
ylist = list(yticks.astype(int))
if ylist[-1] > len(y):
ylist.pop()
if ylist:
ylist = list(y[ylist])
plt.yticks(yticks, ylist + [''] * (len(yticks) - len(ylist)))
except:
LOGGER.warning('xticks could not be reset.')
[docs]def showDiffMatrix(matrix1, matrix2, *args, **kwargs):
"""Show the difference between two cross-correlation matrices from
different models. For given *matrix1* and *matrix2* show the difference
between them in the form of (matrix2 - matrix1) and plot the difference
matrix using :func:`~matplotlib.pyplot.imshow`. When :class:`.NMA` models
are passed instead of matrices, the functions could call
:func:`.calcCrossCorr` function to calculate the matrices for given modes.
To display the absolute values in the difference matrix, user could set
*abs* keyword argument **True**.
By default, *origin=lower* and *interpolation=bilinear* keyword arguments
are passed to this function, but user can overwrite these parameters.
"""
import matplotlib.pyplot as plt
try:
dim1, shape1 = matrix1.ndim, matrix1.shape
except AttributeError:
matrix1 = calcCrossCorr(matrix1)
dim1, shape1 = matrix1.ndim, matrix1.shape
try:
dim2, shape2 = matrix2.ndim, matrix2.shape
except AttributeError:
matrix2 = calcCrossCorr(matrix2)
dim2, shape2 = matrix2.ndim, matrix2.shape
if (not ((dim1 == dim2 == 2) and (shape1 == shape2))):
raise ValueError('Matrices must have same square shape.')
if shape1[0] * shape1[1] == 0:
raise ValueError('There are no data in matrices.')
diff = matrix2 - matrix1
if not 'interpolation' in kwargs:
kwargs['interpolation'] = 'bilinear'
if not 'origin' in kwargs:
kwargs['origin'] = 'lower'
if kwargs.pop('abs', False):
diff = np.abs(diff)
show = plt.imshow(diff, *args, **kwargs), plt.colorbar()
plt.axis([-.5, shape1[1] - .5, -.5, shape1[0] - .5])
plt.title('Difference Matrix')
if SETTINGS['auto_show']:
showFigure()
plt.xlabel('Indices')
plt.ylabel('Indices')
return show