def ply_fig(ts, points=False, color='jet', **kwds):
    """ Convert a timespectra to plotly Figure.  Figures can be then directly
    plotted with plotly.iplot(figure) in the notebook.  Use the layout keyword
    to specify layout parameters; all other keywords are interpreted as line style
    keywords (color
    
    Parameters
    ----------
    
    points: bool
        If true, scatter plot; else, lineplots
        
    color: str
        Any valid matplotlib color or colormap.
    
    layout: dict
        Dictionary of keywords that go into layout.  
        
    """
    
    data = grobs.Data()
    layoutkwds = kwds.pop('layout', {})
    lout = layout(ts, **layoutkwds)    
    
    # List of colors, either single color or color map
    try:
        cmapper = put.cmget(color) #Validate color map
    except AttributeError:
        cmapper = [color for i in range(len(ts.columns))]
    else:
        cmapper = put._df_colormapper(ts, color, axis=0)        
        
    # Map colors to rgb
    cmapper = map(put.to_normrgb, cmapper)    
    
    # Scale by 255 and string format for plotly
    def _rgbplotlycolor(rgb):
        r,g,b = rgb
        return 'rgb(%s, %s, %s)' % (255.0*r, 255.0*g, 255.0*b)
    
    cmapper = map(_rgbplotlycolor, cmapper)

    if points:
        tracefcn = make_pointtrace
    else:
        tracefcn = make_linetrace

    for idx, clabel in enumerate(ts):            
        trace = tracefcn(
            x = np.array(ts.index),               # Not necessary to force to np.array.dtype(float)
            y = np.array(ts[ts.columns[idx]]),
            name=clabel,
            color=cmapper[idx], #marker color
            **kwds
            ) 
        data.append(trace)

    return grobs.Figure(data=data, layout=lout)
def ply_fig(ts, points=False, color='jet', **kwds):
    """ Convert a timespectra to plotly Figure.  Figures can be then directly
    plotted with plotly.iplot(figure) in the notebook.  Use the layout keyword
    to specify layout parameters; all other keywords are interpreted as line style
    keywords (color
    
    Parameters
    ----------
    
    points: bool
        If true, scatter plot; else, lineplots
        
    color: str
        Any valid matplotlib color or colormap.
    
    layout: dict
        Dictionary of keywords that go into layout.  
        
    """

    data = grobs.Data()
    layoutkwds = kwds.pop('layout', {})
    lout = layout(ts, **layoutkwds)

    # List of colors, either single color or color map
    try:
        cmapper = put.cmget(color)  #Validate color map
    except AttributeError:
        cmapper = [color for i in range(len(ts.columns))]
    else:
        cmapper = put._df_colormapper(ts, color, axis=0)

    # Map colors to rgb
    cmapper = map(put.to_normrgb, cmapper)

    # Scale by 255 and string format for plotly
    def _rgbplotlycolor(rgb):
        r, g, b = rgb
        return 'rgb(%s, %s, %s)' % (255.0 * r, 255.0 * g, 255.0 * b)

    cmapper = map(_rgbplotlycolor, cmapper)

    if points:
        tracefcn = make_pointtrace
    else:
        tracefcn = make_linetrace

    for idx, clabel in enumerate(ts):
        trace = tracefcn(
            x=np.array(
                ts.index),  # Not necessary to force to np.array.dtype(float)
            y=np.array(ts[ts.columns[idx]]),
            name=clabel,
            color=cmapper[idx],  #marker color
            **kwds)
        data.append(trace)

    return grobs.Figure(data=data, layout=lout)
Beispiel #3
0
def spec3d(ts, projection=True, samples=5, **pltkwargs):
    """ Wireframe plot with no connected clines.  By default, adds an xz 
    projection. 
    
    Parameters
    ----------
    projection : color/colormap
        Valid colormap or solid color of contour projection.
        
    samples : int
        Number of samples to take from dataset.  Defaults to 5.  Must
        be within 0 and the number of columns in Spectra.
    
    Returns
    -------
    tuple: (Axes, SurfaceFunction)
        Returns axes object and the surface function (e.g. contours for
        contour plot.  Surface for surface plot.)
    
    Notes
    -----
    Mostly a shortcut for a very useful 3d look at data. Thus, did not add
    much customizability as this plot can be assembled from _gen2d3d2d and
    add_projeciton.
    """

    for invalid in ['c_iso', 'r_iso', 'cstride', 'rstride']:
        if invalid in pltkwargs:
            raise PlotError('Unsupported Keyword %s.'
                            'Please use the samples argument' % invalid)

    pltkwargs['kind'] = 'wire'
    pltkwargs['r_iso'] = 0
    pltkwargs['c_iso'] = samples
    ax, mappable = _gen2d3d(ts, **pltkwargs)

    if projection:
        if projection == True:
            projection = 'jet'

        contourkwds = {}

        # Parse colormap vs. color for projection
        try:
            contourkwds['cmap'] = pu.cmget(projection)
            contourkwds['alpha'] = 0.3  #

        except AttributeError:
            contourkwds['colors'] = projection

        ax = add_projection(ts, ax=ax, fill=True, **contourkwds)

    return ax, mappable
Beispiel #4
0
def spec3d(ts, projection=True, samples=5, **pltkwargs):
    """ Wireframe plot with no connected clines.  By default, adds an xz 
    projection. 
    
    Parameters
    ----------
    projection : color/colormap
        Valid colormap or solid color of contour projection.
        
    samples : int
        Number of samples to take from dataset.  Defaults to 5.  Must
        be within 0 and the number of columns in Spectra.
    
    Returns
    -------
    tuple: (Axes, SurfaceFunction)
        Returns axes object and the surface function (e.g. contours for
        contour plot.  Surface for surface plot.)
    
    Notes
    -----
    Mostly a shortcut for a very useful 3d look at data. Thus, did not add
    much customizability as this plot can be assembled from _gen2d3d2d and
    add_projeciton.
    """

    for invalid in ['c_iso', 'r_iso', 'cstride', 'rstride']:
        if invalid in pltkwargs:
            raise PlotError('Unsupported Keyword %s.'
                            'Please use the samples argument' % invalid)
        
    pltkwargs['kind'] = 'wire'
    pltkwargs['r_iso'] = 0
    pltkwargs['c_iso'] = samples
    ax, mappable = _gen2d3d(ts, **pltkwargs)
    
    if projection:
        if projection == True:
            projection = 'jet' 

        contourkwds = {}

        # Parse colormap vs. color for projection
        try: 
            contourkwds['cmap'] = pu.cmget(projection)
            contourkwds['alpha'] = 0.3 #     
            
        except AttributeError:
            contourkwds['colors'] = projection
            
        ax = add_projection(ts, ax=ax, fill=True, **contourkwds)
   
    return ax, mappable
def _gen2d(xx, yy, zz, contours=6, label=None, colorbar=None, 
           background=None, **pltkwargs):
    """ Abstract layout for 2d plot.
    For convienence, a few special labels, colorbar and background keywords 
    have been implemented.  If these are not adequate, it one can add 
    custom colorbars, linelabels background images etc... easily just by 
    using respecitve calls to plot (plt.colorbar(), plt.imshow(), 
    plt.clabel() ); my implementations are only for convienences and
    some predefined, cool styles.
        
    countours: Number of desired contours from output.
    
    label: Predefined label types.  For now, only integer values 1,2.  Use plt.clabel to add a custom label.
    
    background: Integers 1,2 will add gray or autumn colormap under contour plot.  Use plt.imgshow() to generate
                custom background, or pass a PIL-opened image (note, proper image scaling not yet implemented).
                
    fill: bool (False)
        Fill between contour lines.

    **pltkwargs: Will be passed directly to plt.contour().
    
    """
             
    # Boilerplate from basic_plots._genplot(); could refactor as decorator
    xlabel = pltkwargs.pop('xlabel', '')
    ylabel = pltkwargs.pop('ylabel', '')
    title = pltkwargs.pop('title', '')
    grid = pltkwargs.pop('grid', '')
    fill = pltkwargs.pop('fill', True)

    
#    pltkwargs.setdefault('legend', False) #(any purpose in 2d?)
    pltkwargs.setdefault('linewidth', 1)    
    
    cbar = pltkwargs.pop('cbar', False)
    
    fig = pltkwargs.pop('fig', plt.gcf())
    ax = pltkwargs.pop('ax', None)  
    
    # Overwrites fig (desireable?)
    if not ax:
        fig, ax = plt.subplots(1)

    labelsize = pltkwargs.pop('labelsize', 'medium') #Can also be ints
    titlesize = pltkwargs.pop('titlesize', 'large')
    ticksize = pltkwargs.pop('ticksize', '') #Put in default and remove bool gate
    
    
    ### BUG, PLT.CONTOUR() doesn't take 'color'; rather, takes 'colors' for now
    ### This is only for solid colors.  contour takes cmap argument by default.  
    if 'color' in pltkwargs:        
        pltkwargs['colors']=pltkwargs.pop('color')
        
    ### Convienence method to pass in string colors
    if 'cmap' in pltkwargs and isinstance(pltkwargs['cmap'], basestring):
        pltkwargs['cmap']=pu.cmget(pltkwargs['cmap'])
    
    ### I CAN MAKE THIS GENERAL TO ANY PLOT, ADDITION OF IMAGES TO A BACKGROUND MAKE IT A GENERAL ROUTINE TO ALL MY PLOTS ###
    ### More here http://matplotlib.org/examples/pylab_examples/image_demo3.html ###
    # Refactored with xx, yy instead of df.columns/index UNTESTED
    if background:
        xmin, xmax, ymin, ymax = xx.min(), xx.max(), yy.min(), yy.max()
        if background==1:
            im = plt.imshow(zz, interpolation='bilinear', origin='lower',
                        cmap=cm.gray, extent=(xmin, xmax, ymin, ymax))     
            
        elif background==2:
            im = plt.imshow(zz, interpolation='bilinear', origin='lower',
                       cmap=cm.autumn, extent=(xmin, xmax, ymin, ymax))            

    ### This will take a custom image opened in PIL or it will take plt.imshow() returned from somewhere else
        else:
            try:
                im = plt.imshow(background) 
            ### Perhaps image was not correctly opened    
            except Exception:
                raise badvalue_error(background, 'integer 1,2 or a PIL-opened image')
    else:
        im=None
        
    if fill:
        contours = ax.contourf(xx, yy, zz, contours, **pltkwargs)    #linewidths is a pltkwargs arg
    else:
        contours = ax.contour(xx, yy, zz, contours, **pltkwargs)    

    if cbar:
        fig.colorbar(contours)
 
    ### Pick a few label styles to choose from.
    if label:
        if label==1:
            ax.clabel(inline=1, fontsize=10)
        elif label==2:
            ax.clabel(levels[1::2], inline=1, fontsize=10)   #label every second line      
        else:
            raise PlotError(label, 'integer of value 1 or 2')
               
    ax.set_xlabel(xlabel, fontsize=labelsize)
    ax.set_ylabel(ylabel, fontsize=labelsize)
    ax.set_title(title, fontsize=titlesize)    
    if grid:
        ax.grid()
        
    return (ax, contours)    
def plot3d(df, kind='contour', elev=0, azim=0, proj_xy=True, proj_zy=True, proj_xz=True,
               contour_color=None, contour_cmap=None, c_iso=10, r_iso=10,*args, **pltkwargs):
    """ Matplotlib Axes3d wrapper for dataframe. Made to handle surface plots, so pure contour plots,
    polygon plots etc... these need their own classes.
    parameters:
     kind
      contour: Based on Axes3d.contour(x,y,z,*args,**kwargs), returns a plot_surface() with
               relevant spectral projections.
      contourf: Filled contour plot based on Axes3D.conourf(x,y,z,*args,**kwargs).  Same a contour
                except contours are filled.
                
    pltwargs can be any Axes3d keywords, with the following extra keywords being germane to this class.
      xlabel, ylabel, zlabel: Axis labels.  Defaults are provided here.  If none are provided, the 
                              attributes df.index.name and df.columns.name will be examined, aftwards, 
                              defaults are used (see below).
                              
      xlim, ylim, zlim:  These can be passed, but if not, the are inferred from the data.  It's smarter
                         to manipulate the df input than to mess with these.  For now, I'm keeping them
                         because they are relevant to proj_padding, but otherwise, probably not too essential.
                              
      proj_padding: Padding percentage if one does not want contour projections right on the wall of the grid.
                    This actually needs fixed.  It is intended to work as in the user says... 1.1 and this means 
                    that the projections should be 10% outside of the axes grid.  0.9 would be 10% in.  
                    The operation to computes the new limit is actually not correct, and if a minimum axis 
                    value is 0, it won't move it beyond.  
                    If this ever becomes useful again, I think it would be wise to first set the x,y,z lims
                    on the plot, then after that, compute the paddings and set the offset to these values.
                    Something like 
                      ax.set(xlim)
                      newxlim=xlim*padding correction
                      contour(offset=newxlim)
                      
      A note on strides: Strides are step sizes.  Say you have 100 curves, then a stride of 5 would give you 20 
                         isolines over your surface.  As such, a smart keyword (c_iso and r_iso) will make sure
                         that a fixed number of contours are drawn when the user passes in a dataframe.  
                        
                        
      c_iso, r_iso:  See above.  These control how man column and row iso lines will be projected onto the 3d plot.
                    For example, if c_iso=10, then 10 isolines will be plotted as columns, despite the actual length of the
                    columns.  Alternatively, one can pass in c_stride directly, which is a column step size rather than
                    an absolute number, and c_iso will be disregarded.
                    
     contour_color/contour_cmap:  
           Either a solid color, or colormap, passed to the contour projections (proj_xy etc...).
           For now, will be passed to all contour projections (xy, zy, xz).

      """
    
    ### Error raised by cfunc() is not very clear so here's an easier one
    if contour_cmap and contour_color:
        raise AttributeError('plot3d can have non-null values for attributes contour_cmap and contour_color, but not both.')

    zlabel_def=''     
    zlabel=pltkwargs.pop('zlabel', zlabel_def)                    
    
    xlabel = pltkwargs.pop('xlabel', '')
    ylabel = pltkwargs.pop('ylabel', '')
    title = pltkwargs.pop('title', '')
    
    ### If plane (xy) is input backwards (yx), still works    
    proj_xy=pltkwargs.pop('proj_yx', proj_xy)
    proj_zy=pltkwargs.pop('proj_yz', proj_zy)
    proj_xz=pltkwargs.pop('proj_zx', proj_xz)
    
                    
    ### Make mesh grid based on dataframe indicies ###
    fig = plt.figure()
    ax = fig.gca(projection='3d')    
    xx,yy=np.meshgrid(df.columns, df.index)

    ### Set axis limits explicitly from padding and data.
    ### PLOT PADDING NEEDS FIXED AS OF NOW IT IS NOT CORRECT.  FOR EXAMPLE, IF MIN IS 0, NEED AN OPERATION
    ### THAT WILL STILL REDUCE IT TO LESS THAN ZERO.  ONLY WORTH FIGURING OUT IF NEED PROJECTIONS OUTSIDE OF THE GRID.
    ### ALSO BUGS IF THE AXIS VALUES AREN'T NUMBERS.  FOR EXAMPLE, IF THEY ARE NAMED COLUMNS.  FIX WITH TRY EXCEPT
    proj_padding=pltkwargs.pop('projpad', 0.0)
    
    xlim=pltkwargs.pop('xlim', (min(df.columns)*(1.0-proj_padding), max(df.columns)*(1.0+proj_padding)) )
    ylim=pltkwargs.pop('ylim', (min(df.index)*(1.0-proj_padding), max(df.index)*(1.0+proj_padding)) )
    
    ### Min/max of total data (only works if the data is 2d)
    zlim=pltkwargs.pop('zlim',  ((1.0-proj_padding)*(df.min()).min(), (1.0+proj_padding)*(df.max().max())) )  
    
    cstride= _ir( len(df.columns)/float(c_iso) ) 
    rstride= _ir( len(df.index)/float(r_iso) )   
    
    ### This occurs if the 
    if cstride==0:
        print "Warning, dataset is too small to accomodate c_iso of %i, setting to 1."%c_iso
        cstride=1
    if rstride==0:
        print "Warning, dataset is too small to accomodate r_iso of %i, setting to 1."%r_iso        
        rstride=1 #to prevent errors
    
    ### If these values are already passed in, they won't be overwritten.  Cmap here is for surface, not countour
    _surface_defaults={'alpha':0.2, 'rstride':rstride, 'cstride':cstride, 'cmap':pu.cmget('autumn')} #Don't have any special
    _surface_defaults.update(pltkwargs)
    pltkwargs=_surface_defaults #Need to do this in two steps or it errors

    ax.plot_surface(xx,yy,df, *args, **pltkwargs)   

    if kind=='contourf' or kind=='contour':           
        if kind=='contourf':
            cfunc=ax.contourf
        else:
            cfunc=ax.contour
            
        if proj_xy:
            cset = cfunc(xx, yy, df, zdir='z', colors=contour_color, cmap=contour_cmap, offset=zlim[0])   #project z onto xy (zmid to bottom)
    
        if proj_zy:
            cset = cfunc(xx, yy, df, zdir='x',colors=contour_color, cmap=contour_cmap, offset=xlim[0]) #project x onto zy (timestart)  (negative half time interval)

        if proj_xz:
            cset = cfunc(xx, yy, df, zdir='y',colors=contour_color, cmap=contour_cmap, offset=ylim[1]) #project y onto xz (ymid to 0)  (negative mid wavelength)

    else:    
        raise badvalue_error(kind, 'contour, contourf')
   
    ax.set_xlabel(xlabel)        #x 
    ax.set_ylabel(ylabel)  #Y
    ax.set_zlabel(zlabel)   #data     
    ax.set_title(title)       
    
    ax.view_init(elev, azim) 
    
    return ax
