Python matplotlib图例放在外侧保存时显示不完整问题解决
作者:Poul_henry 发布时间:2023-10-08 14:05:35
上次说到的,使用如下代码保存矢量图时,放在外侧的图例往往显示不完整:
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()函数进行保存矢量图时,它是通过一个bounding box (bbox, 边界框),进行范围的框定,只将落入该框中的图像进行保存,如果图例没有完全落在该框中,自然不能被保存。
懂得了其原理,再进行解决问题就比较简单了。
这里有两个解决思想:
1. 将没有完全落入该bbox的图像,通过移动的方法,使其完全落入该框中,那么bbox截取的图像即是完整的 (将图像移入bbox中);
2. 改变bbox的大小,使其完全包含该图像,尤其是往往落入bbox外侧的图例 (将bbox扩大到完全包含图像)。
下面分别介绍基于这两个思想解决这个问题的两种方法:
1. 利用函数subplots_adjust()
在该官方文档中可以看到,subplots_adjust()函数的作用是调整子图布局,它包含6个参数,其中4个参数left, right, bottom, top的作用是分别调整子图的左部,右部,底部,顶部的位置,另外2个参数wspace, hspace的作用分别是调整子图之间的左右之间距离和上下之间距离。
其默认数值分别为:
以上述图为例,现考虑既然图例右侧没有显示,则调整subplots_adjust()函数的right参数,使其位置稍往左移,将参数right默认的数值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的图例显示完整,它是通过图像的右侧位置向左移动而被整体包含在保存的图像中完成的。
同理,若legend的位置在图像下侧,使用savefig()保存时也是不完整的,这时需要修改的是函数subplots_adjust()的参数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. 利用函数savefig()
上个博客讲到,使用savefig()函数中的三个参数fname, dpi, format可用以保存矢量图,现用该函数中另一个参数bbox_inches使
未保存到图中的图例包含进来。
下图可以看到,bbox_inches的作用是调整图的bbox, 即bounding box(边界框)
可以看到,当bbox_inches设为'tight'时,它会计算出距该图像的较紧(tight)边界框bbox,并将该选中的框中的图像保存。
这里的较紧的边界框应该是指完全包含该图像的一个矩形,但和图像有一定的填充距离,和Minimum bounding box(最小边界框),个人认为,有一定区别。单位同样是英寸(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种方法的思想,是将图像的右侧边界向左移动,截取该图用以保存的bbox未变;而scatter2.png,即第2种方法的思想,是直接将截取该图用以保存的bbox扩大为整个图像,而将其全部包括。
注:savefig()还有两个参数需要说明
其中一个是pad_inches,它的作用是当前面的bbox_inches为'tight'时,调整图像和bbox之间的填充距离,这里不需要设置,只要选择默认值即可。
个人认为,如果设置pad_inches参数为0,即pad_inches=0,截取图进行保存的bbox就是minimum bounding box (最小边界框)。
另外一个是bbox_extra_artists,它的作用是计算图像的bbox时,将其它的元素也包含进去。
这里举个例子,如果在图像左侧再加一个文本框text,保存图像时希望该文本框包含在bbox中,则可以使用该参数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中,可以考虑使用该参数
来源:https://blog.csdn.net/Poul_henry/article/details/88311964
猜你喜欢
- 我们公司网站的项目都是采用utf-8编码格式的,一天,发现部分电脑打开网站的一个页面是空白页,要在IE下重新选择编码才显示正常。我们网站的编
- <% Function XMLEncode(byVal sText) sText = Replace(sText, "&am
- 本文整理了一部分我们平时在项目中经常遇到的关于go语言JSON数据与结构体之间相互转换的问题及解决办法。基本的序列化首先我们来看一下Go语言
- 本文实例讲述了python 实现的发送邮件模板。分享给大家供大家参考,具体如下:##发送普通txt文件(与发送html邮件不同的是邮件内容设
- 又一个js加密工具:js混淆,完整源代码如下,有点长呵呵:<HTML><HEAD><TITLE>Cunf
- 例如:将日期格式为2009-6-8的转换为2009-06-08,给小于10的数字补上一个0方法一:year(now)
- 比如可以定义开学时间为2009年2月8日,然后程序可以算出,今天距开学那天已经是第几周,非常急需这个程序,忘高手们能提供一个,先谢谢了!自己
- 由于不同的浏览器,比如Internet Explorer 6,Internet Explorer 7,Mozilla Firefox等,对C
- 本文实例讲述了php生成curl命令行的方法。分享给大家供大家参考,具体如下:示例:curl "http://localhost/
- 这篇博客将介绍如何使用Python,Opencv进行二维直方图的计算及绘制(分别用Opencv和Numpy计算),二维直方图可以让我们对不同
- 下面提供生成XML的Google SiteMap代码[ASP版本]。这个代码是生成全站文件链接的地图:<%Server.S
- 其中一种原因:pycharm没有设置系统解析器解决方法打开pycharm->File->Settings->Project
- 事务日志(Transaction logs)是数据库结构中非常重要但又经常被忽略的部分。由于它并不像数据库中的schema那样活跃,因此很少
- string iconv ( string $in_charset , string $out_charset , string $str
- 记录一下PHP连接MySQL的两种方式。先mock一下数据,可以执行一下sql。/*创建数据库*/CREATE DATABASE IF NO
- 前言登录跳转:不同的用户在登录成功之后跳转到不同的网页当中例如:网站管理员登录成功后跳转到网站后台,vip用户登录成功后跳转到vip页面准备
- 关于截取字符串指定长度的自定义函数很多,各式各样!不过大多原理都是一个样,循环字符串判断每一个字符的asc码!我这里也有一个,示例函数如下:
- new fun的执行过程分析,学习面向对象的朋友可以参考下。(1)创建一个新的对象,并让this指针指向它;(2)将函数的prototype
- 从技术上来说,在ASP环境中,读入并管理XML文本的主要方法有三种: 创建MSXML对象,并且将XML文档载入DOM; 使用服务器端嵌入(S
- BIT[(M)]位字段类型。M表示每个值的位数,范围为从1到64。如果M被省略, 默认为1。TINYINT[(M)] [UNSIGNED]