धुरी के बाहर मैटप्लोटलिब किंवदंती को घुमाते हुए यह आंकड़ा बॉक्स द्वारा कटऑफ बनाता है


222

मैं निम्नलिखित प्रश्नों से परिचित हूं:

प्लॉट के बाहर एक किंवदंती के साथ मैटलपोटलिब सेवफिग

कथा को कथानक से बाहर कैसे रखा जाए

ऐसा लगता है कि इन सवालों के जवाब में धुरी के सटीक सिकुड़ने के साथ फील करने में सक्षम होने की लक्जरी है ताकि किंवदंती फिट हो जाए।

हालांकि, अक्ष को सिकोड़ना एक आदर्श समाधान नहीं है क्योंकि यह डेटा को छोटा बनाता है जिससे वास्तव में व्याख्या करना अधिक कठिन हो जाता है; खासकर जब इसके जटिल और बहुत सारी चीजें चल रही हैं ... इसलिए एक बड़ी किंवदंती की जरूरत है

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

http://matplotlib.sourceforge.net/users/legend_guide.html#legend-of-complex-plots

जो मैं करने में सक्षम होना चाहूंगा, वह है फिगर बॉक्स के आकार का विस्तार करने के लिए विस्तार से लीजेंड को समायोजित करना।

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(-2*np.pi, 2*np.pi, 0.1)
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.plot(x, np.sin(x), label='Sine')
ax.plot(x, np.cos(x), label='Cosine')
ax.plot(x, np.arctan(x), label='Inverse tan')
lgd = ax.legend(loc=9, bbox_to_anchor=(0.5,0))
ax.grid('on')

ध्यान दें कि अंतिम लेबल 'इनवर्स टैन' वास्तव में फिगर बॉक्स के बाहर है (और बुरी तरह से कटऑफ लगता है - प्रकाशन गुणवत्ता नहीं!) यहां छवि विवरण दर्ज करें

अंत में, मुझे बताया गया है कि आर और लाटेक्स में यह सामान्य व्यवहार है, इसलिए मैं थोड़ा उलझन में हूं कि यह अजगर में इतना मुश्किल क्यों है ... क्या कोई ऐतिहासिक कारण है? क्या इस मामले पर मतलाब भी उतना ही गरीब है?

मेरे पास pastebin http://pastebin.com/grVjc007 पर इस कोड का (केवल थोड़ा) लंबा संस्करण है


10
जहां तक ​​यह क्यों है क्योंकि मैटप्लोटलिब इंटरेक्टिव प्लॉट्स की ओर गियर है, जबकि आर, आदि नहीं हैं। (और हां, मैटलैब इस विशेष मामले में "समान रूप से गरीब" है।) इसे ठीक से करने के लिए, आपको हर बार आकृति को आकार देने, ज़ूम करने या किंवदंती की स्थिति अपडेट होने पर कुल्हाड़ियों को आकार देने के बारे में चिंता करने की आवश्यकता है। (प्रभावी रूप से, इसका मतलब है कि हर बार प्लॉट खींचे जाने की जाँच होती है, जो मंदी की ओर जाता है।) Ggplot, इत्यादि, स्थिर होते हैं, इसलिए वे डिफ़ॉल्ट रूप से ऐसा करते हैं, जबकि matplotlib और matlab नहीं। यह कहा गया है, tight_layout()किंवदंतियों को ध्यान में रखते हुए बदल दिया जाना चाहिए।
जो किंग्टन

3
मैं इस सवाल पर matplotlib यूज़र्स की मेलिंग लिस्ट पर भी चर्चा कर रहा हूँ। इसलिए मेरे पास सेवफिग लाइन को समायोजित करने के सुझाव हैं: fig.savefig ('नमूनाफिगर', bbox_extra_artists = (lgd), bbox = 'tight')
jbbiomod

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

जवाबों:


300

क्षमा करें, ईएमएस, लेकिन मुझे वास्तव में सिर्फ एक और प्रतिक्रिया मिली है matplotlib mailling list (धन्यवाद बेंजामिन रूट की ओर जाता है)।

मैं जिस कोड की तलाश कर रहा हूं वह savefig कॉल को इसमें समायोजित कर रहा है:

fig.savefig('samplefigure', bbox_extra_artists=(lgd,), bbox_inches='tight')
#Note that the bbox_extra_artists must be an iterable

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

import matplotlib.pyplot as plt
import numpy as np