def plot2d(df, contours=6, label=None, colorbar=None, background=None, **pltkwds):
    ''' Wrapper for plt.contour that uses np.meshgrid to generate curves.  For convienence, a few special labels, colorbar and background
    keywords have been implemented.  If these are not adequate, it one can add custom colorbars, linelabels background images etc... easily
    just by using respecitve calls to plot (plt.colorbar(), plt.imshow(), plt.clabel() ); my implementations are only for convienences and
    some predefined, cool styles.
    
    df: Dataframe.
    
    countours: Number of desired contours from output.
    
    label: Predefined label types.  For now, only integer values 1,2.  Use plt.clabel to add a custom label.
    
    background: Integers 1,2 will add gray or autumn colormap under contour plot.  Use plt.imgshow() to generate
                custom background, or pass a PIL-opened image (note, proper image scaling not yet implemented).
                
    **pltkwds: Will be passed directly to plt.contour().'''
             
    xlabel, ylabel, title, pltkwds=pu.smart_label(df, pltkwds)

    ### BUG, PLT.CONTOUR() doesn't take 'color'; rather, takes 'colors' for now
    ### This is only for solid colors.  contour takes cmap argument by default.  
    if 'color' in pltkwds:        
        pltkwds['colors']=pltkwds.pop('color')
        
    ### Convienence method to pass in string colors
    if 'cmap' in pltkwds and isinstance(pltkwds['cmap'], basestring):
        pltkwds['cmap']=pu.cmget(pltkwds['cmap'])
    
    ### I CAN MAKE THIS GENERAL TO ANY PLOT, ADDITION OF IMAGES TO A BACKGROUND MAKE IT A GENERAL ROUTINE TO ALL MY PLOTS ###
    ### More here http://matplotlib.org/examples/pylab_examples/image_demo3.html ###
    if background:
        xmin, xmax, ymin, ymax=min(df.columns), max(df.columns), min(df.index), max(df.index)
        if background==1:
            im = plt.imshow(df, interpolation='bilinear', origin='lower',
                        cmap=cm.gray, extent=(xmin, xmax, ymin, ymax))     
            
        elif background==2:
            im = plt.imshow(df, interpolation='bilinear', origin='lower',
                       cmap=cm.autumn, extent=(xmin, xmax, ymin, ymax))            

    ### This will take a custom image opened in PIL or it will take plt.imshow() returned from somewhere else
        else:
            try:
                im = plt.imshow(background) 
            ### Perhaps image was not correctly opened    
            except Exception:
                raise badvalue_error(background, 'integer 1,2 or a PIL-opened image')
    else:
        im=None
        
    xx,yy = np.meshgrid(df.columns, df.index)
    ax = plt.contour(xx, yy, df, contours, **pltkwds)    #linewidths is a pltkwds arg
 
    ### Pick a few label styles to choose from.
    if label:
        if label==1:
            ax.clabel(inline=1, fontsize=10)
        elif label==2:
            ax.clabel(levels[1::2], inline=1, fontsize=10)   #label every second line      
        else:
            raise badvalue_error(label, 'integer of value 1 or 2')
        
            
    ### Add colorbar, for some reason need to do plt.colorbar() even though can do ax.clabel...
    if colorbar:
        if colorbar==1:  ### WHAT OTHER COLORBAR OPTIONS ARETHERE
            CB=plt.colorbar(ax, shrink=0.8) #shringk is heigh of colorbar relative ot height of plot
    
            if im:
                IMCB=plt.colorbar(im, orientation='horizontal', shrink=0.8)

                ### Move original colorbar to more natural to make room for image colorbar
                l,b,w,h = plt.gca().get_position().bounds
                ll,bb,ww,hh = CB.ax.get_position().bounds
                CB.ax.set_position([ll, b+0.1*h, ww, h*0.8])
                
        else:
            raise badvalue_error(colorbar, 'integer of value 1 is only supported for now')
                
         

    plt.xlabel(xlabel)      
    plt.ylabel(ylabel)                  
    plt.title(title)
    return ax    
