2015-10-16 10 views
13

मेरे पास एक मध्यम आकार का सरणी है (उदाहरण के लिए 1500x3000) कि मैं एक छवि है क्योंकि मैं पैमाने पर साजिश करना चाहता हूं। हालांकि, लंबवत और क्षैतिज तराजू बहुत अलग हैं। सरलीकरण के लिए कहें कि एक मीटर/पंक्ति और 10/कॉलम है। साजिश तब एक छवि उत्पन्न करनी चाहिए जो सी है। 1500x30000। मैं विरूपण से बचने के लिए तराजू और पहलू = 1 के लिए kwarg सीमा का उपयोग करता हूं। या तो प्लॉटिंग विंडो (QT4) और imshow() का उपयोग करके या savefig() का उपयोग करके, मैं कभी भी स्केल पर और पूर्ण रिज़ॉल्यूशन पर छवि का उत्पादन करने में सफल नहीं हुआ।matplotlib.pyplot, imshow() और savefig() के साथ पूर्ण रिज़ॉल्यूशन पर प्लॉटिंग?

मैं के रूप में here, here, या here और there या there में संकेत मामले में यह एक बग था कई प्रस्तावित समाधान करने के लिए ध्यान दिया है। मैंने अपने matplotlibrc को बदल दिया है और इसे मेरे प्रदर्शन/savefig विकल्पों को मजबूर करने के लिए ~/.config/matplotlib में रखा है लेकिन इसका कोई फायदा नहीं हुआ है। मैंने pcolormesh() के साथ भी कोशिश की लेकिन सफलता के बिना। मैं अजगरू 14.04 और QT4Agg के रेपो से बैकएंड के रूप में पायथन 2.7 और matplotlib 1.3 का उपयोग करता हूं। मैंने TkAgg भी कोशिश की लेकिन यह धीमा है और एक ही परिणाम देता है। मेरे पास यह धारणा है कि एक्स अक्ष में संकल्प सही है लेकिन यह निश्चित रूप से ऊर्ध्वाधर दिशा में नीचे आ गया है। यहां कोड का एक टुकड़ा है जो मेरी समस्या का अनुकरण करना चाहिए।

import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib.colors 

R, C = 1500, 3000 
DATA = np.random.random((R, C)) 
DATA[::2, :] *= -1 # make every other line negative 
Yi, Xi = 1, 10 # increment 
CMP = 'seismic' 
ImageFormat ='pdf' 
Name = 'Image' 


DataRange = (np.absolute(DATA)).max() # I want my data centred on 0 
EXTENT = [0, Xi*C, 0 ,Yi*R] 
NORM = matplotlib.colors.Normalize(vmin =-DataRange, vmax= DataRange, clip =True) 

for i in range(1,4): 
    Fig=plt.figure(figsize=(45, 10), dpi = 100*i, tight_layout=True) 
    Fig.suptitle(Name+str(i)+'00DPI') 
    ax = Fig.add_subplot(1, 1, 1) 
    Plot = ax.imshow(DATA, cmap=plt.get_cmap(CMP), norm = NORM, extent = EXTENT, aspect = 1, interpolation='none') 
    ax.set_xlabel('metres') 
    ax.set_ylabel('metres') 
    Fig.savefig(Name+str(i)+'00DPI.'+ImageFormat, format = ImageFormat, dpi = Fig.dpi) 
plt.close() 

imshow() में, प्रक्षेप = 'कोई नहीं' या 'निकटतम' या 'द्विरेखीय' किसी कारण से संकल्प परिवर्तन नहीं करता है, हालांकि मुझे लगता है कि अगर मैं इस शो कर इसे कम से कम क्यूटी 4 विंडो में माना जाता है() savefig() के बजाय। ध्यान दें कि संकल्प वही है जो आपने plt.figure (dpi =) में सेट किया है।

मैं इस विचार से बाहर हूं और इस प्रणाली के साथ चीजें कैसे काम करती हैं, इस बारे में मेरी समझ की सीमा पर। किसी भी मदद का बहुत स्वागत है।

अग्रिम धन्यवाद।

+1

एक एसवीजी के रूप में एक विकल्प के रूप में बचत कर रहा है? 'plt.savefig (" test.svg ")' – Eric

+0

मैंने ऊर्ध्वाधर रिज़ॉल्यूशन के संदर्भ में svg के रूप में सुधार सहेजने पर ध्यान नहीं दिया है। – Boorhin

+0

मैंने कोड को संशोधित किया ताकि छवि वैकल्पिक सकारात्मक और नकारात्मक मान लंबवत हो। मुख्य विचार यह है कि यदि छवियों को पूरी तरह से हल किया गया है तो हमें नीले और लाल क्षैतिज पट्टियों को अलग करने में सक्षम होना चाहिए – Boorhin

उत्तर

1

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

यह मेरी व्याख्या है: जब आप आकृति डीपीआई सेट करते हैं, तो आप पूरे आंकड़े (न केवल डेटा क्षेत्र) के डीपीआई सेट कर रहे हैं। मेरे सिस्टम पर, परिणामस्वरूप साजिश क्षेत्र पूरे आंकड़े के लगभग 20% लंबवत पर कब्जा कर रहा है। यदि आप ऊंचाई में 300 डीपीआई और 10 सेट करते हैं, तो आप कुल 300x10x0.2 = 600 पिक्सेल लंबवत डेटा अक्ष के लिए प्राप्त करते हैं, जो 1500 अंक का प्रतिनिधित्व करने के लिए पर्याप्त नहीं हैं, यह मुझे बताता है कि उत्पादन को फिर से क्यों बदला जाना चाहिए। ध्यान दें कि चौड़ाई को कम करना कभी-कभी आकस्मिक रूप से काम करता है क्योंकि यह डेटा प्लॉट द्वारा कब्जे वाले आंकड़े के अंश को बदलता है।

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

यदि निम्न यह करने के लिए सबसे अच्छा तरीका है मैं नहीं पता है, वहाँ अधिक उपयुक्त तरीके और matplotlib में गुण हो सकता है, लेकिन मैं इष्टतम डीपीआई गणना करने के लिए कुछ इस तरह की कोशिश करेंगे:

vsize=ax.get_position().size[1] #fraction of figure occupied by axes 
axesdpi= int((Fig.get_size_inches()[1]*vsize)/R) #(or Yi*R according to what you want to do) 

फिर अपने कोड (पहली पाश करने के लिए कम), हो जाता है:

import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib.colors 

R, C = 1500, 3000 
DATA = np.random.random((R, C)) 
DATA[::2, :] *= -1 # make every other line negative 
Yi, Xi = 1, 10 # increment 
CMP = 'seismic' 
ImageFormat ='pdf' 
Name = 'Image' 


DataRange = (np.absolute(DATA)).max() # I want my data centred on 0 
EXTENT = [0, Xi*C, 0 ,Yi*R] 
NORM = matplotlib.colors.Normalize(vmin =-DataRange, vmax= DataRange, clip =True) 

for i in (1,): 
    print i 
    Fig=plt.figure(figsize=(45, 10), dpi = 100*i, tight_layout=True) 
    Fig.suptitle(Name+str(i)+'00DPI') 
    ax = Fig.add_subplot(1, 1, 1) 
    Plot = ax.imshow(DATA, cmap=plt.get_cmap(CMP), norm = NORM, extent = EXTENT, aspect = 1, interpolation='none') 
    ax.set_xlabel('metres') 
    ax.set_ylabel('metres') 
    vsize=ax.get_position().size[1] #fraction of figure occupied by axes 
    axesdpi= int((Fig.get_size_inches()[1]*vsize)/R) #(or Yi*R according to what you want to do) 
    Fig.savefig(Name+str(axesdpi)+'DPI.'+ImageFormat, format = ImageFormat, dpi = axesdpi) 
    #plt.close() 

यह मेरे लिए काफी काम करता है।

1

सबसे पहले, जब आप .pdf के रूप में सहेज रहे हैं, तो आप पूरी तरह से पीडीएफ बैकएंड का उपयोग कर रहे हैं, भले ही आप अपने विकल्पों में अन्य बैकएंड निर्दिष्ट कर रहे हों। इसका मतलब है कि आपकी छवि वेक्टर प्रारूप में सहेजी गई है और इसलिए डीपीआई बहुत अर्थहीन है। किसी भी संकल्प में, यदि मैं अपने पीडीएफ को एक सभ्य दर्शक में लोड करता हूं (मैंने इंकस्केप का उपयोग किया है, तो अन्य उपलब्ध हैं), आप स्पष्ट रूप से पट्टियों को देख सकते हैं - मुझे वास्तव में यह देखना आसान लगता है कि क्या आप हर दूसरी पंक्ति को शून्य पर सेट करते हैं। जेनरेट किए गए सभी पीडीएफ में पट्टियों को पुन: पेश करने के लिए पूरी जानकारी होती है और इसके परिणामस्वरूप लगभग समान रूप से समान होते हैं। जैसा कि आप figsize=(45, 10) निर्दिष्ट करते हैं, सभी जेनरेट किए गए पीडीएफ ने प्रदर्शन आकार 45 इंच x 10 इंच का सुझाव दिया है।

