简体   繁体   中英

Combining matplotlib quiver and elipses doesn't work

I stumbled upon an unexplained behaviour by matplotlib. If I plot an image using imshow, add quiver plot and an ellipse the quiver plot arrow angle gets corrupted. See sample code below. Executing it makes ellipse and quiver arrow point to different directions even though the angles for both are the same. This happens only when an image is pained with imshow. After a day of debugging I found that setting ylim solves the problem. You can run the code and then uncomment two last lines and run it again. I upgraded matplotlib to the latest version the issue is still there. Do you have the same issue with your installation? Is this a bug or am I missing something else here?

Tested on two Win32 Python 2.7 systems

Thanks!

import numpy as np
import  matplotlib.pyplot as plt
from matplotlib.patches import Ellipse

x,y, width,height,angle=20.0, 20.0, 7.0, 3.0, 160.0

fig = plt.figure(figsize=(12,8))
img=np.zeros((40,40))
ax = fig.add_subplot(111)
ax.imshow(img)
e = Ellipse(xy=(x,y), width=width, height=height, angle=angle)
ax.add_artist(e)
e.set_clip_box(ax.bbox)
e.set_alpha(0.2)
e.set_facecolor('red')
ax.quiver(np.array(x), np.array(y),np.array(x),np.array(x), angles=np.array(angle), headwidth=2, color='green')

#remove comments
#ax.set_xlim([0,40])
#ax.set_ylim([0,40])

Add these lines instead of the current call to ax.imshow :

ax.set_aspect('equal','box')
ax.imshow(img, origin='lower')

the first line makes the axis keep x, y in the same metric, the origin kwarg for imshow makes it use the same (0,0) that most rest of matplotlib does.

A version of your example that's easier to play around with to see what the parts do:

import numpy as np
import  matplotlib.pyplot as plt
from matplotlib.patches import Ellipse

x, y, width, height, angle=10.0, 6.0, 7.0, 3.0, 160.0

fig = plt.figure(figsize=(12,8))
xx, yy = np.meshgrid(range(20), range(20))
img = (2*xx + yy)/40. # something asymmetrical to understand axes

ax1 = fig.add_subplot(121)
ax1.set_aspect('equal','box')
im1 = ax1.imshow(img, interpolation='none')
ax1.set_title('UL imshow origin')
ax2 = fig.add_subplot(122)
im2 = ax2.imshow(img, interpolation='none', origin='lower')
ax2.set_title('LL imshow origin')

def oneEllipse():
    return Ellipse(xy=(x,y), width=width, height=height, angle=angle,
            facecolor='black')
    # Can't define one Ellipse and add it to two axes. Huh. 

for ax in (ax1, ax2):
    ax.add_artist(oneEllipse())
    # quiver can take a bunch of different function signatures
    # comment out the second or the third line to change the signature easily
    qi = ax.quiver(np.array([x, x+1]), np.array([y, y-1]), #
                np.array([width, width*2]),np.array([height, height/2.]),
                #angles='xy', # this uses the U, V args and flips the vectors
                #angles=np.array([angle, angle]), # angles come out the same
                headwidth=2, color=['white', 'red'], zorder=10)

在此处输入图片说明

The ellipse and the imshow flipped together, the origins X, Y of the arrows ditto, angles='xy' flips the arrow directions. Seems right to me, but quiver is finicky.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM