Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f866168

Browse filesBrowse files
authored
Merge pull request #9072 from dstansby/rect-timedelta
Use left/right top/bottom instead of width/height in Rectangle
2 parents 1493192 + 8ee4da2 commit f866168
Copy full SHA for f866168

File tree

Expand file treeCollapse file tree

2 files changed

+90
-45
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+90
-45
lines changed

‎lib/matplotlib/patches.py

Copy file name to clipboardExpand all lines: lib/matplotlib/patches.py
+65-45Lines changed: 65 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -643,29 +643,43 @@ class Rectangle(Patch):
643643
"""
644644

645645
def __str__(self):
646-
pars = self._x, self._y, self._width, self._height, self.angle
646+
pars = self._x0, self._y0, self._width, self._height, self.angle
647647
fmt = "Rectangle(xy=(%g, %g), width=%g, height=%g, angle=%g)"
648648
return fmt % pars
649649

650650
@docstring.dedent_interpd
651651
def __init__(self, xy, width, height, angle=0.0, **kwargs):
652652
"""
653+
Parameters
654+
----------
655+
xy: length-2 tuple
656+
The bottom and left rectangle coordinates
657+
width:
658+
Rectangle width
659+
height:
660+
Rectangle height
661+
angle: float, optional
662+
rotation in degrees anti-clockwise about *xy* (default is 0.0)
663+
fill: bool, optional
664+
Whether to fill the rectangle (default is ``True``)
653665
654-
*angle*
655-
rotation in degrees (anti-clockwise)
656-
657-
*fill* is a boolean indicating whether to fill the rectangle
658-
666+
Notes
667+
-----
659668
Valid kwargs are:
660669
%(Patch)s
661670
"""
662671

663672
Patch.__init__(self, **kwargs)
664673

665-
self._x = xy[0]
666-
self._y = xy[1]
674+
self._x0 = xy[0]
675+
self._y0 = xy[1]
676+
667677
self._width = width
668678
self._height = height
679+
680+
self._x1 = self._x0 + self._width
681+
self._y1 = self._y0 + self._height
682+
669683
self.angle = float(angle)
670684
# Note: This cannot be calculated until this is added to an Axes
671685
self._rect_transform = transforms.IdentityTransform()
@@ -682,56 +696,63 @@ def _update_patch_transform(self):
682696
makes it very important to call the accessor method and
683697
not directly access the transformation member variable.
684698
"""
685-
x = self.convert_xunits(self._x)
686-
y = self.convert_yunits(self._y)
687-
width = self.convert_xunits(self._width)
688-
height = self.convert_yunits(self._height)
689-
bbox = transforms.Bbox.from_bounds(x, y, width, height)
699+
x0, y0, x1, y1 = self._convert_units()
700+
bbox = transforms.Bbox.from_extents(x0, y0, x1, y1)
690701
rot_trans = transforms.Affine2D()
691-
rot_trans.rotate_deg_around(x, y, self.angle)
702+
rot_trans.rotate_deg_around(x0, y0, self.angle)
692703
self._rect_transform = transforms.BboxTransformTo(bbox)
693704
self._rect_transform += rot_trans
694705

706+
def _update_x1(self):
707+
self._x1 = self._x0 + self._width
708+
709+
def _update_y1(self):
710+
self._y1 = self._y0 + self._height
711+
712+
def _convert_units(self):
713+
'''
714+
Convert bounds of the rectangle
715+
'''
716+
x0 = self.convert_xunits(self._x0)
717+
y0 = self.convert_yunits(self._y0)
718+
x1 = self.convert_xunits(self._x1)
719+
y1 = self.convert_yunits(self._y1)
720+
return x0, y0, x1, y1
721+
695722
def get_patch_transform(self):
696723
self._update_patch_transform()
697724
return self._rect_transform
698725

699726
def get_x(self):
700727
"Return the left coord of the rectangle"
701-
return self._x
728+
return self._x0
702729

703730
def get_y(self):
704731
"Return the bottom coord of the rectangle"
705-
return self._y
732+
return self._y0
706733

707734
def get_xy(self):
708735
"Return the left and bottom coords of the rectangle"
709-
return self._x, self._y
736+
return self._x0, self._y0
710737

711738
def get_width(self):
712-
"Return the width of the rectangle"
739+
"Return the width of the rectangle"
713740
return self._width
714741

715742
def get_height(self):
716743
"Return the height of the rectangle"
717744
return self._height
718745

719746
def set_x(self, x):
720-
"""
721-
Set the left coord of the rectangle
722-
723-
ACCEPTS: float
724-
"""
725-
self._x = x
747+
"Set the left coord of the rectangle"
748+
self._x0 = x
749+
self._update_x1()
726750
self.stale = True
727751

728752
def set_y(self, y):
729-
"""
730-
Set the bottom coord of the rectangle
731-
732-
ACCEPTS: float
733-
"""
734-
self._y = y
753+
"Set the bottom coord of the rectangle"
754+
self._y0 = y
755+
self._update_y1()
735756
self.stale = True
736757

737758
def set_xy(self, xy):
@@ -740,25 +761,21 @@ def set_xy(self, xy):
740761
741762
ACCEPTS: 2-item sequence
742763
"""
743-
self._x, self._y = xy
764+
self._x0, self._y0 = xy
765+
self._update_x1()
766+
self._update_y1()
744767
self.stale = True
745768

746769
def set_width(self, w):
747-
"""
748-
Set the width rectangle
749-
750-
ACCEPTS: float
751-
"""
770+
"Set the width of the rectangle"
752771
self._width = w
772+
self._update_x1()
753773
self.stale = True
754774

755775
def set_height(self, h):
756-
"""
757-
Set the width rectangle
758-
759-
ACCEPTS: float
760-
"""
776+
"Set the height of the rectangle"
761777
self._height = h
778+
self._update_y1()
762779
self.stale = True
763780

764781
def set_bounds(self, *args):
@@ -771,15 +788,18 @@ def set_bounds(self, *args):
771788
l, b, w, h = args[0]
772789
else:
773790
l, b, w, h = args
774-
self._x = l
775-
self._y = b
791+
self._x0 = l
792+
self._y0 = b
776793
self._width = w
777794
self._height = h
795+
self._update_x1()
796+
self._update_y1()
778797
self.stale = True
779798

780799
def get_bbox(self):
781-
return transforms.Bbox.from_bounds(self._x, self._y,
782-
self._width, self._height)
800+
x0, y0, x1, y1 = self._convert_units()
801+
return transforms.Bbox.from_extents(self._x0, self._y0,
802+
self._x1, self._y1)
783803

784804
xy = property(get_xy, set_xy)
785805

‎lib/matplotlib/tests/test_patches.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_patches.py
+25Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,3 +362,28 @@ def test_connection_patch():
362362
axesA=ax2, axesB=ax1,
363363
arrowstyle="->")
364364
ax2.add_artist(con)
365+
366+
367+
def test_datetime_rectangle():
368+
# Check that creating a rectangle with timedeltas doesn't fail
369+
from datetime import datetime, timedelta
370+
371+
start = datetime(2017, 1, 1, 0, 0, 0)
372+
delta = timedelta(seconds=16)
373+
patch = mpatches.Rectangle((start, 0), delta, 1)
374+
375+
fig, ax = plt.subplots()
376+
ax.add_patch(patch)
377+
378+
379+
def test_datetime_datetime_fails():
380+
from datetime import datetime
381+
382+
start = datetime(2017, 1, 1, 0, 0, 0)
383+
dt_delta = datetime(1970, 1, 5) # Will be 5 days if units are done wrong
384+
385+
with pytest.raises(TypeError):
386+
mpatches.Rectangle((start, 0), dt_delta, 1)
387+
388+
with pytest.raises(TypeError):
389+
mpatches.Rectangle((0, start), 1, dt_delta)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.