@@ -930,16 +930,25 @@ def iter_ticks(self):
930
930
Iterate through all of the major and minor ticks.
931
931
"""
932
932
major_locs = self .major .locator ()
933
- major_ticks = self .get_major_ticks (len (major_locs ))
934
933
self .major .formatter .set_locs (major_locs )
935
934
major_labels = self .major .formatter .format_ticks (major_locs )
936
-
937
- minor_locs = self .minor .locator ()
938
- minor_ticks = self .get_minor_ticks (len (minor_locs ))
935
+ major_ticks = self .get_major_ticks (len (major_locs ))
936
+ yield from zip (major_ticks , major_locs , major_labels )
937
+ # Remove minor ticks duplicating major ticks; use the range of major
938
+ # tick values to set the scale. 1e-5 is the default rtol for isclose.
939
+ # If there are no major_locs, tol doesn't matter.
940
+ # Ideally, we would like to apply e.g. ax.get_xaxis_transform() to
941
+ # the tick locs and decide based on screen-space proximity, but as
942
+ # of now the axis object doesn't know whether it is associated with
943
+ # ax.get_xaxis_transform(), ax.get_yaxis_transform(), or something
944
+ # else.
945
+ tol = np .abs (major_locs ).ptp () * 1e-5 if len (major_locs ) else 0
946
+ minor_locs = [
947
+ loc for loc in self .minor .locator ()
948
+ if not np .isclose (loc , major_locs , atol = tol , rtol = 0 ).any ()]
939
949
self .minor .formatter .set_locs (minor_locs )
940
950
minor_labels = self .minor .formatter .format_ticks (minor_locs )
941
-
942
- yield from zip (major_ticks , major_locs , major_labels )
951
+ minor_ticks = self .get_minor_ticks (len (minor_locs ))
943
952
yield from zip (minor_ticks , minor_locs , minor_labels )
944
953
945
954
def get_ticklabel_extents (self , renderer ):
@@ -1220,18 +1229,23 @@ def get_ticklines(self, minor=False):
1220
1229
return self .get_majorticklines ()
1221
1230
1222
1231
def get_majorticklocs (self ):
1223
- "Get the major tick locations in data coordinates as a numpy array"
1232
+ "Get the major tick locations in data coordinates as a numpy array. "
1224
1233
return self .major .locator ()
1225
1234
1226
1235
def get_minorticklocs (self ):
1227
- "Get the minor tick locations in data coordinates as a numpy array"
1228
- return self .minor .locator ()
1236
+ "Get the minor tick locations in data coordinates as a numpy array."
1237
+ # See rationale for tol in iter_ticks (which does not reuse this
1238
+ # implementation to avoid calling the major locator twice).
1239
+ major_locs = self .major .locator ()
1240
+ tol = np .abs (major_locs ).ptp () * 1e-5 if major_locs .size else 0
1241
+ minor_locs = [
1242
+ loc for loc in self .minor .locator ()
1243
+ if not np .isclose (loc , major_locs , atol = tol , rtol = 0 ).any ()]
1244
+ return minor_locs
1229
1245
1230
1246
def get_ticklocs (self , minor = False ):
1231
- "Get the tick locations in data coordinates as a numpy array"
1232
- if minor :
1233
- return self .minor .locator ()
1234
- return self .major .locator ()
1247
+ "Get the tick locations in data coordinates as a numpy array."
1248
+ return self .get_minorticklocs () if minor else self .get_majorticklocs ()
1235
1249
1236
1250
def get_ticks_direction (self , minor = False ):
1237
1251
"""
0 commit comments