diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 5066b088c16a..b6f33d3efaf8 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -715,6 +715,7 @@ def axhline(self, y=0, xmin=0, xmax=1, **kwargs): trans = self.get_yaxis_transform(which='grid') l = mlines.Line2D([xmin, xmax], [y, y], transform=trans, **kwargs) self.add_line(l) + self.ignore_existing_data_limits = "x" self._request_autoscale_view(scalex=False, scaley=scaley) return l @@ -782,6 +783,7 @@ def axvline(self, x=0, ymin=0, ymax=1, **kwargs): trans = self.get_xaxis_transform(which='grid') l = mlines.Line2D([x, x], [ymin, ymax], transform=trans, **kwargs) self.add_line(l) + self.ignore_existing_data_limits = "y" self._request_autoscale_view(scalex=scalex, scaley=False) return l @@ -921,6 +923,7 @@ def axhspan(self, ymin, ymax, xmin=0, xmax=1, **kwargs): p = mpatches.Polygon(verts, **kwargs) p.set_transform(self.get_yaxis_transform(which="grid")) self.add_patch(p) + self.ignore_existing_data_limits = "x" self._request_autoscale_view(scalex=False) return p @@ -976,6 +979,7 @@ def axvspan(self, xmin, xmax, ymin=0, ymax=1, **kwargs): p = mpatches.Polygon(verts, **kwargs) p.set_transform(self.get_xaxis_transform(which="grid")) self.add_patch(p) + self.ignore_existing_data_limits = "y" self._request_autoscale_view(scaley=False) return p diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index 26bc28dea71a..e4b383e3b03a 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -546,6 +546,7 @@ def __init__(self, fig, rect, self.set_axisbelow(mpl.rcParams['axes.axisbelow']) self._rasterization_zorder = None + self._ignore_existing_data_limits = 1 self.cla() # funcs used to format x and y - fall back on major formatters @@ -640,6 +641,24 @@ def __repr__(self): fields += [f"ylabel={self.get_ylabel()!r}"] return f"<{self.__class__.__name__}:" + ", ".join(fields) + ">" + @property + def ignore_existing_data_limits(self): + """ + Whether to ignore existing data limits + + value : int, bool or str + - when ``0`` or ``False``, do not ignore either x or y limits + - when ``1`` or ``True``, ignore both x and y limits + - when ``2`` or ``x``, ignore x-limits + - when ``3`` or ``y``, ignore y-limits + """ + return self._ignore_existing_data_limits + + @ignore_existing_data_limits.setter + def ignore_existing_data_limits(self, value): + lu = {False: 0, True: 1, 2: 2, "x": 2, 3: 3, "y": 3} + self._ignore_existing_data_limits = lu[value] + def get_window_extent(self, *args, **kwargs): """ Return the axes bounding box in display space; *args* and *kwargs* diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 7be15cef7e79..4c18e49ee837 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -6814,3 +6814,46 @@ def test_ylabel_ha_with_position(ha): ax.set_ylabel("test", y=1, ha=ha) ax.yaxis.set_label_position("right") assert ax.yaxis.get_label().get_ha() == ha + + +def test_axhline_with_date_xaxis(): + fig, ax = plt.subplots() + ax.axhline(1.5) + x = [datetime.datetime(2020, 1, i) for i in range(1, 3)] + y = [1, 2] + ax.plot(x, y) + assert ax.get_xlim() == (18262.0, 18263.0) + + +def test_axvline_with_date_yaxis(): + fig, ax = plt.subplots() + ax.axvline(1.5) + x = [1, 2] + y = [datetime.datetime(2020, 1, i) for i in range(1, 3)] + ax.plot(x, y) + assert ax.get_ylim() == (18262.0, 18263.0) + + +def test_two_spans(): + fig, ax = plt.subplots() + ax.axhline(1) + ax.axhline(2) + assert ax.get_ylim() == (1.0, 2.0) + + +def test_axhspan_with_date_xaxis(): + fig, ax = plt.subplots() + ax.axhspan(1, 2) + x = [datetime.datetime(2020, 1, i) for i in range(1, 3)] + y = [1, 2] + ax.plot(x, y) + assert ax.get_xlim() == (18262.0, 18263.0) + + +def test_axvspan_with_date_yaxis(): + fig, ax = plt.subplots() + ax.axvspan(1, 2) + x = [1, 2] + y = [datetime.datetime(2020, 1, i) for i in range(1, 3)] + ax.plot(x, y) + assert ax.get_ylim() == (18262.0, 18263.0) diff --git a/src/_path_wrapper.cpp b/src/_path_wrapper.cpp index 708d7d36e67a..66be2573f801 100644 --- a/src/_path_wrapper.cpp +++ b/src/_path_wrapper.cpp @@ -208,25 +208,76 @@ static PyObject *Py_update_path_extents(PyObject *self, PyObject *args, PyObject extent_limits e; - if (ignore) { - CALL_CPP("update_path_extents", reset_limits(e)); - } else { - if (rect.x1 > rect.x2) { + switch(ignore) { + case 0: { + if (rect.x1 > rect.x2) { + e.x0 = std::numeric_limits::infinity(); + e.x1 = -std::numeric_limits::infinity(); + } else { + e.x0 = rect.x1; + e.x1 = rect.x2; + } + if (rect.y1 > rect.y2) { + e.y0 = std::numeric_limits::infinity(); + e.y1 = -std::numeric_limits::infinity(); + } else { + e.y0 = rect.y1; + e.y1 = rect.y2; + } + e.xm = minpos(0); + e.ym = minpos(1); + break; + } + case 1: { + CALL_CPP("update_path_extents", reset_limits(e)); + break; + } + case 2: { e.x0 = std::numeric_limits::infinity(); e.x1 = -std::numeric_limits::infinity(); - } else { - e.x0 = rect.x1; - e.x1 = rect.x2; + if (rect.y1 > rect.y2) { + e.y0 = std::numeric_limits::infinity(); + e.y1 = -std::numeric_limits::infinity(); + } else { + e.y0 = rect.y1; + e.y1 = rect.y2; + } + e.xm = std::numeric_limits::infinity(); + e.ym = minpos(1); + break; } - if (rect.y1 > rect.y2) { + case 3: { + if (rect.x1 > rect.x2) { + e.x0 = std::numeric_limits::infinity(); + e.x1 = -std::numeric_limits::infinity(); + } else { + e.x0 = rect.x1; + e.x1 = rect.x2; + } e.y0 = std::numeric_limits::infinity(); e.y1 = -std::numeric_limits::infinity(); - } else { - e.y0 = rect.y1; - e.y1 = rect.y2; + e.xm = minpos(0); + e.ym = std::numeric_limits::infinity(); + break; + } + default: { + if (rect.x1 > rect.x2) { + e.x0 = std::numeric_limits::infinity(); + e.x1 = -std::numeric_limits::infinity(); + } else { + e.x0 = rect.x1; + e.x1 = rect.x2; + } + if (rect.y1 > rect.y2) { + e.y0 = std::numeric_limits::infinity(); + e.y1 = -std::numeric_limits::infinity(); + } else { + e.y0 = rect.y1; + e.y1 = rect.y2; + } + e.xm = minpos(0); + e.ym = minpos(1); } - e.xm = minpos(0); - e.ym = minpos(1); } CALL_CPP("update_path_extents", (update_path_extents(path, trans, e)));