Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 64c84b4

Browse files
authored
Merge pull request #12909 from anntzer/format_ticks
Let Formatters format all ticks at once.
2 parents 6f709ff + 851442c commit 64c84b4

File tree

6 files changed

+99
-117
lines changed

6 files changed

+99
-117
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
New `Formatter.format_ticks` method
2+
```````````````````````````````````
3+
4+
The `Formatter` class gained a new `~Formatter.format_ticks` method, which
5+
takes the list of all tick locations as a single argument and returns the list
6+
of all formatted values. It is called by the axis tick handling code and, by
7+
default, repeatedly calls `~Formatter.__call__`.
8+
9+
It is intended to be overridden by `Formatter` subclasses for which
10+
the formatting of a tick value depends on other tick values, such as
11+
`ConciseDateFormatter`.

lib/matplotlib/axis.py

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -932,24 +932,18 @@ def iter_ticks(self):
932932
"""
933933
Iterate through all of the major and minor ticks.
934934
"""
935-
majorLocs = self.major.locator()
936-
majorTicks = self.get_major_ticks(len(majorLocs))
937-
self.major.formatter.set_locs(majorLocs)
938-
majorLabels = [self.major.formatter(val, i)
939-
for i, val in enumerate(majorLocs)]
940-
941-
minorLocs = self.minor.locator()
942-
minorTicks = self.get_minor_ticks(len(minorLocs))
943-
self.minor.formatter.set_locs(minorLocs)
944-
minorLabels = [self.minor.formatter(val, i)
945-
for i, val in enumerate(minorLocs)]
946-
947-
major_minor = [
948-
(majorTicks, majorLocs, majorLabels),
949-
(minorTicks, minorLocs, minorLabels)]
950-
951-
for group in major_minor:
952-
yield from zip(*group)
935+
major_locs = self.major.locator()
936+
major_ticks = self.get_major_ticks(len(major_locs))
937+
self.major.formatter.set_locs(major_locs)
938+
major_labels = self.major.formatter.format_ticks(major_locs)
939+
940+
minor_locs = self.minor.locator()
941+
minor_ticks = self.get_minor_ticks(len(minor_locs))
942+
self.minor.formatter.set_locs(minor_locs)
943+
minor_labels = self.minor.formatter.format_ticks(minor_locs)
944+
945+
yield from zip(major_ticks, major_locs, major_labels)
946+
yield from zip(minor_ticks, minor_locs, minor_labels)
953947

954948
def get_ticklabel_extents(self, renderer):
955949
"""

lib/matplotlib/colorbar.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -789,7 +789,7 @@ def _ticker(self, locator, formatter):
789789
self._manual_tick_data_values = b
790790
ticks = self._locate(b)
791791
formatter.set_locs(b)
792-
ticklabels = [formatter(t, i) for i, t in enumerate(b)]
792+
ticklabels = formatter.format_ticks(b)
793793
offset_string = formatter.get_offset()
794794
return ticks, ticklabels, offset_string
795795

lib/matplotlib/dates.py

Lines changed: 66 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -820,8 +820,6 @@ def __init__(self, locator, tz=None, formats=None, offset_formats=None,
820820
"""
821821
self._locator = locator
822822
self._tz = tz
823-
self._oldticks = np.array([])
824-
self._oldlabels = None
825823
self.defaultfmt = '%Y'
826824
# there are 6 levels with each level getting a specific format
827825
# 0: mostly years, 1: months, 2: days,
@@ -869,95 +867,74 @@ def __init__(self, locator, tz=None, formats=None, offset_formats=None,
869867
'%Y-%b-%d',
870868
'%Y-%b-%d %H:%M']
871869
self.offset_string = ''
872-
self._formatter = DateFormatter(self.defaultfmt, self._tz)
873870
self.show_offset = show_offset
874871

875872
def __call__(self, x, pos=None):
876-
if hasattr(self._locator, '_get_unit'):
877-
locator_unit_scale = float(self._locator._get_unit())
878-
else:
879-
locator_unit_scale = 1.0
880-
ticks = self._locator()
881-
if pos is not None:
882-
if not np.array_equal(ticks, self._oldticks):
883-
884-
offset_fmt = ''
885-
fmt = self.defaultfmt
886-
self._formatter = DateFormatter(fmt, self._tz)
887-
tickdatetime = [num2date(tick) for tick in ticks]
888-
tickdate = np.array([tdt.timetuple()[:6]
889-
for tdt in tickdatetime])
890-
891-
# basic algorithm:
892-
# 1) only display a part of the date if it changes over the
893-
# ticks.
894-
# 2) don't display the smaller part of the date if:
895-
# it is always the same or if it is the start of the
896-
# year, month, day etc.
897-
# fmt for most ticks at this level
898-
fmts = self.formats
899-
# format beginnings of days, months, years, etc...
900-
zerofmts = self.zero_formats
901-
# offset fmt are for the offset in the upper left of the
902-
# or lower right of the axis.
903-
offsetfmts = self.offset_formats
904-
905-
# determine the level we will label at:
906-
# mostly 0: years, 1: months, 2: days,
907-
# 3: hours, 4: minutes, 5: seconds, 6: microseconds
908-
for level in range(5, -1, -1):
909-
if len(np.unique(tickdate[:, level])) > 1:
910-
break
911-
912-
# level is the basic level we will label at.
913-
# now loop through and decide the actual ticklabels
914-
zerovals = [0, 1, 1, 0, 0, 0, 0]
915-
ticknew = ['']*len(tickdate)
916-
for nn in range(len(tickdate)):
917-
if level < 5:
918-
if tickdate[nn][level] == zerovals[level]:
919-
fmt = zerofmts[level]
920-
else:
921-
fmt = fmts[level]
922-
else:
923-
# special handling for seconds + microseconds
924-
if (tickdatetime[nn].second == 0 and
925-
tickdatetime[nn].microsecond == 0):
926-
fmt = zerofmts[level]
927-
else:
928-
fmt = fmts[level]
929-
ticknew[nn] = tickdatetime[nn].strftime(fmt)
930-
931-
# special handling of seconds and microseconds:
932-
# strip extra zeros and decimal if possible...
933-
# this is complicated by two factors. 1) we have some
934-
# level-4 strings here (i.e. 03:00, '0.50000', '1.000')
935-
# 2) we would like to have the same number of decimals for
936-
# each string (i.e. 0.5 and 1.0).
937-
if level >= 5:
938-
trailing_zeros = min(
939-
(len(s) - len(s.rstrip('0')) for s in ticknew
940-
if '.' in s),
941-
default=None)
942-
if trailing_zeros:
943-
for nn in range(len(ticknew)):
944-
if '.' in ticknew[nn]:
945-
ticknew[nn] = \
946-
ticknew[nn][:-trailing_zeros].rstrip('.')
947-
948-
result = ticknew[pos]
949-
self._oldticks = ticks
950-
self._oldlabels = ticknew
951-
952-
# set the offset string:
953-
if self.show_offset:
954-
self.offset_string = tickdatetime[-1].strftime(
955-
offsetfmts[level])
956-
957-
result = self._oldlabels[pos]
958-
else:
959-
result = self._formatter(x, pos)
960-
return result
873+
formatter = DateFormatter(self.defaultfmt, self._tz)
874+
return formatter(x, pos=pos)
875+
876+
def format_ticks(self, values):
877+
tickdatetime = [num2date(value) for value in values]
878+
tickdate = np.array([tdt.timetuple()[:6] for tdt in tickdatetime])
879+
880+
# basic algorithm:
881+
# 1) only display a part of the date if it changes over the ticks.
882+
# 2) don't display the smaller part of the date if:
883+
# it is always the same or if it is the start of the
884+
# year, month, day etc.
885+
# fmt for most ticks at this level
886+
fmts = self.formats
887+
# format beginnings of days, months, years, etc...
888+
zerofmts = self.zero_formats
889+
# offset fmt are for the offset in the upper left of the
890+
# or lower right of the axis.
891+
offsetfmts = self.offset_formats
892+
893+
# determine the level we will label at:
894+
# mostly 0: years, 1: months, 2: days,
895+
# 3: hours, 4: minutes, 5: seconds, 6: microseconds
896+
for level in range(5, -1, -1):
897+
if len(np.unique(tickdate[:, level])) > 1:
898+
break
899+
900+
# level is the basic level we will label at.
901+
# now loop through and decide the actual ticklabels
902+
zerovals = [0, 1, 1, 0, 0, 0, 0]
903+
labels = [''] * len(tickdate)
904+
for nn in range(len(tickdate)):
905+
if level < 5:
906+
if tickdate[nn][level] == zerovals[level]:
907+
fmt = zerofmts[level]
908+
else:
909+
fmt = fmts[level]
910+
else:
911+
# special handling for seconds + microseconds
912+
if (tickdatetime[nn].second == tickdatetime[nn].microsecond
913+
== 0):
914+
fmt = zerofmts[level]
915+
else:
916+
fmt = fmts[level]
917+
labels[nn] = tickdatetime[nn].strftime(fmt)
918+
919+
# special handling of seconds and microseconds:
920+
# strip extra zeros and decimal if possible.
921+
# this is complicated by two factors. 1) we have some level-4 strings
922+
# here (i.e. 03:00, '0.50000', '1.000') 2) we would like to have the
923+
# same number of decimals for each string (i.e. 0.5 and 1.0).
924+
if level >= 5:
925+
trailing_zeros = min(
926+
(len(s) - len(s.rstrip('0')) for s in labels if '.' in s),
927+
default=None)
928+
if trailing_zeros:
929+
for nn in range(len(labels)):
930+
if '.' in labels[nn]:
931+
labels[nn] = labels[nn][:-trailing_zeros].rstrip('.')
932+
933+
if self.show_offset:
934+
# set the offset string:
935+
self.offset_string = tickdatetime[-1].strftime(offsetfmts[level])
936+
937+
return labels
961938

962939
def get_offset(self):
963940
return self.offset_string
@@ -2082,7 +2059,7 @@ class ConciseDateConverter(DateConverter):
20822059
"""
20832060

20842061
def __init__(self, formats=None, zero_formats=None, offset_formats=None,
2085-
show_offset=True):
2062+
show_offset=True):
20862063
self._formats = formats
20872064
self._zero_formats = zero_formats
20882065
self._offset_formats = offset_formats

lib/matplotlib/ticker.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,10 @@ def __call__(self, x, pos=None):
253253
"""
254254
raise NotImplementedError('Derived must override')
255255

256+
def format_ticks(self, values):
257+
"""Return the tick labels for all the ticks at once."""
258+
return [self(value, i) for i, value in enumerate(values)]
259+
256260
def format_data(self, value):
257261
"""
258262
Returns the full string representation of the value with the
@@ -291,7 +295,7 @@ def fix_minus(self, s):
291295
return s
292296

293297
def _set_locator(self, locator):
294-
""" Subclasses may want to override this to set a locator. """
298+
"""Subclasses may want to override this to set a locator."""
295299
pass
296300

297301

lib/mpl_toolkits/axisartist/axislines.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -226,14 +226,12 @@ def get_tick_iterators(self, axes):
226226
major = self.axis.major
227227
majorLocs = major.locator()
228228
major.formatter.set_locs(majorLocs)
229-
majorLabels = [major.formatter(val, i)
230-
for i, val in enumerate(majorLocs)]
229+
majorLabels = major.formatter.format_ticks(majorLocs)
231230

232231
minor = self.axis.minor
233232
minorLocs = minor.locator()
234233
minor.formatter.set_locs(minorLocs)
235-
minorLabels = [minor.formatter(val, i)
236-
for i, val in enumerate(minorLocs)]
234+
minorLabels = minor.formatter.format_ticks(minorLocs)
237235

238236
trans_tick = self.get_tick_transform(axes)
239237

@@ -323,14 +321,12 @@ def get_tick_iterators(self, axes):
323321
major = self.axis.major
324322
majorLocs = major.locator()
325323
major.formatter.set_locs(majorLocs)
326-
majorLabels = [major.formatter(val, i)
327-
for i, val in enumerate(majorLocs)]
324+
majorLabels = major.formatter.format_ticks(majorLocs)
328325

329326
minor = self.axis.minor
330327
minorLocs = minor.locator()
331328
minor.formatter.set_locs(minorLocs)
332-
minorLabels = [minor.formatter(val, i)
333-
for i, val in enumerate(minorLocs)]
329+
minorLabels = minor.formatter.format_ticks(minorLocs)
334330

335331
tr2ax = axes.transData + axes.transAxes.inverted()
336332

0 commit comments

Comments
 (0)