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