Example #1
0
    def scatter(self, *args, **kwargs):
        """ attr1/2 default to canvas.scatter """
        
        multi= kwargs.pop('multi', False)
        colors = kwargs.pop('colors', self._request_plotcolors())
        annotate = kwargs.pop('annotate', False)
        
        axes, kwargs = putil._parse_ax(*args, **kwargs)

        # Multiplot style
        if multi:
            raise NotImplementedError
    
        # Overlaid plot style
        else:
            if not axes:
                fig, axes = plt.subplots()
            
            for idx, c in enumerate(self.canvii):
                # Only pass annotate once to avoid re-write axis labels/title
                if idx == 0 and annotate:
                    addlabel = True
                else:
                    addlabel = False
                c.scatter(axes, color=colors[idx], annotate=addlabel, **kwargs)
                

            if annotate:
                axes.legend(self.names)
        
        return axes    
Example #2
0
    def _show(self, *args, **kwargs):
        """ show() and patchshow()** wrap their respective Canvas methods, 
        so any valid arguments (like colormaps, grids etc...) should just
        work.  In addition, multicanvas show methods have the following
        additional keyword arguments:
        
        Parameters
        ----------
        names: bool (False)
            Show multicanvas names at top of plot
            
        colors: bool (True):
            Map stored color to each particle in subplot.

        **kwargs:
            Any valid splot arg (ncols, figsize etc...) or show/patchshow
            args, such as cmap, grid etc...
                    
        If passing a pre-constructed axes/subplots to mc.show(), it must be 
        as a keyword.  As a positional, it will not work! 
        """
        names = kwargs.pop('names', False)
        colors = kwargs.pop('colors', True)
        showstyle = kwargs.pop('showstyle', 'show')
        
        if showstyle not in ['show', 'patchshow']:
            raise MultiError("showstyle must be show or patchshow, "
                             "not %s" % showstyle)
        
        axes, kwargs = putil._parse_ax(*args, **kwargs)	
                
        if not axes:
            axes, kwargs = putil.multi_axes(len(self), **kwargs)

        if len(axes) < len(self):
            logger.warn("MultiCanvas has %s canvas, but only %s axes recieved"
                        " in show()" % (len(self), len(axes)))
            upperlim = len(axes)

        else:
            upperlim = len(self)
            
        pcolors = self._request_plotcolors()
        
        for idx in range(upperlim):
            c = self.canvii[idx]
            if colors:
                def cmap(p):
                    p.color = pcolors[idx]
                    return p             
                c = c.pmap(cmap)
            
            if names:
                kwargs['title'] = self.names[idx]

            getattr(c, showstyle)(axes[idx], **kwargs)
        return axes
Example #3
0
    def scatter(self, *args, **kwargs):
        """ Scatter plot of two particles attributes (eg area vs ccircularity).
        
        Parameters
        ----------
        attr1: str
            X-attribute
            
        attr2: str
            Y-attribute
            
        annotate: False
            Adds title, x and y labels
        """

        # Would it make more sense to default these to something
        attr1 = kwargs.pop('attr1', None)
        attr2 = kwargs.pop('attr2', None)
        
        if not attr1 or not attr2:
            raise CanvasPlotError('Scatter attributes must be specified as'
                ' keywords (IE c.scatter(attr1=area, attr2=eccentricity ...)')
    
        annotate = kwargs.pop('annotate', False)
        title = kwargs.pop('title', None)
        fancy = kwargs.pop('fancy', False)
        
        axes, kwargs = _parse_ax(*args, **kwargs)
        if fancy:
            raise NotImplementedError("Fancy kwarg not yet supported.")

        if not axes:
            fig, axes = plt.subplots()
            
        x, y = getattr(self, attr1), getattr(self, attr2)

        axes.scatter(x, y, **kwargs)

        if annotate:
            if not title:
                title = '%s - %s' % (attr1.title(), attr2.title())
            axes.set_xlabel(attr1)
            axes.set_ylabel(attr2)
       
        if title:
            axes.set_title(title)
         
        return axes
