matplotlib出图细节以及提高出图质量(高dpi)

省流总结

  • 在生成figure时,如fig = plt.figure(figsize=(15,10))不能改变其dpi设定。
  • 根据绘图内容,需要确定保存图形最小尺寸,尺寸过小必然影响出图的质量。可以改变show()方法弹出的图像展示窗口尺寸,选出自己满意的尺寸。如发现窗口1000*800像素,显示的图形比较合理,那么就可以确定绘图的尺寸为(1000/100,800/1000),即(10,6).
  • savefig()时,传入要保存的图片的dpi即可,如dpi=600。保存图形时会自动扩大图形像素大小。
  • 选择不同的matplotlib的backendTkAggQtAgg好,无交互窗口的Agg出图比TkAggQtAgg更好。
  • 注意matplotlib版本,有些版本,如3.3.4的matplotlib的savefigshow会相互影响,出现不可预测的问题。升高或者降低版本能解决问题。

原创不易,如果本文对您有帮助的话,还请点赞收藏~

基础知识

  • 屏幕的尺寸:一般以屏幕的对角线尺寸计量,如15.6寸。
  • 屏幕分辨率:是值屏幕水平和竖直方向上拥有的物理像素点数。如:分辨率是 1920x1080。
  • ppi: 屏幕每英寸的像素密度是ppi。比如我的电脑屏幕尺寸 15.6,分辨率是 1920x1080,用长(1920)跟高的像素数(1080)计算出对角方向的像素数(直角三角形)(2202),然后再用对角的像素数除以屏幕尺寸(15.6),就得到ppi,即141. 如果我们指定显示图像的显示像素,那么由ppi,就可以得到图像在电脑上显示的物理尺寸。然而我们对电脑屏幕截图时,生成的图像大小的dpi一般是100或者96,更有甚者是72. matplotlib的show()的dpi,我更倾向于理解为它是一种dpi,指定100即可,太高在屏幕上还要进行扩大,并不能提高显示质量。
  • dpi: dpi是打印机的像素密度。而showfig()里的dpi就是这个概念。在科研绘图中,我们一般被要求图片的dpi至少要为300. 本文就是要分析如何生成高质量的高dpi图片。主要是对比不同例子之间的显示差距,方便读者体会。

探究过程

matplotlib默认出图(作为参照)

这里使用的matplotlib的版本是3.4.0,完全使用matplotlib的默认参数。

from mpl_toolkits.axes_grid1 import host_subplot
from mpl_toolkits import axisartist

import matplotlib
import matplotlib.pyplot as plt

host = host_subplot(111, axes_class=axisartist.Axes)
fig=plt.gcf()
print(fig)
plt.subplots_adjust(right=0.75)

par1 = host.twinx()
par2 = host.twinx()

par2.axis["right"] = par2.new_fixed_axis(loc="right", offset=(60, 0))

par1.axis["right"].toggle(all=True)
par2.axis["right"].toggle(all=True)

p1, = host.plot([0, 1, 2], [0, 1, 2], label="Density")
p2, = par1.plot([0, 1, 2], [0, 3, 2], label="Temperature")
p3, = par2.plot([0, 1, 2], [50, 30, 15], label="Velocity")

host.set_xlim(0, 2)
host.set_ylim(0, 2)
par1.set_ylim(0, 4)
par2.set_ylim(1, 65)

host.set_xlabel("Distance")
host.set_ylabel("Density")
par1.set_ylabel("Temperature")
par2.set_ylabel("Velocity")

host.legend()

host.axis["left"].label.set_color(p1.get_color())
par1.axis["right"].label.set_color(p2.get_color())
par2.axis["right"].label.set_color(p3.get_color())
fig=plt.gcf()
print(fig)
plt.savefig("demo.jpg",dpi=100)
fig=plt.gcf()
print(fig)
plt.show()
fig=plt.gcf()
print(fig)

控制台打印结果:

Backend Qt5Agg is interactive backend. Turning interactive mode on.
Figure(640x480)
Figure(640x480)
Figure(640x480)
Figure(640x480)

在这里插入图片描述

改变图片的默认尺寸

这里使用的matplotlib的版本是3.4.0。
仅改变figure的尺寸,这里缩小一倍:

from mpl_toolkits.axes_grid1 import host_subplot
from mpl_toolkits import axisartist

