5

I am trying to rotate a matplotlib rectangular patch object about a specific point using the rotate_around() and rotate_deg_around() functions. However, the patch is always rotating about the origin. I am not sure how to ensure that the patch object rotates about a specific point.

Here code is as follows:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib as mpl
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_xlim(-0.05,1);ax.set_ylim(-0.05,1);
grid('on');

#Rotate rectangle patch object
ts = ax.transData
tr = mpl.transforms.Affine2D().rotate_deg_around(0.2,0.5,10)
t= ts + tr

rec0 = patches.Rectangle((0.2,0.5),0.25,0.2,alpha=0.5)
ax.add_patch(rec0)

#Rotated rectangle patch
rect1 = patches.Rectangle((0.2,0.5),0.25,0.2,color='blue',alpha=0.5,transform=t)
ax.add_patch(rect1);

#The (desired) point of rotation
ax.scatter([0.0,0.2],[0.0,0.5],c=['g','r'],zorder=10)
txt = ax.annotate('Desired point of rotation',xy=(0.2,0.5),fontsize=16,\
xytext=(0.25,0.35),arrowprops=dict(arrowstyle="->",connectionstyle="arc3,rad=-.2"))
txt2 = ax.annotate('Actual point of rotation',xy=(0.0,0.0),fontsize=16,\
xytext=(0.15,0.15),arrowprops=dict(arrowstyle="->",connectionstyle="arc3,rad=.2"))

plt.show()

Here is the output of the above code:

enter image description here

I have also tried to do translate, rotate_about_origin, and translate_back. However, the translate transform was not working either. Any help/example of simple translation would also be very useful.