plt.gcf().clear()
x = np.arange(-2*np.pi, 2*np.pi, 0.1)
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.plot(x, np.sin(x), label='Sine')
ax.plot(x, np.cos(x), label='Cosine')
ax.plot(x, np.arctan(x), label='Inverse tan')
handles, labels = ax.get_legend_handles_labels()
lgd = ax.legend(handles, labels, loc='upper center', bbox_to_anchor=(0.5,-0.1))
text = ax.text(-0.2,1.05, "Aribitrary text", transform=ax.transAxes)
ax.set_title("Trigonometry")
ax.grid('on')
fig.savefig('samplefigure', bbox_extra_artists=(lgd,text), bbox_inches='tight')

यह उत्पादन करता है:

[संपादित करें] इस सवाल का इरादा मनमाने ढंग से पाठ के मनमाने समन्वय प्लेसमेंट के उपयोग से पूरी तरह से बचना था क्योंकि इन समस्याओं का पारंपरिक समाधान था। इसके बावजूद, कई संपादनों ने हाल ही में इन्हें डालने पर जोर दिया है, अक्सर ऐसे तरीकों से जो कोड में त्रुटि पैदा करते हैं। मैंने अब मुद्दों को तय कर लिया है और यह दिखाने के लिए मनमाने ढंग से पाठ को टिड्ड कर दिया है कि ये कैसे bbox_extra_artists एल्गोरिथ्म के भीतर माना जाता है।


