示例#1
0
    def labels(self, inline, inline_spacing):
        trans = self.ax.transData # A bit of shorthand

        for icon, lev, fsize, cvalue in zip(
            self.labelIndiceList, self.labelLevelList, self.labelFontSizeList,
            self.labelCValueList ):

            con = self.collections[icon]
            lw = self.get_label_width(lev, self.labelFmt, fsize)
            additions = []
            paths = con.get_paths()
            for segNum, linepath in enumerate(paths):
                lc = linepath.vertices # Line contour
                slc0 = trans.transform(lc) # Line contour in screen coords

                # For closed polygons, add extra point to avoid division by
                # zero in print_label and locate_label.  Other than these
                # functions, this is not necessary and should probably be
                # eventually removed.
                if cbook.is_closed_polygon( lc ):
                    slc = np.r_[ slc0, slc0[1:2,:] ]
                else:
                    slc = slc0

                if self.print_label(slc,lw):
                    x,y,ind  = self.locate_label(slc, lw)

                    if inline: lcarg = lc
                    else: lcarg = None
                    rotation,new=self.calc_label_rot_and_inline(
                        slc0, ind, lw, lcarg,
                        inline_spacing )

                    # Actually add the label
                    self.add_label(x,y,rotation,lev,cvalue)

                    # If inline, add new contours
                    if inline:
                        for n in new:
                            # Add path if not empty or single point
                            if len(n)>1: additions.append( path.Path(n) )

            # After looping over all segments on a contour, remove old
            # paths and add new ones if inlining
            if inline:
                del paths[:]
                paths.extend(additions)
示例#2
0
    def calc_label_rot_and_inline( self, slc, ind, lw, lc=None, spacing=5 ):
        """
        This function calculates the appropriate label rotation given
        the linecontour coordinates in screen units, the index of the
        label location and the label width.

        It will also break contour and calculate inlining if *lc* is
        not empty (lc defaults to the empty list if None).  *spacing*
        is the space around the label in pixels to leave empty.

        Do both of these tasks at once to avoid calling cbook.path_length
        multiple times, which is relatively costly.

        The method used here involves calculating the path length
        along the contour in pixel coordinates and then looking
        approximately label width / 2 away from central point to
        determine rotation and then to break contour if desired.
        """

        if lc is None: lc = []
        # Half the label width
        hlw = lw/2.0

        # Check if closed and, if so, rotate contour so label is at edge
        closed = cbook.is_closed_polygon(slc)
        if closed:
            slc = np.r_[ slc[ind:-1], slc[:ind+1] ]

            if len(lc): # Rotate lc also if not empty
                lc = np.r_[ lc[ind:-1], lc[:ind+1] ]

            ind = 0

        # Path length in pixel space
        pl = cbook.path_length(slc)
        pl = pl-pl[ind]

        # Use linear interpolation to get points around label
        xi = np.array( [ -hlw, hlw ] )
        if closed: # Look at end also for closed contours
            dp = np.array([pl[-1],0])
        else:
            dp = np.zeros_like(xi)

        ll = cbook.less_simple_linear_interpolation( pl, slc, dp+xi,
                                                     extrap=True )

        # get vector in pixel space coordinates from one point to other
        dd = np.diff( ll, axis=0 ).ravel()

        # Get angle of vector - must be calculated in pixel space for
        # text rotation to work correctly
        if np.all(dd==0): # Must deal with case of zero length label
            rotation = 0.0
        else:
            rotation = np.arctan2(dd[1], dd[0]) * 180.0 / np.pi

        # Fix angle so text is never upside-down
        if rotation > 90:
            rotation = rotation - 180.0
        if rotation < -90:
            rotation = 180.0 + rotation

        # Break contour if desired
        nlc = []
        if len(lc):
            # Expand range by spacing
            xi = dp + xi + np.array([-spacing,spacing])

            # Get indices near points of interest
            I = cbook.less_simple_linear_interpolation(
                pl, np.arange(len(pl)), xi, extrap=False )

            # If those indices aren't beyond contour edge, find x,y
            if (not np.isnan(I[0])) and int(I[0])<>I[0]:
                xy1 = cbook.less_simple_linear_interpolation(
                    pl, lc, [ xi[0] ] )

            if (not np.isnan(I[1])) and int(I[1])<>I[1]:
                xy2 = cbook.less_simple_linear_interpolation(
                    pl, lc, [ xi[1] ] )

            # Make integer
            I = [ np.floor(I[0]), np.ceil(I[1]) ]

            # Actually break contours
            if closed:
                # This will remove contour if shorter than label
                if np.all(~np.isnan(I)):
                    nlc.append( np.r_[ xy2, lc[I[1]:I[0]+1], xy1 ] )
            else:
                # These will remove pieces of contour if they have length zero
                if not np.isnan(I[0]):
                    nlc.append( np.r_[ lc[:I[0]+1], xy1 ] )
                if not np.isnan(I[1]):
                    nlc.append( np.r_[ xy2, lc[I[1]:] ] )

            # The current implementation removes contours completely
            # covered by labels.  Uncomment line below to keep
            # original contour if this is the preferred behavoir.
            #if not len(nlc): nlc = [ lc ]

        return (rotation,nlc)