def _gen2d3d(*args, **pltkwargs):
    # UPDATE
    """ Abstract layout for 2d plot.
    For convienence, a few special labels, colorbar and background keywords 
    have been implemented.  If these are not adequate, it one can add 
    custom colorbars, linelabels background images etc... easily just by 
    using respecitve calls to plot (plt.colorbar(), plt.imshow(), 
    plt.clabel() ); my implementations are only for convienences and
    some predefined, cool styles.
        
    countours: Number of desired contours from output.
    
    label: Predefined label types.  For now, only integer values 1,2.  Use plt.clabel to add a custom label.
    
    background: Integers 1,2 will add gray or autumn colormap under contour plot.  Use plt.imgshow() to generate
                custom background, or pass a PIL-opened image (note, proper image scaling not yet implemented).

    c_mesh, r_mesh: These control how man column and row iso lines will be projected onto the 3d plot.
                    For example, if c_mesh=10, then 10 isolines will be plotted as columns, despite the actual length of the
                    columns.  Alternatively, one can pass in c_stride directly, which is a column step size rather than
                    an absolute number, and c_mesh will be disregarded.
                    
                
    fill: bool (False)
        Fill between contour lines.

    **pltkwargs: Will be passed directly to plt.contour().

    Returns
    -------
    tuple: (Axes, SurfaceFunction)
        Returns axes object and the surface function (e.g. contours for
        contour plot.  Surface for surface plot.
    
    """

    # Use a label mapper to allow for datetimes in any plot x/y axis
    _x_dti = _ = _y_dti = False

    # Passed Spectra
    if len(args) == 1:
        ts = args[0]

        try:
            index = np.array([dates.date2num(x) for x in ts.index])
            _x_dti = True
        except AttributeError:
            index = ts.index.values  #VALUES NECESSARY FOR POLY CMAP

        try:
            cols = np.array([dates.date2num(x) for x in ts.columns])
            _y_dti = True
        except AttributeError:
            cols = ts.columns.values  #VALUES NECESSARY FOR POLY CMAP

        yy, xx = np.meshgrid(cols, index)

    # Passed xx, yy, ts/zz
    elif len(args) == 3:
        xx, yy, ts = args
        cols, index = ts.columns.values, ts.index.values

    else:
        raise PlotError(
            "Please pass a single spectra, or xx, yy, zz.  Got %s args" %
            len(args))

    # Boilerplate from basic_plots._genplot(); could refactor as decorator
    xlabel = pltkwargs.pop('xlabel', '')
    ylabel = pltkwargs.pop('ylabel', '')
    zlabel = pltkwargs.pop('zlabel', '')
    title = pltkwargs.pop('title', '')

    labelsize = pltkwargs.pop('labelsize',
                              pvconfig.LABELSIZE)  #Can also be ints
    titlesize = pltkwargs.pop('titlesize', pvconfig.TITLESIZE)

    # Choose plot kind
    kind = pltkwargs.pop('kind', 'contour')
    grid = pltkwargs.pop('grid', True)
    #    pltkwargs.setdefault('legend', False) #(any purpose in 2d?)
    #   LEGEND FOR 2D PLOT: http://stackoverflow.com/questions/10490302/how-do-you-create-a-legend-for-a-contour-plot-in-matplotlib
    pltkwargs.setdefault('linewidth', 1)

    cbar = pltkwargs.pop('cbar', False)

    outline = pltkwargs.pop('outline', None)
    if outline:
        if kind != 'surf' and kind != 'waterfall':
            raise PlotError(
                '"outline" is only valid for "surf" and "waterfall"'
                ' plots.  Please use color/cmap for all other color'
                ' designations.')

    fig = pltkwargs.pop('fig', None)
    ax = pltkwargs.pop('ax', None)
    fill = pltkwargs.pop('fill', pvconfig.FILL_CONTOUR)

    xlim = pltkwargs.pop('xlim', None)
    ylim = pltkwargs.pop('ylim', None)
    zlim = pltkwargs.pop('zlim', None)

    #Private attributes
    _modifyax = pltkwargs.pop('_modifyax', True)
    contours = pltkwargs.pop('contours', pvconfig.NUM_CONTOURS)
    label = pltkwargs.pop('label', None)

    projection = None

    if kind in PLOTPARSER.plots_3d:
        projection = '3d'

        elev = pltkwargs.pop('elev', 35)
        azim = pltkwargs.pop('azim', -135)

        view = pltkwargs.pop('view', None)
        if view:
            if view == 1:
                elev, azim = 35, -135
            elif view == 2:
                elev, azim = 35, -45
            elif view == 3:
                elev, azim = 20, -10  # Side view
            elif view == 4:
                elev, azim = 20, -170
            elif view == 5:
                elev, azim = 0, -90
            elif view == 6:
                elev, azim = 65, -90
            else:
                raise PlotError('View must be between 1 and 6; otherwise set'
                                ' "elev" and "azim" keywords.')

        # Orientation of zlabel (doesn't work...)
        _zlabel_rotation = 0.0
        if azim < 0:
            _zlabel_rotation = 90.0

        if 'mesh' in pltkwargs:
            pltkwargs['c_mesh'] = pltkwargs['r_mesh'] = pltkwargs.pop('mesh')

        # Defaults will be ignored if mesh or ciso in kwargs
        ciso_default = pvconfig.C_MESH
        if len(ts.columns) < ciso_default:
            ciso_default = len(ts.columns)

        riso_default = pvconfig.R_MESH
        if len(ts.index) < riso_default:
            riso_default = len(ts.index)

        c_mesh = pltkwargs.pop('c_mesh', ciso_default)
        r_mesh = pltkwargs.pop('r_mesh', riso_default)

        if c_mesh > ts.shape[1] or c_mesh < 0:
            raise PlotError(
                '"c_mesh/column mesh" must be between 0 and %s, got "%s"' %
                (ts.shape[1], c_mesh))

        if r_mesh > ts.shape[0] or r_mesh < 0:
            raise PlotError(
                '"r_mesh/row mesh" must be between 0 and %s, got "%s"' %
                (ts.shape[0], r_mesh))

        if c_mesh == 0:
            cstride = 0
        else:
            cstride = _ir(ts.shape[1] / float(c_mesh))

        if r_mesh == 0:
            rstride = 0
        else:
            rstride = _ir(ts.shape[0] / float(r_mesh))

        pltkwargs.setdefault('cstride', cstride)
        pltkwargs.setdefault('rstride', rstride)

    elif kind == 'contour':
        pass

    else:
        raise PlotError('_gen2d3d invalid kind: "%s".  '
                        'Choose from %s' % (kind, PLOTPARSER.plots_2d_3d))

    # Is this the best logic for 2d/3d fig?
    if not ax:
        f = plt.figure()
        #        ax = f.gca(projection=projection)
        ax = f.add_subplot(111, projection=projection)
        if not fig:
            fig = f

    # PLT.CONTOUR() doesn't take 'color'; rather, takes 'colors' for now
    if 'color' in pltkwargs:
        if kind == 'contour' or kind == 'contour3d':
            pltkwargs['colors'] = pltkwargs.pop('color')

    # Convienence method to pass in string colors
    if 'colormap' in pltkwargs:
        pltkwargs['cmap'] = pltkwargs.pop('colormap')

    if 'cmap' in pltkwargs:
        if isinstance(pltkwargs['cmap'], basestring):
            pltkwargs['cmap'] = pu.cmget(pltkwargs['cmap'])

    # Contour Plots
    # -------------

    # Broken background image
    ### More here http://matplotlib.org/examples/pylab_examples/image_demo3.html ###
    # Refactored with xx, yy instead of df.columns/index UNTESTED
    #if background:
    #xmin, xmax, ymin, ymax = xx.min(), xx.max(), yy.min(), yy.max()

    ## Could try rescaling contour rather than image:
    ##http://stackoverflow.com/questions/10850882/pyqt-matplotlib-plot-contour-data-on-top-of-picture-scaling-issue
    #if background==1:
    #im = ax.imshow(ts, interpolation='bilinear', origin='lower',
    #cmap=cm.gray, extent=(xmin, xmax, ymin, ymax))

    #### This will take a custom image opened in PIL or it will take plt.imshow() returned from somewhere else
    #else:
    #try:
    #im = ax.imshow(background)
    #### Perhaps image was not correctly opened
    #except Exception:
    #raise badvalue_error(background, 'integer 1,2 or a PIL-opened image')

    # Note this overwrites the 'contours' variable from an int to array
    if kind == 'contour' or kind == 'contour3d':

        # Cornercase datetimeindex and offest from add projection hack
        try:
            pltkwargs['offset'] = dates.date2num(pltkwargs['offset'])
        except Exception:
            pass

        if fill:  #Values of DTI doesn't work
            mappable = ax.contourf(xx, yy, ts.values, contours,
                                   **pltkwargs)  #linewidths is a pltkwargs arg
        else:
            mappable = ax.contour(xx, yy, ts.values, contours, **pltkwargs)

        ### Pick a few label styles to choose from.
        if label:
            if label == 1:
                ax.clabel(inline=1, fontsize=10)
            elif label == 2:
                ax.clabel(levels[1::2], inline=1,
                          fontsize=10)  #label every second line
            else:
                raise PlotError(label, 'integer of value 1 or 2')

    elif kind == 'surf':
        mappable = ax.plot_surface(xx, yy, ts, **pltkwargs)

        if outline:
            try:
                pltkwargs['cmap'] = pu.cmget(outline)
            except Exception:  #Don't change; attribute error fails when outline=None
                pltkwargs['color'] = outline
                pltkwargs.pop('cmap')

        custom_wireframe(ax, xx, yy, ts, **pltkwargs)
        # Wires are thrown out, since mappable is the surface, and only mappable returned

    elif kind == 'wire':
        pltkwargs.setdefault('color', 'black')
        mappable = custom_wireframe(ax, xx, yy, ts, **pltkwargs)

    elif kind == 'waterfall':

        # Parse outline color (if colormap, error!)
        try:
            pu.cmget(outline)
        except Exception:
            pltkwargs['edgecolors'] = outline
        else:
            raise PlotError(
                'Waterfall "outline" must be a solid color, not colormap.')

        pltkwargs.setdefault('closed', False)
        alpha = pltkwargs.setdefault('alpha', None)

        # Need to handle cmap/colors a bit differently for PolyCollection API
        if 'color' in pltkwargs:
            pltkwargs['facecolors'] = pltkwargs.pop('color')
        cmap = pltkwargs.setdefault('cmap', None)

        if alpha is None:  #as opposed to 0
            alpha = 0.6 * (13.0 / ts.shape[1])
            if alpha > 0.6:
                alpha = 0.6

        #Delete stride keywords (waterfall doesn't have strides: not a surface!)
        for key in ['cstride', 'rstride']:
            try:
                del pltkwargs[key]
            except KeyError:
                pass

        # Verts are index dotted with data
        verts = []
        for col in ts.columns:
            values = ts[col]
            values[0], values[-1] = values.min().min(), values.min().min()
            verts.append(list(zip(ts.index, values)))

        mappable = PolyCollection(verts, **pltkwargs)

        if cmap:
            mappable.set_array(
                cols)  #If set array in __init__, autogens a cmap!
            mappable.set_cmap(pltkwargs['cmap'])

        mappable.set_alpha(alpha)

        #zdir is the direction used to plot; dont' fully understand
        ax.add_collection3d(mappable, zs=cols, zdir='x')

        # custom limits/labels polygon plot (reverse x,y)
        if not ylim:
            ylim = (max(index), min(index))  #REVERSE AXIS FOR VIEWING PURPOSES

        if not xlim:
            xlim = (min(cols), max(cols))  #x

        if not zlim:
            zlim = (min(ts.min()), max(ts.max())
                    )  #How to get absolute min/max of ts values

        # Reverse labels/DTI call for correct orientaion HACK HACK HACK
        xlabel, ylabel = ylabel, xlabel
        _x_dti, _y_dti = _y_dti, _x_dti
        azim = -1 * azim

    # General Features
    # ----------------

    # Some applications (like add_projection) shouldn't alther axes features
    if not _modifyax:
        return (ax, mappable)

    if cbar:
        # Do I want colorbar outside of fig?  Wouldn't be better on axes?
        try:
            cb = fig.colorbar(mappable, ax=ax)
            # Label colorbar on contour since no 3d-zlabel
            if kind == 'contour':
                cb.set_label(zlabel)
        except Exception:
            raise PlotError("Colorbar failed; did you pass a colormap?")

    if grid:
        if grid == True:
            ax.grid()
        else:
            ax.grid(color=grid)  #Let's any supported color in

    # Format datetime axis
    # -------------------
    if _x_dti:
        ax.xaxis.set_major_formatter(mplticker.FuncFormatter(format_date))

        # Uncomment for custom 3d timestamp orientation
