@@ -59,6 +59,7 @@ def __init__(self,axes,spine_type,path,**kwargs):
5959 self .set_transform (self .axes .transData ) # default transform
6060
6161 self ._bounds = None # default bounds
62+ self ._smart_bounds = False
6263
6364 # Defer initial position determination. (Not much support for
6465 # non-rectangular axes is currently implemented, and this lets
@@ -78,6 +79,20 @@ def __init__(self,axes,spine_type,path,**kwargs):
7879 # Note: This cannot be calculated until this is added to an Axes
7980 self ._patch_transform = mtransforms .IdentityTransform ()
8081
82+ def set_smart_bounds (self ,value ):
83+ """set the spine and associated axis to have smart bounds"""
84+ self ._smart_bounds = value
85+
86+ # also set the axis if possible
87+ if self .spine_type in ('left' ,'right' ):
88+ self .axes .yaxis .set_smart_bounds (value )
89+ elif self .spine_type in ('top' ,'bottom' ):
90+ self .axes .xaxis .set_smart_bounds (value )
91+
92+ def get_smart_bounds (self ):
93+ """get whether the spine has smart bounds"""
94+ return self ._smart_bounds
95+
8196 def set_patch_circle (self ,center ,radius ):
8297 """set the spine to be circular"""
8398 self ._patch_type = 'circle'
@@ -141,6 +156,26 @@ def cla(self):
141156 if self .axis is not None :
142157 self .axis .cla ()
143158
159+ def is_frame_like (self ):
160+ """return True if directly on axes frame
161+
162+ This is useful for determining if a spine is the edge of an
163+ old style MPL plot. If so, this function will return True.
164+ """
165+ self ._ensure_position_is_set ()
166+ position = self ._position
167+ if cbook .is_string_like (position ):
168+ if position == 'center' :
169+ position = ('axes' ,0.5 )
170+ elif position == 'zero' :
171+ position = ('data' ,0 )
172+ assert len (position )== 2 , "position should be 2-tuple"
173+ position_type , amount = position
174+ if position_type == 'outward' and amount == 0 :
175+ return True
176+ else :
177+ return False
178+
144179 def _adjust_location (self ):
145180 """automatically set spine bounds to the view interval"""
146181
@@ -154,6 +189,61 @@ def _adjust_location(self):
154189 low ,high = self .axes .viewLim .intervalx
155190 else :
156191 raise ValueError ('unknown spine spine_type: %s' % self .spine_type )
192+
193+ if self ._smart_bounds :
194+ # attempt to set bounds in sophisticated way
195+ if low > high :
196+ # handle inverted limits
197+ low ,high = high ,low
198+
199+ viewlim_low = low
200+ viewlim_high = high
201+
202+ del low , high
203+
204+ if self .spine_type in ('left' ,'right' ):
205+ datalim_low ,datalim_high = self .axes .dataLim .intervaly
206+ ticks = self .axes .get_yticks ()
207+ elif self .spine_type in ('top' ,'bottom' ):
208+ datalim_low ,datalim_high = self .axes .dataLim .intervalx
209+ ticks = self .axes .get_xticks ()
210+ # handle inverted limits
211+ ticks = list (ticks )
212+ ticks .sort ()
213+ ticks = np .array (ticks )
214+ if datalim_low > datalim_high :
215+ datalim_low , datalim_high = datalim_high , datalim_low
216+
217+ if datalim_low < viewlim_low :
218+ # Data extends past view. Clip line to view.
219+ low = viewlim_low
220+ else :
221+ # Data ends before view ends.
222+ cond = (ticks <= datalim_low ) & (ticks >= viewlim_low )
223+ tickvals = ticks [cond ]
224+ if len (tickvals ):
225+ # A tick is less than or equal to lowest data point.
226+ low = tickvals [- 1 ]
227+ else :
228+ # No tick is available
229+ low = datalim_low
230+ low = max (low ,viewlim_low )
231+
232+ if datalim_high > viewlim_high :
233+ # Data extends past view. Clip line to view.
234+ high = viewlim_high
235+ else :
236+ # Data ends before view ends.
237+ cond = (ticks >= datalim_high ) & (ticks <= viewlim_high )
238+ tickvals = ticks [cond ]
239+ if len (tickvals ):
240+ # A tick is greater than or equal to highest data point.
241+ high = tickvals [0 ]
242+ else :
243+ # No tick is available
244+ high = datalim_high
245+ high = min (high ,viewlim_high )
246+
157247 else :
158248 low ,high = self ._bounds
159249
@@ -316,11 +406,16 @@ def get_spine_transform(self):
316406 raise ValueError ("unknown spine_transform type: %s" % what )
317407
318408 def set_bounds ( self , low , high ):
409+ """Set the bounds of the spine."""
319410 if self .spine_type == 'circle' :
320411 raise ValueError (
321412 'set_bounds() method incompatible with circular spines' )
322413 self ._bounds = (low , high )
323414
415+ def get_bounds ( self ):
416+ """Get the bounds of the spine."""
417+ return self ._bounds
418+
324419 @classmethod
325420 def linear_spine (cls , axes , spine_type , ** kwargs ):
326421 """
0 commit comments