公司动态
Python matplotlib矢量图输出全攻略:从原理到出版级实战
1. 项目概述为什么用Python画矢量图是必备技能如果你还在用截图、保存为JPG或PNG的方式分享你的数据图表那你可能正在浪费自己宝贵的时间和成果的潜力。作为一名和数据、图表打了十几年交道的从业者我见过太多因为图片格式问题导致的尴尬学术论文投稿时编辑要求提供高分辨率矢量图手忙脚乱重新出图项目报告里的折线图一放大就模糊被领导质疑专业性设计海报需要调整图表颜色和字体却因为位图格式而束手无策。这个项目的核心就是彻底解决这些问题。它关乎的不仅仅是“画图”而是如何高效、专业地生产出可以无限缩放、无损编辑、跨平台通用的高质量图表。Python的matplotlib库是科学计算和数据可视化领域的基石绝大多数人用它生成的是默认的位图如PNG。但它的矢量图输出能力才是其真正价值的体现。掌握这个技能意味着你产出的每一张图都具备了“出版级”的质量可以无缝应用于从学术论文、商业报告到印刷海报的任何场景。简单来说这个项目适合所有需要产出正式图表的人数据科学家、工程师、科研人员、学生甚至是经常需要做PPT的职场人。通过几行代码的调整你就能将日常的分析图表升级为专业资产。接下来我会带你从原理到实操彻底搞懂用matplotlib输出矢量图的方方面面并分享那些官方文档里不会写的“踩坑”经验。2. 核心原理矢量图与位图的本质区别与选型逻辑在动手写代码之前我们必须先弄清楚我们在做什么以及为什么这么做。这决定了后续所有工具选择和参数配置的逻辑。2.1 技术本质数学描述 vs. 像素阵列矢量图如SVG, PDF, EPS和位图如PNG, JPG, BMP的根本区别在于其存储和描述图形的方式。位图Raster Graphics可以理解为一幅“马赛克画”。它由固定数量的像素点组成每个像素点记录一个颜色值。当你保存一张800x600的PNG图时文件里存储的就是这48万个像素点的颜色信息。这种格式的优点是显示速度快色彩表现丰富尤其适合照片类连续色调图像。但致命缺点是分辨率依赖。当你试图放大它时软件只能通过插值算法去“猜测”和填充新的像素结果就是图像变得模糊、出现锯齿。这在学术出版中是完全不可接受的因为期刊印刷可能需要极高的DPI每英寸点数。矢量图Vector Graphics则是一份“绘图指令清单”。它不记录像素而是记录构成图像的一系列数学指令比如“在坐标(0,0)和(100,100)之间画一条1像素宽的黑色线段”、“在坐标(50,50)处画一个半径为20的红色实心圆”。当你放大矢量图时计算机只是重新执行这些指令根据新的画布尺寸重新计算线条和形状的位置与大小。因此放大多少倍都不会失真。这对于由点、线、面、文字构成的图表、示意图、Logo来说是完美的格式。在Python的matplotlib语境下当你调用plt.savefig(‘chart.png’)时matplotlib会在内存中渲染一个固定尺寸比如1000x800像素的位图然后编码成PNG文件。而当你调用plt.savefig(‘chart.pdf’)时matplotlib会生成一份包含所有绘图指令画线、填充、标注文字的PDF文档。2.2 格式选型SVG、PDF、EPS该如何选择matplotlib支持多种矢量格式最常用的是PDF、SVG和EPS。选择哪一个取决于你的下游用途。PDF (Portable Document Format)优点这是最通用、最推荐的首选格式。它本身是一种复合格式可以内嵌字体确保在任何设备上查看时文字显示一致。几乎所有的现代操作系统、文档处理软件Word, LaTeX、阅读器都完美支持。对于包含复杂透明度alpha通道效果的图表PDF也能很好地处理。缺点文件是二进制格式无法直接用文本编辑器查看和简单修改。适用场景绝大多数情况。论文投稿通常要求PDF或EPS、报告嵌入、归档保存。我的经验是除非有特殊要求否则优先存为PDF。SVG (Scalable Vector Graphics)优点基于XML的纯文本格式。这意味着你可以用任何文本编辑器打开它直接查看和修改其中的代码比如改变某个线条的颜色值。它也是Web标准的矢量图形格式可以直接嵌入网页并通过CSS进行样式控制动态交互性好。缺点对于非常复杂的图表例如包含数万个数据点的散点图SVG文件可能会变得非常庞大因为每个图形元素都可能对应一个XML节点。某些老旧的文档处理软件对SVG的支持可能不完美。适用场景需要后期手动微调图形元素时图表需要用于Web前端展示时作为中间格式供设计软件如Adobe Illustrator, Inkscape进一步编辑美化。EPS (Encapsulated PostScript)优点出版行业的传统标准格式尤其在某些严格的学术期刊投稿系统中仍是硬性要求。它是一种更底层的页面描述语言。缺点现代性不如PDF和SVG不支持透明度等一些新特性。在macOS的预览等程序中可能显示不正常但嵌入LaTeX编译时没有问题。适用场景遵守特定投稿指南。只有当期刊或会议明确要求提交EPS格式时才使用它。否则优先使用PDF。注意在matplotlib中保存为EPS格式时如果图表中使用了半透明效果alpha 1可能会导致问题。一个常见的解决方法是在保存前将图形对象的rasterized属性设置为True或者避免在需要存为EPS的图中使用复杂的透明度混合。选择决策流程图内心自问图表最终用在哪儿→ 如果用于网页选SVG用于文档/打印/投稿进入第2步。有无强制格式要求→ 如果要求EPS则存EPS否则进入第3步。是否需要后续人工精细编辑→ 如果需要选SVG如果不需要默认选PDF。理解了这个底层逻辑我们在写代码时就不再是机械地改个后缀名而是清楚地知道每一个参数设置会如何影响最终文件的属性和兼容性。3. 环境准备与基础代码框架工欲善其事必先利其器。确保你的环境正确是避免各种诡异问题的第一步。3.1 依赖库安装与版本确认这个项目的核心依赖就是matplotlib。理论上任何现代版本的matplotlib都支持矢量图输出。但我强烈建议使用较新的版本如3.x以上因为它们对矢量格式的支持更完善Bug更少。# 使用pip安装或升级matplotlib pip install matplotlib --upgrade # 如果你使用Anaconda也可以用conda conda install matplotlib安装后可以在Python中确认版本import matplotlib print(matplotlib.__version__) # 期望看到 3.x.x另一个虽然不是必须但极其推荐的库是scienceplots。它提供了一套预定义的、符合各大顶级期刊如Nature, Science, IEEE出版要求的绘图样式。使用它你可以一键将你的图表风格切换到“学术模式”省去大量手动调整字体、尺寸、边距的繁琐工作。pip install scienceplots3.2 一个可复用的基础绘图与保存模板让我们从一个最基础的例子开始建立肌肉记忆。下面的代码模板涵盖了从创建图表到保存为矢量图的全流程并附上了关键注释。import matplotlib.pyplot as plt import numpy as np # 1. 准备数据示例正弦曲线 x np.linspace(0, 2*np.pi, 100) # 生成0到2π之间的100个点 y np.sin(x) # 2. 创建图形和坐标轴 # figsize 单位是英寸决定了最终输出图像的物理尺寸。DPI每英寸点数与之共同决定位图的像素大小但对矢量图来说DPI主要影响嵌入的位图元素如图片和某些文本的换算。 fig, ax plt.subplots(figsize(6, 4)) # 宽6英寸高4英寸 # 3. 绘制图形 ax.plot(x, y, labelsin(x), colorblue, linewidth2) ax.set_xlabel(X Axis Label, fontsize12) ax.set_ylabel(Y Axis Label, fontsize12) ax.set_title(A Simple Sine Wave, fontsize14) ax.legend() ax.grid(True, linestyle--, alpha0.6) # 添加虚线网格透明度0.6 # 4. 关键步骤保存为矢量图 # dpi 参数在这里对于纯矢量元素线、文字无意义但会影响图中可能存在的栅格化元素。 # bbox_inchestight 是神器它会自动裁剪图形周围多余的空白区域。 output_path ./my_sine_wave.pdf # 可以轻松改为 .svg 或 .eps fig.savefig(output_path, dpi300, bbox_inchestight, pad_inches0.05) # 5. 显示图形可选在脚本中通常保存后就不需要显示了 # plt.show() # 6. 关闭图形释放内存在批量出图时很重要 plt.close(fig) print(f矢量图已保存至{output_path})代码要点解析figsize(6, 4)这是最重要的参数之一。它设定了图形的“物理尺寸”。想象你打印出来的图就是6英寸宽4英寸高。这个尺寸会原封不动地保存在PDF/SVG文件中。后续在Word或LaTeX中插入时可以精确控制大小。savefig()是关键函数。dpi300对于矢量图主体虽无影响但这是一个好习惯确保万一有栅格化部分也是高质量的。bbox_inches‘tight’必须掌握它能自动去除图表周围恼人的多余白边让图形内容紧贴边框。pad_inches0.05在和‘tight’一起使用时可以在裁剪后的图形边缘保留一点点内边距避免坐标轴标签等元素被切掉。把这个模板存下来以后画任何图只需要替换数据准备和绘图部分第1、3步保存部分的代码几乎不用动。4. 高级配置与实战技巧掌握了基础保存后我们会遇到更实际的需求字体嵌入、样式美化、批量导出、与LaTeX的协作。这些是区分“能用”和“好用”的关键。4.1 字体嵌入解决跨平台显示不一致的终极方案这是最常踩坑的地方。你在自己电脑上用微软雅黑画了个图保存为PDF发给别人。对方电脑如果没有安装微软雅黑PDF阅读器就会用其他字体替代导致文字错位、图表布局崩坏。解决方案将字体嵌入PDF文件。matplotlib可以做到这一点。import matplotlib.pyplot as plt import matplotlib from matplotlib import rcParams # 方法一全局设置推荐 rcParams[pdf.fonttype] 42 # 输出TrueType字体兼容性最好 rcParams[ps.fonttype] 42 # 同样适用于EPS输出 # 也可以同时设置svg # rcParams[svg.fonttype] path # 将文字转换为路径一劳永逸但文件稍大且文字不可选 # 方法二在保存时局部设置 plt.rcParams[pdf.fonttype] 42 # 然后正常绘图和保存... fig, ax plt.subplots() ax.plot([1,2,3], [1,4,9]) ax.set_xlabel(这是中文标签, fontpropertiesSimHei) # 指定中文字体 fig.savefig(chart_with_font.pdf)参数解释pdf.fonttype 42这是将字体以TrueType格式嵌入。42是一个魔法数字代表“非嵌入Type 3字体”。Type 3字体是PostScript标准字体但某些阅读器或打印系统可能不支持其所有特性。TrueType嵌入是兼容性最广的方案。中文字体特别处理如果图表中有中文你必须确保系统有该字体并在绘图时通过fontproperties参数明确指定。更一劳永逸的方法是配置matplotlib的默认字体。# 在代码开头设置使用系统中文字体 plt.rcParams[font.sans-serif] [SimHei, DejaVu Sans] # 指定默认字体SimHei是黑体 plt.rcParams[axes.unicode_minus] False # 解决负号‘-’显示为方块的问题实操心得我曾经因为字体问题在论文截止日期前夜差点崩溃。自那以后我在每一个需要导出矢量图的脚本开头都强制加上rcParams[‘pdf.fonttype’] 42和正确的中文字体配置。这就像系安全带习惯了就忘不了但关键时能救命。4.2 使用预定义样式如 scienceplots快速获得出版级图表手动调整每个图的字体大小、线宽、刻度长度、图例边框非常耗时。scienceplots库封装了这些样式。import matplotlib.pyplot as plt import numpy as np # 在导入matplotlib后使用scienceplots样式 plt.style.use([science, ieee]) # ‘ieee’样式包含紧凑的布局适合论文双栏 # plt.style.use([science, nature]) # Nature期刊样式 # plt.style.use([science, scatter]) # 适合散点图 # 后续的绘图代码无需任何样式修改自动应用 fig, ax plt.subplots() x np.linspace(0, 10, 100) for i in range(5): ax.plot(x, np.sin(x i * 0.5), labelfLine {i1}) ax.legend(titleLegend) ax.set_xlabel(Distance (m)) ax.set_ylabel(Amplitude) ax.set_title(Styled with scienceplots) # 保存 fig.savefig(publication_ready.pdf, bbox_inchestight)使用样式后你的图表会立刻变得“专业”起来省去了大量琐碎的调整工作。你可以组合多个样式science是基础ieee/nature等提供了具体的尺寸和字体规范。4.3 批量生成与导出自动化你的工作流在实际项目中我们经常需要为不同的数据集或参数生成一系列图表。手动一个个保存效率太低。import matplotlib.pyplot as plt import numpy as np import os # 假设我们有三组不同的数据要绘图 data_sets { dataset_a: {x: np.linspace(0, 5, 50), y: np.exp(np.linspace(0, 5, 50))}, dataset_b: {x: np.linspace(0, 10, 100), y: np.sin(np.linspace(0, 10, 100))}, dataset_c: {x: np.random.randn(100), y: np.random.randn(100)} } output_dir ./batch_output os.makedirs(output_dir, exist_okTrue) # 创建输出目录 for name, data in data_sets.items(): fig, ax plt.subplots(figsize(5, 3.5)) ax.scatter(data[x], data[y], alpha0.6) # 这里以散点图为例 ax.set_title(fScatter Plot: {name}) ax.set_xlabel(X values) ax.set_ylabel(Y values) ax.grid(True, alpha0.3) # 构建输出文件路径 output_path os.path.join(output_dir, f{name}.pdf) fig.savefig(output_path, dpi300, bbox_inchestight) plt.close(fig) # 非常重要关闭图形以释放内存防止在批量处理时内存泄漏 print(fSaved: {output_path}) print(批量导出完成)关键点使用字典组织数据让代码更清晰易于管理。创建输出目录使用os.makedirs(..., exist_okTrue)避免因目录不存在而报错。循环内创建和关闭图形每次循环都创建新的fig和ax并在保存后立即plt.close(fig)。这是批量出图的最佳实践能有效防止内存随着循环次数增加而不断上涨最终导致程序崩溃。清晰的命名使用数据集的名称name作为文件名的一部分便于后续查找和管理。4.4 与LaTeX珠联璧合生成完美插入的PDF如果你用LaTeX写论文或报告matplotlib生成的PDF可以无缝集成并且保留所有矢量信息和字体。LaTeX端.tex文件\documentclass{article} \usepackage{graphicx} \begin{document} \begin{figure}[htbp] \centering \includegraphics[width0.8\linewidth]{./my_sine_wave.pdf} % 直接引用PDF文件 \caption{This is a sine wave plot generated by matplotlib.} \label{fig:sine} \end{figure} \end{document}Python端需要做的特殊设置 为了让matplotlib的字体与你的LaTeX文档完全一致你可以直接使用LaTeX引擎来渲染图中的所有文字。import matplotlib.pyplot as plt plt.rcParams.update({ text.usetex: True, # 使用LaTeX渲染文本 font.family: serif, # 使用衬线字体与LaTeX文章匹配 # 可能需要指定你的LaTeX命令路径如果遇到错误 # text.latex.preamble: r\usepackage{amsmath} # 添加LaTeX宏包 }) # 此时set_xlabel, set_title等函数中的字符串会被当作LaTeX代码解析 # 你可以写数学公式了 fig, ax plt.subplots() ax.plot([1,2,3], [1,4,9]) ax.set_xlabel(r$\alpha$ (rad)) # 使用LaTeX数学模式 ax.set_ylabel(r$f(\alpha)$) ax.set_title(rA Plot with $\LaTeX$ Typesetting) fig.savefig(latex_plot.pdf)注意启用text.usetex True后图表的渲染速度会变慢因为它需要调用外部的LaTeX引擎。通常只在最终生成用于出版的图表时才开启此选项。在调试和预览阶段建议关闭它以提升效率。5. 常见问题排查与性能优化即使按照指南操作实践中还是会遇到各种问题。这里记录了我踩过的一些坑和解决方案。5.1 文件体积异常增大问题描述一个简单的折线图保存为SVG后居然有几十MB。原因分析SVG文件中每个数据点、每个标记marker都可能是一个独立的XML元素。如果你绘制了包含10万个点的散点图SVG文件就会包含10万个circle标签体积暴增。解决方案对大数据集进行下采样在绘图前如果数据点过于密集可以间隔取样。# 假设有100万个点 x_full, y_full ... # 大数据 stride 1000 # 每隔1000个点取一个 x_plot x_full[::stride] y_plot y_full[::stride] ax.scatter(x_plot, y_plot, s1)使用栅格化对于极大数据集可以将数据部分保存为高分辨率位图嵌入矢量图中。在matplotlib中可以对特定的图形元素设置rasterizedTrue。# 只将散点图部分栅格化坐标轴和标签保持矢量 scatter ax.scatter(x_big, y_big, s1, rasterizedTrue) fig.savefig(hybrid_vector_raster.pdf, dpi300) # 保存时指定高DPI保证栅格部分清晰换用PDF格式PDF格式对于大量简单图形元素的压缩效率通常比SVG高。对于纯图表PDF往往是更优选择。5.2 图形元素丢失或错乱问题描述在Python里显示好好的图保存为PDF后用某些阅读器打开发现图例不见了或者线条颜色变了。原因排查透明度Alpha问题某些老旧的矢量格式如EPS或阅读器对透明度的支持不佳。尝试将alpha参数设置为1完全不透明再测试。复杂路径问题过于复杂的裁剪路径clippath或符号marker可能导致渲染错误。尝试简化图形或使用更简单的标记。后端Backend问题matplotlib使用不同的“后端”来渲染图形。默认的交互式后端如TkAgg, Qt5Agg和保存用的非交互式后端可能略有差异。可以尝试在保存前切换到一个更稳定的非交互式后端。import matplotlib matplotlib.use(Agg) # 切换到‘Agg’后端这是一个可靠的、无界面的渲染后端 import matplotlib.pyplot as plt # ... 绘图代码注意matplotlib.use()必须在import matplotlib.pyplot as plt之前调用且只能调用一次。5.3 保存速度慢问题描述保存一张复杂的矢量图需要十几秒甚至更久。优化策略减少图形复杂度检查是否绘制了不必要的图形元素比如过多的网格线、过于密集的刻度标签。在保存前简化图形对于最终出版图可以关闭交互式功能。plt.ioff() # 关闭交互模式 # ... 绘图代码 fig.savefig(...) plt.ion() # 如果需要再重新打开使用bbox_inches‘tight’的代价这个参数虽然好用但matplotlib需要额外计算图形的精确边界会增加保存时间。如果对布局有绝对把握可以手动调整fig.subplots_adjust()并省略bbox_inches参数。升级库版本新版本的matplotlib通常有性能改进。5.4 与第三方工具协作问题问题描述用Illustrator或Inkscape打开matplotlib生成的SVG/PDF后发现图形被分组或图层结构难以编辑。理解与应对matplotlib生成的矢量文件其内部结构是为了程序化生成优化的不是为了人工编辑优化的。图形元素可能被大量分组g标签。在AI中可以尝试“对象”菜单下的“取消编组”命令多次执行或者使用“释放剪切蒙版”功能。更好的工作流如果预期需要大量人工美化可以在matplotlib中只绘制最核心的数据部分坐标轴、数据线保存为SVG。然后在矢量编辑软件中添加装饰性元素、调整样式。这样能最大程度保持可编辑性。6. 综合实战案例从数据到出版级复合图表让我们通过一个完整的例子串联所有知识点绘制一个包含多个子图、复杂图例、数学公式和自定义标注的复合图表并输出为可用于学术投稿的PDF。import numpy as np import matplotlib.pyplot as plt from scipy import stats # 用于生成一些示例分布 # 1. 全局样式与字体设置 plt.style.use(science) # 应用science样式 plt.rcParams[pdf.fonttype] 42 # 嵌入TrueType字体 plt.rcParams[font.sans-serif] [Arial] # 使用Arial跨平台通用 plt.rcParams[mathtext.fontset] stix # 数学字体 # 2. 准备数据 np.random.seed(42) x np.linspace(0, 10, 200) y1 np.sin(x) y2 np.cos(x) # 生成一些随机数据点用于散点图 x_scatter np.random.normal(5, 1.5, 150) y_scatter 0.5 * x_scatter np.random.normal(0, 0.8, 150) # 生成一些数据用于箱线图 data_box [np.random.normal(i, 1, 50) for i in range(4)] # 3. 创建复合图形 # 使用constrained_layout自动管理子图间距比subplots_adjust更智能 fig, axs plt.subplots(2, 2, figsize(10, 8), constrained_layoutTrue) # 解包四个坐标轴 (ax1, ax2), (ax3, ax4) axs # 4. 绘制子图1双曲线图 ax1.plot(x, y1, labelr$y \sin(x)$, colorC0, linewidth2) # 使用LaTeX数学公式 ax1.plot(x, y2, labelr$y \cos(x)$, colorC1, linewidth2, linestyle--) ax1.fill_between(x, y1, y2, where(y1y2), colorC0, alpha0.3, interpolateTrue) # 填充区域带透明度 ax1.fill_between(x, y1, y2, where(y1y2), colorC1, alpha0.3, interpolateTrue) ax1.set_xlabel(rPhase $\phi$ (rad)) ax1.set_ylabel(Amplitude) ax1.set_title(Trigonometric Functions) ax1.legend(locupper right, frameonTrue, fancyboxTrue, shadowTrue) # 带阴影的图例 ax1.grid(True, linestyle:, alpha0.5) # 5. 绘制子图2带拟合的散点图 scatter ax2.scatter(x_scatter, y_scatter, cnp.sqrt(x_scatter**2 y_scatter**2), cmapviridis, alpha0.7, edgecolorsk, linewidth0.5, s40) # 计算线性回归 slope, intercept, r_value, p_value, std_err stats.linregress(x_scatter, y_scatter) fit_line slope * x intercept ax2.plot(x, fit_line, colorred, linewidth2.5, labelrfFit: $y {slope:.2f}x {intercept:.2f}$) ax2.set_xlabel(Independent Variable) ax2.set_ylabel(Dependent Variable) ax2.set_title(Scatter with Linear Fit\n r($R^2 {:.3f}$).format(r_value**2)) # 标题换行 ax2.legend() # 添加颜色条 cbar fig.colorbar(scatter, axax2, shrink0.8) cbar.set_label(Distance from Origin) # 6. 绘制子图3箱线图 bp ax3.boxplot(data_box, labels[Group A, Group B, Group C, Group D], patch_artistTrue, medianprops{color: black, linewidth: 2}) # 自定义箱体颜色 colors [lightblue, lightgreen, lightpink, lightyellow] for patch, color in zip(bp[boxes], colors): patch.set_facecolor(color) patch.set_alpha(0.7) ax3.set_ylabel(Measurement Value) ax3.set_title(Distribution across Groups) ax3.grid(True, axisy, alpha0.3) # 7. 绘制子图4自定义标注与箭头 ax4.plot(x, np.exp(-x/3) * np.sin(2*x), colordarkgreen, linewidth2) ax4.set_xlabel(Time (s)) ax4.set_ylabel(Signal) ax4.set_title(Damped Oscillation with Annotations) # 添加文本和箭头标注 ax4.annotate(Local Maximum, xy(1.57, 0.6), xytext(3, 0.8), arrowpropsdict(facecolorblack, shrink0.05, width1.5, headwidth8), fontsize10, hacenter) ax4.axvline(x5, colorgray, linestyle--, alpha0.7) ax4.text(5.1, 0.1, Reference Line, rotation90, vabottom, fontsize9) ax4.fill_between(x, 0, np.exp(-x/3) * np.sin(2*x), where(x7), colorred, alpha0.2) ax4.text(8.5, -0.15, Region of Interest, hacenter, fontsize9, styleitalic) # 8. 为整个图形添加大标题 fig.suptitle(Comprehensive Example: Multi-panel Figure for Publication, fontsize16, y1.02) # 9. 保存为高质量矢量图 output_filename comprehensive_publication_figure.pdf fig.savefig(output_filename, dpi600, bbox_inchestight, pad_inches0.02, metadata{Creator: Matplotlib, Title: Publication Figure Example}) plt.close(fig) # 关闭图形释放内存 print(f出版级复合图表已保存为{output_filename}) print(建议使用 Adobe Acrobat 或 macOS 预览 查看以确认字体嵌入和矢量效果。)这个案例涵盖的高级技巧constrained_layoutTrue自动调整子图间距和标签避免重叠比手动调整plt.subplots_adjust()更智能可靠。颜色循环‘C0’, ‘C1’使用matplotlib默认的颜色循环保证图表风格一致。条件填充fill_between(where...)根据条件填充曲线之间的区域。在字符串中使用f-string和LaTeX混合rf‘Fit: $y {slope:.2f}x {intercept:.2f}$’动态生成带公式的图例。箱线图美化自定义箱体颜色和透明度。fig.colorbar()为指定子图添加颜色条并控制其大小 (shrink)。高级标注annotate()带箭头的详细标注。图形级标题fig.suptitle()为整个画布添加总标题。保存元数据在savefig中通过metadata参数添加作者、标题等信息到PDF属性中。生成这个PDF后你可以直接将其插入LaTeX文档或者提交给要求矢量图的学术期刊。它具备了所有专业图表应有的要素清晰的布局、一致的样式、可缩放的矢量图形、嵌入的字体以及丰富的语义信息。