Skip to content

Commit 5ecf50a

Browse files
committed
set_xlim, set_ylim: turn off autoscaling; added autoscale method
svn path=/trunk/matplotlib/; revision=8479
1 parent 721ad89 commit 5ecf50a

File tree

10 files changed

+162
-99
lines changed

10 files changed

+162
-99
lines changed

boilerplate.py

+1
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ def %(func)s(%(argspec)s):
109109
'locator_params',
110110
'tick_params',
111111
'margins',
112+
'autoscale',
112113
)
113114

114115
cmappable = {

lib/matplotlib/axes.py

+113-43
Original file line numberDiff line numberDiff line change
@@ -1715,6 +1715,45 @@ def get_rasterization_zorder(self):
17151715
"""
17161716
return self._rasterization_zorder
17171717

1718+
def autoscale(self, enable=True, axis='both', tight=None):
1719+
"""
1720+
Convenience method for simple axis view autoscaling.
1721+
It turns autoscaling on or off, and then,
1722+
if autoscaling for either axis is on, it performs
1723+
the autoscaling on the specified axis or axes.
1724+
1725+
*enable*: [True | False | None]
1726+
True (default) turns autoscaling on, False turns it off.
1727+
None leaves the autoscaling state unchanged.
1728+
1729+
*axis*: ['x' | 'y' | 'both']
1730+
which axis to operate on; default is 'both'
1731+
1732+
*tight*: [True | False | None]
1733+
If True, set view limits to data limits;
1734+
if False, let the locator and margins expand the view limits;
1735+
if None, use tight scaling if the only artist is an image,
1736+
otherwise treat *tight* as False.
1737+
The *tight* setting is retained for future autoscaling
1738+
until it is explicitly changed.
1739+
1740+
1741+
Returns None.
1742+
"""
1743+
if enable is None:
1744+
scalex = True
1745+
scaley = True
1746+
else:
1747+
scalex = False
1748+
scaley = False
1749+
if axis in ['x', 'both']:
1750+
self._autoscaleXon = bool(enable)
1751+
scalex = self._autoscaleXon
1752+
if axis in ['y', 'both']:
1753+
self._autoscaleYon = bool(enable)
1754+
scaley = self._autoscaleYon
1755+
self.autoscale_view(tight=tight, scalex=scalex, scaley=scaley)
1756+
17181757

17191758
def autoscale_view(self, tight=None, scalex=True, scaley=True):
17201759
"""
@@ -2209,7 +2248,7 @@ def set_axis_bgcolor(self, color):
22092248
def invert_xaxis(self):
22102249
"Invert the x-axis."
22112250
left, right = self.get_xlim()
2212-
self.set_xlim(right, left)
2251+
self.viewLim.intervalx = (right, left)
22132252

22142253
def xaxis_inverted(self):
22152254
'Returns True if the x-axis is inverted.'
@@ -2233,6 +2272,7 @@ def set_xbound(self, lower=None, upper=None):
22332272
"""
22342273
Set the lower and upper numerical bounds of the x-axis.
22352274
This method will honor axes inversion regardless of parameter order.
2275+
It will not change the _autoscaleXon attribute.
22362276
"""
22372277
if upper is None and iterable(lower):
22382278
lower,upper = lower
@@ -2244,46 +2284,59 @@ def set_xbound(self, lower=None, upper=None):
22442284

22452285
if self.xaxis_inverted():
22462286
if lower < upper:
2247-
self.set_xlim(upper, lower)
2287+
self.set_xlim(upper, lower, auto=None)
22482288
else:
2249-
self.set_xlim(lower, upper)
2289+
self.set_xlim(lower, upper, auto=None)
22502290
else:
22512291
if lower < upper:
2252-
self.set_xlim(lower, upper)
2292+
self.set_xlim(lower, upper, auto=None)
22532293
else:
2254-
self.set_xlim(upper, lower)
2294+
self.set_xlim(upper, lower, auto=None)
22552295

22562296
def get_xlim(self):
22572297
"""
22582298
Get the x-axis range [*xmin*, *xmax*]
22592299
"""
22602300
return tuple(self.viewLim.intervalx)
22612301

2262-
def set_xlim(self, xmin=None, xmax=None, emit=True, **kwargs):
2302+
def set_xlim(self, xmin=None, xmax=None, emit=True, auto=False):
22632303
"""
22642304
call signature::
22652305
2266-
set_xlim(self, *args, **kwargs)
2267-
2268-
Set the limits for the xaxis
2306+
set_xlim(self, *args, **kwargs):
22692307
2270-
Returns the current xlimits as a length 2 tuple: [*xmin*, *xmax*]
2308+
Set the data limits for the xaxis
22712309
22722310
Examples::
22732311
2274-
set_xlim((valmin, valmax))
2275-
set_xlim(valmin, valmax)
2276-
set_xlim(xmin=1) # xmax unchanged
2277-
set_xlim(xmax=1) # xmin unchanged
2312+
set_xlim((left, right))
2313+
set_xlim(left, right)
2314+
set_xlim(xmin=1) # right unchanged
2315+
set_xlim(xmax=1) # left unchanged
22782316
22792317
Keyword arguments:
22802318
22812319
*xmin*: scalar
2282-
the min of the ylim
2320+
the left xlim
22832321
*xmax*: scalar
2284-
the max of the ylim
2322+
the right xlim
22852323
*emit*: [ True | False ]
22862324
notify observers of lim change
2325+
*auto*: [ True | False | None ]
2326+
turn *x* autoscaling on (True), off (False; default),
2327+
or leave unchanged (None)
2328+
2329+
Note: the kwarg terminology may be confusing. The first value,
2330+
*xmin*, is the left, and the second, *xmax*, is the right.
2331+
For example, suppose *x* is years before present.
2332+
Then one might use::
2333+
2334+
set_ylim(5000, 0)
2335+
2336+
so 5000 years ago is on the left of the plot and the
2337+
present is on the right.
2338+
2339+
Returns the current xlimits as a length 2 tuple
22872340
22882341
ACCEPTS: len(2) sequence of floats
22892342
"""
@@ -2307,6 +2360,8 @@ def set_xlim(self, xmin=None, xmax=None, emit=True, **kwargs):
23072360
xmin, xmax = self.xaxis.limit_range_for_scale(xmin, xmax)
23082361

23092362
self.viewLim.intervalx = (xmin, xmax)
2363+
if auto is not None:
2364+
self._autoscaleXon = bool(auto)
23102365

23112366
if emit:
23122367
self.callbacks.process('xlim_changed', self)
@@ -2391,25 +2446,26 @@ def set_xticklabels(self, labels, fontdict=None, minor=False, **kwargs):
23912446

23922447
def invert_yaxis(self):
23932448
"Invert the y-axis."
2394-
left, right = self.get_ylim()
2395-
self.set_ylim(right, left)
2449+
bottom, top = self.get_ylim()
2450+
self.viewLim.intervaly = (top, bottom)
23962451

23972452
def yaxis_inverted(self):
23982453
'Returns True if the y-axis is inverted.'
2399-
left, right = self.get_ylim()
2400-
return right < left
2454+
bottom, top = self.get_ylim()
2455+
return top < bottom
24012456

24022457
def get_ybound(self):
24032458
"Return y-axis numerical bounds in the form of lowerBound < upperBound"
2404-
left, right = self.get_ylim()
2405-
if left < right:
2406-
return left, right
2459+
bottom, top = self.get_ylim()
2460+
if bottom < top:
2461+
return bottom, top
24072462
else:
2408-
return right, left
2463+
return top, bottom
24092464

24102465
def set_ybound(self, lower=None, upper=None):
24112466
"""Set the lower and upper numerical bounds of the y-axis.
24122467
This method will honor axes inversion regardless of parameter order.
2468+
It will not change the _autoscaleYon attribute.
24132469
"""
24142470
if upper is None and iterable(lower):
24152471
lower,upper = lower
@@ -2421,42 +2477,57 @@ def set_ybound(self, lower=None, upper=None):
24212477

24222478
if self.yaxis_inverted():
24232479
if lower < upper:
2424-
self.set_ylim(upper, lower)
2480+
self.set_ylim(upper, lower, auto=None)
24252481
else:
2426-
self.set_ylim(lower, upper)
2482+
self.set_ylim(lower, upper, auto=None)
24272483
else:
24282484
if lower < upper:
2429-
self.set_ylim(lower, upper)
2485+
self.set_ylim(lower, upper, auto=None)
24302486
else:
2431-
self.set_ylim(upper, lower)
2487+
self.set_ylim(upper, lower, auto=None)
24322488

24332489
def get_ylim(self):
24342490
"""
24352491
Get the y-axis range [*ymin*, *ymax*]
24362492
"""
24372493
return tuple(self.viewLim.intervaly)
24382494

2439-
def set_ylim(self, ymin=None, ymax=None, emit=True, **kwargs):
2495+
def set_ylim(self, ymin=None, ymax=None, emit=True, auto=False):
24402496
"""
24412497
call signature::
24422498
24432499
set_ylim(self, *args, **kwargs):
24442500
2445-
Set the limits for the yaxis; v = [ymin, ymax]::
2501+
Set the data limits for the yaxis
2502+
2503+
Examples::
24462504
2447-
set_ylim((valmin, valmax))
2448-
set_ylim(valmin, valmax)
2449-
set_ylim(ymin=1) # ymax unchanged
2450-
set_ylim(ymax=1) # ymin unchanged
2505+
set_ylim((bottom, top))
2506+
set_ylim(bottom, top)
2507+
set_ylim(ymin=1) # top unchanged
2508+
set_ylim(ymax=1) # bottom unchanged
24512509
24522510
Keyword arguments:
24532511
24542512
*ymin*: scalar
2455-
the min of the ylim
2513+
the bottom ylim
24562514
*ymax*: scalar
2457-
the max of the ylim
2515+
the top ylim
24582516
*emit*: [ True | False ]
24592517
notify observers of lim change
2518+
*auto*: [ True | False | None ]
2519+
turn *y* autoscaling on (True), off (False; default),
2520+
or leave unchanged (None)
2521+
2522+
Note: the kwarg terminology may be confusing. The first value,
2523+
*ymin*, is the bottom, and the second, *ymax*, is the top.
2524+
For example, suppose *y* is depth in the ocean.
2525+
Then one might use::
2526+
2527+
set_ylim(5000, 0)
2528+
2529+
so 5000 m depth is at the bottom of the plot and the
2530+
surface, 0 m, is at the top.
24602531
24612532
Returns the current ylimits as a length 2 tuple
24622533
@@ -2480,7 +2551,10 @@ def set_ylim(self, ymin=None, ymax=None, emit=True, **kwargs):
24802551

24812552
ymin, ymax = mtransforms.nonsingular(ymin, ymax, increasing=False)
24822553
ymin, ymax = self.yaxis.limit_range_for_scale(ymin, ymax)
2554+
24832555
self.viewLim.intervaly = (ymin, ymax)
2556+
if auto is not None:
2557+
self._autoscaleYon = bool(auto)
24842558

24852559
if emit:
24862560
self.callbacks.process('ylim_changed', self)
@@ -6647,14 +6721,10 @@ def imshow(self, X, cmap=None, norm=None, aspect=None,
66476721
im.autoscale_None()
66486722
im.set_url(url)
66496723

6650-
xmin, xmax, ymin, ymax = im.get_extent()
6724+
# update ax.dataLim, and, if autoscaling, set viewLim
6725+
# to tightly fit the image, regardless of dataLim.
6726+
im.set_extent(im.get_extent())
66516727

6652-
corners = (xmin, ymin), (xmax, ymax)
6653-
self.update_datalim(corners)
6654-
if self._autoscaleXon:
6655-
self.set_xlim((xmin, xmax))
6656-
if self._autoscaleYon:
6657-
self.set_ylim((ymin, ymax))
66586728
self.images.append(im)
66596729
im._remove_method = lambda h: self.images.remove(h)
66606730

lib/matplotlib/blocking_input.py

+5-28
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
from matplotlib import path, verbose
2121
from matplotlib.cbook import is_sequence_of_strings
22+
import matplotlib.lines as mlines
2223

2324
class BlockingInput(object):
2425
"""
@@ -222,18 +223,10 @@ def add_click(self,event):
222223

223224
# If desired plot up click
224225
if self.show_clicks:
225-
226-
# make sure we don't mess with the axes zoom
227-
xlim = event.inaxes.get_xlim()
228-
ylim = event.inaxes.get_ylim()
229-
230-
# plot the clicks
231-
self.marks.extend(
232-
event.inaxes.plot([event.xdata,], [event.ydata,], 'r+') )
233-
234-
# before we draw, make sure to reset the limits
235-
event.inaxes.set_xlim(xlim)
236-
event.inaxes.set_ylim(ylim)
226+
line = mlines.Line2D([event.xdata], [event.ydata],
227+
marker='+', color='r')
228+
event.inaxes.add_line(line)
229+
self.marks.append(line)
237230
self.fig.canvas.draw()
238231

239232

@@ -247,16 +240,9 @@ def pop_click(self,event,index=-1):
247240

248241
if self.show_clicks:
249242

250-
# make sure we don't mess with the axes zoom
251-
xlim = event.inaxes.get_xlim()
252-
ylim = event.inaxes.get_ylim()
253-
254243
mark = self.marks.pop(index)
255244
mark.remove()
256245

257-
# before we draw, make sure to reset the limits
258-
event.inaxes.set_xlim(xlim)
259-
event.inaxes.set_ylim(ylim)
260246
self.fig.canvas.draw()
261247
# NOTE: I do NOT understand why the above 3 lines does not work
262248
# for the keyboard backspace event on windows XP wxAgg.
@@ -275,20 +261,11 @@ def pop(self,event,index=-1):
275261
def cleanup(self,event=None):
276262
# clean the figure
277263
if self.show_clicks:
278-
if event:
279-
# make sure we don't mess with the axes zoom
280-
xlim = event.inaxes.get_xlim()
281-
ylim = event.inaxes.get_ylim()
282264

283265
for mark in self.marks:
284266
mark.remove()
285267
self.marks = []
286268

287-
if event:
288-
# before we draw, make sure to reset the limits
289-
event.inaxes.set_xlim(xlim)
290-
event.inaxes.set_ylim(ylim)
291-
292269
self.fig.canvas.draw()
293270

294271
# Call base class to remove callbacks

lib/matplotlib/image.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -605,16 +605,22 @@ def _check_unsampled_image(self, renderer):
605605
def set_extent(self, extent):
606606
"""
607607
extent is data axes (left, right, bottom, top) for making image plots
608+
609+
This updates ax.dataLim, and, if autoscaling, sets viewLim
610+
to tightly fit the image, regardless of dataLim. Autoscaling
611+
state is not changed, so following this with ax.autoscale_view
612+
will redo the autoscaling in accord with dataLim.
613+
608614
"""
609615
self._extent = extent
610616

611617
xmin, xmax, ymin, ymax = extent
612618
corners = (xmin, ymin), (xmax, ymax)
613619
self.axes.update_datalim(corners)
614620
if self.axes._autoscaleXon:
615-
self.axes.set_xlim((xmin, xmax))
621+
self.axes.set_xlim((xmin, xmax), auto=None)
616622
if self.axes._autoscaleYon:
617-
self.axes.set_ylim((ymin, ymax))
623+
self.axes.set_ylim((ymin, ymax), auto=None)
618624

619625
def get_extent(self):
620626
'get the image extent: left, right, bottom, top'

0 commit comments

Comments
 (0)