@@ -78,9 +78,37 @@ def _plot_args_replacer(args, data):
7878 "multiple plotting calls instead." )
7979
8080
81+ def _make_inset_locator (bounds , trans , parent ):
82+ """
83+ Helper function to locate inset axes, used in
84+ `.Axes.inset_axes`.
85+
86+ A locator gets used in `Axes.set_aspect` to override the default
87+ locations... It is a function that takes an axes object and
88+ a renderer and tells `set_aspect` where it is to be placed.
89+
90+ Here *rect* is a rectangle [l, b, w, h] that specifies the
91+ location for the axes in the transform given by *trans* on the
92+ *parent*.
93+ """
94+ _bounds = mtransforms .Bbox .from_bounds (* bounds )
95+ _trans = trans
96+ _parent = parent
97+
98+ def inset_locator (ax , renderer ):
99+ bbox = _bounds
100+ bb = mtransforms .TransformedBbox (bbox , _trans )
101+ tr = _parent .figure .transFigure .inverted ()
102+ bb = mtransforms .TransformedBbox (bb , tr )
103+ return bb
104+
105+ return inset_locator
106+
107+
81108# The axes module contains all the wrappers to plotting functions.
82109# All the other methods should go in the _AxesBase class.
83110
111+
84112class Axes (_AxesBase ):
85113 """
86114 The :class:`Axes` contains most of the figure elements:
@@ -384,6 +412,227 @@ def legend(self, *args, **kwargs):
384412 def _remove_legend (self , legend ):
385413 self .legend_ = None
386414
415+ def inset_axes (self , bounds , * , transform = None , zorder = 5 ,
416+ ** kwargs ):
417+ """
418+ Add a child inset axes to this existing axes.
419+
420+ Warnings
421+ --------
422+
423+ This method is experimental as of 3.0, and the API may change.
424+
425+ Parameters
426+ ----------
427+
428+ bounds : [x0, y0, width, height]
429+ Lower-left corner of inset axes, and its width and height.
430+
431+ transform : `.Transform`
432+ Defaults to `ax.transAxes`, i.e. the units of *rect* are in
433+ axes-relative coordinates.
434+
435+ zorder : number
436+ Defaults to 5 (same as `.Axes.legend`). Adjust higher or lower
437+ to change whether it is above or below data plotted on the
438+ parent axes.
439+
440+ **kwargs
441+
442+ Other *kwargs* are passed on to the `axes.Axes` child axes.
443+
444+ Returns
445+ -------
446+
447+ Axes
448+ The created `.axes.Axes` instance.
449+
450+ Examples
451+ --------
452+
453+ This example makes two inset axes, the first is in axes-relative
454+ coordinates, and the second in data-coordinates::
455+
456+ fig, ax = plt.suplots()
457+ ax.plot(range(10))
458+ axin1 = ax.inset_axes([0.8, 0.1, 0.15, 0.15])
459+ axin2 = ax.inset_axes(
460+ [5, 7, 2.3, 2.3], transform=ax.transData)
461+
462+ """
463+ if transform is None :
464+ transform = self .transAxes
465+ label = kwargs .pop ('label' , 'inset_axes' )
466+
467+ # This puts the rectangle into figure-relative coordinates.
468+ inset_locator = _make_inset_locator (bounds , transform , self )
469+ bb = inset_locator (None , None )
470+
471+ inset_ax = Axes (self .figure , bb .bounds , zorder = zorder ,
472+ label = label , ** kwargs )
473+
474+ # this locator lets the axes move if in data coordinates.
475+ # it gets called in `ax.apply_aspect() (of all places)
476+ inset_ax .set_axes_locator (inset_locator )
477+
478+ self .add_child_axes (inset_ax )
479+
480+ return inset_ax
481+
482+ def indicate_inset (self , bounds , inset_ax = None , * , transform = None ,
483+ facecolor = 'none' , edgecolor = '0.5' , alpha = 0.5 ,
484+ zorder = 4.99 , ** kwargs ):
485+ """
486+ Add an inset indicator to the axes. This is a rectangle on the plot
487+ at the position indicated by *bounds* that optionally has lines that
488+ connect the rectangle to an inset axes
489+ (`.Axes.inset_axes`).
490+
491+ Warnings
492+ --------
493+
494+ This method is experimental as of 3.0, and the API may change.
495+
496+
497+ Parameters
498+ ----------
499+
500+ bounds : [x0, y0, width, height]
501+ Lower-left corner of rectangle to be marked, and its width
502+ and height.
503+
504+ inset_ax : `.Axes`
505+ An optional inset axes to draw connecting lines to. Two lines are
506+ drawn connecting the indicator box to the inset axes on corners
507+ chosen so as to not overlap with the indicator box.
508+
509+ transform : `.Transform`
510+ Transform for the rectangle co-ordinates. Defaults to
511+ `ax.transAxes`, i.e. the units of *rect* are in axes-relative
512+ coordinates.
513+
514+ facecolor : Matplotlib color
515+ Facecolor of the rectangle (default 'none').
516+
517+ edgecolor : Matplotlib color
518+ Color of the rectangle and color of the connecting lines. Default
519+ is '0.5'.
520+
521+ alpha : number
522+ Transparency of the rectangle and connector lines. Default is 0.5.
523+
524+ zorder : number
525+ Drawing order of the rectangle and connector lines. Default is 4.99
526+ (just below the default level of inset axes).
527+
528+ **kwargs
529+ Other *kwargs* are passed on to the rectangle patch.
530+
531+ Returns
532+ -------
533+
534+ rectangle_patch: `.Patches.Rectangle`
535+ Rectangle artist.
536+
537+ connector_lines: 4-tuple of `.Patches.ConnectionPatch`
538+ One for each of four connector lines. Two are set with visibility
539+ to *False*, but the user can set the visibility to True if the
540+ automatic choice is not deemed correct.
541+
542+ """
543+
544+ # to make the axes connectors work, we need to apply the aspect to
545+ # the parent axes.
546+ self .apply_aspect ()
547+
548+ if transform is None :
549+ transform = self .transData
550+ label = kwargs .pop ('label' , 'indicate_inset' )
551+
552+ xy = (bounds [0 ], bounds [1 ])
553+ rectpatch = mpatches .Rectangle (xy , bounds [2 ], bounds [3 ],
554+ facecolor = facecolor , edgecolor = edgecolor , alpha = alpha ,
555+ zorder = zorder , label = label , transform = transform , ** kwargs )
556+ self .add_patch (rectpatch )
557+
558+ if inset_ax is not None :
559+ # want to connect the indicator to the rect....
560+
561+ pos = inset_ax .get_position () # this is in fig-fraction.
562+ coordsA = 'axes fraction'
563+ connects = []
564+ xr = [bounds [0 ], bounds [0 ]+ bounds [2 ]]
565+ yr = [bounds [1 ], bounds [1 ]+ bounds [3 ]]
566+ for xc in range (2 ):
567+ for yc in range (2 ):
568+ xyA = (xc , yc )
569+ xyB = (xr [xc ], yr [yc ])
570+ connects += [mpatches .ConnectionPatch (xyA , xyB ,
571+ 'axes fraction' , 'data' ,
572+ axesA = inset_ax , axesB = self , arrowstyle = "-" ,
573+ zorder = zorder , edgecolor = edgecolor , alpha = alpha )]
574+ self .add_patch (connects [- 1 ])
575+ # decide which two of the lines to keep visible....
576+ pos = inset_ax .get_position ()
577+ bboxins = pos .transformed (self .figure .transFigure )
578+ rectbbox = mtransforms .Bbox .from_bounds (
579+ * bounds ).transformed (transform )
580+ if rectbbox .x0 < bboxins .x0 :
581+ sig = 1
582+ else :
583+ sig = - 1
584+ if sig * rectbbox .y0 < sig * bboxins .y0 :
585+ connects [0 ].set_visible (False )
586+ connects [3 ].set_visible (False )
587+ else :
588+ connects [1 ].set_visible (False )
589+ connects [2 ].set_visible (False )
590+
591+ return rectpatch , connects
592+
593+ def indicate_inset_zoom (self , inset_ax , ** kwargs ):
594+ """
595+ Add an inset indicator rectangle to the axes based on the axis
596+ limits for an *inset_ax* and draw connectors between *inset_ax*
597+ and the rectangle.
598+
599+ Warnings
600+ --------
601+
602+ This method is experimental as of 3.0, and the API may change.
603+
604+ Parameters
605+ ----------
606+
607+ inset_ax : `.Axes`
608+ Inset axes to draw connecting lines to. Two lines are
609+ drawn connecting the indicator box to the inset axes on corners
610+ chosen so as to not overlap with the indicator box.
611+
612+ **kwargs
613+ Other *kwargs* are passed on to `.Axes.inset_rectangle`
614+
615+ Returns
616+ -------
617+
618+ rectangle_patch: `.Patches.Rectangle`
619+ Rectangle artist.
620+
621+ connector_lines: 4-tuple of `.Patches.ConnectionPatch`
622+ One for each of four connector lines. Two are set with visibility
623+ to *False*, but the user can set the visibility to True if the
624+ automatic choice is not deemed correct.
625+
626+ """
627+
628+ xlim = inset_ax .get_xlim ()
629+ ylim = inset_ax .get_ylim ()
630+ rect = [xlim [0 ], ylim [0 ], xlim [1 ] - xlim [0 ], ylim [1 ] - ylim [0 ]]
631+ rectpatch , connects = self .indicate_inset (
632+ rect , inset_ax , ** kwargs )
633+
634+ return rectpatch , connects
635+
387636 def text (self , x , y , s , fontdict = None , withdash = False , ** kwargs ):
388637 """
389638 Add text to the axes.
0 commit comments