Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Add angle kwarg to patches.Rectangle #1405

Merged
merged 5 commits into from

4 participants

@dmcdougall
Collaborator

Allows rotation of a rectangle upon instantiation.

Addresses #987.
The old attempt was #1156.

@dmcdougall
Collaborator

Here's an example:

import matplotlib
matplotlib.use('agg')
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
r = Rectangle((0.5, 1.0), 2, 1, angle=45.0)
ax.add_patch(r)
ax.set_xlim(0, 3)
ax.set_ylim(0, 3)
ax.set_aspect('equal')
fig.savefig('rect.pdf')
@pelson
Collaborator

Nice solution to the problem. :+1:

@wkerzendorf

When will this be merged? It's really useful to me.

@dmcdougall
Collaborator

I should add an entry to api_changes or whats_new (one of the other devs should advise me on this). It may be the case we are able to extend this for other artists, too. That should be done in a different pull request, though. This PR was only meant to satisfy the feature request in #987.

@WeatherGod
Collaborator
@dmcdougall
Collaborator

Added a note in whats_new and added a test, too. Go me. When my friend Travis goes green, I consider this ready to merge. Others should review the code for any heinous style issues or hidden treasures.

doc/users/whats_new.rst
@@ -20,6 +20,11 @@ revision, see the :ref:`github-stats`.
new in matplotlib-1.3
=====================
+Initialize a rotated rectangle
+------------------------------
+Damon McDougall extended the `~matplotlib.patches.Rectangle` constructor to
@WeatherGod Collaborator

should be :class:`~matplotlib.patches.Rectangle`

@dmcdougall Collaborator

Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/matplotlib/patches.py
@@ -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.translate(-x, -y).rotate_deg(self._angle).translate(x, y)
self._rect_transform = transforms.BboxTransformTo(bbox)
@WeatherGod Collaborator

Why the translation?

@dmcdougall Collaborator

Because I didn't know rotate_deg_around existed. I will push an update to use that instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@wkerzendorf

@dmcdougall How's your friend Travis going?

@dmcdougall
Collaborator

@wkerzendorf He gave this PR the all-clear. I'm just waiting on some of the other devs to give feedback and merge it. I am against merging my own pull requests unless they're trivial changes.

@pelson pelson merged commit 17e1cf8 into matplotlib:master
@pelson
Collaborator

Thanks @dmcdougall (and @wkerzendorf for the nudging :wink: ). Merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Nov 11, 2012
  1. @dmcdougall

    Add angle kwarg to patches.Rectangle

    dmcdougall authored
    Allows rotation of a rectangle upon instantiation.
  2. @dmcdougall
  3. @dmcdougall
  4. @dmcdougall
  5. @dmcdougall

    Fix sphinx syntax

    dmcdougall authored
This page is out of date. Refresh to see the latest.
View
5 doc/users/whats_new.rst
@@ -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
View
9 lib/matplotlib/patches.py
@@ -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:
@@ -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()
@@ -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()
View
25 lib/matplotlib/tests/test_patches.py
@@ -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():
"""
@@ -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)
Something went wrong with that request. Please try again.