@@ -84,9 +84,37 @@ def _plot_args_replacer(args, data):
84
84
"multiple plotting calls instead." )
85
85
86
86
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
+
87
114
# The axes module contains all the wrappers to plotting functions.
88
115
# All the other methods should go in the _AxesBase class.
89
116
117
+
90
118
class Axes (_AxesBase ):
91
119
"""
92
120
The :class:`Axes` contains most of the figure elements:
@@ -390,6 +418,227 @@ def legend(self, *args, **kwargs):
390
418
def _remove_legend (self , legend ):
391
419
self .legend_ = None
392
420
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
+
393
642
def text (self , x , y , s , fontdict = None , withdash = False , ** kwargs ):
394
643
"""
395
644
Add text to the axes.
0 commit comments