Example #4
0
    def show(self, *args, **kwargs):
        """ Wrapper to imshow.  Converts to gray to allow color maps.
        
        Notes
        -----
        Differs from patchshow in that the collective image (bg, grid, particles)
        is a series of masks, so they have to be drawn onto a single ndarray and 
        then plotted.  Sicne patchshow is writing patchs, it can plot the background
        separate from the grid and particles, which is slightly easier"""

        # This will pull out "ax", leaving remaing args/kwargs
        axes, kwargs = _parse_ax(*args, **kwargs)
        title = kwargs.pop('title', None)
        save = kwargs.pop('save', None)
        bgonly = kwargs.pop('bgonly', False)
        annotate = kwargs.pop('annotate', False)
        
        grid = kwargs.pop('grid', False)
        gcolor = kwargs.pop('gcolor', None)
        gunder = kwargs.pop('gunder', False)
        gstyle = kwargs.pop('gstyle', None) #NOT USED
        nolabel = kwargs.pop('nolabel', False)
        zoom = kwargs.pop('zoom', None)
        
        if gstyle:
            raise CanvasPlotError('"gstyle" only valid for patchshow()')
        
        if 'pmap' in kwargs:
            raise CanvasPlotError('"pmap" is only valid for patchshow() method')
        
        PBINARY = False
        if 'cmap' in kwargs:
            if kwargs['cmap'] == 'pbinary' or kwargs['cmap'] == 'pbinary_r':
                PBINARY = kwargs['cmap']
                del kwargs['cmap']
        
        # Get the background
        if bgonly: 
            if 'cmap' not in kwargs:
                raise CanvasPlotError('"bgonly" is only valid when a colormap is' 
                ' passed.')
            bg = kwargs['cmap'](self.graybackground)[... , :3]
            del kwargs['cmap']

        else:
            bg = self.background
            if PBINARY:
                if PBINARY == 'pbinary_r':
                    bg = np.ones(bg.shape).astype(bool)
                else:
                    bg = np.zeros(bg.shape).astype(bool)
                              
        # grid overlay
        if gcolor or gunder and not grid:
            grid = True
            
        # If user enters gcolor, assume default grid
        if grid and not gcolor:
            gcolor = GCOLOR
        
        # Map attributes from grid (centers, corners, grid)
        gattr = np.zeros(bg.shape).astype(bool)  #IE pass
        if grid:
            if not gcolor:
                gcolor = GCOLOR
            if grid == True:
                grid = 'grid'

            # Validate grid keyword
            try:
                gattr=getattr( self.grid, grid.lower() )
            except Exception:
                raise CanvasPlotError('Invalid grid argument, "%s".  Choose from:  '
                    'True, "grid", "centers", "corners", "hlines", "vlines"' 
                    % grid)            
            gcolor = to_normrgb(gcolor)
                                  
        #Draw grid over or under?            
        if gunder:
            bg[gattr] = gcolor
            image = self._draw_particles(bg, force_binary=PBINARY)
        else:
            image = self._draw_particles(bg, force_binary=PBINARY)
            image[gattr] = gcolor
            
                        
        # GRAY CONVERT
        if 'cmap' in kwargs:
            image = rgb2uint(image)           
            
            
        # Matplotlib
        if axes:
            axes.imshow(image, **kwargs)
        else:     
            axes = plt.imshow(image, **kwargs).axes         
            
        axes = self._annotate_plot(axes, annotate, title)            
        
        # SHOW DOESNT ACTUALLY CROP ANYTHING WHEN ZOOMING
        if zoom:
            xi, yi, xf, yf = zoom
            axes.set_xlim(xi, xf)
            axes.set_ylim(yf, yi)

        if nolabel:
            axes.xaxis.set_visible(False)
            axes.yaxis.set_visible(False)
            if nolabel == 'x':
                axes.yaxis.set_visible(True)
            elif nolabel == 'y':
                axes.xaxis.set_visible(True)

        if save:
            path = _parse_path(save)
            skimage.io.imsave(path, image)   
        return axes
Example #5
0
    def patchshow(self, *args, **kwargs):
        """ ...
        args/kwargs include alpha, edgecolors, linestyles 

        Notes:
        Matplotlib API is setup that args or kwargs can be entered.  Order is
        important for args, but the correspond to same kwargs.
        """

        axes, kwargs = _parse_ax(*args, **kwargs)	
        
        title = kwargs.pop('title', None)        
        bgonly = kwargs.pop('bgonly', False)
        annotate = kwargs.pop('annotate', False)
        zoom = kwargs.pop('zoom', None)

        grid = kwargs.pop('grid', False)
        gcolor = kwargs.pop('gcolor', None)
        gstyle = kwargs.pop('gstyle', None)
        gunder = kwargs.pop('gunder',False)
        pmap = kwargs.pop('pmap', None)
        nolabel = kwargs.pop('nolabel', None)
        
        alpha = kwargs.get('alpha', None)
        edgecolor = kwargs.get('edgecolor', None)
        linewidth = kwargs.get('linewidth', None)
        linestyle = kwargs.get('linestyle', None)

        # Some keywords to savefig; not all supported
        save = kwargs.pop('save', None)
        dpi = kwargs.pop('dpi', None)
        bbox_inches = kwargs.pop('bbox_inches', None)
        
        # GET NOT POP
        cmap = kwargs.get('cmap', None)       
        
        # Implement later
        if cmap in ['pbinary', 'pbinary_r']:
            raise CanvasPlotError('"pbinary(_r)" color map only valid for .show()')
        
        # grid defaults
        if gcolor or gunder or gstyle and not grid:
            grid = True
            
        # If user enters gcolor/gstyle, assume default grid
        if grid and not gcolor:
            gcolor = GCOLOR       
            
        if grid and not gstyle:
            gstyle = 'solid'        
        
        # Corner case, don't touch
        if pmap and cmap and bgonly:
            bgonly = False
        
        if bgonly and not cmap: 
            raise CanvasPlotError('"bgonly" is only valid when a colormap is' 
            ' passed.')

        if cmap:
            bg = self.graybackground
        else:
            bg = self.background
            
        if zoom:
            xi, yi, xf, yf = zoom
            bg = crop(bg, zoom) 
                        
        #Overwrite axes image
        if not axes:
            fig, axes = plt.subplots()
        else:
            axes.images=[]
        # DONT PASS ALL KWARGS
        axes.imshow(bg, cmap=cmap)

        # FOR PATICLES IN IMAGE ONLY.
        in_and_edges = self.pin + self.pedge
        
        # PARTICLE FACECOLOR, ALPHA and other PATCH ARGS
        # http://matplotlib.org/api/artist_api.html#matplotlib.patches.Patch
        patches = [p.particle.as_patch(facecolor=p.color, alpha=alpha, 
                    edgecolor=edgecolor, linestyle=linestyle, linewidth=linewidth)
                   for p in in_and_edges]

        # If no particles or grid, just pass to avoid deep mpl exceptiosn
        if patches or grid:
            if patches:
                if pmap:
                    kwargs['cmap'] = pmap               
                if 'cmap' in kwargs and not bgonly:
                    ppatch = PatchCollection(patches, **kwargs) #cmap and Patch Args
                    ppatch.set_array(np.arange(len(patches)))        
        
                # Use settings passed to "patches"
                else:                                                  
                    ppatch = PatchCollection(patches, match_original=True, **kwargs) #
        
            # Grid under particles
            if gunder:
                axes.add_collection(self.grid.as_patch(
                    edgecolors=gcolor, linestyles=gstyle))
                if patches:
                    axes.add_collection(ppatch)
            # Grid over particles
            else:
                if patches:
                    axes.add_collection(ppatch)          
                if grid:
                    axes.add_collection(self.grid.as_patch(
                        edgecolors=gcolor, linestyles=gstyle))    
        
        axes = self._annotate_plot(axes, annotate, title)    
        
        if zoom:
            axes.set_xlim(xi, xf)
            axes.set_ylim(yf, yi)
        
        if nolabel:
            axes.xaxis.set_visible(False)
            axes.yaxis.set_visible(False)
            if nolabel == 'x':
                axes.yaxis.set_visible(True)
            elif nolabel == 'y':
                axes.xaxis.set_visible(True)        
        
        if save:
            path = _parse_path(save)
            plt.savefig(path, dpi=dpi, bbox_inches=bbox_inches)
        return axes
