diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 03f103730db5..22402eb93f60 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -633,63 +633,13 @@ def text(self, x, y, s, fontdict=None, @docstring.dedent_interpd def annotate(self, *args, **kwargs): - """ - Create an annotation: a piece of text referring to a data - point. - - Parameters - ---------- - s : string - label - - xy : (x, y) - position of element to annotate. See *xycoords* to control what - coordinate system this value is interpretated in. - - xytext : (x, y) , optional, default: None - position of the label `s`. See *textcoords* to control what - coordinate system this value is interpreted in. - - xycoords : string, optional, default: "data" - string that indicates what type of coordinates `xy` is. Examples: - "figure points", "figure pixels", "figure fraction", "axes - points", .... See `matplotlib.text.Annotation` for more details. - - textcoords : string, optional, default: None - string that indicates what type of coordinates `text` is. Examples: - "figure points", "figure pixels", "figure fraction", "axes - points", .... See `matplotlib.text.Annotation` for more details. - - arrowprops : `matplotlib.lines.Line2D` properties, optional - Dictionary of line properties for the arrow that connects - the annotation to the point. If the dictionnary has a key - `arrowstyle`, a `~matplotlib.patches.FancyArrowPatch` - instance is created and drawn. See - `matplotlib.text.Annotation` for more details on valid - options. Default is None. - - Returns - ------- - a : `~matplotlib.text.Annotation` - - - Notes - ----- - - %(Annotation)s - - Examples - -------- - - .. plot:: mpl_examples/pylab_examples/annotation_demo2.py - """ a = mtext.Annotation(*args, **kwargs) a.set_transform(mtransforms.IdentityTransform()) if 'clip_on' in kwargs: a.set_clip_path(self.patch) self._add_text(a) return a - + annotate.__doc__ = mtext.Annotation.__init__.__doc__ #### Lines and spans @docstring.dedent_interpd diff --git a/lib/matplotlib/text.py b/lib/matplotlib/text.py index d2a8bebc49bd..add32afbfa03 100644 --- a/lib/matplotlib/text.py +++ b/lib/matplotlib/text.py @@ -1657,17 +1657,45 @@ def set_figure(self, fig): class OffsetFrom(object): + 'Callable helper class for working with `Annotation`' def __init__(self, artist, ref_coord, unit="points"): + ''' + Parameters + ---------- + artist : `Artist`, `BboxBase`, or `Transform` + The object to compute the offset from. + + ref_coord : length 2 sequence + If `artist` is an `Artist` or `BboxBase`, this values is + the location to of the offset origin in fractions of the + `artist` bounding box. + + If `artist` is a transform, the offset origin is the + transform applied to this value. + + unit : {'points, 'pixels'} + The screen units to use (pixels or points) for the offset + input. + + ''' self._artist = artist self._ref_coord = ref_coord self.set_unit(unit) def set_unit(self, unit): + ''' + The unit for input to the transform used by ``__call__`` + + Parameters + ---------- + unit : {'points', 'pixels'} + ''' if unit not in ["points", "pixels"]: raise ValueError("'unit' must be one of [ 'points' | 'pixels' ]") self._unit = unit def get_unit(self): + 'The unit for input to the transform used by ``__call__``' return self._unit def _get_scale(self, renderer): @@ -1678,6 +1706,20 @@ def _get_scale(self, renderer): return renderer.points_to_pixels(1.) def __call__(self, renderer): + ''' + Return the offset transform. + + Parameters + ---------- + renderer : `RendererBase` + The renderer to use to compute the offset + + Returns + ------- + transform : `Transform` + Maps (x, y) in pixel or point units to screen units + relative to the given artist. + ''' if isinstance(self._artist, Artist): bbox = self._artist.get_window_extent(renderer) l, b, w, h = bbox.bounds @@ -1915,16 +1957,6 @@ def draggable(self, state=None, use_blit=False): class Annotation(Text, _AnnotationBase): - """ - A :class:`~matplotlib.text.Text` class to make annotating things - in the figure, such as :class:`~matplotlib.figure.Figure`, - :class:`~matplotlib.axes.Axes`, - :class:`~matplotlib.patches.Rectangle`, etc., easier. - - Annotate the *x*, *y* point *xy* with text *s* at *x*, *y* - location *xytext*. (If *xytext* = *None*, defaults to *xy*, - and if *textcoords* = *None*, defaults to *xycoords*). - """ def __str__(self): return "Annotation(%g,%g,%s)" % (self.xy[0], self.xy[1], @@ -1938,102 +1970,154 @@ def __init__(self, s, xy, arrowprops=None, annotation_clip=None, **kwargs): - """ - *arrowprops*, if not *None*, is a dictionary of line properties - (see :class:`matplotlib.lines.Line2D`) for the arrow that connects - annotation to the point. - - If the dictionary has a key *arrowstyle*, a - `~matplotlib.patches.FancyArrowPatch` instance is created with - the given dictionary and is drawn. Otherwise, a - `~matplotlib.patches.YAArrow` patch instance is created and - drawn. Valid keys for `~matplotlib.patches.YAArrow` are: - - - ========= =========================================================== - Key Description - ========= =========================================================== - width the width of the arrow in points - frac the fraction of the arrow length occupied by the head - headwidth the width of the base of the arrow head in points - shrink oftentimes it is convenient to have the arrowtip - and base a bit away from the text and point being - annotated. If *d* is the distance between the text and - annotated point, shrink will shorten the arrow so the tip - and base are shink percent of the distance *d* away from - the endpoints. i.e., ``shrink=0.05 is 5%%`` - ? any key for :class:`matplotlib.patches.polygon` - ========= =========================================================== - - - Valid keys for `~matplotlib.patches.FancyArrowPatch` are: - - - =============== ====================================================== - Key Description - =============== ====================================================== - arrowstyle the arrow style - connectionstyle the connection style - relpos default is (0.5, 0.5) - patchA default is bounding box of the text - patchB default is None - shrinkA default is 2 points - shrinkB default is 2 points - mutation_scale default is text size (in points) - mutation_aspect default is 1. - ? any key for :class:`matplotlib.patches.PathPatch` - =============== ====================================================== - - - *xycoords* and *textcoords* are strings that indicate the - coordinates of *xy* and *xytext*, and may be one of the - following values: - - ================= =================================================== - Property Description - ================= =================================================== - 'figure points' points from the lower left corner of the figure - 'figure pixels' pixels from the lower left corner of the figure - 'figure fraction' 0,0 is lower left of figure and 1,1 is upper right - 'axes points' points from lower left corner of axes - 'axes pixels' pixels from lower left corner of axes - 'axes fraction' 0,0 is lower left of axes and 1,1 is upper right - 'data' use the coordinate system of the object being - annotated (default) - 'offset points' Specify an offset (in points) from the *xy* value - - 'polar' you can specify *theta*, *r* for the annotation, - even in cartesian plots. Note that if you - are using a polar axes, you do not need - to specify polar for the coordinate - system since that is the native "data" coordinate - system. - ================= =================================================== - - If a 'points' or 'pixels' option is specified, values will be - added to the bottom-left and if negative, values will be - subtracted from the top-right. e.g.:: - - # 10 points to the right of the left border of the axes and - # 5 points below the top border - xy=(10,-5), xycoords='axes points' - - You may use an instance of - :class:`~matplotlib.transforms.Transform` or - :class:`~matplotlib.artist.Artist`. See - :ref:`plotting-guide-annotation` for more details. - - The *annotation_clip* attribute controls the visibility of the - annotation when it goes outside the axes area. If `True`, the - annotation will only be drawn when the *xy* is inside the - axes. If `False`, the annotation will always be drawn - regardless of its position. The default is `None`, which - behave as `True` only if *xycoords* is "data". - - Additional kwargs are `~matplotlib.text.Text` properties: + ''' + Annotate the point ``xy`` with text ``s``. + + Additional kwargs are passed to `~matplotlib.text.Text`. + + Parameters + ---------- + + s : str + The text of the annotation + + xy : iterable + Length 2 sequence specifying the *(x,y)* point to annotate + + xytext : iterable, optional + Length 2 sequence specifying the *(x,y)* to place the text + at. If None, defaults to ``xy``. + + xycoords : str, Artist, Transform, callable or tuple, optional + + The coordinate system that ``xy`` is given in. + + For a `str` the allowed values are: + + ================= =============================================== + Property Description + ================= =============================================== + 'figure points' points from the lower left of the figure + 'figure pixels' pixels from the lower left of the figure + 'figure fraction' fraction of figure from lower left + 'axes points' points from lower left corner of axes + 'axes pixels' pixels from lower left corner of axes + 'axes fraction' fraction of axes from lower left + 'data' use the coordinate system of the object being + annotated (default) + 'polar' *(theta,r)* if not native 'data' coordinates + ================= =============================================== + + If a `~matplotlib.artist.Artist` object is passed in the units are + fraction if it's bounding box. + + If a `~matplotlib.transforms.Transform` object is passed + in use that to transform ``xy`` to screen coordinates + + If a callable it must take a + `~matplotlib.backend_bases.RendererBase` object as input + and return a `~matplotlib.transforms.Transform` or + `~matplotlib.transforms.Bbox` object + + If a `tuple` must be length 2 tuple of str, `Artist`, + `Transform` or callable objects. The first transform is + used for the *x* coordinate and the second for *y*. + + See :ref:`plotting-guide-annotation` for more details. + + Defaults to ``'data'`` + + textcoords : str, `Artist`, `Transform`, callable or tuple, optional + The coordinate system that ``xytext`` is given, which + may be different than the coordinate system used for + ``xy``. + + All ``xycoords`` values are valid as well as the following + strings: + + ================= ========================================= + Property Description + ================= ========================================= + 'offset points' offset (in points) from the *xy* value + 'offset pixels' offset (in pixels) from the *xy* value + ================= ========================================= + + defaults to the input of ``xycoords`` + + arrowprops : dict, optional + If not None, properties used to draw a + `~matplotlib.patches.FancyArrowPatch` arrow between ``xy`` and + ``xytext``. + + If `arrowprops` does not contain the key ``'arrowstyle'`` the + allowed keys are: + + ========== ====================================================== + Key Description + ========== ====================================================== + width the width of the arrow in points + headwidth the width of the base of the arrow head in points + headlength the length of the arrow head in points + shrink fraction of total length to 'shrink' from both ends + ? any key to :class:`matplotlib.patches.FancyArrowPatch` + ========== ====================================================== + + If the `arrowprops` contains the key ``'arrowstyle'`` the + above keys are forbidden. The allowed values of + ``'arrowstyle'`` are: + + ============ ============================================= + Name Attrs + ============ ============================================= + ``'-'`` None + ``'->'`` head_length=0.4,head_width=0.2 + ``'-['`` widthB=1.0,lengthB=0.2,angleB=None + ``'|-|'`` widthA=1.0,widthB=1.0 + ``'-|>'`` head_length=0.4,head_width=0.2 + ``'<-'`` head_length=0.4,head_width=0.2 + ``'<->'`` head_length=0.4,head_width=0.2 + ``'<|-'`` head_length=0.4,head_width=0.2 + ``'<|-|>'`` head_length=0.4,head_width=0.2 + ``'fancy'`` head_length=0.4,head_width=0.4,tail_width=0.4 + ``'simple'`` head_length=0.5,head_width=0.5,tail_width=0.2 + ``'wedge'`` tail_width=0.3,shrink_factor=0.5 + ============ ============================================= + + Valid keys for `~matplotlib.patches.FancyArrowPatch` are: + + =============== ================================================== + Key Description + =============== ================================================== + arrowstyle the arrow style + connectionstyle the connection style + relpos default is (0.5, 0.5) + patchA default is bounding box of the text + patchB default is None + shrinkA default is 2 points + shrinkB default is 2 points + mutation_scale default is text size (in points) + mutation_aspect default is 1. + ? any key for :class:`matplotlib.patches.PathPatch` + =============== ================================================== + + Defaults to None + + annotation_clip : bool, optional + Controls the visibility of the annotation when it goes + outside the axes area. + + If `True`, the annotation will only be drawn when the + ``xy`` is inside the axes. If `False`, the annotation will + always be drawn regardless of its position. + + The default is `None`, which behave as `True` only if + *xycoords* is "data". + + Returns + ------- + Annotation - %(Text)s - """ + ''' _AnnotationBase.__init__(self, xy, @@ -2155,7 +2239,7 @@ def _update_position_xytext(self, renderer, xy_pixel): frac = d.pop('frac', None) if frac is not None: warnings.warn( - "'frac' option in 'arrowstyle' is no longer supported;" + "'frac' option in 'arrowprops' is no longer supported;" " use 'headlength' to set the head length in points.") headlength = d.pop('headlength', 12)