Skip to content

Commit bab3658

Browse files
committed
Fix matplotlib#5488: Adjust nticks based on length of axis
1 parent 6dd4103 commit bab3658

2 files changed

Lines changed: 72 additions & 2 deletions

File tree

‎lib/matplotlib/axis.py‎

Lines changed: 28 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,17 @@ def set_default_intervals(self):
19881995
self.axes.viewLim.intervalx = xmin, xmax
19891996
self.stale = True
19901997

1998+
def get_tick_space(self):
1999+
# TODO: cache this computation
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 4:1
2005+
size = tick.label1.get_size() * 4
2006+
size *= np.cos(np.deg2rad(tick.label1.get_rotation()))
2007+
return np.floor(length / size)
2008+
19912009

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

‎lib/matplotlib/ticker.py‎

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1449,6 +1449,48 @@ def view_limits(self, dmin, dmax):
14491449
return np.take(self.bin_boundaries(dmin, dmax), [0, -1])
14501450

14511451

1452+
class AutoSpacedLocator(MaxNLocator):
1453+
"""
1454+
Behaves like a MaxNLocator, except N is automatically determined
1455+
from the length of the axis.
1456+
"""
1457+
def __init__(self, *args, **kwargs):
1458+
"""
1459+
Keyword args:
1460+
1461+
*steps*
1462+
Sequence of nice numbers starting with 1 and ending with 10;
1463+
e.g., [1, 2, 4, 5, 10]
1464+
1465+
*integer*
1466+
If True, ticks will take only integer values.
1467+
1468+
*symmetric*
1469+
If True, autoscaling will result in a range symmetric
1470+
about zero.
1471+
1472+
*prune*
1473+
['lower' | 'upper' | 'both' | None]
1474+
Remove edge ticks -- useful for stacked or ganged plots
1475+
where the upper tick of one axes overlaps with the lower
1476+
tick of the axes above it.
1477+
If prune=='lower', the smallest tick will
1478+
be removed. If prune=='upper', the largest tick will be
1479+
removed. If prune=='both', the largest and smallest ticks
1480+
will be removed. If prune==None, no ticks will be removed.
1481+
1482+
"""
1483+
if 'nbins' in kwargs:
1484+
raise ValueError(
1485+
'AutoSpacedLocator does not take nbins as an argument')
1486+
self.set_params(**self.default_params)
1487+
self.set_params(**kwargs)
1488+
1489+
def __call__(self):
1490+
self._nbins = self.axis.get_tick_space()
1491+
return super(AutoSpacedLocator, self).__call__()
1492+
1493+
14521494
def decade_down(x, base=10):
14531495
'floor x to the nearest lower decade'
14541496
if x == 0.0:
@@ -1872,9 +1914,9 @@ def tick_values(self, vmin, vmax):
18721914
return self.raise_if_exceeds(np.array(ticklocs))
18731915

18741916

1875-
class AutoLocator(MaxNLocator):
1917+
class AutoLocator(AutoSpacedLocator):
18761918
def __init__(self):
1877-
MaxNLocator.__init__(self, nbins=9, steps=[1, 2, 5, 10])
1919+
AutoSpacedLocator.__init__(self, steps=[1, 2, 5, 10])
18781920

18791921

18801922
class AutoMinorLocator(Locator):

0 commit comments

Comments
 (0)