#       if projection:
#           for t1 in ax.yaxis.get_ticklabels():
#               t1.set_ha('right')
#               t1.set_rotation(30)
#           ax.yaxis._axinfo['label']['space_factor'] = _TIMESTAMPPADDING

    if _y_dti:
        ax.yaxis.set_major_formatter(mplticker.FuncFormatter(format_date))

        # Uncomment for custom 3d timestamp orientation
#      if projection:
#          for t1 in ax.yaxis.get_ticklabels():
#              t1.set_ha('right')
#              t1.set_rotation(30)
#          ax.yaxis._axinfo['label']['space_factor'] = _TIMESTAMPPADDING

    if xlim:
        ax.set_xlim3d(xlim)

    if ylim:
        ax.set_ylim3d(ylim)

    if zlim:
        ax.set_zlim3d(zlim)

    # Set elevation/azimuth for 3d plots
    if projection:
        ax.view_init(elev, azim)
        ax.set_zlabel(zlabel, fontsize=labelsize, rotation=_zlabel_rotation)

    ax.set_xlabel(xlabel, fontsize=labelsize)
    ax.set_ylabel(ylabel, fontsize=labelsize)
    ax.set_title(title, fontsize=titlesize)

    # Return Ax, contours/surface/polygons etc...
    return (ax, mappable)
