def showCrossProjection(ensemble, mode_x, mode_y, scale=None, scalar=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: Ensemble for which deviations will be projected :type ensemble: :class:`~prody.ensemble.Ensemble` :arg mode_x: Projection onto this mode will be shown along x-axis. :type mode_x: :class:`Mode` :arg mode_y: Projection onto this mode will be shown along y-axis. :type mode_y: :class:`Mode` :arg scale: Scale width of the projection onto one of modes. ``x`` and ``y`` are accepted. :type scale: str :arg scalar: Scalar factor for ``x`` or ``y``. If ``scalar=None`` is passed, best scaling factor will be calculated and printed on the console. :type scalar: float The projected values are by default converted to RMSD. Pass ``rmsd=False`` to calculate raw projection values. :class:`Vector` instances are accepted as *ensemble* argument to allow for projecting a deformation vector onto normal modes. By default ``marker='o', ls='None'`` is passed to the plotting function to disable lines. .. plot:: :context: :include-source: plt.figure(figsize=(5.2,4)) showCrossProjection(p38_ensemble, p38_pca[0], p38_anm[2]) .. plot:: :context: :nofigs: plt.close('all') |example| See :ref:`pca-xray-plotting` for a more elaborate example.""" import matplotlib.pyplot as plt if not isinstance(ensemble, (Ensemble, Conformation, Vector)): raise TypeError('ensemble must be Ensemble, Conformation, or Vector, ' 'not {0:s}'.format(type(ensemble))) if not isinstance(mode_x, VectorBase): raise TypeError('mode_x must be a Mode instance, not {0:s}' .format(type(mode_x))) if not mode_x.is3d(): raise ValueError('mode_x must be 3-dimensional') if not isinstance(mode_y, VectorBase): raise TypeError('mode_y must be a Mode instance, not {0:s}' .format(type(mode_y))) if not mode_y.is3d(): raise ValueError('mode_y must be 3-dimensional') if scale is not None: assert isinstance(scale, str), 'scale must be a string' scale = scale.lower() assert scale in ('x', 'y'), 'scale must be x or y' if scalar is not None: assert isinstance(scalar, float), 'scalar must be a float' xcoords = calcProjection(ensemble, mode_x, kwargs.get('rmsd', True)) ycoords = calcProjection(ensemble, mode_y, kwargs.pop('rmsd', True)) if scale: if scalar is None: scalar = ((ycoords.max() - ycoords.min()) / (xcoords.max() - xcoords.min())) scalar = scalar * np.sign(calcOverlap(mode_x, mode_y)) if scale == 'x': LOGGER.info('Projection onto {0:s} is scaled by {1:.2f}' .format(mode_x, scalar)) else: scalar = 1 / scalar LOGGER.info('Projection onto {0:s} is scaled by {1:.2f}' .format(mode_y, scalar)) if scale == 'x': xcoords = xcoords * scalar else: ycoords = ycoords * scalar if 'ls' not in kwargs: kwargs['ls'] = 'None' if 'marker' not in kwargs: kwargs['marker'] = 'o' show = plt.plot(xcoords, ycoords, *args, **kwargs) plt.xlabel('{0:s} coordinate'.format(mode_x)) plt.ylabel('{0:s} coordinate'.format(mode_y)) return show
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` .. plot:: :context: :include-source: plt.figure(figsize=(5,4)) showProjection(p38_ensemble, p38_pca[0]) plt.title('Projection onto PC1') plt.figure(figsize=(5,4)) showProjection(p38_ensemble, p38_pca[:2]) plt.title('Projection onto PC1-2') plt.figure(figsize=(5,4)) showProjection(p38_ensemble, p38_pca[:3]) # onto top 3 PCs plt.title('Projection onto PC1-3') .. plot:: :context: :nofigs: plt.close('all')""" 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:s} 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:d} 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:d}'.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:d}'.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:d}'.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:d}'.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)): indict[opts].append(i) args = list(args) for opts, indices in indict.iteritems(): 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:d} coordinate'.format(int(modes[0])+1)) plt.ylabel('{0:d} coordinate'.format(int(modes[1])+1)) elif len(modes) == 3: show.set_xlabel('Mode {0:d} coordinate'.format(int(modes[0])+1)) show.set_ylabel('Mode {0:d} coordinate'.format(int(modes[1])+1)) show.set_zlabel('Mode {0:d} coordinate'.format(int(modes[2])+1)) return show
def showProjection(ensemble, modes, *args, **kwargs): """Show a projection of conformational deviations onto up to three normal modes from the same model. :arg ensemble: a :class:`~prody.ensemble.Ensemble` instance :arg modes: a :class:`Mode`, :class:`ModeSet`, or :class:`NMA` instance The projected values are by default converted to RMSD. Pass ``rmsd=False`` to use projection itself. :class:`Vector` instances are accepted as *ensemble* argument to allow for projecting a deformation vector onto normal modes. 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` By default ``marker='o', ls='None'`` is passed to the plotting function to disable lines in projections onto 2 or 3-d spaces. .. plot:: :context: :include-source: plt.figure(figsize=(5,4)) showProjection(p38_ensemble, p38_pca[0]) plt.title('Projection onto PC1') plt.figure(figsize=(5,4)) showProjection(p38_ensemble, p38_pca[:2]) plt.title('Projection onto PC1-2') plt.figure(figsize=(5,4)) showProjection(p38_ensemble, p38_pca[:3]) # onto top 3 PCs plt.title('Projection onto PC1-3') .. plot:: :context: :nofigs: plt.close('all')""" import matplotlib.pyplot as plt if not isinstance(ensemble, (Ensemble, Conformation, Vector)): raise TypeError('ensemble must be Ensemble, Conformation, or Vector, ' 'not {0:s}'.format(type(ensemble))) if not isinstance(modes, (NMA, ModeSet, Mode)): raise TypeError('modes must be NMA, ModeSet, or Mode, not {0:s}' .format(type(modes))) if not modes.is3d(): raise Exception('modes must be 3-dimensional') if isinstance(modes, Mode) or (isinstance(modes, (ModeSet, NMA)) and len(modes)==1): if not isinstance(modes, Mode): modes = modes[0] projection = calcProjection(ensemble, modes, kwargs.pop('rmsd', True)) show = plt.hist(projection.flatten(), *args, **kwargs) plt.xlabel('Mode {0:d} coordinate'.format(modes.getIndex()+1)) plt.ylabel('Number of conformations') elif len(modes) == 2: if 'ls' not in kwargs: kwargs['ls'] = 'None' if 'marker' not in kwargs: kwargs['marker'] = 'o' projection = calcProjection(ensemble, modes, kwargs.pop('rmsd', True)) show = plt.plot(projection[:, 0], projection[:, 1], *args, **kwargs) modes = [m for m in modes] plt.xlabel('Mode {0:d} coordinate'.format(modes[0].getIndex()+1)) plt.ylabel('Mode {0:d} coordinate'.format(modes[1].getIndex()+1)) elif len(modes) == 3: if 'ls' not in kwargs: kwargs['ls'] = 'None' if 'marker' not in kwargs: kwargs['marker'] = 'o' from mpl_toolkits.mplot3d import Axes3D projection = calcProjection(ensemble, modes, kwargs.pop('rmsd', True)) modes = [m for m in modes] 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(projection[:, 0], projection[:, 1], projection[:, 2], *args, **kwargs) show.set_xlabel('Mode {0:d} coordinate'.format(modes[0].getIndex()+1)) show.set_ylabel('Mode {0:d} coordinate'.format(modes[1].getIndex()+1)) show.set_zlabel('Mode {0:d} coordinate'.format(modes[2].getIndex()+1)) else: raise ValueError('Projection onto upto 3 modes can be shown. ' 'You have given {0:d} mode.'.format(len(modes))) return show