资讯动态

Matplotlib可视化核心指南:从figure到中文字体与高清导出

发布时间:2026/10/24 9:10:16 来源:尧图企业网站定制
写Matplotlib最折磨人的地方从来不是API记不住而是照着教程画出来了但换个字体就乱码、调个坐标轴就变形、存个高清图又发虚。很多人问现在有Seaborn、Plotly这么方便的可视化库为什么还要回头学Matplotlib我的答案很直接Matplotlib可视化是Python绘图生态的底座pandas的plot接口、Seaborn的高层封装、甚至不少高级库的底层渲染都在依赖它。只要你需要精细控制图表的任何一个细节——坐标轴刻度、图例位置、文字标注、颜色映射早晚要回到Matplotlib。这篇教程不会把官方文档搬一遍而是按我自己的学习路径和踩坑经验带你一次把核心概念、高频绘图、中文字体、布局配色、导出这条链路走通。适合刚接触Python数据分析的同学也适合用Seaborn画过几张图、但一遇到自定义需求就抓耳挠腮的人。1. 为什么这个老牌库依然是可视化的第一选择Matplotlib诞生于2003年最初是模仿MATLAB的绘图风格做的Python库。二十年过去新的可视化工具层出不穷但它依然是数据分析和论文绘图里绕不开的基础设施。必须先把它到底解决了什么问题、和当下流行的工具是什么关系讲清楚你才知道该不该投入时间学。1.1 它解决的核心问题可复现的程序化绘图很多人第一次用Excel画图觉得挺好为什么还要换成代码画图因为Excel的图表是手动操作出来的你拖一次数据、改一次样式下次换一份数据又要重拖一遍。Matplotlib的核心价值是把图表变成一段可执行、可复现、可版本管理的代码。举个例子你有一份每日销售额数据需要每周生成一张折线图发到群里。用Excel做你每周要打开文件、选中数据、修改图例、导出图片用Matplotlib写一个函数数据文件一换图片自动生成连水印、标注、文件名都一起处理好。这就是程序化绘图的威力人只写一次规则机器重复执行。另一个价值是精确控制。论文投稿时期刊经常要求图宽不得小于10厘米、字体统一为小五号、坐标轴刻度朝内这类要求在海量案例里只有Matplotlib这种具备底层控制力的库能一条条做到。Seaborn当然更漂亮但漂亮是它给你设定好的审美Matplotlib是把你直接扔到画室里每种工具都摆在你面前。1.2 和Seaborn、Plotly的定位差异很多新手有个误区学可视化就只学Seaborn因为它画出来好看。实际上Seaborn是建立在Matplotlib之上的高级封装它的每一个图表最终都会转换成Matplotlib的Figure和Axes对象。你用Seaborn画图等于先绕了一层但底层的齿轮还是Matplotlib在转。维度MatplotlibSeabornPlotly控制粒度像素级精细控制中等封装了常用统计图中等偏交互配置默认美观度一般需要手动调好看开箱即用好看支持交互输出形式PNG/PDF/SVG静态图静态图HTML交互页面学习曲线较陡概念多平缓平缓适用场景论文、报表、自定义需求数据探索、统计图形网页展示、仪表盘我个人的建议是入门先把Matplotlib的核心概念吃透然后用Seaborn提升出图效率最后根据场景决定要不要上Plotly。只学Seaborn的问题是当需要调整Seaborn内部某个细节时你还是得回去查Matplotlib文档绕不开。1.3 学习Matplotlib的正确心态别背API理解模型我见过不少人学Matplotlib时抱着一本API手册死记今天记住plt.plot的参数明天忘掉ax.set_xlabel。这样学很痛苦因为Matplotlib的API多到官方文档都列不完。正确的路径是理解它的三层模型画布层、绘图区层、艺术家对象层。你不需要记住几百个函数只需要知道我在哪里画、画在什么区域、这个元素有哪些可调属性。等到需要某个具体功能查文档就行。后文我会按照这个思路逐步展开你会发现Matplotlib一共就那么几件事建画布、绘图形、调细节、存文件。2. 先搞懂figure、axes这对核心概念后面少走一半弯路Matplotlib入门最大的认知门槛就是figure、axes、axis这三个词。很多人画了半年图还是搞不清它们之间的关系。我当年就是直接plt.plot()一把梭等到想画多子图时彻底懵了。这一节把这三个概念一次讲透。2.1 pyplot脚本层和面向对象接口两种写法的区别Matplotlib提供两套使用方式。第一套是直接用plt模块比如plt.plot(x, y)、plt.title(xxx)这是脚本层pyplot接口它内部偷偷维护了一个当前图表的全局状态你调什么函数它就作用到当前图表上。import matplotlib.pyplot as plt import numpy as np x np.linspace(0, 10, 100) y np.sin(x) # pyplot风格隐式跟踪当前figure和axes plt.figure(figsize(8, 5)) plt.plot(x, y) plt.title(sin(x)) plt.xlabel(x) plt.ylabel(y) plt.show()第二套是面向对象接口显式地创建figure和axes对象然后调用它们的方法fig, ax plt.subplots(figsize(8, 5)) ax.plot(x, y) ax.set_title(sin(x)) ax.set_xlabel(x) ax.set_ylabel(y) plt.show()两套写法画出的结果几乎一样。区别在于pyplot风格写起来快适合交互式探索和一两张图的简单场景面向对象风格可控性强特别适合多子图、循环绘图、需要保存figure对象的场景。我推荐从一开始就养成写面向对象风格的习惯因为你在网上看到的复杂图表案例绝大多数都是这种写法。2.2 figure、axes、axis到底各指什么用我们熟悉的画画流程来类比就很容易记住figure画布整张纸。可以包含多个绘图区它负责设置画布大小、分辨率、背景色。axes绘图区画布上的一块区域相当于在纸上框出的一个画框。每个axes有自己的坐标系、坐标轴、刻度、标题。一张figure上可以有一个或多个axes。axis坐标轴axes里的x轴和y轴属于axes的一部分控制刻度位置和刻度标签。搞混这三个词很正常因为它们英文长得很像。记住一个关键关系figure包含axesaxes包含axis。你在plt.subplots(2, 2)时创建的是1个figure和4个axes你调ax.set_xlabel()时改的是某个axes的x轴标签。# 创建一个包含2行2列子图的figure fig, axes plt.subplots(2, 2, figsize(10, 8)) # axes是shape为(2,2)的数组可以用下标访问 axes[0, 0].plot(x, np.sin(x)) axes[0, 0].set_title(sin) axes[0, 1].plot(x, np.cos(x)) axes[0, 1].set_title(cos) axes[1, 0].plot(x, x ** 2) axes[1, 1].plot(x, np.exp(x * 0.1)) plt.tight_layout() plt.show()2.3 一套可以直接复用的标准绘图骨架关于我每次做Matplotlib图都会用的骨架结构你可以直接复制使用。它是把绘图过程的必需动作都列出来避免画到一半发现少了某一步import matplotlib.pyplot as plt import numpy as np # 1. 数据准备 x np.linspace(0, 10, 100) y np.sin(x) np.random.normal(0, 0.1, sizex.shape) # 2. 创建画布和绘图区同时指定尺寸 fig, ax plt.subplots(figsize(8, 5)) # 3. 画图 ax.plot(x, y, labelsignal, color#2A6F97) ax.axhline(0, colorgray, linewidth0.8, linestyle--) # 4. 设置标题和坐标轴标签 ax.set_title(带噪声的正弦信号) ax.set_xlabel(时间) ax.set_ylabel(幅值) # 5. 图例与网格 ax.legend() ax.grid(True, linestyle:, alpha0.6) # 6. 自动调整布局避免元素重叠 fig.tight_layout() # 7. 展示 plt.show()这套骨架每一步都有明确作用第1步准备数据第2步创建画布并指定尺寸第3步画具体图形第4、5步补全文字信息第6步防止标题或标签被截断第7步把图显示出来。后续所有图表都是在这个骨架基础上替换第3步的绘图函数而已。3. 五种高频图表上手实录从一行代码到一张完整图Matplotlib几百种图表类型里实际工作高频用到的其实就那几种。我按使用频率挑了5类最常遇到的每类讲清楚什么时候用、核心参数是什么、常见的坑在哪里。3.1 折线图趋势分析的基础打底折线图用于展示数据随时间或其他连续变量的变化趋势。最基础的调用是ax.plot(x, y)但要让图有可读性几个参数值得记住fig, ax plt.subplots(figsize(8, 5)) x np.linspace(0, 10, 50) y1 np.sin(x) y2 np.cos(x) ax.plot(x, y1, labelsin, color#E63946, linewidth2, linestyle-, markero, markersize4, markevery5) ax.plot(x, y2, labelcos, color#457B9D, linewidth2, linestyle--, markers, markersize4, markevery5) ax.set_title(折线图示例) ax.set_xlabel(x) ax.set_ylabel(y) ax.legend() ax.grid(True, alpha0.3) plt.show()参数的含义color控制颜色可以用英文名、十六进制色号linewidth控制线宽linestyle控制线型-实线、--虚线、-.点划线、:点线marker控制数据点标记形状o圆点、s方块、^三角markevery控制每隔几个点画一个标记数据密集时特别有用。一个容易踩的坑数据点很多时不建议直接用默认方式显示所有标记会导致标记糊成一团。用markevery每隔一段画一个标记既保留数据分布又保持图面清爽。3.2 柱状图分类对比的常客柱状图适合对比不同类别之间的数值。比如各产品线销售额、各班级人数、各月份订单量。基础用法是ax.bar(x, height)但实际工作中分组柱状图更常见categories [产品A, 产品B, 产品C, 产品D] values_2023 [34, 28, 45, 39] values_2024 [40, 31, 43, 52] x np.arange(len(categories)) width 0.35 fig, ax plt.subplots(figsize(8, 5)) bars1 ax.bar(x - width / 2, values_2023, width, label2023, color#A8D5BA) bars2 ax.bar(x width / 2, values_2024, width, label2024, color#4A90D9) ax.set_xticks(x) ax.set_xticklabels(categories) ax.set_ylabel(销售额万元) ax.set_title(两年产品线销售额对比) ax.legend() plt.show()关键技巧是位置偏移两个柱子要并排横坐标得错开。宽度width设为0.35左边柱子偏移-width/2右边偏移width/2。ax.set_xticks和ax.set_xticklabels必须配合使用前者定位置后者改名字。我还常用水平柱状图当分类名称很长时比垂直柱状图舒服得多用ax.barh即可。堆叠柱状图则用bottom参数适合展示总量构成。3.3 散点图两变量关系的初步判断散点图用于观察两个连续变量之间的相关性。比如广告投入和销售额、身高和体重。它的核心是可以把第三维信息通过颜色或大小映射到图上rng np.random.default_rng(42) n 200 x rng.normal(50, 10, n) y x * 1.2 rng.normal(0, 15, n) sizes rng.uniform(30, 200, n) colors rng.uniform(0, 1, n) fig, ax plt.subplots(figsize(8, 5)) sc ax.scatter(x, y, ssizes, ccolors, cmapviridis, alpha0.7) cbar fig.colorbar(sc, axax) cbar.set_label(强度) ax.set_xlabel(广告投入) ax.set_ylabel(销售额) ax.set_title(散点图示例点大小和颜色映射第三维) plt.show()ax.scatter的s参数控制点大小c参数控制颜色值cmap指定颜色映射表alpha控制透明度。fig.colorbar(sc, axax)为颜色值添加一个颜色条图例这在数据点密集、颜色有连续含义时特别重要。散点图常见的坑是过度绘制当数据有几万个点且重叠严重时直接画出来就是一团黑。解决办法一是调低alpha让重叠区域显示出密度差异二是用plt.hexbin做六边形分箱图适合展示二维密度。3.4 直方图分布形态的快速体检直方图用来查看数据的分布形态是否正态、是否有双峰、是否存在极端值。它的难点在于bins分组数的选择分组数量直接影响你看到的信息data np.concatenate([ np.random.normal(0, 1, 2000), np.random.normal(4, 0.8, 500) ]) fig, ax plt.subplots(figsize(8, 5)) ax.hist(data, bins40, color#2A9D8F, alpha0.8, edgecolorwhite) ax.set_xlabel(数值) ax.set_ylabel(频数) ax.set_title(直方图示例双峰分布) plt.show()关于bins我的经验是数据量小时用较少分组比如10到20数据量大时用较多分组50到100但也别盲目多分否则直方图会变成一堆稀疏的细条。如果不想肉眼猜可以试试binsauto让Matplotlib根据数据量自动计算建议分组数。想比较两组不同样本量的分布时记得加densityTrue把频数归一化为密度否则样本量大的那组会显得“更高”。3.5 饼图与箱线图占比和离群值的补充饼图适合展示整体中各部分占比但我的实际经验是饼图别超过6个扇区否则标签会挤成一团读起来很费劲。优先用柱状图代替饼图是很多可视化的经典建议但如果一定要用可以这样sizes [35, 25, 20, 12, 8] labels [A类, B类, C类, D类, E类] colors [#264653, #2A9D8F, #E9C46A, #F4A261, #E76F51] fig, ax plt.subplots(figsize(6, 6)) ax.pie(sizes, labelslabels, colorscolors, autopct%1.1f%%, startangle90, counterclockFalse, explode[0.05, 0, 0, 0, 0]) ax.set_title(占比示例) plt.show()explode参数可以让某个扇区略微突出适合强调重点autopct自动显示百分比startangle控制起始角度。箱线图展示数据的五数概括最小值、下四分位数、中位数、上四分位数、最大值以及异常值点。它可以快速识别数据中的离群点和分布偏态rng np.random.default_rng(7) data_1 rng.normal(100, 15, 200) data_2 rng.normal(90, 25, 200) data_3 rng.normal(105, 10, 200) fig, ax plt.subplots(figsize(8, 5)) ax.boxplot([data_1, data_2, data_3], labels[车间1, 车间2, 车间3]) ax.set_ylabel(产量) ax.set_title(多组数据箱线图) plt.show()ax.boxplot的第一个参数传入一个列表每个元素是一组数据。箱体内部的线是中位数箱子的上下边是四分位数“须”延伸到非异常值范围内的最远点而圆点是个别极端值。当你发现某组数据的须特别长或者离群点很多就该警觉这组数据有异常情况。4. 中文乱码与全局配置第一道坎一次解决别再每次现查中文乱码几乎是Matplotlib新手第一个会撞上的问题。画图一切正常标题一用中文就显示成一个个小方框或者抛出一堆字体警告。这个问题的根源和一次性的解决办法我在这里讲透。4.1 乱码的根源默认字体里没有中文字形Matplotlib内置的默认字体是DejaVu Sans它不包含中文字形。所以当你用ax.set_title(销售额)时渲染器找不到对应字形只能显示方框或乱码。解决办法就是手动指定一个系统里已有的中文字体。4.2 先查看系统有哪些可用字体在配置之前先确认你的环境里到底装了什么中文字体import matplotlib.font_manager as fm # 列出所有已注册的字体名称 fonts {f.name for f in fm.fontManager.ttflist} # 查看包含常见中文字体的项 zh_fonts [name for name in fonts if any(k in name for k in [Hei, Song, Kai, Microsoft, PingFang, Noto, WenQuanYi])] for name in sorted(zh_fonts): print(name)Windows系统通常有SimHei黑体、SimSun宋体、Microsoft YaHei微软雅黑macOS有PingFang SC、STHeitiLinux可以安装Noto Sans CJK或文泉驿微米黑。列出来之后从中选一个你偏好的字体名。4.3 每次会话里设置rcParams最直接的方式是在绘图代码前设置全局参数import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] # Windows示例其他系统替换 plt.rcParams[axes.unicode_minus] False # 解决负号显示为方块的问题第一行指定无衬线字体优先使用SimHei第二行关掉Unicode负号处理。为什么第二行必要因为默认的负号用的是字体里的一种特殊编码换了中文字体后那个负号往往渲染不出来变成方块。关掉之后负号会用普通连字符显示。如果你找不准字体名或者想一劳永逸还有一个更稳的方案注册字体文件路径。尤其在公司服务器上字体可能没有安装到标准目录但你有字体文件import matplotlib.font_manager as fm font_path /path/to/your/font.ttf # 换成实际路径 fm.fontManager.addfont(font_path) plt.rcParams[font.family] fm.FontProperties(fnamefont_path).get_name()这样用绝对路径加载字体不依赖系统是否安装了该字体。4.4 推荐做法把配置抽成一个统一的绘图配置模块与其每次画图前复制那两行配置不如直接在代码库里建立一个公共配置模块。我在团队里就是给所有画图脚本统一一个公共配置文件里面一次性定义好中文字体、图幅尺寸、配色、网格样式大家在各自脚本里直接引用# plot_config.py import matplotlib.pyplot as plt def setup_style(): plt.rcParams[font.sans-serif] [Microsoft YaHei, SimHei, Noto Sans CJK SC] plt.rcParams[axes.unicode_minus] False plt.rcParams[figure.dpi] 120 plt.rcParams[savefig.dpi] 300 plt.rcParams[axes.grid] True plt.rcParams[grid.linestyle] : plt.rcParams[grid.alpha] 0.5 plt.rcParams[legend.framealpha] 0.8这个文件在其他脚本里用from plot_config import setup_style; setup_style()即可。字体列表写成多个候选值的好处是跨平台兼容Windows没有Noto时自动沿用列表里的下一个可用字体。4.5 配置后仍乱码的排查思路如果你配置了rcParams还是乱码按这个顺序排查确认字体名真的存在于plt.rcParams[font.sans-serif]的列表里且系统装有该字体。用第4.2节的方法打印字体列表核对。确认是在绘图之前执行的rcParams设置。如果在plt.show()之后设置自然不会生效。在Jupyter Notebook里如果改过配置在设置rcParams后即时重启绘图内核或者重新执行全部单元格。注意字体名带不带空格或大小写。比如Microsoft YaHei写成microsoft yahei就匹配不到。5. 子图布局、配色与导出让图表从能看到好看图能画出来只是第一步实际交付时还会遇到多图排版、配色难受、导出图片发虚的问题。这一节把常用布局和美化手段集中讲一遍。5.1 subplots多子图布局的完整用法多子图是Matplotlib的强项之一。用plt.subplots(nrows, ncols)一步创建画布和所有子图fig, axes plt.subplots(2, 2, figsize(10, 8), constrained_layoutTrue) x np.linspace(0, 10, 100) axes[0, 0].plot(x, np.sin(x), color#E63946) axes[0, 0].set_title(sin) axes[0, 1].plot(x, np.cos(x), color#457B9D) axes[0, 1].set_title(cos) axes[1, 0].plot(x, x ** 2 / 100, color#2A9D8F) axes[1, 0].set_title(quadratic) axes[1, 1].plot(x, np.sqrt(x), color#E9C46A) axes[1, 1].set_title(sqrt) plt.show()constrained_layoutTrue和tight_layout()都是用来防止子图之间互相重叠、标题被裁剪的布局机制。我推荐直接在subplots里用constrained_layoutTrue它比后面再调tight_layout()更省心。如果你希望几个子图共享x轴或y轴可以加sharexTrue或shareyTrue。共享坐标轴在对比多组数据时特别有用因为这样读者才不会被不同的量程误导。当四个子图的坐标范围差异很大时需要注意设置统一的坐标轴范围否则对比效果会被量程差异淹没。5.2 坐标轴、刻度和网格的精细调整坐标轴相关的调整是最常用的操作我把高频的几个功能集中列出来fig, ax plt.subplots(figsize(8, 5)) ax.plot(x, y) ax.set_xlim(0, 12) # 设置x轴显示范围 ax.set_ylim(-1.5, 1.5) # 设置y轴显示范围 ax.set_xticks([0, 2, 4, 6, 8, 10, 12]) # 手动指定刻度 ax.set_xticklabels([0, 2, 4, 6, 8, 10, 12], fontsize9) ax.tick_params(axisboth, directionin, length3) # 刻度朝内 ax.grid(True, whichmajor, linestyle:, alpha0.5)tick_params里的directionin是期刊图常用的风格刻度朝内whichmajor表示只调整主刻度。刻度朝内还是朝外没有绝对标准关键是全篇统一。在数据范围跨数量级时可以考虑用对数坐标轴用ax.set_xscale(log)或ax.set_yscale(log)在金融数据和天文数据里几乎必用。5.3 配色与样式别再用默认的“大蓝大橙”Matplotlib默认的蓝色和橙色虽然辨识度高但多了之后显得廉价。想让图好看两个方向整体样式和配色方案。整体样式可以用内置样式快速切换plt.style.use(seaborn-v0_8) # 或者看看都有哪些样式 print(plt.style.available)plt.style.available里有很多预设比如ggplot、bmh、fivethirtyeight。选定一个样式后后面所有图都会带上这个风格。我个人常用seaborn-v0_8或ggplot作为底子再盖一层自己的配色。配色方面几个值得记住的方案单个数据系列时给一个“品牌色”比如#2A6F97这类深蓝不要用默认亮蓝。多类别离散数据时用Set2、Set3、tab10等离散色板。连续数值映射时用viridis、plasma、cividis这些颜色映射表对色盲友好且深浅变化均匀。手动指定颜色循环的方法是修改rcParams里的axes.prop_cycle或者更简单地在每次绘图函数里传color参数。配色没有绝对标准但有一个底线不要让色盲读者无法区分你的数据。红绿对比、蓝黄对比在色弱人群眼里很接近尽量用viridis这类均匀过渡方案。5.4 导出高清图片dpi、格式和裁剪屏幕上看很正常的图保存到本地之后经常出现两种问题发虚、四周空白太多。这都和导出参数有关fig.savefig(output.png, dpi300, bbox_inchestight, facecolorwhite) fig.savefig(output.pdf) # 矢量图论文常用 fig.savefig(output.svg) # 网页矢量图dpi300是印刷级别的最低标准屏幕浏览用150足够论文投稿建议300及以上。bbox_inchestight会自动裁掉外围空白让图片紧贴内容。facecolorwhite把背景设置成白色防止导出后的图变成透明底。如果你的图之后要在Word或者论文里使用PDF或SVG矢量格式是首选。矢量图放大多少倍都不会模糊能保持文字清晰。PNG类是位图放大会出现锯齿。5.5 标注与注释把关键信息直接画在图上一张好图不只是数据曲线还要有必要的文字提醒。我常用四个标注手段# 在某个坐标位置添加文字 ax.text(5, 0.5, 峰值区域, fontsize12, color#E63946, hacenter) # 添加带箭头的注释指向某个数据点 ax.annotate(最大值, xy(np.pi / 2, 1), xytext(4.5, 1.2), arrowpropsdict(arrowstyle-, color#333333)) # 画水平参考线和垂直参考线 ax.axhline(0, colorgray, linestyle--, linewidth1) ax.axvline(np.pi, colorgray, linestyle:, linewidth1)ax.text的ha参数控制水平对齐方式常用center或left。ax.annotate的xy是被指向的数据点位置xytext是注释文字的位置arrowprops里可以设置箭头样式和颜色。axhline和axvline用于标注阈值线、零线、基准值在风险分析里几乎必用。6. 踩坑记录图例、坐标轴、内存和大数据的几个真实案例最后这部分是我这几年帮人排查Matplotlib问题时最常遇到的几类坑每个都给出完整的排查思路而不是直接甩答案。6.1 图例不显示或重复图例不显示的各种原因里最常见的是plot的时候忘了加label参数或者加了label但后面又单独调用了一次plt.legend()。后者的场景通常是画图循环里每画一条线就调一次legend()最终导致图例堆积了重复的项。排查顺序检查ax.plot()里是否写了labelxxx。检查是否只有一次ax.legend()调用。如果用了plt.legend()而图是用ax.plot()画的要把两种风格统一。如果图例项太多用ax.legend(locupper right, ncol2)分列显示避免图例遮住数据区域。6.2 坐标轴自动范围太“聪明”让图产生误导Matplotlib默认会根据数据自动调整坐标轴范围这在大多数时候是好事但也会带来误导。比如想展示从0开始的变化趋势结果坐标轴自动从数据最小值开始把细微波动放大成巨大波动。这在报表里是常见的信息失真源。解决方式ax.set_ylim(0, max_value * 1.1)手动固定下界ax.set_xlim同理。还有一个容易忽略的点多子图比较时如果每个子图坐标范围不同但视觉高度相同读者会误以为量级相当。用shareyTrue或手动set_ylim统一几个子图的y轴范围对比才公平。6.3 循环绘图内存飙升如果你在循环里反复创建figure却不关闭内存会一路涨最后图形界面卡死或者Kernel重启。这在批量生成几百张图时特别常见。正确的做法是在循环结束时关闭figurefor i in range(100): fig, ax plt.subplots() ax.plot(x, y) ax.set_title(f图 {i}) fig.savefig(foutput_{i}.png, dpi150) plt.close(fig) # 关键关闭figure释放内存plt.close(fig)的作用是显式释放这个figure占用的内存。尤其在脚本批量导出图片时关与不关内存表现差一个量级。在Jupyter Notebook里还有一个常见坑重复执行同一个绘图单元格旧图不会消失叠加显示越多越卡。这是因为Notebook会保留上一次执行的输出最好在执行前清空旧的输出。6.4 大数据量绘制卡顿当数据点数量达到几十万甚至上百万时ax.plot直接画会非常慢图也糊成一团。几个应对方案按性价比排序降采样先抽样再画。比如每10个点取1个肉眼几乎看不出差别。减少单个点渲染开销用linewidth1而不是linewidth2用:rasterizedTrue让这个图形栅格化。二维大数据用pcolormesh或imshow如果你画的是热力图、地形图优先用网格化的绘图函数而不是逐个画散点。我见过最典型的场景是绘制传感器一年内的分钟级数据大概50万个点。直接plot会卡顿用plot(x[::10], y[::10])抽稀之后画面依然完整但渲染速度提升了几十倍。6.5 保存后的图片与屏幕显示不一致屏幕上看是正常的保存后字体变了、图被裁剪了这通常是两个原因叠加第一显示时用的是GUI窗口的渲染DPI保存时用的是rcParams里的savefig.dpi。把保存DPI设成300文字在图里的物理尺寸就会发生变化。想要保证导出和屏幕一致就得接受屏幕预览只是近似的事实最终以保存文件的表现为准。第二个原因是字体嵌入。在PDF里保存时如果图表使用了系统字体但该字体没有被嵌入换一台电脑打开PDF就会字体替换、布局错乱。处理方式在保存前用font_manager显式注册字体或者导出SVG后用专业软件编辑检查。论文投稿时这个问题尤其烦人我的习惯是在投稿前把PDF放大200%逐页检查一遍图表字体。最后再分享一个我自己的效率习惯我现在做任何可视化项目都先花5分钟把统一的绘图配置模块、字体方案和主题色固定下来再针对每类图写一个小的绘图函数。比如折线图的函数接收数据、标题、文件名三个参数内部自动完成字体设置、配色、图例、导出。这样反复修改数据时只改数据文件脚本一行不用动。这个习惯是从第一次给论文紧急重画20多张图被折腾到半夜之后养成的之后我再也不想手工改图了。Matplotlib的可控性强但可控的前提是你要有一套自己的固定套路套路一旦建立它的强大程度远超那些开箱即用的高级库。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