Skip to content

Commit

Permalink
Move major/minor tick overstrike logic to Axis.
Browse files Browse the repository at this point in the history
The Axis knows what the major and the minor ticker are so it makes sense
to let it handle the deduplication logic.

Revert some heuristic deduplication logic from the Locators themselves
(which effectively tests that the new code works).
  • Loading branch information
anntzer committed Jan 29, 2019
1 parent 851442c commit a67157d
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 25 deletions.
10 changes: 10 additions & 0 deletions doc/api/next_api_changes/2018-01-30-AL.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Minor Locator no longer try to avoid overstriking major Locators
````````````````````````````````````````````````````````````````

Previously, various locator classes contained custom logic to detect whether
they are used as minor locators, and, if so, attempted to avoid emitting tick
locations that collided with major ticks.

This logic has now moved to the Axis class; thus, for example,
``xaxis.minor.locator()`` now includes positions that collide with
``xaxis.major.locator()``, but ``xaxis.get_minorticklocs()`` does not.
37 changes: 23 additions & 14 deletions lib/matplotlib/axis.py
Original file line number Diff line number Diff line change
Expand Up @@ -929,17 +929,15 @@ def iter_ticks(self):
"""
Iterate through all of the major and minor ticks.
"""
major_locs = self.major.locator()
major_ticks = self.get_major_ticks(len(major_locs))
major_locs = self.get_majorticklocs()
self.major.formatter.set_locs(major_locs)
major_labels = self.major.formatter.format_ticks(major_locs)

minor_locs = self.minor.locator()
minor_ticks = self.get_minor_ticks(len(minor_locs))
major_ticks = self.get_major_ticks(len(major_locs))
yield from zip(major_ticks, major_locs, major_labels)
minor_locs = self.get_minorticklocs()
self.minor.formatter.set_locs(minor_locs)
minor_labels = self.minor.formatter.format_ticks(minor_locs)

yield from zip(major_ticks, major_locs, major_labels)
minor_ticks = self.get_minor_ticks(len(minor_locs))
yield from zip(minor_ticks, minor_locs, minor_labels)

def get_ticklabel_extents(self, renderer):
Expand Down Expand Up @@ -1220,18 +1218,29 @@ def get_ticklines(self, minor=False):
return self.get_majorticklines()

def get_majorticklocs(self):
"Get the major tick locations in data coordinates as a numpy array"
"""Get the array of major tick locations in data coordinates."""
return self.major.locator()

def get_minorticklocs(self):
"Get the minor tick locations in data coordinates as a numpy array"
return self.minor.locator()
"""Get the array of minor tick locations in data coordinates."""
# Remove minor ticks duplicating major ticks.
major_locs = self.major.locator()
minor_locs = self.minor.locator()
transform = self._scale.get_transform()
tr_minor_locs = transform.transform(minor_locs)
tr_major_locs = transform.transform(major_locs)
lo, hi = sorted(transform.transform(self.get_view_interval()))
# Use the transformed view limits as scale. 1e-5 is the default rtol
# for np.isclose.
tol = (hi - lo) * 1e-5
minor_locs = [
loc for loc, tr_loc in zip(minor_locs, tr_minor_locs)
if not np.isclose(tr_loc, tr_major_locs, atol=tol, rtol=0).any()]
return minor_locs

def get_ticklocs(self, minor=False):
"Get the tick locations in data coordinates as a numpy array"
if minor:
return self.minor.locator()
return self.major.locator()
"""Get the array of tick locations in data coordinates."""
return self.get_minorticklocs() if minor else self.get_majorticklocs()

def get_ticks_direction(self, minor=False):
"""
Expand Down
14 changes: 3 additions & 11 deletions lib/matplotlib/ticker.py
Original file line number Diff line number Diff line change
Expand Up @@ -2258,13 +2258,9 @@ def tick_values(self, vmin, vmax):
# If we're a minor locator *that expects at least two ticks per
# decade* and the major locator stride is 1 and there's no more
# than one minor tick, switch to AutoLocator.
ticklocs = AutoLocator().tick_values(vmin, vmax)
# Don't overstrike the major labels. Assumes major locs are
# at b = self._base
ticklocs = ticklocs[
~is_close_to_int(np.log(ticklocs) / np.log(b))]
return ticklocs
return self.raise_if_exceeds(ticklocs)
return AutoLocator().tick_values(vmin, vmax)
else:
return self.raise_if_exceeds(ticklocs)

def view_limits(self, vmin, vmax):
'Try to choose the view limits intelligently'
Expand Down Expand Up @@ -2643,10 +2639,6 @@ def __call__(self):
tmin = ((vmin - t0) // minorstep + 1) * minorstep
tmax = ((vmax - t0) // minorstep + 1) * minorstep
locs = np.arange(tmin, tmax, minorstep) + t0
mod = np.abs((locs - t0) % majorstep)
cond1 = mod > minorstep / 10.0
cond2 = ~np.isclose(mod, majorstep, atol=0)
locs = locs.compress(cond1 & cond2)

return self.raise_if_exceeds(np.array(locs))

Expand Down

0 comments on commit a67157d

Please sign in to comment.