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)
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)