예제 #1
0
파일: plotting.py 프로젝트: crosvera/ProDy
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
예제 #2
0
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
예제 #3
0
파일: plotting.py 프로젝트: crosvera/ProDy
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