Python matplotlib圖例放在外側(cè)保存時顯示不完整問題解決
上次說到的,使用如下代碼保存矢量圖時,放在外側(cè)的圖例往往顯示不完整:
import numpy as np import matplotlib.pyplot as plt fig, ax = plt.subplots() x1 = np.random.uniform(-10, 10, size=20) x2 = np.random.uniform(-10, 10, size=20) #print(x1) #print(x2) number = [] x11 = [] x12 = [] for i in range(20): number.append(i+1) x11.append(i+1) x12.append(i+1) plt.figure(1) # you can specify the marker size two ways directly: plt.plot(number, x1, 'bo', markersize=20,label='a') # blue circle with size 20 plt.plot(number, x2, 'ro', ms=10,label='b') # ms is just an alias for markersize lgnd=plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0,numpoints=1,fontsize=10) lgnd.legendHandles[0]._legmarker.set_markersize(16) lgnd.legendHandles[1]._legmarker.set_markersize(10) plt.show() fig.savefig('scatter.png',dpi=600)
保存為scatter.png之后的效果為:
可以看到放在圖像右上的圖例只顯示了左邊一小部分。
這里的原因很簡單,使用savefig()函數(shù)進行保存矢量圖時,它是通過一個bounding box (bbox, 邊界框),進行范圍的框定,只將落入該框中的圖像進行保存,如果圖例沒有完全落在該框中,自然不能被保存。
懂得了其原理,再進行解決問題就比較簡單了。
這里有兩個解決思想:
1. 將沒有完全落入該bbox的圖像,通過移動的方法,使其完全落入該框中,那么bbox截取的圖像即是完整的 (將圖像移入bbox中);
2. 改變bbox的大小,使其完全包含該圖像,尤其是往往落入bbox外側(cè)的圖例 (將bbox擴大到完全包含圖像)。
下面分別介紹基于這兩個思想解決這個問題的兩種方法:
1. 利用函數(shù)subplots_adjust()
在該官方文檔中可以看到,subplots_adjust()函數(shù)的作用是調(diào)整子圖布局,它包含6個參數(shù),其中4個參數(shù)left, right, bottom, top的作用是分別調(diào)整子圖的左部,右部,底部,頂部的位置,另外2個參數(shù)wspace, hspace的作用分別是調(diào)整子圖之間的左右之間距離和上下之間距離。
其默認數(shù)值分別為:
以上述圖為例,現(xiàn)考慮既然圖例右側(cè)沒有顯示,則調(diào)整subplots_adjust()函數(shù)的right參數(shù),使其位置稍往左移,將參數(shù)right默認的數(shù)值0.9改為0.8,那么可以得到一個完整的圖例:
import numpy as np import matplotlib.pyplot as plt fig, ax = plt.subplots() x1 = np.random.uniform(-10, 10, size=20) x2 = np.random.uniform(-10, 10, size=20) #print(x1) #print(x2) number = [] x11 = [] x12 = [] for i in range(20): number.append(i+1) x11.append(i+1) x12.append(i+1) plt.figure(1) # you can specify the marker size two ways directly: plt.plot(number, x1, 'bo', markersize=20,label='a') # blue circle with size 20 plt.plot(number, x2, 'ro', ms=10,label='b') # ms is just an alias for markersize lgnd=plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0,numpoints=1,fontsize=10) lgnd.legendHandles[0]._legmarker.set_markersize(16) lgnd.legendHandles[1]._legmarker.set_markersize(10) fig.subplots_adjust(right=0.8) plt.show() fig.savefig('scatter1.png',dpi=600)
保存為scatter1.png之后和scatter.png的對比效果為:
可以看到這時scatter1.png的圖例顯示完整,它是通過圖像的右側(cè)位置向左移動而被整體包含在保存的圖像中完成的。
同理,若legend的位置在圖像下側(cè),使用savefig()保存時也是不完整的,這時需要修改的是函數(shù)subplots_adjust()的參數(shù)bottom,使其向上移,而被包含在截取圖像進行保存的框中,即下文介紹的bbox。
import numpy as np import matplotlib.pyplot as plt fig, ax = plt.subplots() x1 = np.random.uniform(-10, 10, size=20) x2 = np.random.uniform(-10, 10, size=20) #print(x1) #print(x2) number = [] x11 = [] x12 = [] for i in range(20): number.append(i+1) x11.append(i+1) x12.append(i+1) plt.figure(1) # you can specify the marker size two ways directly: plt.plot(number, x1, 'bo', markersize=20,label='a') # blue circle with size 20 plt.plot(number, x2, 'ro', ms=10,label='b') # ms is just an alias for markersize lgnd=plt.legend(bbox_to_anchor=(0.4, -0.1), loc=2, borderaxespad=0,numpoints=1,fontsize=10) lgnd.legendHandles[0]._legmarker.set_markersize(16) lgnd.legendHandles[1]._legmarker.set_markersize(10) plt.show() fig.savefig('scatter#1.png',dpi=600)
由于subplots_adjust()中默認的bottom值為0.1,故添加fig.subplots_adjust(bottom=0.2),使其底部上移,修改為
import numpy as np import matplotlib.pyplot as plt fig, ax = plt.subplots() x1 = np.random.uniform(-10, 10, size=20) x2 = np.random.uniform(-10, 10, size=20) #print(x1) #print(x2) number = [] x11 = [] x12 = [] for i in range(20): number.append(i+1) x11.append(i+1) x12.append(i+1) plt.figure(1) # you can specify the marker size two ways directly: plt.plot(number, x1, 'bo', markersize=20,label='a') # blue circle with size 20 plt.plot(number, x2, 'ro', ms=10,label='b') # ms is just an alias for markersize lgnd=plt.legend(bbox_to_anchor=(0.4, -0.1), loc=2, borderaxespad=0,numpoints=1,fontsize=10) lgnd.legendHandles[0]._legmarker.set_markersize(16) lgnd.legendHandles[1]._legmarker.set_markersize(10) fig.subplots_adjust(bottom=0.2) plt.show() fig.savefig('scatter#1.png',dpi=600)
效果對比:
圖例legend在其它位置同理。
2. 利用函數(shù)savefig()
上個博客講到,使用savefig()函數(shù)中的三個參數(shù)fname, dpi, format可用以保存矢量圖,現(xiàn)用該函數(shù)中另一個參數(shù)bbox_inches使
未保存到圖中的圖例包含進來。
下圖可以看到,bbox_inches的作用是調(diào)整圖的bbox, 即bounding box(邊界框)
可以看到,當bbox_inches設(shè)為'tight'時,它會計算出距該圖像的較緊(tight)邊界框bbox,并將該選中的框中的圖像保存。
這里的較緊的邊界框應(yīng)該是指完全包含該圖像的一個矩形,但和圖像有一定的填充距離,和Minimum bounding box(最小邊界框),個人認為,有一定區(qū)別。單位同樣是英寸(inch)。
這樣圖例就會被bbox包含進去,進而被保存。
完整代碼:
import numpy as np import matplotlib.pyplot as plt fig, ax = plt.subplots() x1 = np.random.uniform(-10, 10, size=20) x2 = np.random.uniform(-10, 10, size=20) #print(x1) #print(x2) number = [] x11 = [] x12 = [] for i in range(20): number.append(i+1) x11.append(i+1) x12.append(i+1) plt.figure(1) # you can specify the marker size two ways directly: plt.plot(number, x1, 'bo', markersize=20,label='a') # blue circle with size 20 plt.plot(number, x2, 'ro', ms=10,label='b') # ms is just an alias for markersize lgnd=plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0,numpoints=1,fontsize=10) lgnd.legendHandles[0]._legmarker.set_markersize(16) lgnd.legendHandles[1]._legmarker.set_markersize(10) #fig.subplots_adjust(right=0.8) plt.show() fig.savefig('scatter2.png',dpi=600,bbox_inches='tight')
保存為scatter2.png,下面是scatter.png, scatter1.png, scatter2.png三張圖的對比:
可以看到,scatter1.png,即第1種方法的思想,是將圖像的右側(cè)邊界向左移動,截取該圖用以保存的bbox未變;而scatter2.png,即第2種方法的思想,是直接將截取該圖用以保存的bbox擴大為整個圖像,而將其全部包括。
注:savefig()還有兩個參數(shù)需要說明
其中一個是pad_inches,它的作用是當前面的bbox_inches為'tight'時,調(diào)整圖像和bbox之間的填充距離,這里不需要設(shè)置,只要選擇默認值即可。
個人認為,如果設(shè)置pad_inches參數(shù)為0,即pad_inches=0,截取圖進行保存的bbox就是minimum bounding box (最小邊界框)。
另外一個是bbox_extra_artists,它的作用是計算圖像的bbox時,將其它的元素也包含進去。
這里舉個例子,如果在圖像左側(cè)再加一個文本框text,保存圖像時希望該文本框包含在bbox中,則可以使用該參數(shù)bbox_extra_artists將text包含進去(實際使用中,即使未使用bbox_extra_artists,保存的圖像也包含該text):
import numpy as np import matplotlib.pyplot as plt fig, ax = plt.subplots() x1 = np.random.uniform(-10, 10, size=20) x2 = np.random.uniform(-10, 10, size=20) #print(x1) #print(x2) number = [] x11 = [] x12 = [] for i in range(20): number.append(i+1) x11.append(i+1) x12.append(i+1) plt.figure(1) # you can specify the marker size two ways directly: plt.plot(number, x1, 'bo', markersize=20,label='a') # blue circle with size 20 plt.plot(number, x2, 'ro', ms=10,label='b') # ms is just an alias for markersize lgnd=plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0,numpoints=1,fontsize=10) lgnd.legendHandles[0]._legmarker.set_markersize(16) lgnd.legendHandles[1]._legmarker.set_markersize(10) text = ax.text(-0.3,1, "test", transform=ax.transAxes) #fig.subplots_adjust(right=0.8) plt.show() fig.savefig('scatter3.png',dpi=600, bbox_extra_artists=(lgnd,text),bbox_inches='tight')
顯示效果:
為防止有的元素沒有被包含在bbox中,可以考慮使用該參數(shù)
到此這篇關(guān)于Python matplotlib圖例放在外側(cè)保存時顯示不完整問題解決的文章就介紹到這了,更多相關(guān)matplotlib外側(cè)保存顯示不完整內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
pyqt 實現(xiàn)QlineEdit 輸入密碼顯示成圓點的方法
今天小編就為大家分享一篇pyqt 實現(xiàn)QlineEdit 輸入密碼顯示成圓點的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-06-06Python基于keras訓(xùn)練實現(xiàn)微笑識別的示例詳解
Keras是一個由Python編寫的開源人工神經(jīng)網(wǎng)絡(luò)庫,可用于深度學(xué)習(xí)模型的設(shè)計、調(diào)試、評估、應(yīng)用和可視化。本文將基于keras訓(xùn)練實現(xiàn)微笑識別效果,需要的可以參考一下2022-01-01