diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index 31ec36f8e86e..4c4e0ec4b358 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -1028,62 +1028,29 @@ def _update_ticks(self, renderer): ihigh = locs[-1] tick_tups = [ti for ti in tick_tups if ilow <= ti[1] <= ihigh] - # so that we don't lose ticks on the end, expand out the interval ever - # so slightly. The "ever so slightly" is defined to be the width of a - # half of a pixel. We don't want to draw a tick that even one pixel - # outside of the defined axis interval. - if interval[0] <= interval[1]: - interval_expanded = interval - else: - interval_expanded = interval[1], interval[0] - - if hasattr(self, '_get_pixel_distance_along_axis'): - # normally, one does not want to catch all exceptions that - # could possibly happen, but it is not clear exactly what - # exceptions might arise from a user's projection (their - # rendition of the Axis object). So, we catch all, with - # the idea that one would rather potentially lose a tick - # from one side of the axis or another, rather than see a - # stack trace. - # We also catch users warnings here. These are the result of - # invalid numpy calculations that may be the result of out of - # bounds on axis with finite allowed intervals such as geo - # projections i.e. Mollweide. - with np.errstate(invalid='ignore'): - try: - ds1 = self._get_pixel_distance_along_axis( - interval_expanded[0], -0.5) - except Exception: - cbook._warn_external("Unable to find pixel distance " - "along axis for interval padding of " - "ticks; assuming no interval " - "padding needed.") - ds1 = 0.0 - if np.isnan(ds1): - ds1 = 0.0 - try: - ds2 = self._get_pixel_distance_along_axis( - interval_expanded[1], +0.5) - except Exception: - cbook._warn_external("Unable to find pixel distance " - "along axis for interval padding of " - "ticks; assuming no interval " - "padding needed.") - ds2 = 0.0 - if np.isnan(ds2): - ds2 = 0.0 - interval_expanded = (interval_expanded[0] - ds1, - interval_expanded[1] + ds2) + if interval[1] <= interval[0]: + interval = interval[1], interval[0] + inter = self.get_transform().transform(interval) ticks_to_draw = [] for tick, loc, label in tick_tups: + # draw each tick if it is in interval. Note the transform + # to pixel space to take care of log transforms etc. + # interval_contains has a floating point tolerance. if tick is None: continue # NB: always update labels and position to avoid issues like #9397 tick.update_position(loc) tick.set_label1(label) tick.set_label2(label) - if not mtransforms.interval_contains(interval_expanded, loc): + try: + loct = self.get_transform().transform(loc) + except AssertionError: + # transforms.transform doesn't allow masked values but + # some scales might make them, so we need this try/except. + loct = None + continue + if not mtransforms._interval_contains_close(inter, loct): continue ticks_to_draw.append(tick) diff --git a/lib/matplotlib/tests/baseline_images/test_axes/specgram_angle_noise.png b/lib/matplotlib/tests/baseline_images/test_axes/specgram_angle_noise.png index 6cef67f8a483..a9e3c4d20791 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/specgram_angle_noise.png and b/lib/matplotlib/tests/baseline_images/test_axes/specgram_angle_noise.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_freqs.png b/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_freqs.png index dab0acc3e2aa..ce598a5fd2ab 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_freqs.png and b/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_freqs.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_freqs_linear.png b/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_freqs_linear.png index dab0acc3e2aa..ce598a5fd2ab 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_freqs_linear.png and b/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_freqs_linear.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_noise.png b/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_noise.png index 2c52f47c8fc5..4d25d92b4010 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_noise.png and b/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_noise.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_noise_linear.png b/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_noise_linear.png index 2c52f47c8fc5..4d25d92b4010 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_noise_linear.png and b/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_noise_linear.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/specgram_noise.png b/lib/matplotlib/tests/baseline_images/test_axes/specgram_noise.png index 9bc8bfa31440..584cf973d51d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/specgram_noise.png and b/lib/matplotlib/tests/baseline_images/test_axes/specgram_noise.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/specgram_noise_linear.png b/lib/matplotlib/tests/baseline_images/test_axes/specgram_noise_linear.png index 9bc8bfa31440..584cf973d51d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/specgram_noise_linear.png and b/lib/matplotlib/tests/baseline_images/test_axes/specgram_noise_linear.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/specgram_phase_noise.png b/lib/matplotlib/tests/baseline_images/test_axes/specgram_phase_noise.png index eea4e75f58d0..5980e91135f5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/specgram_phase_noise.png and b/lib/matplotlib/tests/baseline_images/test_axes/specgram_phase_noise.png differ diff --git a/lib/matplotlib/transforms.py b/lib/matplotlib/transforms.py index 424876d74fb9..d215ad44a22a 100644 --- a/lib/matplotlib/transforms.py +++ b/lib/matplotlib/transforms.py @@ -2900,10 +2900,39 @@ def interval_contains(interval, val): Returns ------- bool - Returns true if given val is within the interval. + Returns *True* if given *val* is within the *interval*. + """ + a, b = interval + if a > b: + a, b = b, a + return a <= val <= b + + +def _interval_contains_close(interval, val, rtol=1e-10): + """ + Check, inclusively, whether an interval includes a given value, with the + interval expanded by a small tolerance to admit floating point errors. + + Parameters + ---------- + interval : sequence of scalar + A 2-length sequence, endpoints that define the interval. + val : scalar + Value to check is within interval. + rtol : scalar + Tolerance slippage allowed outside of this interval. Default + 1e-10 * (b - a). + + Returns + ------- + bool + Returns *True* if given *val* is within the *interval* (with tolerance) """ a, b = interval - return a <= val <= b or a >= val >= b + if a > b: + a, b = b, a + rtol = (b - a) * rtol + return a - rtol <= val <= b + rtol def interval_contains_open(interval, val):