import matplotlib
import matplotlib.pyplot as plt
fig_width = 8.26
fig_height = 8.77
width = fig_width / 2.54 #3.25英寸
height = fig_height / 2.54#3.45
fig=plt.figure(figsize=(width,height))
print(fig)
host = host_subplot(111, axes_class=axisartist.Axes)
fig=plt.gcf()
print(fig)
plt.subplots_adjust(right=0.75)

par1 = host.twinx()
par2 = host.twinx()

par2.axis["right"] = par2.new_fixed_axis(loc="right", offset=(60, 0))

par1.axis["right"].toggle(all=True)
par2.axis["right"].toggle(all=True)

p1, = host.plot([0, 1, 2], [0, 1, 2], label="Density")
p2, = par1.plot([0, 1, 2], [0, 3, 2], label="Temperature")
p3, = par2.plot([0, 1, 2], [50, 30, 15], label="Velocity")

host.set_xlim(0, 2)
host.set_ylim(0, 2)
par1.set_ylim(0, 4)
par2.set_ylim(1, 65)

host.set_xlabel("Distance")
host.set_ylabel("Density")
par1.set_ylabel("Temperature")
par2.set_ylabel("Velocity")

host.legend()

host.axis["left"].label.set_color(p1.get_color())
par1.axis["right"].label.set_color(p2.get_color())
par2.axis["right"].label.set_color(p3.get_color())
fig=plt.gcf()
print(fig)
plt.savefig("demo.jpg",dpi=100)
fig=plt.gcf()
print(fig)
plt.show()
fig=plt.gcf()
print(fig)

控制台打印出的结果:

Backend Qt5Agg is interactive backend. Turning interactive mode on.
Figure(325x345)
Figure(325x345)
Figure(325x345)
Figure(325x345)
Figure(325x345)

可以看到由于show指定的 dpi 是 100,而屏幕显示一般ppi就是100.而绘图的大小是 3.25*3.45 英寸。所以占屏幕像素的大小是 325*345.

这里的图形如下:
在这里插入图片描述
这里的一些细节就没有显示全,**说明我们改变图片大小时,有些元素是不能等比例缩放的。**如果要显示全最简单的就是增加图片的尺寸。如果真的对图片大小有限制,那么就得对绘图元素的大小进行改变。如果这里的多副y轴的参数。
另外有一点非常重要,就是绘图内容的合理布局需要给它提供合理的尺寸。这个合理的尺寸可以通过手动调节show()弹出窗口,然后测量窗口的尺寸,将其尺寸更新到figure里面,比如如窗口1000*800像素,显示的图形比较合理,那么就可以确定绘图的尺寸为(1000/100,800/1000),即(10,6).

改变matplotlib的show的dpi

这里使用的matplotlib的版本是3.4.0。show()的dpi设定为600.

from mpl_toolkits.axes_grid1 import host_subplot
from mpl_toolkits import axisartist

import matplotlib
matplotlib.use("Qt5Agg")
import matplotlib.pyplot as plt
fig_width = 8.26
fig_height = 8.77
width = fig_width / 2.54
height = fig_height / 2.54
fig=plt.figure(figsize=(6.4,4.8),dpi=600)
print(fig)
host = host_subplot(111, axes_class=axisartist.Axes)
fig=plt.gcf()
print(fig)
plt.subplots_adjust(right=0.75)

par1 = host.twinx()
par2 = host.twinx()

par2.axis["right"] = par2.new_fixed_axis(loc="right", offset=(60, 0))

par1.axis["right"].toggle(all=True)
par2.axis["right"].toggle(all=True)

p1, = host.plot([0, 1, 2], [0, 1, 2], label="Density")
p2, = par1.plot([0, 1, 2], [0, 3, 2], label="Temperature")
p3, = par2.plot([0, 1, 2], [50, 30, 15], label="Velocity")

host.set_xlim(0, 2)
host.set_ylim(0, 2)
par1.set_ylim(0, 4)
par2.set_ylim(1, 65)

font2 = {'family' : 'Times New Roman',
'weight' : 'normal',
'fontsize'   : 30,
         }
# 对于这个AxesHostAxesSubplot,这样设定label是无效的。
host.set_xlabel("Distance",fontdict=font2)
host.set_ylabel("Density")

par1.set_ylabel("Temperature")
par2.set_ylabel("Velocity")

host.legend()

