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
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:
@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:
Image saved using the save button in the navigation panel:
Image(s) saved using the save button in the navigation panel after re-sizing:
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.