ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Matplotlib实操指南:从基础绘图到多子图与对数轴的高频技巧

Matplotlib实操指南:从基础绘图到多子图与对数轴的高频技巧 Matplotlib 这个库只要接触过 Python 数据相关的工作基本绕不开它。这几年我处理数据分析、做实验可视化、甚至临时画个论文插图都是用它顶上去的。标题里写“03-Matplotlib”看起来像系列教程的某一节但这恰恰说明它是个绕不过去的核心章节——折线图、散点图、标题坐标轴图例设置、多子图拼接、对数坐标轴再到和 pandas、numpy、scikit-learn 的联动全是最实用的高频操作。这篇文章我不打算写成一册说明书而是把我平时真正在用的套路和踩过的坑一并拿出来给刚开始接触 Matplotlib、或者用它画图总觉得别扭的朋友做个参考。看完这篇文章你能搞定日常 80% 的绘图需求而且知道出了问题时该往哪个方向排查。1. 先把环境搞定安装 Matplotlib 与核心机制速览1.1 安装与版本选择不管你是用 pip 还是 conda安装 Matplotlib 都非常简单pip install matplotlib如果你用的是 Anaconda 发行版通常已经预装了终端里执行conda install matplotlib装完之后验证一下import matplotlib import matplotlib.pyplot as plt print(matplotlib.__version__)我这里当前稳定版本是 3.8.x 系列。对于大多数用户来说不用刻意追求最新版3.7 以上都够用。要注意的是Matplotlib 的版本会影响到默认样式和部分 API 的行为比如 3.6 之后默认字体族调整过、3.7 之后plt.subplots的layout参数可以选择constrained。如果你在复现别人的代码时发现绘图效果对不上先看一眼版本号往往是排查第一步。1.2 先说清楚 pyplot、Figure 和 Axes 的关系很多新手一开始会被plt.plot()、plt.subplot()、plt.subplots()这几个用法搞晕。我用大白话给你捋一遍Figure可以理解成一张空白的画布它决定了整张图有多大、保存时多少分辨率。Axes是画布上的一个绘图区域真正画线、画点、写字都是在 Axes 上进行的。一个 Figure 可以装一个或多个 Axes。pyplot即 plt是一个面向过程的接口它帮你管理当前“正在操作的 Figure 和 Axes”让你可以连续用plt.plot()、plt.xlabel()这样的方式快速画图。打个比方plt.subplots()一次性创建了画布和绘图区返回给你两个对象后续操作都在这两个对象上完成。而直接plt.plot()走的是 pyplot 的隐式状态机——它自动创建 Figure 和 Axes并把当前操作环境指向它们。我用一个对比表格帮你区分操作方式典型代码适用场景隐式接口plt.plot(x, y)快速画一张临时图、交互调试面向对象fig, ax plt.subplots(); ax.plot(x, y)多子图、精细控制、出版级插图实际项目里我几乎全部用面向对象的方式因为一旦涉及多个子图或需要对坐标轴做精细调整面向对象的写法更清晰也避免 pyplot 隐式状态带来的一些“幽灵图”问题。1.3 三种画图后端的选择逻辑Matplotlib 有不同后端backend默认情况下在 Jupyter Notebook 里是module://matplotlib_inline.backend_inline在脚本里是agg或TkAgg。这直接影响你的plt.show()是否能弹窗显示。我的建议是写脚本并且只需要保存图片完全不需要plt.show()用 Agg 后端最省心它不依赖 GUI。在 Jupyter 里分析数据用%matplotlib inline即可新版本甚至不需要手动设置。需要交互式缩放、查看数据点坐标改用%matplotlib notebook或%matplotlib widget需要安装 ipympl。后端选择出问题的典型表现是脚本运行不报错但是图片不弹出来或者 Jupyter 里画了图不显示。大多数情况下检查后端就能解决。2. 核心绘图实操折线图与散点图的正确打开方式2.1 一张图的完整要素拆解说到绘图最基本的场景就是画一条折线或一组散点然后给它配齐标题、坐标轴名称和图例。很多人随手plt.plot(x, y)就算完事但这种图只能自己调试用拿不出手。我习惯把一张图拆成下面几个部分数据层x 轴数据、y 轴数据、误差条等修饰层线条颜色、线型、标记样式、透明度文字层标题、坐标轴标签、图例、注释文本坐标层刻度范围、刻度标签、对数坐标、网格线布局层图例位置、子图间距、画布留白。每次画图前对照这个清单过一遍基本不会漏东西。下面是一个典型的折线图示例import numpy as np import matplotlib.pyplot as plt x np.linspace(0, 10, 100) y np.sin(x) fig, ax plt.subplots(figsize(8, 5)) ax.plot(x, y, color#1f77b4, linewidth2, labelsin(x)) ax.set_title(正弦函数曲线, fontsize14) ax.set_xlabel(x, fontsize12) ax.set_ylabel(y, fontsize12) ax.legend(locupper right) ax.grid(True, linestyle--, alpha0.6) plt.show()这里有个小细节ax.plot()的linewidth最好用磅值points而不是像素默认是 1.5 左右。做报告或论文时线条宽度建议设置在 1.5 到 2.5 之间太细印刷出来看不清太粗又显得笨重。2.2 散点图颜色映射与气泡图的进阶玩法散点图不只是画点它非常适合展示两个变量之间的关系还能通过点的颜色和大小编码第三第四个维度rng np.random.default_rng(42) n 200 x rng.normal(0, 1, n) y rng.normal(0, 1, n) z np.sqrt(x**2 y**2) fig, ax plt.subplots(figsize(8, 6)) sc ax.scatter(x, y, cz, cmapviridis, sz*80, alpha0.7) cbar fig.colorbar(sc, axax) cbar.set_label(距离, fontsize12) ax.set_title(带颜色映射和大小编码的散点图) ax.set_xlabel(X) ax.set_ylabel(Y) plt.show()这里s参数是散点的大小单位是点的平方。如果直接s100所有点一样大像我这样让s跟随数据变化就实现了气泡图效果。c参数控制颜色搭配cmap指定颜色映射表fig.colorbar()自动生成一个颜色条相当于第四维度的图例。我用过很多次这个技巧比如分析城市房价时把 x 轴设为面积、y 轴设为总价、颜色设为单价、大小设为房龄一张图就能看到几个维度的信息比单纯看表格直观得多。2.3 设置标题、坐标轴名称和图例的细节这部分看着简单实际坑不少。先看代码ax.set_title(主标题, fontsize16, pad15) ax.set_xlabel(时间 (s), fontsize13) ax.set_ylabel(振幅 (mV), fontsize13) ax.legend(locbest, frameonTrue, shadowFalse)几个容易被忽略的点pad控制标题与绘图区之间的像素距离。默认情况下标题会贴着图的上边缘加个 10 到 20 的pad更透气。loc参数可以通过字符串指定位置best、upper right、lower left等。如果图例内容较多best会自动选择空白最多的位置但不一定是最合适的手动指定更可控。图例的frameon参数控制是否显示边框默认是 True如果图中网格线或数据较杂乱把边框去掉并设置半透明背景会更清爽frameonFalse或framealpha0.5。如果图例标签里有中文记得同时处理好中文字体配置否则你会看到一堆小方框这个问题我在第 6 节单独说。坐标轴名称不仅要有还要带单位。像“时间 (s)”、“距离 (km)”这种表述比光写“时间”、“距离”专业许多。单位尽量用斜体或括号括起来的规范形式这个习惯在大学实验报告阶段就该养成。2.4 保存图片时最容易忽略的参数画完图保存通常一行代码fig.savefig(output.png, dpi150, bbox_inchestight)但这里有两个参数值得记住dpi保存分辨率。屏幕展示 100-150 足够打印或论文投稿建议 300 以上。bbox_inchestight自动裁剪画布空白边缘让图片内容紧密贴合。不设这个参数时图片四周会多出大量留白尤其在 Jupyter 里用subplots时特别明显。需要透明背景时加transparentTrue在制作 PPT 或网页素材时很实用。如果是矢量图需求保存 PDF 或 SVG 格式缩放不模糊。另外存图有一个常见误区在plt.show()之后才调用savefig。某些交互式后端下show()会清空或重置画布导致保存的图空白或内容丢失。我建议把savefig放在show之前或者直接从 Axes/Figure 对象上保存不要依赖 pyplot 的隐式状态。3. 进阶布局六张图合在一个 Figure 上该怎么操作3.1 用 subplots 快速创建多子图“六张图合在一个图上”这类需求在对比实验、展示多个传感器通道、或者罗列算法中间结果时非常常见。实现方式不复杂fig, axes plt.subplots(2, 3, figsize(12, 8))这行代码创建了一个 2 行 3 列的子图网格返回的axes是一个 2x3 的二维数组。你可以用索引访问每个子图for row in range(2): for col in range(3): ax axes[row, col] ax.plot(x, np.sin(x row col)) ax.set_title(f子图 {row}-{col})两点经验figsize要按子图数量调整子图越多单个画布越大不然每个小图挤在一起坐标轴文字全都重叠。子图之间默认间距可能不够加一行plt.tight_layout()或fig.tight_layout()它能自动调整子图间距让标题和标签不重叠。新版本也可以用plt.subplots(layoutconstrained)效果更稳定。3.2 共享坐标轴与隐藏重复标签多子图对比数据时不同子图如果用相同的 x 轴范围可以共享 x 轴避免重复的刻度标签占用空间fig, axes plt.subplots(2, 2, figsize(10, 6), sharexTrue, shareyTrue)这样上下子图共用 x 轴刻度左右子图共用 y 轴刻度你会发现只有边缘的子图显示刻度标签内部子图自动隐藏。这在展示多条趋势线时非常省空间整体也更清爽。还有一个我常配合使用的技巧多张子图代表不同分组时先用fig.suptitle()加上总标题然后再用ax.set_title()为每个子图设置副标题这样层级关系非常清楚。3.3 网格不均匀时用 GridSpec偶尔你会遇到不均匀的布局需求比如上面一个大图下面两个小图。这时候subplots就不好使了可以用GridSpecimport matplotlib.gridspec as gridspec fig plt.figure(figsize(10, 8)) gs gridspec.GridSpec(2, 2, height_ratios[2, 1], width_ratios[1, 1]) ax0 fig.add_subplot(gs[0, :]) # 第一行整行 ax1 fig.add_subplot(gs[1, 0]) # 左下 ax2 fig.add_subplot(gs[1, 1]) # 右下height_ratios和width_ratios控制行高和列宽的比例。上面代码里第一行是第二行的两倍高度正好适合上方放一张大趋势图下方放两个细节展开图。我画实验数据时经常用这个布局上边是完整时间序列下边两个图分别放大两个关键时间段。3.4 循环绘图时的清理与缓存问题如果你在 Jupyter 里循环生成多张图比如一个循环里画了 20 个样本的分布每次调用plt.subplots()创建新图旧图的内存并不会立刻释放。次数多了内存占用会飙升。我的习惯是循环里显式关闭画布for i in range(20): fig, ax plt.subplots() ax.plot(x, y[i]) fig.savefig(foutput_{i}.png, dpi150, bbox_inchestight) plt.close(fig) # 关键关闭当前画布释放内存如果是在 Jupyter 里想要内联显示多张图又不想刷屏可以合并成一个大图或者控制只显示最后一张用plt.close()把中间过程关掉。3.5 多子图之间共享图例的技巧多子图如果都要显示图例每个子图都加一个ax.legend()会非常占空间。更好的做法是只保留一个统一图例放在 Figure 级别fig, axes plt.subplots(2, 2, figsize(10, 8)) lines [] labels [] for ax in axes.flat: line, ax.plot(x, np.sin(x), label信号A) lines.append(line) labels.append(信号A) fig.legend(lines, [统一图例], locupper center, ncol2, bbox_to_anchor(0.5, 0.98))bbox_to_anchor控制图例在 Figure 坐标系中的位置(0.5, 0.98)表示水平居中、靠近顶部。这种方式让整个图片只有一条图例干净利落特别适合学术报告或数据复盘。4. 对数坐标轴数据跨度大时的必备武器4.1 什么时候必须用对数坐标轴当你的数据跨越多个数量级时线性坐标轴会让小数值被压成一条贴近零的线完全看不出变化。比如物理中的频率响应曲线从 1 Hz 到 100 kHz跨了 5 个数量级再比如收入分布、城市人口、网络节点度数这类长尾数据天然适合对数坐标。我用一个例子说明。假设有一组数据从 0.1 到 1000如果用线性 y 轴绘图0.1 到 1 这段曲线几乎贴地你根本看不出细节换成对数轴之后每个数量级占据相同的视觉高度趋势一目了然。Matplotlib 设置对数坐标轴非常方便fig, ax plt.subplots(figsize(8, 5)) ax.plot(x, y) ax.set_xscale(log) ax.set_yscale(log)设置之后坐标轴的刻度标签会自动变成 10 的幂次形式(10^{-1}, 10^0, 10^1) 等。如果你想要更细的刻度网格可以使用ax.grid(True, whichboth)这样主刻度和次刻度都会显示网格线。4.2 三种对数坐标接口的取舍Matplotlib 提供三种相关接口容易让人混淆接口作用ax.set_xscale(log)/ax.set_yscale(log)单独设置某个轴为对数轴ax.loglog(x, y)x 轴和 y 轴同时设置为对数轴ax.semilogx(x, y)/ax.semilogy(x, y)只对 x 轴或只对 y 轴取对数我个人的习惯是如果只是快速画一张探索图直接用loglog或semilogy方便快捷如果是正式的可视化代码我会用set_xscale的写法因为这样代码读起来更明确后续还能继续叠加其他坐标轴设置。4.3 对数坐标轴的三个大坑对数轴看起来只是多了一行代码实际使用时坑不少。第一个坑数据里有零或负值。对数函数在 0 和负数处无定义Matplotlib 会自动过滤掉这些点但不会给你明确提示结果是曲线出现莫名断裂。处理办法是先判断数据范围对非正值做偏移或截断例如只绘制大于 0 的部分如果是计数类数据常用np.log1p(x)先把数据转换到线性空间再绘图或者用 symlog 坐标后面会说。第二个坑次刻度标签的位置。对数坐标轴上次刻度不是均匀分布的而是在每个主刻度之间按照 1-2-5 的模式排列。如果你想自定义刻度位置要用ax.set_xticks()配合LogLocator不要自己硬算刻度坐标。我推荐使用 matplotlib.ticker 模块里的LogLocatorfrom matplotlib.ticker import LogLocator ax.yaxis.set_major_locator(LogLocator(base10.0))第三个坑图例显示时丢数据点。如果脚本里既有线性坐标轴的子图又有对数坐标轴的子图在同一个 Figure 里共享 y 轴时对数轴会把线性轴的负值数据吃掉。解决办法是不要跨越不同类型的轴共享坐标或者统一用shareyFalse。4.4 symlog既要有对数又要有负值如果你数据里同时有正负数而且范围很大log轴是没法用的。这种情况下可以考虑symlog它是对数坐标的一个变体允许负值存在ax.set_xscale(symlog, linthresh1.0)linthresh参数表示在线性范围内保留的阈值比如 1.0 表示在 [-1, 1] 区间内使用线性刻度超出部分使用对数刻度。这样既保留了对数轴大范围压缩数据的优势又不丢失负值信息。我在地震波形分析里用过这种方式效果相当不错。5. 生态联动pandas、numpy、scikit-learn 与 Matplotlib 搭配5.1 numpy 生成模拟数据的常规套路实际画图时很少直接用现成的表格数据往往要先通过 numpy 生成或预处理数据。最常用的几个 numpy 函数np.linspace(start, stop, num)生成等间隔的数值序列用于平滑曲线的 x 轴。np.arange(start, stop, step)按步长生成序列适合离散点。np.random.default_rng(seed)随机数生成器用于生成模拟数据。np.fft.fft()信号频谱分析时常用。比如要模拟一个带噪声的传感信号可以这样rng np.random.default_rng(0) t np.linspace(0, 1, 500) clean np.sin(2 * np.pi * 5 * t) noise rng.normal(0, 0.2, sizet.shape) signal clean noise配合前面的折线图绘制代码就能快速看到信号的大致形态。5.2 pandas 的数据直接喂给 Matplotlibpandas 的 DataFrame 有内置的plot方法本质上封装了 Matplotlibimport pandas as pd df pd.DataFrame({ time: pd.date_range(2024-01-01, periods100, freqD), value: np.random.default_rng(1).normal(100, 10, 100), }) df.plot(xtime, yvalue, figsize(10, 4), gridTrue)这样做的好处是省去了手动拆列赋值的步骤而且 pandas 会自动处理时间索引。但我建议不能只依赖 DataFrame.plot因为一旦需要精细控制比如双 y 轴、自定义图例、多子图布局还是要回到 Matplotlib 原生接口上去。我的做法是先用df.plot()快速看数据正式出图时用fig, ax plt.subplots()然后ax.plot(df[x], df[y])完全掌控每个细节。5.3 机器学习结果可视化散点图、混淆矩阵与学习曲线用 scikit-learn 做完模型训练可视化是理解结果的重要手段。几个常见场景我列一下画分类结果的决策边界需要结合np.meshgrid生成网格点用模型预测后填充颜色from sklearn.datasets import make_classification from sklearn.svm import SVC X, y make_classification(n_samples200, n_features2, n_redundant0, random_state0) model SVC(kernelrbf, C1.0) model.fit(X, y) xx, yy np.meshgrid( np.linspace(X[:, 0].min() - 1, X[:, 0].max() 1, 200), np.linspace(X[:, 1].min() - 1, X[:, 1].max() 1, 200), ) Z model.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape) fig, ax plt.subplots(figsize(8, 6)) ax.contourf(xx, yy, Z, alpha0.4, cmapcoolwarm) ax.scatter(X[:, 0], X[:, 1], cy, cmapcoolwarm, edgecolorsk)决策边界的可视化帮助理解模型在高维空间的行为。除此之外混淆矩阵可以用ConfusionMatrixDisplay特征重要性可以直接用条形图展示学习曲线则把训练集和验证集的得分随训练样本数变化画成折线这些都是 Matplotlib 搭配 scikit-learn 的经典操作。5.4 使用样式表让整批图片风格统一如果你经常需要输出一批风格统一的图表不要每张图都手动设置颜色和字体。我建议用 rcParams 或样式表plt.style.use(seaborn-v0_8-whitegrid) plt.rcParams.update({ font.size: 12, axes.titlesize: 14, axes.labelsize: 12, legend.fontsize: 10, lines.linewidth: 2, figure.dpi: 120, })这种全局设置只需写一次后续所有图表都继承这些样式。不同场景还可以切换不同风格ggplot适合做报告seaborn-v0_8-whitegrid适合数据分析bmh适合学术风格的曲线图。注意不同 Matplotlib 版本里 seaborn 风格名可能略有不同如果你看到报错说找不到风格先执行print(plt.style.available)看看可用的风格名。5.5 动画与交互式图表顺带一提Matplotlib 还能做动画和交互式图表虽然这两块不是它最擅长的方向但当你想在演示时展示动态变化过程FuncAnimation是现成的方案from matplotlib.animation import FuncAnimation fig, ax plt.subplots() (line,) ax.plot([], []) def update(frame): y np.sin(2 * np.pi * frame / 50) line.set_data(range(len(y)), y) return line ani FuncAnimation(fig, update, frames100, blitTrue) ani.save(animation.mp4, writerffmpeg, dpi100)如果只是想在 Jupyter 里做可交互缩放、悬停显示数值的图表更合适的工具是 Plotly 或 Bokeh。Matplotlib 做好静态图交互部分交给专业工具分工更合理。6. 常见问题与排查技巧实录6.1 中文乱码与负号显示问题这是 Matplotlib 本地化使用里遇到最多的坑。默认的 Matplotlib 字体不支持中文一遇到中文字符就显示成方框而且负号也会变成奇怪的矩形。解决方案分两步首先查看当前系统有哪些中文字体可用import matplotlib.font_manager as fm font_list [f.name for f in fm.fontManager.ttflist if Hei in f.name or Song in f.name or WenQuanYi in f.name] print(font_list)然后在代码开头设置中文字体plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei, WenQuanYi Micro Hei] plt.rcParams[axes.unicode_minus] False设置之后负号就能正常显示了。如果你在 Linux 服务器上运行没有微软雅黑或黑体可以安装文泉驿微米黑或者思源黑体字体安装完成后刷新字体缓存fc-cache -fv再运行 Python 时就能识别到。6.2 图例边框和重复标签的怪现象有时候你发现图例里出现两行相同的标签或者图例被画到绘图区外面去了。这些大多数是循环画图时的重复 label 导致的for i in range(5): ax.plot(x, y[i], label曲线) # 每次都是同一个 label ax.legend() # 图例里会显示 5 条“曲线”解决办法有两个要么在循环里给 label 加上索引区分要么在循环外面手动指定图例句柄和标签。还有一个常用技巧是在ax.plot调用里省略label画完所有线后统一手动添加图例。图例位置超出画布的问题首选bbox_to_anchor配合loc精确调整ax.legend(locupper left, bbox_to_anchor(1.02, 1.0))这个写法会把图例放在绘图区右侧外部适合图例文字较长、画布内放不下的场景。记得保存图片时配合bbox_inchestight避免图例被截断。6.3 日期坐标轴刻度过密的处理时间序列画图最常见的两个问题x 轴刻度挤成一团、日期解析报错。如果你直接传字符串日期给ax.plot()Matplotlib 可能会把日期当成普通字符串处理刻度标签乱序。正确做法是先把字符串转成datetime类型import pandas as pd df pd.read_csv(data.csv, parse_dates[date]) fig, ax plt.subplots(figsize(12, 4)) ax.plot(df[date], df[value])如果刻度还是太密可以用AutoDateLocator和DateFormatter调整显示密度import matplotlib.dates as mdates locator mdates.AutoDateLocator(minticks3, maxticks8) formatter mdates.ConciseDateFormatter(locator) ax.xaxis.set_major_locator(locator) ax.xaxis.set_major_formatter(formatter)ConciseDateFormatter是较新版本才有它能自动把刻度标签简化成“1月”、“2024年”这类精简形式比默认的“2024-01-01 00:00:00”清爽太多。6.4 大数据量绘图卡顿与内存问题画几十万、上百万个点的时候Matplotlib 会明显卡顿甚至内存暴涨。我的处理思路按优先级排列对数据进行降采样比如每 10 个点取 1 个只看趋势完全够用。使用ax.plot(..., rasterizedTrue)把矢量图栅格化保存 PDF 时的体积会大幅减小。用LineCollection而不是逐个ax.plot()绘制大量线段。如果只是探索性分析可以用plt.hexbin(x, y, gridsize30)代替散点图用六边形网格统计点的密度既能避免点重叠又高性能。比如我有一次处理 200 万个 GPS 轨迹点直接ax.scatter画了十几分钟还没出来换成ax.hexbin之后瞬间出图而且视觉效果更好能明显看出热点区域。6.5 坐标轴范围自动调整导致的误导Matplotlib 默认会自动调整坐标轴范围让数据曲线恰好填满画布。这在大多数时候是好事但有时候会误导读者。比如数据从 4.98 到 5.02默认 y 轴范围可能只有 4.97 到 5.03这让微小的波动看起来像剧烈震荡。解决方法是手动指定坐标轴范围ax.set_ylim(0, 10) ax.set_xlim(-1, 11)如果你想让坐标轴从零开始或者为了对比多张图统一尺度这一步必不可少。我画实验对比图时经常是先把所有组数据的全局最大值最小值算出来再统一设置坐标范围保证每组图之间可比。6.6 绘图结果与预期不一致时的通用排查路径如果你发现画出来的图和预想不一样我提供一个经验性的排查顺序先确认数据本身没问题打印数据的长度、最大值、最小值、是否有 NaN。检查坐标轴范围是不是数据被自动裁剪或缩放得看不出来了。检查是否有多余的绘图语句叠加在同一张图上特别是循环里没有清理画布的情况。检查颜色和线型是否被某个全局样式覆盖。确认当前后端类型必要时切回默认后端。最后才怀疑库的 bug大部分情况其实是前面几类问题。这套排查路径帮我解决过无数奇怪的绘图问题包括“图不见了”“线消失了”“颜色不对劲”等等。如果你把每一步都走一遍10 分钟之内基本能定位根因。再说几句由实操引出的经验前面写了这么多最后分享一个我自认为最值得养成的习惯画图代码尽量封装成函数。别嫌麻烦把数据加载、清洗、绘图、保存封装成plot_xxx(conf)这样的函数之后你会发现自己出图的效率翻倍而且换数据、换风格都只需要改参数不用复制粘贴整段绘图代码。另一个小技巧是画完图之后用fig.canvas.draw()主动触发一次绘制这样在交互环境中不会出现最终图片缺少某一段数据的情况。Matplotlib 的 API 看起来简单但真正用顺了靠的就是在细节上多留一分心把每一次踩坑都沉淀成自己的标注。
返回列表