Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add angle kwarg to patches.Rectangle #1405

Merged
merged 5 commits into from Nov 13, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions doc/users/whats_new.rst
Expand Up @@ -20,6 +20,11 @@ revision, see the :ref:`github-stats`.
new in matplotlib-1.3
=====================

Initialize a rotated rectangle
------------------------------
Damon McDougall extended the :class:`~matplotlib.patches.Rectangle` constructor
to accept an `angle` kwarg, specifying the rotation of a rectangle in degrees.

Rectangular colorbar extensions
-------------------------------
Andrew Dawson added a new keyword argument *extendrect* to
Expand Down
9 changes: 8 additions & 1 deletion lib/matplotlib/patches.py
Expand Up @@ -539,9 +539,12 @@ def __str__(self):
+ "(%g,%g;%gx%g)" % (self._x, self._y, self._width, self._height)

@docstring.dedent_interpd
def __init__(self, xy, width, height, **kwargs):
def __init__(self, xy, width, height, angle=0.0, **kwargs):
"""

*angle*
rotation in degrees (anti-clockwise)

*fill* is a boolean indicating whether to fill the rectangle

Valid kwargs are:
Expand All @@ -554,6 +557,7 @@ def __init__(self, xy, width, height, **kwargs):
self._y = xy[1]
self._width = width
self._height = height
self._angle = angle
# Note: This cannot be calculated until this is added to an Axes
self._rect_transform = transforms.IdentityTransform()

Expand All @@ -574,7 +578,10 @@ def _update_patch_transform(self):
width = self.convert_xunits(self._width)
height = self.convert_yunits(self._height)
bbox = transforms.Bbox.from_bounds(x, y, width, height)
rot_trans = transforms.Affine2D()
rot_trans.rotate_deg_around(x, y, self._angle)
self._rect_transform = transforms.BboxTransformTo(bbox)
self._rect_transform += rot_trans

def get_patch_transform(self):
self._update_patch_transform()
Expand Down
25 changes: 25 additions & 0 deletions lib/matplotlib/tests/test_patches.py
Expand Up @@ -2,8 +2,11 @@
Tests specific to the patches module.
"""

import numpy as np
from numpy.testing import assert_array_equal
from numpy.testing import assert_almost_equal
from matplotlib.patches import Polygon
from matplotlib.patches import Rectangle

def test_Polygon_close():
"""
Expand Down Expand Up @@ -40,3 +43,25 @@ def test_Polygon_close():
p.set_xy(xyclosed)
assert_array_equal(p.get_xy(), xyclosed)

def test_rotate_rect():
loc = np.asarray([1.0, 2.0])
width = 2
height = 3
angle = 30.0

# A rotated rectangle
rect1 = Rectangle(loc, width, height, angle=angle)

# A non-rotated rectangle
rect2 = Rectangle(loc, width, height)

# Set up an explicit rotation matrix (in radians)
angle_rad = np.pi * angle / 180.0
rotation_matrix = np.array([[np.cos(angle_rad), -np.sin(angle_rad)],
[np.sin(angle_rad), np.cos(angle_rad)]])

# Translate to origin, rotate each vertex, and then translate back
new_verts = np.inner(rotation_matrix, rect2.get_verts() - loc).T + loc

# They should be the same
assert_almost_equal(rect1.get_verts(), new_verts)