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