Example #6
0
    def hist(self, *histargs, **histkwargs):
        """ Matplotlib histogram wrapper. 
    
        Parameters
        ----------
        **annotate:** bool - True
            Add general legend, title, axis labels. 
            
        **attr:** str - "area"
            Particle attribute for data.  (Also a pie chart keyword).
            
        **xlim:** range(start, stop) - None
            Shortcut to set x-limits.  If **xlim=auto**, absolute min and 
            absolute max of data will be used.  
            This crops data AND sets axis limits; to only change plot axes,
            use *axes.set_xlim()*.
            
        Notes
        -----
        We see that the **annotate** option adds a legend, title and axis 
        labels.  The default attribute of the histogram is *area*, 
        corresponding to the **attr** kwargs.  All other valid matplotlib 
        histogram kwargs should work.
        """
        
        annotate = histkwargs.pop('annotate', True)   
        attr = histkwargs.pop('attr', 'area')  
        histkwargs.setdefault('stacked', True)
        histkwargs.setdefault('label', self.names)  
        histkwargs.setdefault('bins', 10)
        metavar = histkwargs.pop('metavar', None)    
        xlim = histkwargs.pop('xlim', None)     
        
        #MPL api asymmetry with pie
        if 'colors' in histkwargs:
            histkwargs['color'] = histkwargs.pop('colors')        
            
        # If not colors, set colors based on _colors
        if 'color' not in histkwargs:
            histkwargs['color'] = self._request_plotcolors()
            
        axes, histkwargs = putil._parse_ax(*histargs, **histkwargs)	
        if not axes:
            fig, axes = plt.subplots()        
        
        # Get list of arrays for descriptor, slice if xlim
        attr_list = [getattr(c, attr) for c in self.canvii]   
        if xlim:
            if xlim == 'auto':
                xi, xf = min(map(min, attr_list)), max(map(max, attr_list))
            else:
                xi, xf = xlim     
            
            attr_list = [array[(array >= xi) & (array <= xf)] 
                         for array in attr_list]
            axes.set_xlim(xi, xf)

        # Validate attr_list for empy arrays; avoid ambiguous mpl error
        for idx, array in enumerate(attr_list):
            if len(array) == 0:
                raise MultiError('Empty array returned for "%s" attribute'
                    ' on "%s" Canvas.' % (attr, self.names[idx]) )
                
        axes.hist(attr_list, **histkwargs)         
        
        if annotate:
            axes.set_xlabel(attr.title()) #Capitalize first letter
            axes.set_ylabel('Counts')
            if metavar:
                attr = metavar
            axes.set_title('%s Distribution (%s bins)' % 
                           (attr.title(), histkwargs['bins']) )
            axes.legend()
        return axes
Example #7
0
    def pie(self, *chartargs, **chartkwargs):
        """ Pie chart wrapper to matplotlib.
        
        Parameters
        ----------
        attr : Str or None
            Sum of variable to show in the pie.  Generally particle 
            descriptor (eg area).  If None or "count", the particle
            counts by species are used.
            
        annotate : Bool (True)
            Add auto title to piechart.
            
        autopct : str or fcn or None
            Label of pie slices.  Some built in short cuts include
            "count", "percentage", "both".  Note results in no labels.
            See matplotlib.pie for more.

        usetex : bool (False)
            Label of pie slcies use latex rendering.  If matplotlib.rcparams
            usetex = True, then set this to True.
        
        """
        attr = chartkwargs.pop('attr', None)
        annotate = chartkwargs.pop('annotate', True)     
        usetex = chartkwargs.pop('usetex', False)     
        chartkwargs.setdefault('shadow', False)      
        metavar = chartkwargs.pop('metavar', None)
        
        # If not colors, set colors based on _colors
        if 'colors' not in chartkwargs:
            chartkwargs['colors'] = self._request_plotcolors()        
        
        if annotate:
            autopct = chartkwargs.get('autopct', 'percent')
            chartkwargs.setdefault('labels', self.names)                        
        else:
            autopct = chartkwargs.get('autopct', None)
    
        axes, chartkwargs = putil._parse_ax(*chartargs, **chartkwargs)	
        if not axes:
            fig, axes = plt.subplots()       
        
        if attr is None or attr == 'count':
            attr_list = [len(c) for c in self.canvii]
            attr = 'number' # for title
        else:
            attr_list = [sum(getattr(c, attr)) for c in self.canvii]
                
        # Percentage or true values
        if autopct == 'percent':
            if usetex:
                chartkwargs['autopct'] = r'\bf{%.1f\%%}' #Label size and position                      
            else:
                chartkwargs['autopct'] = '%.1f%%' #Label size and position                                      

        elif autopct == 'count':
            if usetex:
                chartkwargs['autopct'] = \
                    lambda(p): r'\bf{:.0f}'.format(p * sum(attr_list) / 100)
            else:
                chartkwargs['autopct'] = \
                    lambda(p): '{:.0f}'.format(p * sum(attr_list) / 100)                    

        elif autopct == 'both':
            
            def double_autopct(pct):
                total = sum(attr_list)
                val = int(round(pct*total/100.0, 0))
                if usetex:
                    texstring = r'{v} ({p:.1f}\%)'.format(p=pct,v=val)   
                    return r'\bf{%s}' % texstring  
                else:
                    return '{v}\n({p:.1f}%)'.format(p=pct,v=val)                                    

            chartkwargs['autopct'] = double_autopct

        axes.pie(attr_list, **chartkwargs)

        if annotate:
            if metavar:
                attr = metavar
            axes.set_title('%s Distribution' % attr.title())
        return axes