17
17
from axis import XAxis , YAxis
18
18
from cbook import iterable , is_string_like , flatten , enumerate , \
19
19
allequal , dict_delall , popd , popall , silent_list , is_numlike , dedent
20
+
20
21
from collections import RegularPolyCollection , PolyCollection , LineCollection , \
21
22
QuadMesh , StarPolygonCollection , BrokenBarHCollection
22
23
from colors import colorConverter , Normalize , Colormap , \
53
54
54
55
import matplotlib
55
56
57
+ from matplotlib import cbook
58
+
56
59
if matplotlib ._havedate :
57
60
from dates import AutoDateFormatter , AutoDateLocator , DateLocator , DateFormatter
58
61
@@ -457,6 +460,13 @@ class Axes(Artist):
457
460
"""
458
461
The Axes contains most of the figure elements: Axis, Tick, Line2D,
459
462
Text, Polygon etc, and sets the coordinate system
463
+
464
+ The Axes instance supports callbacks through a callbacks attribute
465
+ which is a cbook.CallbackRegistry instance. The events you can
466
+ connect to are 'xlim_changed' and 'ylim_changed' and the callback
467
+ will be called with func(ax) where ax is the Axes instance
468
+
469
+
460
470
"""
461
471
462
472
scaled = {IDENTITY : 'linear' ,
@@ -567,6 +577,69 @@ def _init_axis(self):
567
577
self .yaxis = YAxis (self )
568
578
569
579
580
+ def sharex_foreign (self , axforeign ):
581
+ """
582
+ You can share your x-axis view limits with another Axes in the
583
+ same Figure by using the sharex and sharey property of the
584
+ Axes. But this doesn't work for Axes in a different figure.
585
+ This function sets of the callbacks so that when the xaxis of
586
+ this Axes or the Axes in a foreign figure are changed, both
587
+ will be synchronized.
588
+
589
+ The connection ids for the self.callbacks and
590
+ axforeign.callbacks cbook.CallbackRegistry instances are
591
+ returned in case you want to disconnect the coupling
592
+ """
593
+
594
+ def follow_foreign_xlim (ax ):
595
+ xmin , xmax = axforeign .get_xlim ()
596
+ # do not emit here or we'll get a ping png effect
597
+ self .set_xlim (xmin , xmax , emit = False )
598
+ self .figure .canvas .draw_idle ()
599
+
600
+ def follow_self_xlim (ax ):
601
+ xmin , xmax = self .get_xlim ()
602
+ # do not emit here or we'll get a ping png effect
603
+ axforeign .set_xlim (xmin , xmax , emit = False )
604
+ axforeign .figure .canvas .draw_idle ()
605
+
606
+
607
+ cidForeign = axforeign .callbacks .connect ('xlim_changed' , follow_foreign_xlim )
608
+ cidSelf = self .callbacks .connect ('xlim_changed' , follow_self_xlim )
609
+ return cidSelf , cidForeign
610
+
611
+
612
+ def sharey_foreign (self , axforeign ):
613
+ """
614
+ You can share your y-axis view limits with another Axes in the
615
+ same Figure by using the sharey and sharey property of the
616
+ Axes. But this doesn't work for Axes in a different figure.
617
+ This function sets of the callbacks so that when the yaxis of
618
+ this Axes or the Axes in a foreign figure are changed, both
619
+ will be synchronized.
620
+
621
+ The connection ids for the self.callbacks and
622
+ axforeign.callbacks cbook.CallbackRegistry instances are
623
+ returned in case you want to disconnect the coupling
624
+ """
625
+
626
+ def follow_foreign_ylim (ax ):
627
+ ymin , ymax = axforeign .get_ylim ()
628
+ # do not emit here or we'll get a ping png effect
629
+ self .set_ylim (ymin , ymax , emit = False )
630
+ self .figure .canvas .draw_idle ()
631
+
632
+ def follow_self_ylim (ax ):
633
+ ymin , ymax = self .get_ylim ()
634
+ # do not emit here or we'll get a ping png effect
635
+ axforeign .set_ylim (ymin , ymax , emit = False )
636
+ axforeign .figure .canvas .draw_idle ()
637
+
638
+
639
+ cidForeign = axforeign .callbacks .connect ('ylim_changed' , follow_foreign_ylim )
640
+ cidSelf = self .callbacks .connect ('ylim_changed' , follow_self_ylim )
641
+ return cidSelf , cidForeign
642
+
570
643
def set_figure (self , fig ):
571
644
"""
572
645
Set the Axes figure
@@ -678,6 +751,8 @@ def cla(self):
678
751
self .yaxis .cla ()
679
752
680
753
self .dataLim .ignore (1 )
754
+ self .callbacks = cbook .CallbackRegistry (('xlim_changed' , 'ylim_changed' ))
755
+
681
756
if self ._sharex is not None :
682
757
self .xaxis .major = self ._sharex .xaxis .major
683
758
self .xaxis .minor = self ._sharex .xaxis .minor
@@ -1456,7 +1531,7 @@ def get_xlim(self):
1456
1531
return self .viewLim .intervalx ().get_bounds ()
1457
1532
1458
1533
1459
- def set_xlim (self , xmin = None , xmax = None , emit = False , ** kwargs ):
1534
+ def set_xlim (self , xmin = None , xmax = None , emit = True , ** kwargs ):
1460
1535
"""
1461
1536
set_xlim(self, *args, **kwargs):
1462
1537
@@ -1501,7 +1576,7 @@ def set_xlim(self, xmin=None, xmax=None, emit=False, **kwargs):
1501
1576
1502
1577
xmin , xmax = nonsingular (xmin , xmax , increasing = False )
1503
1578
self .viewLim .intervalx ().set_bounds (xmin , xmax )
1504
- if emit : self ._send_xlim_event ( )
1579
+ if emit : self .callbacks . process ( 'xlim_changed' , self )
1505
1580
1506
1581
return xmin , xmax
1507
1582
@@ -1580,7 +1655,7 @@ def get_ylim(self):
1580
1655
'Get the y axis range [ymin, ymax]'
1581
1656
return self .viewLim .intervaly ().get_bounds ()
1582
1657
1583
- def set_ylim (self , ymin = None , ymax = None , emit = False , ** kwargs ):
1658
+ def set_ylim (self , ymin = None , ymax = None , emit = True , ** kwargs ):
1584
1659
"""
1585
1660
set_ylim(self, *args, **kwargs):
1586
1661
@@ -1621,7 +1696,8 @@ def set_ylim(self, ymin=None, ymax=None, emit=False, **kwargs):
1621
1696
1622
1697
ymin , ymax = nonsingular (ymin , ymax , increasing = False )
1623
1698
self .viewLim .intervaly ().set_bounds (ymin , ymax )
1624
- if emit : self ._send_ylim_event ()
1699
+ if emit : self .callbacks .process ('ylim_changed' , self )
1700
+
1625
1701
return ymin , ymax
1626
1702
1627
1703
def get_yscale (self ):
@@ -1819,13 +1895,6 @@ def set_cursor_props(self, *args):
1819
1895
c = colorConverter .to_rgba (c )
1820
1896
self ._cursorProps = lw , c
1821
1897
1822
- def _send_xlim_event (self ):
1823
- for cid , func in self ._connected .get ('xlim_changed' , []):
1824
- func (self )
1825
-
1826
- def _send_ylim_event (self ):
1827
- for cid , func in self ._connected .get ('ylim_changed' , []):
1828
- func (self )
1829
1898
1830
1899
def panx (self , numsteps ):
1831
1900
'Pan the x axis numsteps (plus pan right, minus pan left)'
@@ -1849,9 +1918,8 @@ def zoomy(self, numsteps):
1849
1918
self .yaxis .zoom (numsteps )
1850
1919
self ._send_ylim_event ()
1851
1920
1852
- _cid = 0
1853
- _events = ('xlim_changed' , 'ylim_changed' )
1854
1921
1922
+
1855
1923
def connect (self , s , func ):
1856
1924
"""
1857
1925
Register observers to be notified when certain events occur. Register
@@ -1868,23 +1936,11 @@ def connect(self, s, func):
1868
1936
disconnect to disconnect from the axes event
1869
1937
1870
1938
"""
1871
-
1872
- if s not in Axes ._events :
1873
- raise ValueError ('You can only connect to the following axes events: %s' % ', ' .join (Axes ._events ))
1874
-
1875
- cid = Axes ._cid
1876
- self ._connected .setdefault (s , []).append ((cid , func ))
1877
- Axes ._cid += 1
1878
- return cid
1939
+ raise DeprecationWarning ('use the callbacks CallbackRegistry instance instead' )
1879
1940
1880
1941
def disconnect (self , cid ):
1881
1942
'disconnect from the Axes event.'
1882
- for key , val in self ._connected .items ():
1883
- for item in val :
1884
- if item [0 ] == cid :
1885
- self ._connected [key ].remove (item )
1886
- return
1887
-
1943
+ raise DeprecationWarning ('use the callbacks CallbackRegistry instance instead' )
1888
1944
def get_children (self ):
1889
1945
'return a list of child artists'
1890
1946
children = []
0 commit comments