2012-02-10 238 views

回答

29

只是爲了擴大帝斯曼的正確答案。默認情況下,繪圖沿着一個軸線具有更多的像素。當您添加一個圓時,它通常會以數據單位添加。如果你的座標軸有一個對稱的範圍,那意味着沿着x軸的一個步驟將涉及不同於y軸上的一個步驟的像素數目。因此數據單位中的對稱圓在您的Pixel單位中是不對稱的(您實際看到的)。

正如DSM正確指出的那樣,您可以強制x軸和y軸具有相同數量的像素/數據單元。這是通過使用plt.axis("equal")ax.axis("equal")方法(其中axAxes的實例)完成的。

您還可以繪製一個Ellipse,使其適當縮放以使其看起來像您的情節中的一個圓圈。下面是這種情況的一個例子:

import matplotlib.pyplot as plt 
from matplotlib.patches import Ellipse, Circle 


fig = plt.figure() 
ax1 = fig.add_subplot(211) 
# calculate asymmetry of x and y axes: 
x0, y0 = ax1.transAxes.transform((0, 0)) # lower left in pixels 
x1, y1 = ax1.transAxes.transform((1, 1)) # upper right in pixes 
dx = x1 - x0 
dy = y1 - y0 
maxd = max(dx, dy) 
width = .15 * maxd/dx 
height = .15 * maxd/dy 

# a circle you expect to be a circle, but it is not 
ax1.add_artist(Circle((.5, .5), .15)) 
# an ellipse you expect to be an ellipse, but it's a circle 
ax1.add_artist(Ellipse((.75, .75), width, height)) 
ax2 = fig.add_subplot(212) 

ax2.axis('equal') 
# a circle you expect to be a circle, and it is 
ax2.add_artist(Circle((.5, .5), .15)) 
# an ellipse you expect to be an ellipse, and it is 
ax2.add_artist(Ellipse((.75, .75), width, height)) 

fig.savefig('perfectCircle1.png') 

導致這個數字:

enter image description here

另外,使Axes是正方形的,你可以調整你的身材:

# calculate dimensions of axes 1 in figure units 
x0, y0, dx, dy = ax1.get_position().bounds 
maxd = max(dx, dy) 
width = 6 * maxd/dx 
height = 6 * maxd/dy 

fig.set_size_inches((width, height)) 

fig.savefig('perfectCircle2.png') 

導致:

enter image description here

注意具有axis("equal")選項的第二根軸現在具有x和y軸的相同範圍。該數字已被縮放,以便每個數據的日期單位由相同數量的像素表示。

您還可以將您的座標軸調整爲正方形,即使該數字不是。或者,您可以將Circle的默認轉換更改爲None,這意味着所用的單位是像素。目前我很難成功做到這一點(圓圈是一個圓圈,但不是我想要的位置)。

+0

這比我的更詳細(是),它應該成爲規範的答案。 – DSM 2012-02-10 19:13:10

+0

優秀的答案 - 一個通用的TL; DR確保你馬上做matplotlib.pyplot.axis(「equal」):-) – 2016-10-10 16:49:05

0

我今天遇到同樣的問題,我想我可能有更靈活的解決方案。前面的答案仍然存在兩個主要問題(如果您不使用平等方面函數)。首先,如果您調整整個圖表的大小,則像素數量將發生變化,因此比例將不相同。第二點,如果你對x軸和y軸沒有相同的限制,這個技巧就不起作用。

此解決方案使用自定義對象欺騙mpl。實際上,無論何時你改變一個軸的邊界或你的圖形大小,mpl都會調用一個內部函數,它將橢圓的寬度和高度值乘以變換函數值。由於寬度和高度值存儲在橢圓形物體,一個方法是創建與更新時被調用的函數值的自定義對象,基於當前的斧頭屬性:

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

class GraphDist() : 
    def __init__(self, size, ax, x=True) : 
     self.size = size 
     self.ax = ax 
     self.x = x 

    @property 
    def dist_real(self) : 
     x0, y0 = self.ax.transAxes.transform((0, 0)) # lower left in pixels 
     x1, y1 = self.ax.transAxes.transform((1, 1)) # upper right in pixes 
     value = x1 - x0 if self.x else y1 - y0 
     return value 

    @property 
    def dist_abs(self) : 
     bounds = self.ax.get_xlim() if self.x else self.ax.get_ylim() 
     return bounds[0] - bounds[1] 

    @property 
    def value(self) : 
     return (self.size/self.dist_real) * self.dist_abs 

    def __mul__(self, obj) : 
     return self.value * obj 

fig = plt.figure() 
ax = fig.add_subplot(111) 
ax.set_xlim((0,10)) 
ax.set_ylim((0,5)) 
width = GraphDist(10, ax, True) 
height = GraphDist(10, ax, False) 
ax.add_artist(Ellipse((1, 3), width, height)) 
plt.show()