host.axis["left"].label.set_color(p1.get_color())
# 对于这个AxesHostAxesSubplot设定标签的大小,似乎只能用这种方法?
# host.axis["left"].label.set_fontsize(30)
par1.axis["right"].label.set_color(p2.get_color())
par2.axis["right"].label.set_color(p3.get_color())
fig=plt.gcf()
print(fig)
plt.savefig("demo.jpg")
fig=plt.gcf()
print(fig)
fig.show()
fig=plt.gcf()
print(fig)

控制台输出:

Backend Qt5Agg is interactive backend. Turning interactive mode on.
Figure(3290x1015)
Figure(3290x1015)
Figure(3290x1015)
Figure(3290x1015)
Figure(3290x1015)

这里可以看到QtAgg的像素的垂直最大值就1050.再大就会被截断。显示的图如下:

在这里插入图片描述再查看保存的图片:
在这里插入图片描述保存的图片也受到了影响

不同backend的影响

在matplotlib 3.4.0版本上,换用TkAgg作为show的backend,并再次运行上节代码:

控制台输出为

Backend TkAgg is interactive backend. Turning interactive mode on.
Figure(3840x2880)
Figure(3840x2880)
Figure(3840x2880)
Figure(3840x2880)
Figure(3840x2880)

此时显示完整的超大图片。但是由于电脑屏幕的限制,窗口垂直方向上也不能显示完全。
在这里插入图片描述
但保存的图片不受任何的影响。

在这里插入图片描述这里可以看到TkAgg比Qt5Agg好不少,但是show()这个函数没必要设定dpi,不然会改变图片的比例以及显示质量。

改变matplotlib的showfig的dpi

这里使用的matplotlib的版本是3.4.0。


from mpl_toolkits.axes_grid1 import host_subplot
from mpl_toolkits import axisartist

import matplotlib
import matplotlib.pyplot as plt
fig_width = 8.26
fig_height = 8.77
width = fig_width / 2.54
height = fig_height / 2.54
fig=plt.figure(figsize=(6.4,4.8))
print(fig)
host = host_subplot(111, axes_class=axisartist.Axes)
fig=plt.gcf()
print(fig)
plt.subplots_adjust(right=0.75)

par1 = host.twinx()
par2 = host.twinx()

par2.axis["right"] = par2.new_fixed_axis(loc="right", offset=(60, 0))

par1.axis["right"].toggle(all=True)
par2.axis["right"].toggle(all=True)

p1, = host.plot([0, 1, 2], [0, 1, 2], label="Density")
p2, = par1.plot([0, 1, 2], [0, 3, 2], label="Temperature")
p3, = par2.plot([0, 1, 2], [50, 30, 15], label="Velocity")

host.set_xlim(0, 2)
host.set_ylim(0, 2)
par1.set_ylim(0, 4)
par2.set_ylim(1, 65)

host.set_xlabel("Distance")
host.set_ylabel("Density")
par1.set_ylabel("Temperature")
par2.set_ylabel("Velocity")

host.legend()

host.axis["left"].label.set_color(p1.get_color())
par1.axis["right"].label.set_color(p2.get_color())
par2.axis["right"].label.set_color(p3.get_color())
fig=plt.gcf()
print(fig)
plt.savefig("demo.jpg",dpi=600) # 一般论文出图dpi为600就不错了
fig=plt.gcf()
print(fig)
plt.show()
fig=plt.gcf()
print(fig)

关于 fig 的控制台输出:

Backend Qt5Agg is interactive backend. Turning interactive mode on.
Figure(640x480)
Figure(640x480)
Figure(640x480)
Figure(640x480)
Figure(640x480)

输出demo.jpg的信息:
在这里插入图片描述可以看到尺寸增加到了 3840x2800,恰好是 640*6 与 480*6

再 win 自带的画图工具里打开 demo.jpg,然后再调整回原来的大小,跟 show 图形的对比是一致的:

在这里插入图片描述到这里就能完成高dpi的出图的。但是如果你的python版本是3.6,那不能升级matplotlib为3.4.0以上的版本。你使用showfig会出现问题的。

不同版本matplotlib的showfig

如果是matplotlib的版本是3.3.4,运行上一节代码,那么这里大概率就出错了,3.3.4的控制台信息为:

Backend Qt5Agg is interactive backend. Turning interactive mode on.
Figure(640x480)
Figure(640x480)
Figure(640x480)
Figure(106.667x80)
Figure(106.667x80)

show的图片十分诡异:

在这里插入图片描述
保存的图片:

在这里插入图片描述

这里暴露了 matplotlib版本对出图质量的影响。3.3.4版本的savefig的dpi设定会影响到show()。即使这里切换到TkAgg也一样。那么就只能切换到Agg的backend.

