@@ -78,9 +78,37 @@ def _plot_args_replacer(args, data):
78
78
"multiple plotting calls instead." )
79
79
80
80
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
+
81
108
# The axes module contains all the wrappers to plotting functions.
82
109
# All the other methods should go in the _AxesBase class.
83
110
111
+
84
112
class Axes (_AxesBase ):
85
113
"""
86
114
The :class:`Axes` contains most of the figure elements:
@@ -384,6 +412,227 @@ def legend(self, *args, **kwargs):
384
412
def _remove_legend (self , legend ):
385
413
self .legend_ = None
386
414
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
+
387
636
def text (self , x , y , s , fontdict = None , withdash = False , ** kwargs ):
388
637
"""
389
638
Add text to the axes.
0 commit comments