1717import matplotlib .text as text
1818import matplotlib .cbook as cbook
1919
20- # Import needed for adding manual selection capability to clabel
21- from matplotlib .blocking_input import BlockingContourLabeler
22-
2320# We can't use a single line collection for contour because a line
2421# collection can have only a single line style, and we want to be able to have
2522# dashed negative contours, for example, and solid positive contours.
@@ -71,26 +68,15 @@ def clabel(self, *args, **kwargs):
7168
7269 *fmt*:
7370 a format string for the label. Default is '%1.3f'
74- Alternatively, this can be a dictionary matching contour
75- levels with arbitrary strings to use for each contour level
76- (i.e., fmt[level]=string)
77-
78- *manual*:
79- if *True*, contour labels will be placed manually using
80- mouse clicks. Click the first button near a contour to
81- add a label, click the second button (or potentially both
82- mouse buttons at once) to finish adding labels. The third
83- button can be used to remove the last label added, but
84- only if labels are not inline.
71+
8572
8673 """
8774 fontsize = kwargs .get ('fontsize' , None )
8875 inline = kwargs .get ('inline' , 1 )
8976 self .fmt = kwargs .get ('fmt' , '%1.3f' )
9077 _colors = kwargs .get ('colors' , None )
9178
92- # Detect if manual selection is desired and remove from argument list
93- self .manual_select = kwargs .get ('manual' ,False )
79+
9480
9581 if len (args ) == 0 :
9682 levels = self .levels
@@ -140,16 +126,10 @@ def clabel(self, *args, **kwargs):
140126 #self.cl_cvalues = [] # same
141127 self .cl_xy = []
142128
143- if self .manual_select :
144- print 'Select label locations manually using first mouse button.'
145- print 'End manual selection with second mouse button.'
146- if not inline :
147- print 'Remove last label by clicking third mouse button.'
129+ self .labels (inline )
148130
149- blocking_contour_labeler = BlockingContourLabeler (self )
150- blocking_contour_labeler (inline )
151- else :
152- self .labels (inline )
131+ for label in self .cl :
132+ self .ax .add_artist (label )
153133
154134 self .label_list = cbook .silent_list ('text.Text' , self .cl )
155135 return self .label_list
@@ -161,10 +141,10 @@ def print_label(self, linecontour,labelwidth):
161141 if lcsize > 10 * labelwidth :
162142 return 1
163143
164- xmax = np .amax (linecontour [:,0 ])
165- xmin = np .amin (linecontour [:,0 ])
166- ymax = np .amax (linecontour [:,1 ])
167- ymin = np .amin (linecontour [:,1 ])
144+ xmax = np .amax (np . array ( linecontour ) [:,0 ])
145+ xmin = np .amin (np . array ( linecontour ) [:,0 ])
146+ ymax = np .amax (np . array ( linecontour ) [:,1 ])
147+ ymin = np .amin (np . array ( linecontour ) [:,1 ])
168148
169149 lw = labelwidth
170150 if (xmax - xmin ) > 1.2 * lw or (ymax - ymin ) > 1.2 * lw :
@@ -213,7 +193,7 @@ def get_label_width(self, lev, fmt, fsize):
213193 if cbook .is_string_like (lev ):
214194 lw = (len (lev )) * fsize
215195 else :
216- lw = (len (self . get_text ( lev , fmt ) )) * fsize
196+ lw = (len (fmt % lev )) * fsize
217197
218198 return lw
219199
@@ -230,10 +210,8 @@ def get_text(self, lev, fmt):
230210 if cbook .is_string_like (lev ):
231211 return lev
232212 else :
233- if isinstance (fmt ,dict ):
234- return fmt [lev ]
235- else :
236- return fmt % lev
213+ return fmt % lev
214+
237215
238216 def break_linecontour (self , linecontour , rot , labelwidth , ind ):
239217 "break a contour in two contours at the location of the label"
@@ -248,8 +226,8 @@ def break_linecontour(self, linecontour, rot, labelwidth, ind):
248226
249227 slc = trans .transform (linecontour )
250228 x ,y = slc [ind ]
251- xx = slc [:,0 ].copy ()
252- yy = slc [:,1 ].copy ()
229+ xx = np . asarray ( slc ) [:,0 ].copy ()
230+ yy = np . asarray ( slc ) [:,1 ].copy ()
253231
254232 #indices which are under the label
255233 inds , = np .nonzero (((xx < x + xlabel ) & (xx > x - xlabel )) &
@@ -330,8 +308,8 @@ def locate_label(self, linecontour, labelwidth):
330308 else :
331309 ysize = labelwidth
332310
333- XX = np .resize (linecontour [:,0 ],(xsize , ysize ))
334- YY = np .resize (linecontour [:,1 ],(xsize , ysize ))
311+ XX = np .resize (np . asarray ( linecontour ) [:,0 ],(xsize , ysize ))
312+ YY = np .resize (np . asarray ( linecontour ) [:,1 ],(xsize , ysize ))
335313 #I might have fouled up the following:
336314 yfirst = YY [:,0 ].reshape (xsize , 1 )
337315 ylast = YY [:,- 1 ].reshape (xsize , 1 )
@@ -357,85 +335,19 @@ def locate_label(self, linecontour, labelwidth):
357335
358336 return x ,y , rotation , dind
359337
360- def add_label (self ,x ,y ,rotation ,icon ):
361- dx ,dy = self .ax .transData .inverted ().transform_point ((x ,y ))
362- t = text .Text (dx , dy , rotation = rotation ,
363- horizontalalignment = 'center' ,
364- verticalalignment = 'center' )
365-
366- color = self .label_mappable .to_rgba (self .label_cvalues [icon ],
367- alpha = self .alpha )
368-
369- _text = self .get_text (self .label_levels [icon ],self .fmt )
370- self .set_label_props (t , _text , color )
371- self .cl .append (t )
372- self .cl_cvalues .append (self .label_cvalues [icon ])
373-
374- # Add label to plot here - useful for manual mode label selection
375- self .ax .add_artist (t )
376-
377- def pop_label (self ,index = - 1 ):
378- '''Defaults to removing last label, but any index can be supplied'''
379- self .cl_cvalues .pop (index )
380- t = self .cl .pop (index )
381- t .remove ()
382-
383- def find_nearest_contour ( self , x , y , pixel = True ):
384- """
385- Finds contour that is closest to a point. Defaults to
386- measuring distance in pixels (screen space - useful for manual
387- contour labeling), but this can be controlled via a keyword
388- argument.
389-
390- Returns a tuple containing the contour, segment, index of
391- segment, x & y of segment point and distance to minimum point.
392- """
393-
394- # This function uses a method that is probably quite
395- # inefficient based on converting each contour segment to
396- # pixel coordinates and then comparing the given point to
397- # those coordinates for each contour. This will probably be
398- # quite slow for complex contours, but for normal use it works
399- # sufficiently well that the time is not noticeable.
400- # Nonetheless, improvements could probably be made.
401-
402- dmin = 1e10
403- conmin = None
404- segmin = None
405- xmin = None
406- ymin = None
407-
408- for icon in self .label_indices :
409- con = self .collections [icon ]
410- paths = con .get_paths ()
411- for segNum , linepath in enumerate (paths ):
412- lc = linepath .vertices
413-
414- # transfer all data points to screen coordinates if desired
415- if pixel :
416- lc = self .ax .transData .transform (lc )
417-
418- ds = (lc [:,0 ]- x )** 2 + (lc [:,1 ]- y )** 2
419- d = min ( ds )
420- if d < dmin :
421- dmin = d
422- conmin = icon
423- segmin = segNum
424- imin = mpl .mlab .find ( ds == d )[0 ]
425- xmin = lc [imin ,0 ]
426- ymin = lc [imin ,1 ]
427-
428- return (conmin ,segmin ,imin ,xmin ,ymin ,dmin )
429-
430338 def labels (self , inline ):
431339 levels = self .label_levels
432340 fslist = self .fslist
433341 trans = self .ax .transData
434-
435- for icon , lev , fsize in zip (self .label_indices ,
436- self .label_levels , fslist ):
342+ _colors = self .label_mappable .to_rgba (self .label_cvalues ,
343+ alpha = self .alpha )
344+ fmt = self .fmt
345+ for icon , lev , color , cvalue , fsize in zip (self .label_indices ,
346+ self .label_levels ,
347+ _colors ,
348+ self .label_cvalues , fslist ):
437349 con = self .collections [icon ]
438- lw = self .get_label_width (lev , self . fmt , fsize )
350+ lw = self .get_label_width (lev , fmt , fsize )
439351 additions = []
440352 paths = con .get_paths ()
441353 for segNum , linepath in enumerate (paths ):
@@ -450,8 +362,16 @@ def labels(self, inline):
450362 slc = trans .transform (linecontour )
451363 if self .print_label (slc ,lw ):
452364 x ,y , rotation , ind = self .locate_label (slc , lw )
453- self .add_label (x ,y ,rotation ,icon )
454-
365+ # transfer the location of the label back to
366+ # data coordinates
367+ dx ,dy = trans .inverted ().transform_point ((x ,y ))
368+ t = text .Text (dx , dy , rotation = rotation ,
369+ horizontalalignment = 'center' ,
370+ verticalalignment = 'center' )
371+ _text = self .get_text (lev ,fmt )
372+ self .set_label_props (t , _text , color )
373+ self .cl .append (t )
374+ self .cl_cvalues .append (cvalue )
455375 if inline :
456376 new = self .break_linecontour (linecontour , rotation , lw , ind )
457377 if len (new [0 ]):
@@ -882,7 +802,18 @@ def set_alpha(self, alpha):
882802 Use keyword args to control colors, linewidth, origin, cmap ... see
883803 below for more details.
884804
885- *X*, *Y*, and *Z* must be arrays with the same dimensions.
805+ *X*, *Y*, and *Z* may be arrays all with the same 2-D shape, or
806+ *X* and *Y* can be 1-D while *Z* is 2-D. In the latter
807+ case, the following must be true:
808+
809+ ::
810+
811+ Z.shape == len(Y), len(X)
812+
813+ Note that the first index of *Z*, the row number, corresponds
814+ to the vertical coordinate on the page, while the second
815+ index, the column number, corresponds to the horizontal
816+ coordinate on the page.
886817
887818 *Z* may be a masked array, but filled contouring may not
888819 handle internal masked regions correctly.
0 commit comments