diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index 7dd29757e35b..e42280f6e29c 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -643,29 +643,43 @@ class Rectangle(Patch): """ def __str__(self): - pars = self._x, self._y, self._width, self._height, self.angle + pars = self._x0, self._y0, self._width, self._height, self.angle fmt = "Rectangle(xy=(%g, %g), width=%g, height=%g, angle=%g)" return fmt % pars @docstring.dedent_interpd def __init__(self, xy, width, height, angle=0.0, **kwargs): """ + Parameters + ---------- + xy: length-2 tuple + The bottom and left rectangle coordinates + width: + Rectangle width + height: + Rectangle height + angle: float, optional + rotation in degrees anti-clockwise about *xy* (default is 0.0) + fill: bool, optional + Whether to fill the rectangle (default is ``True``) - *angle* - rotation in degrees (anti-clockwise) - - *fill* is a boolean indicating whether to fill the rectangle - + Notes + ----- Valid kwargs are: %(Patch)s """ Patch.__init__(self, **kwargs) - self._x = xy[0] - self._y = xy[1] + self._x0 = xy[0] + self._y0 = xy[1] + self._width = width self._height = height + + self._x1 = self._x0 + self._width + self._y1 = self._y0 + self._height + self.angle = float(angle) # Note: This cannot be calculated until this is added to an Axes self._rect_transform = transforms.IdentityTransform() @@ -682,34 +696,47 @@ def _update_patch_transform(self): makes it very important to call the accessor method and not directly access the transformation member variable. """ - x = self.convert_xunits(self._x) - y = self.convert_yunits(self._y) - width = self.convert_xunits(self._width) - height = self.convert_yunits(self._height) - bbox = transforms.Bbox.from_bounds(x, y, width, height) + x0, y0, x1, y1 = self._convert_units() + bbox = transforms.Bbox.from_extents(x0, y0, x1, y1) rot_trans = transforms.Affine2D() - rot_trans.rotate_deg_around(x, y, self.angle) + rot_trans.rotate_deg_around(x0, y0, self.angle) self._rect_transform = transforms.BboxTransformTo(bbox) self._rect_transform += rot_trans + def _update_x1(self): + self._x1 = self._x0 + self._width + + def _update_y1(self): + self._y1 = self._y0 + self._height + + def _convert_units(self): + ''' + Convert bounds of the rectangle + ''' + x0 = self.convert_xunits(self._x0) + y0 = self.convert_yunits(self._y0) + x1 = self.convert_xunits(self._x1) + y1 = self.convert_yunits(self._y1) + return x0, y0, x1, y1 + def get_patch_transform(self): self._update_patch_transform() return self._rect_transform def get_x(self): "Return the left coord of the rectangle" - return self._x + return self._x0 def get_y(self): "Return the bottom coord of the rectangle" - return self._y + return self._y0 def get_xy(self): "Return the left and bottom coords of the rectangle" - return self._x, self._y + return self._x0, self._y0 def get_width(self): - "Return the width of the rectangle" + "Return the width of the rectangle" return self._width def get_height(self): @@ -717,21 +744,15 @@ def get_height(self): return self._height def set_x(self, x): - """ - Set the left coord of the rectangle - - ACCEPTS: float - """ - self._x = x + "Set the left coord of the rectangle" + self._x0 = x + self._update_x1() self.stale = True def set_y(self, y): - """ - Set the bottom coord of the rectangle - - ACCEPTS: float - """ - self._y = y + "Set the bottom coord of the rectangle" + self._y0 = y + self._update_y1() self.stale = True def set_xy(self, xy): @@ -740,25 +761,21 @@ def set_xy(self, xy): ACCEPTS: 2-item sequence """ - self._x, self._y = xy + self._x0, self._y0 = xy + self._update_x1() + self._update_y1() self.stale = True def set_width(self, w): - """ - Set the width rectangle - - ACCEPTS: float - """ + "Set the width of the rectangle" self._width = w + self._update_x1() self.stale = True def set_height(self, h): - """ - Set the width rectangle - - ACCEPTS: float - """ + "Set the height of the rectangle" self._height = h + self._update_y1() self.stale = True def set_bounds(self, *args): @@ -771,15 +788,18 @@ def set_bounds(self, *args): l, b, w, h = args[0] else: l, b, w, h = args - self._x = l - self._y = b + self._x0 = l + self._y0 = b self._width = w self._height = h + self._update_x1() + self._update_y1() self.stale = True def get_bbox(self): - return transforms.Bbox.from_bounds(self._x, self._y, - self._width, self._height) + x0, y0, x1, y1 = self._convert_units() + return transforms.Bbox.from_extents(self._x0, self._y0, + self._x1, self._y1) xy = property(get_xy, set_xy) diff --git a/lib/matplotlib/tests/test_patches.py b/lib/matplotlib/tests/test_patches.py index 7693148bef57..2ea7af52e509 100644 --- a/lib/matplotlib/tests/test_patches.py +++ b/lib/matplotlib/tests/test_patches.py @@ -362,3 +362,28 @@ def test_connection_patch(): axesA=ax2, axesB=ax1, arrowstyle="->") ax2.add_artist(con) + + +def test_datetime_rectangle(): + # Check that creating a rectangle with timedeltas doesn't fail + from datetime import datetime, timedelta + + start = datetime(2017, 1, 1, 0, 0, 0) + delta = timedelta(seconds=16) + patch = mpatches.Rectangle((start, 0), delta, 1) + + fig, ax = plt.subplots() + ax.add_patch(patch) + + +def test_datetime_datetime_fails(): + from datetime import datetime + + start = datetime(2017, 1, 1, 0, 0, 0) + dt_delta = datetime(1970, 1, 5) # Will be 5 days if units are done wrong + + with pytest.raises(TypeError): + mpatches.Rectangle((start, 0), dt_delta, 1) + + with pytest.raises(TypeError): + mpatches.Rectangle((0, start), 1, dt_delta)
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: