2017-03-24 7 views
5

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

एक विशिष्ट आकृति आकार सेट करने के लिए मैं बस plt.figure(figsize = [w, h]) का उपयोग करता हूं, और मैं पैडिंग को हटाने के लिए tight_layout = {'pad': 0} तर्क जोड़ता हूं। यह पूरी तरह से काम करता है, और यहां तक ​​कि अगर मैं एक शीर्षक जोड़ने, वाई/x-लेबल आदि उदाहरण काम करता है:

fig = plt.figure(
    figsize = [3,2], 
    tight_layout = {'pad': 0} 
) 
ax = fig.add_subplot(111) 
plt.title('title') 
ax.set_ylabel('y label') 
ax.set_xlabel('x label') 
plt.savefig('figure01.pdf') 

यह सटीक आकार 3x2 (इंच) के साथ एक पीडीएफ फ़ाइल बनाता है।

figure01.png

मुद्दा रहा है कि जब मैं उदाहरण के लिए अक्ष (आमतौर पर एक किंवदंती बॉक्स) के बाहर एक पाठ बॉक्स जोड़ने के लिए, matplotlib पाठ बॉक्स के लिए जगह बनाने नहीं होती जब खिताब/धुरी को जैसे चाहें यह करता है लेबल। आम तौर पर टेक्स्ट बॉक्स काट दिया जाता है, या सहेजे गए आंकड़े में बिल्कुल नहीं दिखाया जाता है। उदाहरण:

plt.close('all') 
fig = plt.figure(
    figsize = [3,2], 
    tight_layout = {'pad': 0} 
) 
ax = fig.add_subplot(111) 
plt.title('title') 
ax.set_ylabel('y label') 
ax.set_xlabel('x label') 
t = ax.text(0.7, 1.1, 'my text here', bbox = dict(boxstyle = 'round')) 
plt.savefig('figure02.pdf') 

figure02.png

एक समाधान मैं इतना पर कहीं भी पाई savefig आदेश को तर्क bbox_inches = 'tight' जोड़ने के लिए किया गया था। टेक्स्ट बॉक्स अब शामिल था जैसे मैं चाहता था, लेकिन पीडीएफ अब गलत आकार है। ऐसा लगता है कि Matplotlib सिर्फ आंकड़े को बड़ा बनाता है, अक्षरों के आकार को कम करने के बजाय जैसे शीर्षक और एक्स/वाई-लेबल जोड़ता है।

उदाहरण:

plt.close('all') 
fig = plt.figure(
    figsize = [3,2], 
    tight_layout = {'pad': 0} 
) 
ax = fig.add_subplot(111) 
plt.title('title') 
ax.set_ylabel('y label') 
ax.set_xlabel('x label') 
t = ax.text(0.7, 1.1, 'my text here', bbox = dict(boxstyle = 'round')) 
plt.savefig('figure03.pdf', bbox_inches = 'tight') 

figure03.png

वहाँ इस के लिए किसी भी समाधान है कि बस कुल्हाड़ियों के बाहर एक पौराणिक कथा के साथ ज्यादातर मामलों को शामिल किया गया है (यह आंकड़ा 3.307x2.248 है)?

उत्तर

5

तो आवश्यकताएँ हैं:

  1. एक निश्चित, पूर्वनिर्धारित आंकड़ा आकार
  2. होने के लिए एक पाठ लेबल या कथा कुल्हाड़ियों के बाहर जोड़ना
  3. अक्ष और पाठ
  4. कुल्हाड़ियों एक साथ ओवरलैप नहीं कर सकते, के साथ शीर्षक और धुरी लेबल, आकृति सीमा को कसकर बैठता है।

तो tight_layoutpad = 0 साथ, 1. हल करती है और 4. लेकिन 2.

एक के विपरीत है एक बड़ा मूल्य को pad स्थापित करने पर सोच सकता है। यह 2 हल करेगा। हालांकि, चूंकि यह सभी दिशाओं में सममित है, यह विरोधाभास करेगा 4.

bbox_inches = 'tight' का उपयोग आकार के आकार को बदलता है। Contradicts 1.

तो मुझे लगता है कि इस समस्या का कोई सामान्य समाधान नहीं है।

कुछ जो मैं साथ आ सकता हूं वह निम्न है: यह आंकड़े निर्देशांक में पाठ सेट करता है और फिर धुरी को क्षैतिज या लंबवत दिशा में बदलता है जैसे अक्ष और पाठ के बीच कोई ओवरलैप नहीं होता है।

import matplotlib.pyplot as plt 
import matplotlib.transforms 

fig = plt.figure(figsize = [3,2]) 
ax = fig.add_subplot(111) 
plt.title('title') 
ax.set_ylabel('y label') 
ax.set_xlabel('x label') 

def text_legend(ax, x0, y0, text, direction = "v", padpoints = 3, margin=1.,**kwargs): 
    ha = kwargs.pop("ha", "right") 
    va = kwargs.pop("va", "top") 
    t = ax.figure.text(x0, y0, text, ha=ha, va=va, **kwargs) 
    otrans = ax.figure.transFigure 

    plt.tight_layout(pad=0) 
    ax.figure.canvas.draw() 
    plt.tight_layout(pad=0) 
    offs = t._bbox_patch.get_boxstyle().pad * t.get_size() + margin # adding 1pt 
    trans = otrans + \ 
      matplotlib.transforms.ScaledTranslation(-offs/72.,-offs/72.,fig.dpi_scale_trans) 
    t.set_transform(trans) 
    ax.figure.canvas.draw() 

    ppar = [0,-padpoints/72.] if direction == "v" else [-padpoints/72.,0] 
    trans2 = matplotlib.transforms.ScaledTranslation(ppar[0],ppar[1],fig.dpi_scale_trans) + \ 
      ax.figure.transFigure.inverted() 
    tbox = trans2.transform(t._bbox_patch.get_window_extent()) 
    bbox = ax.get_position() 
    if direction=="v": 
     ax.set_position([bbox.x0, bbox.y0,bbox.width, tbox[0][1]-bbox.y0]) 
    else: 
     ax.set_position([bbox.x0, bbox.y0,tbox[0][0]-bbox.x0, bbox.height]) 

# case 1: place text label at top right corner of figure (1,1). Adjust axes height. 
#text_legend(ax, 1,1, 'my text here', bbox = dict(boxstyle = 'round'),) 

# case 2: place text left of axes, (1, y), direction=="v" 
text_legend(ax, 1., 0.8, 'my text here', margin=2., direction="h", bbox = dict(boxstyle = 'round')) 

plt.savefig(__file__+'.pdf') 
plt.show() 

मामले 1 (बाएं) और मामला 2 (दाएं):
enter image description here enter image description here


चल रहा एक पौराणिक कथा के साथ एक ही, थोड़ा आसान है, क्योंकि हम सीधे bbox_to_anchor तर्क और डॉन का उपयोग कर सकते पौराणिक कथाओं के चारों ओर फैंसी बॉक्स को नियंत्रित करने की आवश्यकता नहीं है।

import matplotlib.pyplot as plt 
import matplotlib.transforms 

fig = plt.figure(figsize = [3.5,2]) 
ax = fig.add_subplot(111) 
ax.set_title('title') 
ax.set_ylabel('y label') 
ax.set_xlabel('x label') 
ax.plot([1,2,3], marker="o", label="quantity 1") 
ax.plot([2,1.7,1.2], marker="s", label="quantity 2") 

def legend(ax, x0=1,y0=1, direction = "v", padpoints = 3,**kwargs): 
    otrans = ax.figure.transFigure 
    t = ax.legend(bbox_to_anchor=(x0,y0), loc=1, bbox_transform=otrans,**kwargs) 
    plt.tight_layout(pad=0) 
    ax.figure.canvas.draw() 
    plt.tight_layout(pad=0) 
    ppar = [0,-padpoints/72.] if direction == "v" else [-padpoints/72.,0] 
    trans2=matplotlib.transforms.ScaledTranslation(ppar[0],ppar[1],fig.dpi_scale_trans)+\ 
      ax.figure.transFigure.inverted() 
    tbox = t.get_window_extent().transformed(trans2) 
    bbox = ax.get_position() 
    if direction=="v": 
     ax.set_position([bbox.x0, bbox.y0,bbox.width, tbox.y0-bbox.y0]) 
    else: 
     ax.set_position([bbox.x0, bbox.y0,tbox.x0-bbox.x0, bbox.height]) 

# case 1: place text label at top right corner of figure (1,1). Adjust axes height. 
#legend(ax, borderaxespad=0) 
# case 2: place text left of axes, (1, y), direction=="h" 
legend(ax,y0=0.8, direction="h", borderaxespad=0.2) 

plt.savefig(__file__+'.pdf') 
plt.show() 

enter image description here enter image description here


क्यों 72? 72 अंक प्रति इंच (पीपीआई) की संख्या है। यह एक निश्चित टाइपोग्राफिक इकाई है उदा। फ़ॉन्ट्स हमेशा अंक में दिए जाते हैं (जैसे 12pt)। चूंकि matplotlib फ़ॉन्ट्स के सापेक्ष इकाइयों में टेक्स्ट बॉक्स के पैडिंग को परिभाषित करता है, जो बिंदु है, हमें 72 का उपयोग वापस इंच में बदलने के लिए (और फिर निर्देशांक प्रदर्शित करने के लिए) करने की आवश्यकता है। डिफ़ॉल्ट डॉट्स प्रति इंच (डीपीआई) यहां छुआ नहीं है, लेकिन fig.dpi_scale_trans में इसके लिए जिम्मेदार है। यदि आप डीपीआई को बदलना चाहते हैं तो आपको यह सुनिश्चित करने की ज़रूरत है कि चित्र बनाने के साथ-साथ इसे सहेजते समय चित्र डीपीआई सेट किया गया हो ( dpi=.. पर plt.figure() पर कॉल के साथ-साथ plt.savefig()) का उपयोग करें।

+0

धन्यवाद, यह शानदार है! क्या आप समझते हैं कि कुछ जगहों पर हार्डकोडेड '72' क्या दिखाई देता है? मुझे लगता है कि यह डिफ़ॉल्ट डीपीआई है, लेकिन मुझे यकीन नहीं है। –

+0

मैंने उत्तर में कुछ स्पष्टीकरण जोड़ा। – ImportanceOfBeingErnest

+0

फिर से धन्यवाद। क्या इस काम को किंवदंती के साथ बनाने का कोई आसान तरीका है? अर्थात। जब अक्ष के बाहर एक किंवदंती रखती है। –

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