यदि मैं छवि प्रकार के रूप में png निर्दिष्ट करता हूं, तो मुझे dpi पैरामीटर के आधार पर फ़ाइल आकार में एक अंतर दिखाई देता है, जो मुझे लगता है कि आप क्या उम्मीद कर रहे हैं। यदि आप 100 डीपीआई छवि देखते हैं, तो इसमें 4500000 है, 200 डीपीआई छवि में 18000000 पिक्सल (4x जितने अधिक हैं) और 300 डीपीआई छवि में 40500000 (9एक्स कई) हैं। आप देखेंगे कि 4500000 == 1500 x 3000 यानी आपके मूल सरणी के प्रति सदस्य एक पिक्सेल है। यह तब चलता है, कि बड़ी डीपीआई सेटिंग्स आपको वास्तव में कोई और परिभाषा नहीं प्राप्त करती हैं - इसके बजाय, आपकी धारियां क्रमशः 2 या 3 पिक्सल चौड़ी हैं।

I सोचें जो आप करना चाहते हैं वह प्रभावी रूप से है हर कॉलम 10 बार प्लॉट करें, इसलिए आपको एक छवि 1500 x 30000 पिक्सेल मिलती है। सभी अपने कोड का उपयोग कर ऐसा करने के लिए, आप निम्नलिखित की तरह कुछ करने के लिए इस्तेमाल कर सकते हैं np.repeat:

import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib.colors 

R, C = 1500, 3000 
DATA = np.random.random((R, C)) 
DATA[::2, :] = 0 # make every other line plain white 
Yi, Xi = 1, 10 # increment 
DATA = np.repeat(DATA, Xi, axis=1) 
DATA = np.repeat(DATA, Yi) 

CMP = 'seismic' 
ImageFormat ='pdf' 
Name = 'Image' 


DataRange = (np.absolute(DATA)).max() # I want my data centred on 0 
EXTENT = [0, Xi*C, 0 ,Yi*R] 
NORM = matplotlib.colors.Normalize(vmin =-DataRange, vmax= DataRange, clip =True) 

for i in range(1,4): 
    Fig=plt.figure(figsize=(45, 10), dpi = 100*i, tight_layout=True) 
    Fig.suptitle(Name+str(i)+'00DPI') 
    ax = Fig.add_subplot(1, 1, 1) 
    Plot = ax.imshow(DATA, cmap=plt.get_cmap(CMP), norm = NORM, extent = EXTENT, aspect = 1, interpolation='none') 
    ax.set_xlabel('metres') 
    ax.set_ylabel('metres') 
    Fig.savefig(Name+str(i)+'00DPI.'+ImageFormat, format = ImageFormat, dpi = Fig.dpi) 
plt.close() 

चेतावनी: यह एक स्मृति गहन समाधान - वहाँ बेहतर तरीके वहाँ बाहर हो सकता है।आप pdf की वेक्टर ग्राफिक्स उत्पादन की जरूरत नहीं है, तो आप png


यह मेरे हमलों है कि दूसरी बात यह आप के साथ संबंध हो सकता है चित्र उचित पहलू अनुपात दे रहा है करने के लिए अपने ImageFormat चर बदल सकते हैं (यानी 20 गुना चौड़ा जितना ऊंचा है)। यह आप पहले से ही कर रहे हैं। इसलिए, यदि आप pdf में पिक्सेल के प्रत्येक प्रतिनिधित्व को देखते हैं, तो वे आयताकार (10 गुना चौड़े होते हैं), वर्ग नहीं।

+0

बस स्पष्ट करने के लिए, वृद्धि मीटर में एक पैमाने है। डेटा हर मीटर लंबवत और हर 10 मीटर क्षैतिज नमूना है। तो मैं वास्तव में मूल्यों को दोहराना नहीं चाहता हूं, मैं एक इंटरपोलेशन पसंद करता हूं (एक औसत फ़िल्टर की तरह)। हालांकि मैं समझता हूं कि फिलहाल मेरा कोड उस के लिए डिज़ाइन नहीं किया गया है (मैंने सादगी के लिए उस हिस्से को हटा दिया है)। स्पष्टीकरण के लिए धन्यवाद, मुझे np.repeat फ़ंक्शन नहीं पता था। मैं एक रास्टर प्रारूप का भी उपयोग करूंगा, यह अधिक सार्थक है। यह सिर्फ इतना है कि मैं पीडीएफ में फोंट/अक्ष का प्रतिपादन पसंद करता हूं, फिर मैं प्रकाशन के लिए इनक्सकेप में उन्हें संपादित कर सकता हूं। – Boorhin

संबंधित मुद्दे