Python matplotlib图例放在外侧保存时显示不完整问题解决


Posted in Python onJuly 28, 2020

上次说到的,使用如下代码保存矢量图时,放在外侧的图例往往显示不完整:

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之后的效果为:

Python matplotlib图例放在外侧保存时显示不完整问题解决

可以看到放在图像右上的图例只显示了左边一小部分。

这里的原因很简单,使用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的作用分别是调整子图之间的左右之间距离和上下之间距离。

其默认数值分别为:

Python matplotlib图例放在外侧保存时显示不完整问题解决

以上述图为例,现考虑既然图例右侧没有显示,则调整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的对比效果为: 

Python matplotlib图例放在外侧保存时显示不完整问题解决

可以看到这时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)

效果对比:

Python matplotlib图例放在外侧保存时显示不完整问题解决

图例legend在其它位置同理。 

2. 利用函数savefig()

上个博客讲到,使用savefig()函数中的三个参数fname, dpi, format可用以保存矢量图,现用该函数中另一个参数bbox_inches使

未保存到图中的图例包含进来。

下图可以看到,bbox_inches的作用是调整图的bbox, 即bounding box(边界框)

Python matplotlib图例放在外侧保存时显示不完整问题解决

 可以看到,当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三张图的对比:

Python matplotlib图例放在外侧保存时显示不完整问题解决

可以看到,scatter1.png,即第1种方法的思想,是将图像的右侧边界向左移动,截取该图用以保存的bbox未变;而scatter2.png,即第2种方法的思想,是直接将截取该图用以保存的bbox扩大为整个图像,而将其全部包括。

注:savefig()还有两个参数需要说明

其中一个是pad_inches,它的作用是当前面的bbox_inches为'tight'时,调整图像和bbox之间的填充距离,这里不需要设置,只要选择默认值即可。

Python matplotlib图例放在外侧保存时显示不完整问题解决

个人认为,如果设置pad_inches参数为0,即pad_inches=0,截取图进行保存的bbox就是minimum bounding box (最小边界框)。 

另外一个是bbox_extra_artists,它的作用是计算图像的bbox时,将其它的元素也包含进去。

Python matplotlib图例放在外侧保存时显示不完整问题解决

这里举个例子,如果在图像左侧再加一个文本框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')

显示效果:

Python matplotlib图例放在外侧保存时显示不完整问题解决

 为防止有的元素没有被包含在bbox中,可以考虑使用该参数

到此这篇关于Python matplotlib图例放在外侧保存时显示不完整问题解决的文章就介绍到这了,更多相关matplotlib外侧保存显示不完整内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python爬虫辅助利器PyQuery模块的安装使用攻略
Apr 24 Python
python实现list元素按关键字相加减的方法示例
Jun 09 Python
对pandas中时间窗函数rolling的使用详解
Nov 28 Python
python 格式化输出百分号的方法
Jan 20 Python
python使用pipeline批量读写redis的方法
Feb 18 Python
python函数修饰符@的使用方法解析
Sep 02 Python
python numpy中cumsum的用法详解
Oct 17 Python
python实现吃苹果小游戏
Mar 21 Python
Python过滤掉numpy.array中非nan数据实例
Jun 08 Python
基于matplotlib中ion()和ioff()的使用详解
Jun 16 Python
详解Python openpyxl库的基本应用
Feb 26 Python
Python  Asyncio模块实现的生产消费者模型的方法
Mar 01 Python
Python 如何反方向迭代一个序列
Jul 28 #Python
Python Matplotlib简易教程(小白教程)
Jul 28 #Python
Python把图片转化为pdf代码实例
Jul 28 #Python
关于python3.7安装matplotlib始终无法成功的问题的解决
Jul 28 #Python
Python 合并拼接字符串的方法
Jul 28 #Python
Python reques接口测试框架实现代码
Jul 28 #Python
如何用Matplotlib 画三维图的示例代码
Jul 28 #Python
You might like
php代码把全角数字转为半角数字
2007/12/10 PHP
php join函数应用
2011/05/04 PHP
一个PHP缓存类代码(附详细说明)
2011/06/09 PHP
PHP自定义函数实现assign()数组分配到模板及extract()变量分配到模板功能示例
2018/05/23 PHP
PHP convert_uudecode()函数讲解
2019/02/14 PHP
Gambit vs ForZe BO3 第三场 2.13
2021/03/10 DOTA
比较全的JS checkbox全选、取消全选、删除功能代码
2008/12/19 Javascript
使用AmplifyJS组件配合JavaScript进行编程的指南
2015/07/28 Javascript
JS实现的网页背景闪电闪烁效果代码
2015/10/17 Javascript
jQuery实现下拉框左右移动(全部移动,已选移动)
2016/04/15 Javascript
JS中位置与大小的获取方法
2016/11/22 Javascript
NodeJS父进程与子进程资源共享原理与实现方法
2018/03/16 NodeJs
深入理解JS中Number(),parseInt(),parseFloat()三者比较
2018/08/24 Javascript
es6数值的扩展方法
2019/03/11 Javascript
vue-cli3 项目优化之通过 node 自动生成组件模板 generate View、Component
2019/04/30 Javascript
JS使用H5实现图片预览功能
2019/09/30 Javascript
JS实现TITLE悬停长久显示效果完整示例
2020/02/11 Javascript
详解微信小程序入门从这里出发(登录注册、开发工具、文件及结构介绍)
2020/07/21 Javascript
JavaScript实现多球运动效果
2020/09/07 Javascript
vue 防止页面加载时看到花括号的解决操作
2020/11/09 Javascript
[40:53]完美世界DOTA2联赛PWL S3 Magma vs DLG 第二场 12.18
2020/12/20 DOTA
在Python中使用mongoengine操作MongoDB教程
2015/04/24 Python
Python2.x版本中cmp()方法的使用教程
2015/05/14 Python
Python下调用Linux的Shell命令的方法
2018/06/12 Python
如何基于python实现画不同品种的樱花树
2020/01/03 Python
wxpython自定义下拉列表框过程图解
2020/02/14 Python
Python填充任意颜色,不同算法时间差异分析说明
2020/05/16 Python
老板电器官方购物商城:老板油烟机、燃气灶、消毒柜、电烤箱
2018/05/30 全球购物
德国大型箱包和皮具商店:Koffer
2019/10/01 全球购物
建筑个人求职信范文
2014/01/25 职场文书
2014年关于两会精神的心得体会
2014/03/17 职场文书
承诺书格式
2014/06/03 职场文书
赔偿协议书怎么写
2015/01/28 职场文书
家长对学校的意见和建议
2015/06/03 职场文书
六年级作文之关于梦
2019/10/22 职场文书
使用Redis实现秒杀功能的简单方法
2021/05/08 Redis