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

Skip to content

Commit bbd10ba

Browse files
authored
Merge pull request #13908 from tacaswell/enh_control_tick_deconflict2
Enh control tick deconflict2
2 parents b52b160 + 00fbd77 commit bbd10ba

File tree

3 files changed

+77
-11
lines changed

3 files changed

+77
-11
lines changed

doc/api/axis_api.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ Formatters and Locators
6060
Axis.set_major_locator
6161
Axis.set_minor_formatter
6262
Axis.set_minor_locator
63-
63+
Axis.remove_overlapping_locs
6464

6565
Axis Label
6666
----------

lib/matplotlib/axis.py

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,8 @@ def __init__(self, axes, pickradius=15):
723723
`.Axis.contains`.
724724
"""
725725
martist.Artist.__init__(self)
726+
self._remove_overlapping_locs = True
727+
726728
self.set_figure(axes.figure)
727729

728730
self.isDefault_label = True
@@ -754,6 +756,17 @@ def __init__(self, axes, pickradius=15):
754756
majorTicks = _LazyTickList(major=True)
755757
minorTicks = _LazyTickList(major=False)
756758

759+
def get_remove_overlapping_locs(self):
760+
return self._remove_overlapping_locs
761+
762+
def set_remove_overlapping_locs(self, val):
763+
self._remove_overlapping_locs = bool(val)
764+
765+
remove_overlapping_locs = property(
766+
get_remove_overlapping_locs, set_remove_overlapping_locs,
767+
doc=('If minor ticker locations that overlap with major '
768+
'ticker locations should be trimmed.'))
769+
757770
def set_label_coords(self, x, y, transform=None):
758771
"""
759772
Set the coordinates of the label.
@@ -1064,23 +1077,29 @@ def _update_ticks(self):
10641077
Update ticks (position and labels) using the current data interval of
10651078
the axes. Return the list of ticks that will be drawn.
10661079
"""
1067-
1068-
major_locs = self.major.locator()
1069-
major_ticks = self.get_major_ticks(len(major_locs))
1080+
major_locs = self.get_majorticklocs()
10701081
major_labels = self.major.formatter.format_ticks(major_locs)
1082+
major_ticks = self.get_major_ticks(len(major_locs))
1083+
self.major.formatter.set_locs(major_locs)
10711084
for tick, loc, label in zip(major_ticks, major_locs, major_labels):
10721085
tick.update_position(loc)
10731086
tick.set_label1(label)
10741087
tick.set_label2(label)
1075-
minor_locs = self.minor.locator()
1076-
minor_ticks = self.get_minor_ticks(len(minor_locs))
1088+
minor_locs = self.get_minorticklocs()
10771089
minor_labels = self.minor.formatter.format_ticks(minor_locs)
1090+
minor_ticks = self.get_minor_ticks(len(minor_locs))
1091+
self.minor.formatter.set_locs(minor_locs)
10781092
for tick, loc, label in zip(minor_ticks, minor_locs, minor_labels):
10791093
tick.update_position(loc)
10801094
tick.set_label1(label)
10811095
tick.set_label2(label)
10821096
ticks = [*major_ticks, *minor_ticks]
10831097

1098+
# mark the ticks that we will not be using as not visible
1099+
for t in (self.minorTicks[len(minor_locs):] +
1100+
self.majorTicks[len(major_locs):]):
1101+
t.set_visible(False)
1102+
10841103
view_low, view_high = self.get_view_interval()
10851104
if view_low > view_high:
10861105
view_low, view_high = view_high, view_low
@@ -1322,9 +1341,10 @@ def get_minorticklocs(self):
13221341
# Use the transformed view limits as scale. 1e-5 is the default rtol
13231342
# for np.isclose.
13241343
tol = (hi - lo) * 1e-5
1325-
minor_locs = [
1326-
loc for loc, tr_loc in zip(minor_locs, tr_minor_locs)
1327-
if not np.isclose(tr_loc, tr_major_locs, atol=tol, rtol=0).any()]
1344+
if self.remove_overlapping_locs:
1345+
minor_locs = [
1346+
loc for loc, tr_loc in zip(minor_locs, tr_minor_locs)
1347+
if ~np.isclose(tr_loc, tr_major_locs, atol=tol, rtol=0).any()]
13281348
return minor_locs
13291349

13301350
def get_ticklocs(self, minor=False):
@@ -1390,7 +1410,7 @@ def get_minor_formatter(self):
13901410
def get_major_ticks(self, numticks=None):
13911411
'Get the tick instances; grow as necessary.'
13921412
if numticks is None:
1393-
numticks = len(self.get_major_locator()())
1413+
numticks = len(self.get_majorticklocs())
13941414

13951415
while len(self.majorTicks) < numticks:
13961416
# Update the new tick label properties from the old.
@@ -1404,7 +1424,7 @@ def get_major_ticks(self, numticks=None):
14041424
def get_minor_ticks(self, numticks=None):
14051425
'Get the minor tick instances; grow as necessary.'
14061426
if numticks is None:
1407-
numticks = len(self.get_minor_locator()())
1427+
numticks = len(self.get_minorticklocs())
14081428

14091429
while len(self.minorTicks) < numticks:
14101430
# Update the new tick label properties from the old.

lib/matplotlib/tests/test_ticker.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -923,3 +923,49 @@ def minorticksubplot(xminor, yminor, i):
923923
minorticksubplot(True, False, 2)
924924
minorticksubplot(False, True, 3)
925925
minorticksubplot(True, True, 4)
926+
927+
928+
@pytest.mark.parametrize('remove_overlapping_locs, expected_num',
929+
((True, 6),
930+
(None, 6), # this tests the default
931+
(False, 9)))
932+
def test_remove_overlap(remove_overlapping_locs, expected_num):
933+
import numpy as np
934+
import matplotlib.dates as mdates
935+
936+
t = np.arange("2018-11-03", "2018-11-06", dtype="datetime64")
937+
x = np.ones(len(t))
938+
939+
fig, ax = plt.subplots()
940+
ax.plot(t, x)
941+
942+
ax.xaxis.set_major_locator(mdates.DayLocator())
943+
ax.xaxis.set_major_formatter(mdates.DateFormatter('\n%a'))
944+
945+
ax.xaxis.set_minor_locator(mdates.HourLocator((0, 6, 12, 18)))
946+
ax.xaxis.set_minor_formatter(mdates.DateFormatter('%H:%M'))
947+
# force there to be extra ticks
948+
ax.xaxis.get_minor_ticks(15)
949+
if remove_overlapping_locs is not None:
950+
ax.xaxis.remove_overlapping_locs = remove_overlapping_locs
951+
952+
# check that getter/setter exists
953+
current = ax.xaxis.remove_overlapping_locs
954+
assert (current == ax.xaxis.get_remove_overlapping_locs())
955+
plt.setp(ax.xaxis, remove_overlapping_locs=current)
956+
new = ax.xaxis.remove_overlapping_locs
957+
assert (new == ax.xaxis.remove_overlapping_locs)
958+
959+
# check that the accessors filter correctly
960+
# this is the method that does the actual filtering
961+
assert len(ax.xaxis.get_minorticklocs()) == expected_num
962+
# these three are derivative
963+
assert len(ax.xaxis.get_minor_ticks()) == expected_num
964+
assert len(ax.xaxis.get_minorticklabels()) == expected_num
965+
assert len(ax.xaxis.get_minorticklines()) == expected_num*2
966+
967+
# force a draw to call _update_ticks under the hood
968+
fig.canvas.draw()
969+
# check that the correct number of ticks report them selves as
970+
# visible
971+
assert sum(t.get_visible() for t in ax.xaxis.minorTicks) == expected_num

0 commit comments

Comments
 (0)