Thank you.

  • I want to mention that all of the solutions to this question are actually doing the wrong transformation. Instead of first transforming to display coordinates and then rotating about a point in display space, one should first rotate in data coordinates and then transform to display coordinates. See the answer to [this follow-up question](http://stackoverflow.com/questions/43000288/unable-to-rotate-a-matplotlib-patch-object-about-a-specific-point-using-rotate-d). – ImportanceOfBeingErnest Mar 24 '17 at 15:59

3 Answers3

5

The coordinates you rotate around are not the data coordinates. You have to transform them first, i.e.

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib as mpl
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_xlim(-0.05,1);ax.set_ylim(-0.05,1);
plt.grid('on');

#Rotate rectangle patch object
ts = ax.transData
coords = ts.transform([0.2, 0.5])
tr = mpl.transforms.Affine2D().rotate_deg_around(coords[0], coords[1], 10)
t= ts + tr

rec0 = patches.Rectangle((0.2,0.5),0.25,0.2,alpha=0.5)
ax.add_patch(rec0)

#Rotated rectangle patch
rect1 = patches.Rectangle((0.2,0.5),0.25,0.2,color='blue',alpha=0.5,transform=t)
ax.add_patch(rect1);

#The (desired) point of rotation
ax.scatter([0.0,0.2],[0.0,0.5],c=['g','r'],zorder=10)
txt = ax.annotate('Desired point of rotation',xy=(0.2,0.5),fontsize=16,\
xytext=(0.25,0.35),arrowprops=dict(arrowstyle="->",connectionstyle="arc3,rad=-.2"))
txt2 = ax.annotate('Actual point of rotation',xy=(0.0,0.0),fontsize=16,\
xytext=(0.15,0.15),arrowprops=dict(arrowstyle="->",connectionstyle="arc3,rad=.2"))

plt.show()

Edit:

Apparently, the code only works for the interactive display, but not when the window is resized or the figure is saved. Compare these two images:

interactive display saved figure

David Zwicker
  • 23,581
  • 6
  • 62
  • 77
  • Hi David, firstly thank you so much for the help and pointing out the problem. Unfortunately, there is something missing still. I mean the object is still not rotating about the red dot (in the picture above), but about some point near it. Here is a [image](https://dl.dropbox.com/u/20104715/Stackoverflow/MatplotlibRotObjectAbtPoint2.png). – Indranil Sinharoy Mar 22 '13 at 11:41
  • When I run my code exactly as posted, the rectangle is rotated correctly in the interactive window. Funny enough this is not the case anymore, if I resize the window or if I save the figure. It seems I didn't get the transformations correctly, but I hope I directed you in the right direction. – David Zwicker Mar 22 '13 at 11:59
  • David, this is really strange! I was executing the code in IPython notebook in inline mode, which always re-sized the figure before embedding into the notebook. So, it seemed that I was always getting the wrong rotation point (of course after adding the coordinate transform as you rightly pointed out). Thanks you very much. – Indranil Sinharoy Mar 22 '13 at 14:40
  • I want to mention that all of the solutions to this question are actually doing the wrong transformation. Instead of first transforming to display coordinates and then rotating about a point in display space, one should first rotate in data coordinates and then transform to display coordinates. See the answer to [this follow-up question](http://stackoverflow.com/questions/43000288/unable-to-rotate-a-matplotlib-patch-object-about-a-specific-point-using-rotate-d). – ImportanceOfBeingErnest Mar 24 '17 at 16:01
0

@David Zwicker, thanks for pointing me to the right direction. The following code works properly in interactive mode (i.e. can re-size the figure window), executed either independently or within the Ipython QtConsole environment. See the embedded figures below. However, it still doesn't work within an Ipython webnotebook environment! Any help/ideas on that would be great. Thank you.

#Imports
import matplotlib.pyplot as plt
import matplotlib as mpl
mpl.rcParams['figure.dpi'] = 80   # default = 80
mpl.rcParams['savefig.dpi'] = 80  # default = 100
import matplotlib.patches as patches
import numpy as np

#Need to ensure that the figure.dpi (for displaying figure window) and 
#savefig.dpi are consistent.

def redraw(event):
    """Redraw the plot on a resize event"""
    if  np.size(plt.get_figlabels()):
        #Need to check if figure is closed or not and only then do the following
        #operations. Else, the following operations will create a new figure
        ax.clear()
        drawRectangles(ax)
        fig.canvas.draw()
    else:
        pass


def drawRectangles(ax):
    """Function to draw the normal and rotated patch in the transformed domain"""
    #Transform for data coordinates to display coordinates
    td2dis = ax.transData
    coords = td2dis.transform([0.2, 0.5])
    #rotate transform
    tr = mpl.transforms.Affine2D().rotate_deg_around(coords[0], coords[1], 10)
    t = td2dis + tr
    rec0 = patches.Rectangle((0.2,0.5),0.25,0.2,color='blue',alpha=0.5)
    ax.add_patch(rec0)
    #Rotated rectangle patch
    rect1 = patches.Rectangle((0.2,0.5),0.25,0.2,color='blue',alpha=0.5,transform=t)
    ax.add_patch(rect1);
    plt.grid()


figSize = (8,6)
fig = plt.figure("Patch rotate",figsize=figSize)

ax = fig.add_subplot(111)
ax.set_xlim(0,1);ax.set_ylim(0,1);
fig.canvas.mpl_connect('resize_event', redraw)
drawRectangles(ax)

plt.savefig("myfigure.png")
plt.show()

Here are some samples from the above code:

Image saved using the savefig( ) function within the code: enter image description here

Image saved using the save button in the navigation panel: enter image description here

Image(s) saved using the save button in the navigation panel after re-sizing: enter image description here enter image description here

  • you should make another question with this answer and please consider deleting this answer... – Saullo G. P. Castro Jun 09 '13 at 10:24
  • I want to mention that all of the solutions to this question are actually doing the wrong transformation. Instead of first transforming to display coordinates and then rotating about a point in display space, one should first rotate in data coordinates and then transform to display coordinates. See the answer to [this follow-up question](http://stackoverflow.com/questions/43000288/unable-to-rotate-a-matplotlib-patch-object-about-a-specific-point-using-rotate-d). – ImportanceOfBeingErnest Mar 24 '17 at 16:01
0

It seems that when saving, Ipython changes the layer out. The transformation for the rotating the rectangle depends on the display coordinate which can be change when zooming or changing the layer out, eg.zooming in the interactive window.

We can just rotated rectangle in the data coordinate. See Rotating a figure (patch) and applying colors in python

While we need "ax.set_aspect('equal')" to avoid the rotated rectangle is deformed.

Community
  • 1
  • 1