diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index 76e605d71b03..ac7e8095ae1a 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -2863,8 +2863,8 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True): if self.get_yscale() == 'log': y_stickies = y_stickies[y_stickies > 0] - def handle_single_axis(scale, autoscaleon, shared_axes, interval, - minpos, axis, margin, stickies, set_bound): + def handle_single_axis(scale, autoscaleon, shared_axes, name, + axis, margin, stickies, set_bound): if not (scale and autoscaleon): return # nothing to do... @@ -2876,12 +2876,16 @@ def handle_single_axis(scale, autoscaleon, shared_axes, interval, x_values = [] minimum_minpos = np.inf for ax in shared: - x_values.extend(getattr(ax.dataLim, interval)) + x_values.extend(getattr(ax.dataLim, f"interval{name}")) minimum_minpos = min(minimum_minpos, - getattr(ax.dataLim, minpos)) + getattr(ax.dataLim, f"minpos{name}")) x_values = np.extract(np.isfinite(x_values), x_values) if x_values.size >= 1: x0, x1 = (x_values.min(), x_values.max()) + elif getattr(self._viewLim, f"mutated{name}")(): + # No data, but explicit viewLims already set: + # in mutatedx or mutatedy. + return else: x0, x1 = (-np.inf, np.inf) # If x0 and x1 are non finite, use the locator to figure out @@ -2925,11 +2929,11 @@ def handle_single_axis(scale, autoscaleon, shared_axes, interval, # End of definition of internal function 'handle_single_axis'. handle_single_axis( - scalex, self._autoscaleXon, self._shared_x_axes, 'intervalx', - 'minposx', self.xaxis, self._xmargin, x_stickies, self.set_xbound) + scalex, self._autoscaleXon, self._shared_x_axes, 'x', + self.xaxis, self._xmargin, x_stickies, self.set_xbound) handle_single_axis( - scaley, self._autoscaleYon, self._shared_y_axes, 'intervaly', - 'minposy', self.yaxis, self._ymargin, y_stickies, self.set_ybound) + scaley, self._autoscaleYon, self._shared_y_axes, 'y', + self.yaxis, self._ymargin, y_stickies, self.set_ybound) def _get_axis_list(self): return self.xaxis, self.yaxis diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index f758f4537363..ff51196f3553 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -1457,7 +1457,7 @@ def update_units(self, data): if default is not None and self.units is None: self.set_units(default) - if neednew: + elif neednew: self._update_axisinfo() self.stale = True return True @@ -2267,17 +2267,15 @@ def set_inverted(self, inverted): def set_default_intervals(self): # docstring inherited xmin, xmax = 0., 1. - dataMutated = self.axes.dataLim.mutatedx() - viewMutated = self.axes.viewLim.mutatedx() - if not dataMutated or not viewMutated: + # only change view if dataLim has not changed and user has + # not changed the view: + if (not self.axes.dataLim.mutatedx() and + not self.axes.viewLim.mutatedx()): if self.converter is not None: info = self.converter.axisinfo(self.units, self) if info.default_limits is not None: xmin, xmax = self.convert_units(info.default_limits) - if not dataMutated: - self.axes.dataLim.intervalx = xmin, xmax - if not viewMutated: - self.axes.viewLim.intervalx = xmin, xmax + self.axes.viewLim.intervalx = xmin, xmax self.stale = True def get_tick_space(self): @@ -2530,17 +2528,15 @@ def set_inverted(self, inverted): def set_default_intervals(self): # docstring inherited ymin, ymax = 0., 1. - dataMutated = self.axes.dataLim.mutatedy() - viewMutated = self.axes.viewLim.mutatedy() - if not dataMutated or not viewMutated: + # only change view if dataLim has not changed and user has + # not changed the view: + if (not self.axes.dataLim.mutatedy() and + not self.axes.viewLim.mutatedy()): if self.converter is not None: info = self.converter.axisinfo(self.units, self) if info.default_limits is not None: ymin, ymax = self.convert_units(info.default_limits) - if not dataMutated: - self.axes.dataLim.intervaly = ymin, ymax - if not viewMutated: - self.axes.viewLim.intervaly = ymin, ymax + self.axes.viewLim.intervaly = ymin, ymax self.stale = True def get_tick_space(self): diff --git a/lib/matplotlib/tests/baseline_images/test_dates/date_empty.png b/lib/matplotlib/tests/baseline_images/test_dates/date_empty.png deleted file mode 100644 index 4bb9efcba428..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_dates/date_empty.png and /dev/null differ diff --git a/lib/matplotlib/tests/test_dates.py b/lib/matplotlib/tests/test_dates.py index fc59b6b3f5fd..af13c2de5b4a 100644 --- a/lib/matplotlib/tests/test_dates.py +++ b/lib/matplotlib/tests/test_dates.py @@ -70,13 +70,55 @@ def test_date2num_NaT_scalar(units): assert np.isnan(tmpl) -@image_comparison(['date_empty.png']) def test_date_empty(): # make sure we do the right thing when told to plot dates even # if no date data has been presented, cf # http://sourceforge.net/tracker/?func=detail&aid=2850075&group_id=80706&atid=560720 fig, ax = plt.subplots() ax.xaxis_date() + fig.draw_no_output() + np.testing.assert_allclose(ax.get_xlim(), + [mdates.date2num(np.datetime64('2000-01-01')), + mdates.date2num(np.datetime64('2010-01-01'))]) + + mdates._reset_epoch_test_example() + mdates.set_epoch('0000-12-31') + fig, ax = plt.subplots() + ax.xaxis_date() + fig.draw_no_output() + np.testing.assert_allclose(ax.get_xlim(), + [mdates.date2num(np.datetime64('2000-01-01')), + mdates.date2num(np.datetime64('2010-01-01'))]) + mdates._reset_epoch_test_example() + + +def test_date_not_empty(): + fig = plt.figure() + ax = fig.add_subplot() + + ax.plot([50, 70], [1, 2]) + ax.xaxis.axis_date() + np.testing.assert_allclose(ax.get_xlim(), [50, 70]) + + +def test_axhline(): + # make sure that axhline doesn't set the xlimits... + fig, ax = plt.subplots() + ax.axhline(1.5) + ax.plot([np.datetime64('2016-01-01'), np.datetime64('2016-01-02')], [1, 2]) + np.testing.assert_allclose(ax.get_xlim(), + [mdates.date2num(np.datetime64('2016-01-01')), + mdates.date2num(np.datetime64('2016-01-02'))]) + + mdates._reset_epoch_test_example() + mdates.set_epoch('0000-12-31') + fig, ax = plt.subplots() + ax.axhline(1.5) + ax.plot([np.datetime64('2016-01-01'), np.datetime64('2016-01-02')], [1, 2]) + np.testing.assert_allclose(ax.get_xlim(), + [mdates.date2num(np.datetime64('2016-01-01')), + mdates.date2num(np.datetime64('2016-01-02'))]) + mdates._reset_epoch_test_example() @image_comparison(['date_axhspan.png']) diff --git a/lib/matplotlib/tests/test_units.py b/lib/matplotlib/tests/test_units.py index b0c5998c5338..c7a06e0e32ac 100644 --- a/lib/matplotlib/tests/test_units.py +++ b/lib/matplotlib/tests/test_units.py @@ -67,7 +67,8 @@ def default_units(value, axis): return None qc.convert = MagicMock(side_effect=convert) - qc.axisinfo = MagicMock(side_effect=lambda u, a: munits.AxisInfo(label=u)) + qc.axisinfo = MagicMock(side_effect=lambda u, a: + munits.AxisInfo(label=u, default_limits=(0, 100))) qc.default_units = MagicMock(side_effect=default_units) return qc @@ -219,3 +220,44 @@ def test_shared_axis_categorical(): ax2.plot(d2.keys(), d2.values()) ax1.xaxis.set_units(UnitData(["c", "d"])) assert "c" in ax2.xaxis.get_units()._mapping.keys() + + +def test_empty_default_limits(quantity_converter): + munits.registry[Quantity] = quantity_converter + fig, ax1 = plt.subplots() + ax1.xaxis.update_units(Quantity([10], "miles")) + fig.draw_no_output() + assert ax1.get_xlim() == (0, 100) + ax1.yaxis.update_units(Quantity([10], "miles")) + fig.draw_no_output() + assert ax1.get_ylim() == (0, 100) + + fig, ax = plt.subplots() + ax.axhline(30) + ax.plot(Quantity(np.arange(0, 3), "miles"), + Quantity(np.arange(0, 6, 2), "feet")) + fig.draw_no_output() + assert ax.get_xlim() == (0, 2) + assert ax.get_ylim() == (0, 30) + + fig, ax = plt.subplots() + ax.axvline(30) + ax.plot(Quantity(np.arange(0, 3), "miles"), + Quantity(np.arange(0, 6, 2), "feet")) + fig.draw_no_output() + assert ax.get_xlim() == (0, 30) + assert ax.get_ylim() == (0, 4) + + fig, ax = plt.subplots() + ax.xaxis.update_units(Quantity([10], "miles")) + ax.axhline(30) + fig.draw_no_output() + assert ax.get_xlim() == (0, 100) + assert ax.get_ylim() == (28.5, 31.5) + + fig, ax = plt.subplots() + ax.yaxis.update_units(Quantity([10], "miles")) + ax.axvline(30) + fig.draw_no_output() + assert ax.get_ylim() == (0, 100) + assert ax.get_xlim() == (28.5, 31.5)