2012-02-10 37 views

Trả lời

29

Chỉ cần để mở rộng câu trả lời đúng của DSM. Theo mặc định, các ô có nhiều pixel dọc theo một trục so với mặt kia. Khi bạn thêm vòng kết nối, nó được thêm theo truyền thống trong đơn vị dữ liệu. Nếu các trục của bạn có một phạm vi đối xứng, điều đó có nghĩa là một bước dọc theo trục x sẽ liên quan đến một số lượng pixel khác nhau so với một bước dọc theo trục y của bạn. Vì vậy, một vòng tròn đối xứng trong các đơn vị dữ liệu là không đối xứng trong các đơn vị Pixel của bạn (những gì bạn thực sự thấy).

Như DSM một cách chính xác chỉ ra, bạn có thể buộc các trục X và Y có số lượng tương đương của pixel trên một đơn vị dữ liệu. Điều này được thực hiện bằng cách sử dụng các phương pháp plt.axis("equal") hoặc ax.axis("equal") (trong đó ax là một phiên bản của Axes).

Bạn cũng có thể rút ra một Ellipse như vậy mà nó được một cách thích hợp quy mô để trông giống như một vòng tròn trên cốt truyện của bạn. Dưới đây là một ví dụ về một trường hợp như vậy:

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') 

dẫn đến con số này:

enter image description here

Ngoài ra, bạn có thể điều chỉnh con số của bạn để các Axes là vuông:

# 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') 

dẫn đến:

enter image description here

Lưu ý cách trục thứ hai, có tùy chọn axis("equal"), giờ đây có cùng phạm vi cho trục x và trục y. Con số đã được thu nhỏ sao cho các đơn vị ngày của mỗi được biểu diễn bằng cùng số lượng pixel.

Bạn cũng có thể điều chỉnh các trục của bạn sẽ được vuông, ngay cả khi con số này không phải là. Hoặc bạn có thể thay đổi biến đổi mặc định cho Vòng kết nối thành None, có nghĩa là các đơn vị được sử dụng là pixel. Tôi gặp khó khăn khi thực hiện thành công việc này vào lúc này (vòng tròn là một vòng tròn, nhưng không phải là nơi tôi muốn nó).

+0

Điều này chi tiết hơn nhiều so với tôi (là) rằng nó sẽ trở thành câu trả lời kinh điển. – DSM

+0

Câu trả lời tuyệt vời - TL thường hữu ích, DR là đảm bảo bạn làm matplotlib.pyplot.axis ("bằng") ngay lập tức :-) –

0

Tôi đã gặp phải cùng một vấn đề ngày hôm nay và tôi nghĩ rằng tôi có thể có một giải pháp linh hoạt hơn. Hai vấn đề chính vẫn còn với câu trả lời trước (nếu bạn không sử dụng chức năng khía cạnh bằng nhau). Trước tiên, nếu bạn thay đổi kích thước toàn bộ biểu đồ, tỷ lệ sẽ không giống nhau vì số lượng pixel sẽ thay đổi. Điểm thứ hai, thủ thuật này không hoạt động nếu bạn không có cùng giới hạn cho xaxis và yaxis.

Giải pháp này thủ đoạn MPL sử dụng một đối tượng tùy chỉnh. Thật vậy, bất cứ khi nào bạn thay đổi một trong các trục lim hoặc kích thước đồ thị của bạn, mpl sẽ gọi một hàm bên trong sẽ lấy giá trị chiều rộng và chiều cao của hình elip nhân với giá trị hàm biến đổi. Vì giá trị chiều rộng và chiều cao được lưu trữ trong đối tượng hình elip, một cách là tạo đối tượng tùy chỉnh với giá trị được cập nhật bất cứ khi nào hàm được gọi, dựa trên thuộc tính axe hiện tại:

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() 
Các vấn đề liên quan