Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f866168

Browse 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

File tree

2 files changed

+90
-45
lines changed

2 files changed

+90
-45
lines changed

lib/matplotlib/patches.py

Lines 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

Lines 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)