Skip to content

Commit d203807

Browse files
committed
Fix #5488: Adjust nticks based on length of axis
1 parent 1fe4df7 commit d203807

2 files changed

Lines changed: 73 additions & 2 deletions

File tree

‎lib/matplotlib/axis.py‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1665,6 +1665,13 @@ def axis_date(self, tz=None):
16651665
tz = pytz.timezone(tz)
16661666
self.update_units(datetime.datetime(2009, 1, 1, 0, 0, 0, 0, tz))
16671667

1668+
def get_tick_space(self):
1669+
"""
1670+
Return the estimated number of ticks that can fit on the axis.
1671+
"""
1672+
# Must be overridden in the subclass
1673+
raise NotImplementedError()
1674+
16681675

16691676
class XAxis(Axis):
16701677
__name__ = 'xaxis'
@@ -1988,6 +1995,18 @@ def set_default_intervals(self):
19881995
self.axes.viewLim.intervalx = xmin, xmax
19891996
self.stale = True
19901997

1998+
def get_tick_space(self):
1999+
if self._tick_space is None:
2000+
ends = self.axes.transAxes.transform([[0, 0], [1, 0]])
2001+
length = ((ends[1][0] - ends[0][0]) / self.axes.figure.dpi) * 72.0
2002+
tick = self._get_tick(True)
2003+
# There is a heuristic here that the aspect ratio of tick text
2004+
# is no more than 2:1
2005+
size = tick.label1.get_size() * 3
2006+
size *= np.cos(np.deg2rad(tick.label1.get_rotation()))
2007+
self._tick_space = np.floor(length / size)
2008+
return self._tick_space
2009+
19912010

19922011
class YAxis(Axis):
19932012
__name__ = 'yaxis'
@@ -2318,3 +2337,13 @@ def set_default_intervals(self):
23182337
if not viewMutated:
23192338
self.axes.viewLim.intervaly = ymin, ymax
23202339
self.stale = True
2340+
2341+
def get_tick_space(self):
2342+
# TODO: cache this computation
2343+
ends = self.axes.transAxes.transform([[0, 0], [0, 1]])
2344+
length = ((ends[1][1] - ends[0][1]) / self.axes.figure.dpi) * 72.0
2345+
tick = self._get_tick(True)
2346+
# Having a spacing of at least 2 just looks good.
2347+
size = tick.label1.get_size() * 2.0
2348+
size *= np.cos(np.deg2rad(tick.label1.get_rotation()))
2349+
return np.floor(length / size)

‎lib/matplotlib/ticker.py‎

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1472,6 +1472,48 @@ def view_limits(self, dmin, dmax):
14721472
return dmin, dmax
14731473

14741474

1475+
class AutoSpacedLocator(MaxNLocator):
1476+
"""
1477+
Behaves like a MaxNLocator, except N is automatically determined
1478+
from the length of the axis.
1479+
"""
1480+
def __init__(self, *args, **kwargs):
1481+
"""
1482+
Keyword args:
1483+
1484+
*steps*
1485+
Sequence of nice numbers starting with 1 and ending with 10;
1486+
e.g., [1, 2, 4, 5, 10]
1487+
1488+
*integer*
1489+
If True, ticks will take only integer values.
1490+
1491+
*symmetric*
1492+
If True, autoscaling will result in a range symmetric
1493+
about zero.
1494+
1495+
*prune*
1496+
['lower' | 'upper' | 'both' | None]
1497+
Remove edge ticks -- useful for stacked or ganged plots
1498+
where the upper tick of one axes overlaps with the lower
1499+
tick of the axes above it.
1500+
If prune=='lower', the smallest tick will
1501+
be removed. If prune=='upper', the largest tick will be
1502+
removed. If prune=='both', the largest and smallest ticks
1503+
will be removed. If prune==None, no ticks will be removed.
1504+
1505+
"""
1506+
if 'nbins' in kwargs:
1507+
raise ValueError(
1508+
'AutoSpacedLocator does not take nbins as an argument')
1509+
self.set_params(**self.default_params)
1510+
self.set_params(**kwargs)
1511+
1512+
def __call__(self):
1513+
self._nbins = self.axis.get_tick_space()
1514+
return super(AutoSpacedLocator, self).__call__()
1515+
1516+
14751517
def decade_down(x, base=10):
14761518
'floor x to the nearest lower decade'
14771519
if x == 0.0:
@@ -1899,9 +1941,9 @@ def tick_values(self, vmin, vmax):
18991941
return self.raise_if_exceeds(np.array(ticklocs))
19001942

19011943

1902-
class AutoLocator(MaxNLocator):
1944+
class AutoLocator(AutoSpacedLocator):
19031945
def __init__(self):
1904-
MaxNLocator.__init__(self, nbins=9, steps=[1, 2, 5, 10])
1946+
AutoSpacedLocator.__init__(self, steps=[1, 2, 5, 10])
19051947

19061948

19071949
class AutoMinorLocator(Locator):

0 commit comments

Comments
 (0)