1
/! (केवल matplotlib से काम करने के लिए लगता है> = 1.0 (डेबियन निचोड़ 0.99 है और यह काम नहीं करता है)
जुलिएन पैलार्ड

1
यह काम करने के लिए नहीं मिल सकता है :( मैं बचाने के लिए lgd में गुजरता हूं, लेकिन यह अभी भी आकार नहीं देता है। समस्या यह हो सकती है कि मैं एक सबप्लॉट का उपयोग नहीं कर रहा हूं।
6005

8
आह! मुझे बस bbox_inches = "टाइट" का उपयोग करने की आवश्यकता थी जैसा आपने किया। धन्यवाद!
6005

7
यह अच्छा है, लेकिन जब मैं इसके लिए कोशिश करता हूं, तब भी मुझे अपना फिगर कट जाता plt.show()है। उसके लिए कोई फिक्स?
अगस्टिनो


23

जोड़ा गया: मुझे कुछ ऐसा मिला, जिसे तुरंत करना चाहिए, लेकिन नीचे दिए गए बाकी कोड भी एक विकल्प प्रदान करते हैं।

subplots_adjust()उपप्लॉट के नीचे ले जाने के लिए फ़ंक्शन का उपयोग करें :

fig.subplots_adjust(bottom=0.2) # <-- Change the 0.02 to work for your plot.

फिर bbox_to_anchorकिंवदंती कमांड के लीजेंड भाग में ऑफसेट के साथ खेलें , जहां आप इसे चाहते हैं, किंवदंती बॉक्स प्राप्त करने के लिए। सेट करने figsizeऔर उपयोग करने के कुछ संयोजन subplots_adjust(bottom=...)को आपके लिए एक गुणवत्ता प्लॉट का उत्पादन करना चाहिए।

वैकल्पिक: मैंने बस लाइन बदल दी है:

fig = plt.figure(1)

सेवा:

fig = plt.figure(num=1, figsize=(13, 13), dpi=80, facecolor='w', edgecolor='k')

और बदल गया

lgd = ax.legend(loc=9, bbox_to_anchor=(0.5,0))

सेवा

lgd = ax.legend(loc=9, bbox_to_anchor=(0.5,-0.02))

और यह मेरी स्क्रीन (24-इंच CRT मॉनिटर) पर ठीक दिखाई देता है।

यहाँ figsize=(M,N)फिगर विंडो को N इंच से M इंच होना चाहिए। बस इसके साथ तब तक खेलें जब तक यह आपके लिए सही न लगे। इसे और अधिक स्केलेबल छवि प्रारूप में कनवर्ट करें और यदि आवश्यक हो तो संपादित करने के लिए जीआईएमपी का उपयोग करें, या viewportग्राफिक्स सहित लाटेक्स विकल्प के साथ बस फसल करें ।


ऐसा लगता है कि यह मौजूदा समय में सबसे अच्छा समाधान है, भले ही इसके लिए अभी भी 'खेल रहे हैं जब तक कि यह अच्छा नहीं लगता है' जो कि एक ऑटोरपोर्ट जनरेटर के लिए एक अच्छा समाधान नहीं है। मैं वास्तव में पहले से ही इस समाधान का उपयोग करता हूं, असली समस्या यह है कि मैट्रिक्स के अक्ष के बॉक्स के बाहर होने के लिए matplotlib गतिशील रूप से क्षतिपूर्ति नहीं करता है। जैसा कि @ जोए ने कहा, टाइट_लेआउट को केवल अक्ष, शीर्षक और लैब्स की तुलना में अधिक विशेषताओं को ध्यान में रखना चाहिए । मैं इसे matplotlib पर एक सुविधा अनुरोध के रूप में जोड़ सकता हूं।
jbbiomed

मेरे लिए एक बड़ी पर्याप्त तस्वीर पाने के लिए भी काम करता है ताकि पहले से काटे जा रहे xlabels को फिट किया जा सके
फ्रेडरिक नॉर्ड

1
यहाँ matplotlib.org से उदाहरण कोड के साथ प्रलेखन है
Yojimbo

14

यहाँ एक और, बहुत मैनुअल समाधान है। आप अक्ष के आकार को परिभाषित कर सकते हैं और पैडिंग को तदनुसार (किंवदंती और टिकमार्क सहित) माना जाता है। आशा है कि यह किसी के लिए उपयोग की है।

उदाहरण (कुल्हाड़ियों का आकार समान है!):

यहां छवि विवरण दर्ज करें

कोड:

#==================================================
# Plot table

colmap = [(0,0,1) #blue
         ,(1,0,0) #red
         ,(0,1,0) #green
         ,(1,1,0) #yellow
         ,(1,0,1) #magenta
         ,(1,0.5,0.5) #pink
         ,(0.5,0.5,0.5) #gray
         ,(0.5,0,0) #brown
         ,(1,0.5,0) #orange
         ]


import matplotlib.pyplot as plt
import numpy as np

import collections
df = collections.OrderedDict()
df['labels']        = ['GWP100a\n[kgCO2eq]\n\nasedf\nasdf\nadfs','human\n[pts]','ressource\n[pts]'] 
df['all-petroleum long name'] = [3,5,2]
df['all-electric']  = [5.5, 1, 3]
df['HEV']           = [3.5, 2, 1]
df['PHEV']          = [3.5, 2, 1]

numLabels = len(df.values()[0])
numItems = len(df)-1
posX = np.arange(numLabels)+1
width = 1.0/(numItems+1)

fig = plt.figure(figsize=(2,2))
ax = fig.add_subplot(111)
for iiItem in range(1,numItems+1):
  ax.bar(posX+(iiItem-1)*width, df.values()[iiItem], width, color=colmap[iiItem-1], label=df.keys()[iiItem])
ax.set(xticks=posX+width*(0.5*numItems), xticklabels=df['labels'])

#--------------------------------------------------
# Change padding and margins, insert legend

fig.tight_layout() #tight margins
leg = ax.legend(loc='upper left', bbox_to_anchor=(1.02, 1), borderaxespad=0)
plt.draw() #to know size of legend

padLeft   = ax.get_position().x0 * fig.get_size_inches()[0]
padBottom = ax.get_position().y0 * fig.get_size_inches()[1]
padTop    = ( 1 - ax.get_position().y0 - ax.get_position().height ) * fig.get_size_inches()[1]
padRight  = ( 1 - ax.get_position().x0 - ax.get_position().width ) * fig.get_size_inches()[0]
dpi       = fig.get_dpi()
padLegend = ax.get_legend().get_frame().get_width() / dpi 

widthAx = 3 #inches
heightAx = 3 #inches
widthTot = widthAx+padLeft+padRight+padLegend
heightTot = heightAx+padTop+padBottom

# resize ipython window (optional)
posScreenX = 1366/2-10 #pixel
posScreenY = 0 #pixel
canvasPadding = 6 #pixel
canvasBottom = 40 #pixel
ipythonWindowSize = '{0}x{1}+{2}+{3}'.format(int(round(widthTot*dpi))+2*canvasPadding
                                            ,int(round(heightTot*dpi))+2*canvasPadding+canvasBottom
                                            ,posScreenX,posScreenY)
fig.canvas._tkcanvas.master.geometry(ipythonWindowSize) 
plt.draw() #to resize ipython window. Has to be done BEFORE figure resizing!

# set figure size and ax position
fig.set_size_inches(widthTot,heightTot)
ax.set_position([padLeft/widthTot, padBottom/heightTot, widthAx/widthTot, heightAx/heightTot])
plt.draw()
plt.show()
#--------------------------------------------------
#==================================================

यह जब तक मैं पहली बार बदल मेरे लिए काम नहीं किया था plt.draw()करने के लिए ax.figure.canvas.draw()। मुझे यकीन नहीं है कि क्यों, लेकिन इस बदलाव से पहले किंवदंती का आकार अपडेट नहीं हो रहा था।
ws_e_c421 23

यदि आप GUI विंडो पर इसका उपयोग करने का प्रयास कर रहे हैं, तो आपको बदलने की आवश्यकता fig.set_size_inches(widthTot,heightTot)है fig.set_size_inches(widthTot,heightTot, forward=True)
ws_e_c421 23
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.