低版本matplotlib使用Agg作为backend提高出图质量

from mpl_toolkits.axes_grid1 import host_subplot
from mpl_toolkits import axisartist

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
fig_width = 8.26
fig_height = 8.77
width = fig_width / 2.54
height = fig_height / 2.54
fig=plt.figure(figsize=(6.4,4.8))
print(fig)
host = host_subplot(111, axes_class=axisartist.Axes)
fig=plt.gcf()
print(fig)
plt.subplots_adjust(right=0.75)

par1 = host.twinx()
par2 = host.twinx()

par2.axis["right"] = par2.new_fixed_axis(loc="right", offset=(60, 0))

par1.axis["right"].toggle(all=True)
par2.axis["right"].toggle(all=True)

p1, = host.plot([0, 1, 2], [0, 1, 2], label="Density")
p2, = par1.plot([0, 1, 2], [0, 3, 2], label="Temperature")
p3, = par2.plot([0, 1, 2], [50, 30, 15], label="Velocity")

host.set_xlim(0, 2)
host.set_ylim(0, 2)
par1.set_ylim(0, 4)
par2.set_ylim(1, 65)

font2 = {'family' : 'Times New Roman',
'weight' : 'normal',
'fontsize'   : 30,
         }
# 对于这个AxesHostAxesSubplot,这样设定label是无效的。
host.set_xlabel("Distance",fontdict=font2)
host.set_ylabel("Density")

par1.set_ylabel("Temperature")
par2.set_ylabel("Velocity")

host.legend()

host.axis["left"].label.set_color(p1.get_color())
# 对于这个AxesHostAxesSubplot设定标签的大小,似乎只能用这种方法?
# host.axis["left"].label.set_fontsize(30)
par1.axis["right"].label.set_color(p2.get_color())
par2.axis["right"].label.set_color(p3.get_color())
fig=plt.gcf()
print(fig)
plt.savefig("demo.jpg",dpi=600)
fig=plt.gcf()
print(fig)
fig.show()
fig=plt.gcf()
print(fig)

控制台输出:

Figure(640x480)
Figure(640x480)
Figure(640x480)
Figure(640x480)
demo_host_subplot_raw.py:68: UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure.
  fig.show()
Figure(640x480)

这里可以看到Agg的backend是不支持show方法的。但是保存的图片却没有任何的问题:
在这里插入图片描述
在这里插入图片描述

其他的情况

在进行二维和三维混合出图的时候,也发现了一个问题,就是我们show()以及我们保存的图片的像素大小跟指定的大小有偏差,即使我们是采用Agg作为backend,也不能解决这个问题。那么最简单的解决方法,就是视情况多给一些图片尺寸或者少给图片一些尺寸,进行微调。

  • 29
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
Matplotlib是一个强大的Python数据可视化库,可以用于创建各种类型的图表和图形。根据引用,Matplotlib可以输出矢量图像,例如PDF和SVG,这些图像具有尺度不变性,并且不会丢失细节。而根据引用,Matplotlib也可以输出位图图像,例如PNG,这些图像可以包含透明度和颜色。因此,Matplotlib是非常灵活的,可以满足不同需求的出图需求。 要使用Matplotlib进行图像输出,首先需要导入相关的库和模块,例如numpy和pyplot。然后,可以使用Matplotlib的函数和方法来创建和配置图形,并将其保存为文件。例如,可以使用plot函数创建一个函数图形,然后使用savefig方法将该图形保存为PDF或PNG文件。 下面是一个示例代码,展示了如何使用Matplotlib创建并保存图形: ```python import numpy as np from matplotlib import pyplot as plt # 创建数据 x = np.linspace(-10, 10, 1024) y = np.sinc(x) # 创建图形 plt.plot(x, y) # 保存为PDF文件 plt.savefig('sinc.pdf') # 保存为PNG文件 plt.savefig('sinc.png', c='c') ``` 在这个例子中,我们使用linspace函数创建了一个包含1024个点的x轴数据,然后使用sinc函数计算了对应的y轴数据。接下来,使用plot函数创建了一个函数图形,并使用savefig方法将图形保存为sinc.pdf和sinc.png文件。注意,对于PNG文件,我们还可以指定颜色参数(c='c')来控制保存图像时的颜色。 因此,通过使用Matplotlib的函数和方法,我们可以轻松地创建和保存各种类型的图形文件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月司

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值