2012-02-10 10 views
20

क्या एक पूर्ण सर्कल प्लॉट करने के लिए matplotlib पाने का कोई तरीका है? वे अंडाकार की तरह दिखते हैं।matplotlib क्यों मेरी मंडलियों को अंडाकार के रूप में साजिश कर रहा है?

+1

आप अपने वीडियो संकल्प जांच की है यह सुनिश्चित करने के लिए कि यह आपके मॉनीटर रिज़ॉल्यूशन जैसा ही है? यह हो सकता है कि आप जो कुछ भी प्रदर्शित कर रहे हैं वह विकृत हो। –

उत्तर

29

बस डीएसएम के सही उत्तर पर विस्तार करने के लिए। डिफ़ॉल्ट रूप से, प्लॉट्स में एक अक्ष के साथ दूसरे पिक्सल होते हैं। जब आप एक सर्कल जोड़ते हैं, तो यह परंपरागत रूप से डेटा इकाइयों में जोड़ा जाता है। यदि आपके अक्षों में एक सममित रेंज है, तो इसका मतलब है कि एक्स अक्ष के साथ एक चरण में आपके वाई अक्ष के साथ एक चरण की तुलना में पिक्सल की एक अलग संख्या शामिल होगी। इसलिए डेटा इकाइयों में एक सममित सर्कल आपकी पिक्सेल इकाइयों में असममित है (जो आप वास्तव में देखते हैं)।

जैसा कि डीएसएम सही ढंग से इंगित करता है, आप एक्स और वाई अक्षों को प्रति डेटा इकाई के बराबर संख्या में पिक्सल के लिए मजबूर कर सकते हैं। यह 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 axes के लिए एक ही सीमा है। आंकड़े को स्केल कर दिया गया है ताकि प्रत्येक की तिथि इकाइयों को समान संख्या में पिक्सेल द्वारा दर्शाया जा सके।

आप अपनी अक्ष को वर्ग के रूप में भी समायोजित कर सकते हैं, भले ही आंकड़ा न हो। या आप मंडल के लिए डिफ़ॉल्ट परिवर्तन को None में बदल सकते हैं, जिसका अर्थ है कि उपयोग की जाने वाली इकाइयां पिक्सेल हैं। मुझे इस समय सफलतापूर्वक ऐसा करने में कठिनाई हो रही है (सर्कल एक सर्कल है, लेकिन जहां मैं इसे होना चाहता हूं)।

+0

यह मेरी तुलना में इतना अधिक विस्तृत है (था) कि यह कैनोलिक जवाब बनना चाहिए। – DSM

+0

उत्कृष्ट उत्तर - आम तौर पर उपयोगी टीएल; डीआर सुनिश्चित करता है कि आप matplotlib.pyplot.axis ("बराबर") तुरंत करें :-) –

0

मुझे आज भी यही समस्या आती है और मुझे लगता है कि मेरे पास अधिक लचीला समाधान हो सकता है। पिछले उत्तर के साथ दो मुख्य समस्याएं बनी रहती हैं (यदि आप समान पहलू फ़ंक्शन का उपयोग नहीं करते हैं)। सबसे पहले यदि आप अपने पूरे ग्राफ का आकार बदलते हैं, तो अनुपात समान नहीं होगा क्योंकि पिक्सल की संख्या बदल जाएगी। दूसरा बिंदु, यह चाल काम नहीं करती है यदि आपके पास xaxis और yaxis के लिए समान lim नहीं है।

यह समाधान एक कस्टम ऑब्जेक्ट का उपयोग कर 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() 
संबंधित मुद्दे