Beispiel #9
0
def _gen2d3d(*args, **pltkwargs):
    # UPDATE
    """ Abstract layout for 2d plot.
    For convienence, a few special labels, colorbar and background keywords 
    have been implemented.  If these are not adequate, it one can add 
    custom colorbars, linelabels background images etc... easily just by 
    using respecitve calls to plot (plt.colorbar(), plt.imshow(), 
    plt.clabel() ); my implementations are only for convienences and
    some predefined, cool styles.
        
    countours: Number of desired contours from output.
    
    label: Predefined label types.  For now, only integer values 1,2.  Use plt.clabel to add a custom label.
    
    background: Integers 1,2 will add gray or autumn colormap under contour plot.  Use plt.imgshow() to generate
                custom background, or pass a PIL-opened image (note, proper image scaling not yet implemented).

    c_iso, r_iso: These control how man column and row iso lines will be projected onto the 3d plot.
                    For example, if c_iso=10, then 10 isolines will be plotted as columns, despite the actual length of the
                    columns.  Alternatively, one can pass in c_stride directly, which is a column step size rather than
                    an absolute number, and c_iso will be disregarded.
                    
                
    fill: bool (False)
        Fill between contour lines.

    **pltkwargs: Will be passed directly to plt.contour().

    Returns
    -------
    tuple: (Axes, SurfaceFunction)
        Returns axes object and the surface function (e.g. contours for
        contour plot.  Surface for surface plot.
    
    """
    
    # Use a label mapper to allow for datetimes in any plot x/y axis
    _x_dti = _ = _y_dti = False

    # Passed Spectra
    if len(args) == 1:
        ts = args[0]

        try:
            index = np.array([dates.date2num(x) for x in ts.index])
            _x_dti = True
        except AttributeError:
            index = ts.index.values #VALUES NECESSARY FOR POLY CMAP
            
        try:
            cols = np.array([dates.date2num(x) for x in ts.columns])
            _y_dti = True
        except AttributeError:
            cols = ts.columns.values #VALUES NECESSARY FOR POLY CMAP
                
        yy, xx = np.meshgrid(cols, index)

    # Passed xx, yy, ts/zz
    elif len(args) == 3:
        xx, yy, ts = args
        cols, index = ts.columns.values, ts.index.values
        
    else:
        raise PlotError("Please pass a single spectra, or xx, yy, zz.  Got %s args"
                        % len(args))
             
    # Boilerplate from basic_plots._genplot(); could refactor as decorator
    xlabel = pltkwargs.pop('xlabel', '')
    ylabel = pltkwargs.pop('ylabel', '')
    zlabel = pltkwargs.pop('zlabel', '')    
    title = pltkwargs.pop('title', '')

    # Choose plot kind
    kind = pltkwargs.pop('kind', 'contour')
    grid = pltkwargs.pop('grid', '')
#    pltkwargs.setdefault('legend', False) #(any purpose in 2d?)
#   LEGEND FOR 2D PLOT: http://stackoverflow.com/questions/10490302/how-do-you-create-a-legend-for-a-contour-plot-in-matplotlib
    pltkwargs.setdefault('linewidth', 1)    
    
    cbar = pltkwargs.pop('cbar', False)
    
    fig = pltkwargs.pop('fig', None)
    ax = pltkwargs.pop('ax', None)  
    fill = pltkwargs.pop('fill', False)  
    
    xlim = pltkwargs.pop('xlim', None)
    ylim = pltkwargs.pop('ylim', None)
    zlim = pltkwargs.pop('zlim', None)
    
    #Private attributes
    _modifyax = pltkwargs.pop('_modifyax', True)
    contours = pltkwargs.pop('contours', 6)
    label = pltkwargs.pop('label', None)
    
    projection = None
        
    if kind in PLOTPARSER.plots_3d:
        projection = '3d'

        elev = pltkwargs.pop('elev', 35)
        azim = pltkwargs.pop('azim', -135)        
        
        view = pltkwargs.pop('view', None)
        if view:
            if view == 1:
                elev, azim = 35, -135
            elif view == 2:
                elev, azim = 35, -45 
            elif view == 3:
                elev, azim = 20, -10  # Side view
            elif view == 4:
                elev, azim = 20, -170
            elif view == 5:
                elev, azim = 0,-90          
            elif view == 6:
                elev, azim = 65, -90
            else:
                raise PlotError('View must be between 1 and 6; otherwise set'
                                ' "elev" and "azim" keywords.')

        # Orientation of zlabel (doesn't work...)
        _zlabel_rotation = 0.0
        if azim < 0:
            _zlabel_rotation = 90.0

        c_iso = pltkwargs.pop('c_iso', 10)
        r_iso = pltkwargs.pop('r_iso', 10)
        
        if c_iso > ts.shape[1] or c_iso < 0:
            raise PlotError('"c_iso" must be between 0 and %s, got "%s"' %
                            (ts.shape[1], c_iso))

        if r_iso > ts.shape[0] or r_iso < 0:
            raise PlotError('"r_iso" must be between 0 and %s, got "%s"' % 
                            (ts.shape[0], r_iso))
        

        if c_iso == 0:
            cstride = 0
        else:
            cstride = _ir(ts.shape[1]/float(c_iso) ) 
            
        if r_iso == 0:
            rstride = 0
        else:
            rstride = _ir(ts.shape[0]/float(r_iso) )   
    
                        
        pltkwargs.setdefault('cstride', cstride)
        pltkwargs.setdefault('rstride', rstride)

    elif kind == 'contour':
        pass

    else:
        raise PlotError('_gen2d3d invalid kind: "%s".  '
               'Choose from %s' % (kind, PLOTPARSER.plots_2d_3d))

    # Is this the best logic for 2d/3d fig?
    if not ax:
        f = plt.figure()
#        ax = f.gca(projection=projection)       
        ax = f.add_subplot(111, projection=projection)
        if not fig:
            fig = f
        

    labelsize = pltkwargs.pop('labelsize', 'medium') #Can also be ints
    titlesize = pltkwargs.pop('titlesize', 'large')
    ticksize = pltkwargs.pop('ticksize', '') #Put in default and remove bool gate
    
    
    # PLT.CONTOUR() doesn't take 'color'; rather, takes 'colors' for now
    if 'color' in pltkwargs:       
        if kind == 'contour':
            pltkwargs['colors'] = pltkwargs.pop('color')
        
    # Convienence method to pass in string colors
    if 'colormap' in pltkwargs:
        pltkwargs['cmap'] = pltkwargs.pop('colormap')

    if 'cmap' in pltkwargs:
        if isinstance(pltkwargs['cmap'], basestring):
            pltkwargs['cmap'] = pu.cmget(pltkwargs['cmap'])
    
    # Contour Plots    
    # -------------

        # Broken background image
        ### More here http://matplotlib.org/examples/pylab_examples/image_demo3.html ###
        # Refactored with xx, yy instead of df.columns/index UNTESTED
        #if background:
            #xmin, xmax, ymin, ymax = xx.min(), xx.max(), yy.min(), yy.max()
            
            ## Could try rescaling contour rather than image:
            ##http://stackoverflow.com/questions/10850882/pyqt-matplotlib-plot-contour-data-on-top-of-picture-scaling-issue
            #if background==1:
                #im = ax.imshow(ts, interpolation='bilinear', origin='lower',
                            #cmap=cm.gray, extent=(xmin, xmax, ymin, ymax))             
    
        #### This will take a custom image opened in PIL or it will take plt.imshow() returned from somewhere else
            #else:
                #try:
                    #im = ax.imshow(background) 
                #### Perhaps image was not correctly opened    
                #except Exception:
                    #raise badvalue_error(background, 'integer 1,2 or a PIL-opened image')


    # Note this overwrites the 'contours' variable from an int to array
    if kind == 'contour' or kind == 'contour3d':
        if fill:
            mappable = ax.contourf(xx, yy, ts, contours, **pltkwargs)    #linewidths is a pltkwargs arg
        else:
            mappable = ax.contour(xx, yy, ts, contours, **pltkwargs)    


        ### Pick a few label styles to choose from.
        if label:
            if label==1:
                ax.clabel(inline=1, fontsize=10)
            elif label==2:
                ax.clabel(levels[1::2], inline=1, fontsize=10)   #label every second line      
            else:
                raise PlotError(label, 'integer of value 1 or 2')

 
    elif kind == 'surf': 
        mappable = ax.plot_surface(xx, yy, ts, **pltkwargs)
#        pltkwargs.pop('edgecolors')
        wires = overload_plot_wireframe(ax, xx, yy, ts, **pltkwargs)
#        print np.shape(wires._segments3d)
        wires = wire_cmap(wires, ax, cmap='jet')
        
    elif kind == 'wire':
        pltkwargs.setdefault('color', 'black')
        mappable = overload_plot_wireframe(ax, xx, yy, ts, **pltkwargs)

    elif kind == 'waterfall':
        
        edgecolors = pltkwargs.setdefault('edgecolors', None)
        pltkwargs.setdefault('closed', False)
        alpha = pltkwargs.setdefault('alpha', None)

        # Need to handle cmap/colors a bit differently for PolyCollection API
        if 'color' in pltkwargs:
            pltkwargs['facecolors']=pltkwargs.pop('color')
        cmap = pltkwargs.setdefault('cmap', None)
        
        if alpha is None: #as opposed to 0
            alpha = 0.6 * (13.0/ts.shape[1])
            if alpha > 0.6:
                alpha = 0.6        
        
        #Delete stride keywords
        for key in ['cstride', 'rstride']:
            try:
                del pltkwargs[key]
            except KeyError:
                pass
        
        # Verts are index dotted with data
        verts = []
        for col in ts.columns:  
            values = ts[col]
            values[0], values[-1] = values.min().min(), values.min().min()
            verts.append(list(zip(ts.index, values)))
    
        mappable = PolyCollection(verts, **pltkwargs)
        
        if cmap:
            mappable.set_array(cols) #If set array in __init__, autogens a cmap!
            mappable.set_cmap(pltkwargs['cmap'])

        mappable.set_alpha(alpha)      
                    
        #zdir is the direction used to plot; dont' fully understand
        ax.add_collection3d(mappable, zs=cols, zdir='x' )      

        # custom limits/labels polygon plot (reverse x,y)
        if not ylim:
            ylim = (max(index), min(index))  #REVERSE AXIS FOR VIEWING PURPOSES

        if not xlim:
            xlim = (min(cols), max(cols))    #x 

        if not zlim:
            zlim = (min(ts.min()), max(ts.max()))  #How to get absolute min/max of ts values
            
        # Reverse labels/DTI call for correct orientaion HACK HACK HACK
        xlabel, ylabel = ylabel, xlabel    
        _x_dti, _y_dti = _y_dti, _x_dti
        azim = -1 * azim

    # General Features
    # ----------------
    
    # Some applications (like add_projection) shouldn't alther axes features
    if not _modifyax:
        return (ax, mappable)

    if cbar:
        # Do I want colorbar outside of fig?  Wouldn't be better on axes?
        try:
            fig.colorbar(mappable, ax=ax)
        except Exception:
            raise PlotError("Colorbar failed; did you pass a colormap?")
               
    if grid:
        ax.grid()        
          

    # Format datetime axis
    # -------------------
    if _x_dti:
        ax.xaxis.set_major_formatter(mplticker.FuncFormatter(format_date))
            
        # Uncomment for custom 3d timestamp orientation
 #       if projection:
 #           for t1 in ax.yaxis.get_ticklabels():
 #               t1.set_ha('right')
 #               t1.set_rotation(30)        
 #           ax.yaxis._axinfo['label']['space_factor'] = _TIMESTAMPPADDING

    if _y_dti:
        ax.yaxis.set_major_formatter(mplticker.FuncFormatter(format_date))

        # Uncomment for custom 3d timestamp orientation
  #      if projection:
  #          for t1 in ax.yaxis.get_ticklabels():
  #              t1.set_ha('right')
  #              t1.set_rotation(30)        
  #          ax.yaxis._axinfo['label']['space_factor'] = _TIMESTAMPPADDING

    if xlim:
        ax.set_xlim3d(xlim)

    if ylim:
        ax.set_ylim3d(ylim)        
     
    if zlim:
        ax.set_zlim3d(zlim)    
                
    # Set elevation/azimuth for 3d plots
    if projection:        
        ax.view_init(elev, azim)                 
        ax.set_zlabel(zlabel, fontsize=labelsize, rotation= _zlabel_rotation)  
    
    ax.set_xlabel(xlabel, fontsize=labelsize)
    ax.set_ylabel(ylabel, fontsize=labelsize)
    ax.set_title(title, fontsize=titlesize) 
        
    # Return Ax, contours/surface/polygons etc...
    return (ax, mappable)