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读取json文件并将数据插入到mongodb的方法
Mar 23 Python
关于Django显示时间你应该知道的一些问题
Dec 25 Python
Python之reload流程实例代码解析
Jan 29 Python
python实现字符串加密成纯数字
Mar 19 Python
Python连接SQLite数据库并进行增册改查操作方法详解
Feb 18 Python
python 计算概率密度、累计分布、逆函数的例子
Feb 25 Python
django从后台返回html代码的实例
Mar 11 Python
Python多进程编程multiprocessing代码实例
Mar 12 Python
Python多线程通信queue队列用法实例分析
Mar 24 Python
深入浅析pycharm中 Make available to all projects的含义
Sep 15 Python
通过Django Admin+HttpRunner1.5.6实现简易接口测试平台
Nov 11 Python
使用python绘制横竖条形图
Apr 21 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
239军机修复记
2021/03/02 无线电
ThinkPHP中html:list标签用法分析
2016/01/09 PHP
php实现的一段简单概率相关代码
2016/05/30 PHP
php array_map使用自定义的函数处理数组中的每个值
2016/10/26 PHP
PHP的PDO预处理语句与存储过程
2019/01/27 PHP
PHP执行系统命令函数实例讲解
2021/03/03 PHP
TNC vs IO BO3 第一场2.13
2021/03/10 DOTA
JQuery的Alert消息框插件使用介绍
2010/10/09 Javascript
Jquery 一次处理多个ajax请求的代码
2011/09/02 Javascript
js控制table合并具体实现
2014/02/20 Javascript
jQuery中弹出iframe内嵌页面元素到父页面并全屏化的实例代码
2016/12/27 Javascript
利用JQUERY实现多个AJAX请求等待的实例
2017/12/14 jQuery
webpack热模块替换(HMR)/热更新的方法
2018/04/05 Javascript
浅谈vue中.vue文件解析流程
2018/04/24 Javascript
11个教程中不常被提及的JavaScript小技巧(推荐)
2019/04/17 Javascript
Vue.js项目实战之多语种网站的功能实现(租车)
2019/08/07 Javascript
webpack 最佳配置指北(推荐)
2020/01/07 Javascript
关于uniApp editor微信滑动问题
2021/01/15 Javascript
python str与repr的区别
2013/03/23 Python
Python批量重命名同一文件夹下文件的方法
2015/05/25 Python
Python 26进制计算实现方法
2015/05/28 Python
Python队列的定义与使用方法示例
2017/06/24 Python
Django实现分页功能
2018/07/02 Python
python opencv图片编码为h264文件的实例
2019/12/12 Python
css3 border-radius属性详解
2017/07/05 HTML / CSS
详解移动端html5页面长按实现高亮全选文本内容的兼容解决方案
2016/12/03 HTML / CSS
俄罗斯金苹果网上化妆品和香水商店:Goldapple
2019/12/01 全球购物
化工机械应届生求职信
2013/11/04 职场文书
2014年党员承诺书范文
2014/05/20 职场文书
Nginx已编译的nginx-添加新模块
2021/04/01 Servers
游戏开发中如何使用CocosCreator进行音效处理
2021/04/14 Javascript
tensorflow中的数据类型dtype用法说明
2021/05/26 Python
python数据可视化JupyterLab实用扩展程序Mito
2021/11/20 Python
剖析后OpLog订阅MongoDB的数据变更就没那么难了
2022/02/24 MongoDB
Oracle用户管理及赋权
2022/04/24 Oracle
通过feDisplacementMap和feImage实现水波特效
2022/04/24 HTML / CSS