Indranil Sinharoy
Indranil Sinharoy

Reputation: 523

Unable to rotate a matplotlib patch object about a specific point using rotate_around( )

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.

Upvotes: 5

Views: 5832

Answers (3)

Jianhui
Jianhui

Reputation: 1

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.

Upvotes: 0

Indranil Sinharoy
Indranil Sinharoy

Reputation: 523

@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

Upvotes: 0

David Zwicker
David Zwicker

Reputation: 24328

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

Upvotes: 5

Related Questions