ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Matplotlib入门:从环境配置到三层架构与绘图流程

2026/10/6 10:28:26 拓冰建站 浏览量
Matplotlib入门:从环境配置到三层架构与绘图流程 Matplotlib这玩意儿我在刚开始学Python数据可视化的时候差点被它劝退。不是因为它难而是因为网上教程东一榔头西一棒子今天教你画个折线明天教你调个颜色结果看完还是不知道一张图是怎么从数据变成成品的。后来我把Matplotlib的核心翻来覆去捋了好几遍才发现它其实就三件事环境先弄干净、搞懂三层架构、走通一套绘图流程。这篇就把我实际用过、踩过坑的经验一次讲清楚适合刚入门Python、想正儿八经把绘图基础打牢的朋友。1. 环境配置装对、装稳、少踩坑1.1 准备工作先有一个干净的Python环境很多新手一上来就在系统全局Python里pip install matplotlib短期看着能用后面装别的库就开始互相打架了。我自己早期就干过这种事装完pandas再装某个绘图增强库结果Matplotlib的版本被强行升级一堆绘图函数行为都变了排查了半天。所以我现在的习惯是任何项目都先建独立虚拟环境。用Anaconda的话conda create -n viz python3.10 conda activate viz如果是原生Python环境可以用venvpython -m venv myviz source myviz/bin/activate # Windows下是 myviz\Scripts\activate为什么要独立环境因为Matplotlib的版本迭代很快某些老代码在新版本里会报警告甚至直接报错独立环境可以锁住版本避免殃及池鱼。另外数据分析常用的是matplotlib搭配numpy、pandas、jupyter这些库之间的依赖关系有时候很微妙独立环境一次性装好省得后面反复折腾。1.2 安装Matplotlib三条路线怎么选官方推荐的是pip安装pip install matplotlib国内用户如果速度慢可以用镜像源加速pip install matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple用Anaconda的话也可以走conda渠道conda install matplotlib这三条路我实测下来最稳的是Anaconda环境下用conda装因为它会自动匹配当前conda环境里numpy等底层库的兼容版本pip则胜在版本最新想尝鲜新功能可以选它。纯小白我更推荐conda省心不容易把依赖关系搞坏。安装完成后验证一下是否真的能正常导入import matplotlib print(matplotlib.__version__)如果能打印出版本号比如3.9.0那说明基本环境是通的。这里有个小细节如果你在Jupyter Notebook里还需要额外跑一行%matplotlib inline否则图像不会嵌在单元格里显示这也算一个常见的初学者拦路虎。1.3 后端与启动检查为什么有时import报错或画图不显示Matplotlib有个“后端backend”的概念通俗讲就是画图最终交给谁去渲染。在脚本里运行时它默认用Agg后端只负责把图画成文件不弹窗口在Jupyter里则用inline后端直接把图嵌进页面。如果环境没有图形界面比如纯服务器环境某些后端就会出错。可以用下面这行查看当前后端import matplotlib print(matplotlib.get_backend())在没显示器的Linux服务器上跑如果代码用了plt.show()经常会发现什么都没发生——因为Agg后端根本不支持交互窗口。这种时候要么改用plt.savefig()保存图片要么明确切换到支持交互的后端。我踩过的另一个坑是import matplotlib报ImportError: libGL.so.1: cannot open shared object file这类错。这通常是系统缺依赖库尤其Linux里常见。解决办法是装上对应的系统库再重新导入。所以安装完成后先跑一遍导入测试能提前筛掉环境层面的问题别一上来就写绘图代码。2. 三层架构Figure、Axes、Axis到底谁管谁2.1 容器从大到小Figure是大画板你新建一张图先创建的是一个Figure对象。我的理解是Figure就是一张空白的画板。你可以在这块画板上摆放一张或多张独立的图就像把几幅画拼在同一面展览墙上面。import matplotlib.pyplot as plt # 创建一块画板尺寸为8x6英寸 fig plt.figure(figsize(8, 6))这里figsize指的是画板整体大小单位是英寸。分辨率是由后续保存时指定的dpi决定的。很多新手的误区是以为设置figsize就决定了图片清晰度其实它只决定画板物理尺寸清不清晰要看dpi。2.2 Axes才是真正画图的区域新手最容易绕晕的就是这个Axes。它不是坐标轴而是一个包含数据区域、坐标轴、刻度、标题等所有元素的完整绘图区。你可以理解成在画板上用笔画出一个矩形框这个框里头才是你真正作画的地方。# 在画板上添加一个绘图区 ax fig.add_subplot(1, 1, 1) # 1行1列的第1个 # 或者更常用的一句 fig, ax plt.subplots()用plt.subplots()一次返回画板和绘图区两个对象这是现代Matplotlib的推荐用法。一个Figure上可以有多个Axes比如plt.subplots(2, 2)会创建一个2行2列的网格返回四个绘图区。2.3 Axis让数据有刻度、有标签Axis是坐标轴通常有x轴和y轴负责给Axes提供刻度、刻度标签和轴标签。轴管的是数据映射的“尺子”比如x轴范围0到10如何分刻度怎么显示刻度文字全由Axis负责。ax.set_xlabel(时间) # 设置x轴标签 ax.set_ylabel(数值) # 设置y轴标签 ax.set_xticks([0, 2, 4, 6]) # 手动设置刻度位置新手常把“Axes”和“Axis”混为一谈一搜栈溢出看到“ax.set_title”不知道在说什么。其实记住Axes是画图区的大总管Axis是它手下的两个打工小弟一个管横坐标一个管纵坐标。2.4 三层关系用一段代码看明白直接看代码最快理解import matplotlib.pyplot as plt # 创建Figure和Axes fig, ax plt.subplots(figsize(8, 5)) # 这是在一个绘图区里画线 ax.plot([1, 2, 3], [3, 1, 4]) # 设置整个Axes的标题 ax.set_title(这是Axes的标题) # 设置Axis的标签 ax.set_xlabel(这是X Axis的标签) ax.set_ylabel(这是Y Axis的标签) plt.show()ax.plot是在Axes里添加数据ax.set_title影响的是整个绘图区ax.set_xlabel影响的则是x这个Axis。以后看到任何ax.xxx开头的函数都是在操作一个名叫Axes的绘图区这个认知一旦建立理解Matplotlib代码就会顺利很多。好记的类比是三层结构像画框Figure是整面墙Axes是画框Axis是画框边缘用来标尺的刻痕。3. 绘图流程从数据到图形的五步法3.1 数据准备先想好用哪种图表达画图前先想清楚数据长什么样适合用哪种图形。时间趋势用折线图对比大小用柱状图看分布用直方图或箱线图观察两个变量关系用散点图。这个前置判断很重要很多图丑不是画得不好而是图没选对。比如你要展示某商品一年12个月的销量变化这就是明显的趋势数据用折线图要看不同产品线销量对比柱状图更直观。选定图之后数据通常准备成列表或numpy数组import numpy as np x np.array([1, 2, 3, 4, 5]) y np.array([2, 4, 1, 8, 5])3.2 创建画布和坐标系subplots是黄金入口之前的习惯是plt.figure()加plt.subplot()两步走现在官方推荐直接plt.subplots()因为画板和绘图区一步到位返回的fig和ax后续都用得上。fig, ax plt.subplots(figsize(8, 5))如果一张图不够要并排画两个子图fig, axes plt.subplots(1, 2, figsize(12, 5)) # axes是一个包含两个Axes对象的数组 axes[0].plot(x, y) axes[1].scatter(x, y)这里有个细节如果只创建一个子图axes返回的是单个Axes对象创建多个子图时返回的是Axes数组。这个差异曾让不少新手在axes[0]处报错因为单个Axes不支持下标。稳妥的做法是创建时就声明结构然后按数组访问。3.3 数据到图形映射plt绘图和ax绘图选哪个Matplotlib有两种写代码的风格。一种是plt风格plt.plot(x, y) plt.xlabel(...) plt.ylabel(...) plt.title(...)另一种是ax风格fig, ax plt.subplots() ax.plot(x, y) ax.set_xlabel(...) ax.set_ylabel(...) ax.set_title(...)两者的差别在于plt风格是“隐式获取当前Axes”适合快速画图、交互式探索ax风格是“显式指定目标Axes”适合复杂布局和多子图场景。我建议新手直接学ax风格因为一旦要用子图、共享坐标轴、循环绘图plt风格就会很难受。养成习惯后写代码的逻辑也更清楚画哪、怎么设置全都在ax上完成。3.4 定制细节标签、标题、图例、配色这一步决定图形是否专业。基本操作不复杂ax.set_title(2024年销量趋势, fontsize14) ax.set_xlabel(月份) ax.set_ylabel(销量件) ax.grid(True, linestyle--, alpha0.6) ax.legend([产品A], locupper left)颜色这块常见做法是直接用名称或十六进制ax.plot(x, y, colorcrimson, linewidth2, linestyle-, markero)linestyle控制线型marker控制数据点标记。新手画折线图常忘记加marker导致数据点少时线看着空洞。如果数据点是离散采集、频次不高建议带上marker。图例要先给数据加标签才能在legend()中显示出来ax.plot(x, y, label实际值) ax.legend()3.5 展示与保存显示、透明化、清晰度与格式在Jupyter里画完自动能显示在脚本里则要plt.show()。如果是保存图片用fig.savefig(output.png, dpi300, bbox_inchestight)dpi越高图越清晰一般纸质打印用300屏幕显示用150就够。bbox_inchestight会去掉多余空白让图片边缘紧凑这个参数我是次次都用的。注意保存时用的是fig.savefig不是plt.savefig一个作用在具体画板上一个隐式作用在当前画板多子图场景下fig.savefig更可靠。4. 一个完整的实操案例一周气温折线图加柱状图组合4.1 场景与数据准备这里用一个具体场景串起前面的所有知识点。假设你要展示某城市一周内每天的最高气温和最低气温需求是一张图里同时呈现高低气温的折线趋势并用柱状图对比每天温差。先造数据import matplotlib.pyplot as plt import numpy as np days [周一, 周二, 周三, 周四, 周五, 周六, 周日] high np.array([26, 28, 31, 30, 27, 29, 32]) low np.array([18, 19, 21, 20, 19, 22, 23]) diff high - low4.2 代码一步步拆解首选方案是双轴绘图high和low用折线画在同一个坐标系diff用柱状图画在次坐标轴上。# 第一步创建画板和主坐标系 fig, ax1 plt.subplots(figsize(10, 6)) # 第二步画两条折线 ax1.plot(days, high, colorred, markero, linewidth2, label最高气温) ax1.plot(days, low, colorblue, markers, linewidth2, label最低气温) # 第三步设置主坐标轴标签 ax1.set_xlabel(星期) ax1.set_ylabel(气温℃) ax1.set_title(某城市一周气温变化与温差对比, fontsize14) ax1.grid(True, linestyle--, alpha0.5) ax1.legend(locupper left) # 第四步创建共享x轴的次坐标系 ax2 ax1.twinx() ax2.bar(days, diff, colororange, alpha0.3, label当日温差) # 第五步设置次坐标轴标签和图例 ax2.set_ylabel(温差℃) ax2.legend(locupper right) plt.tight_layout() plt.show()这里的ax1.twinx()意思是创建一个共享x轴、但坐标独立的“孪生”Axes两个Axes重叠显示但刻度可以不同。这在同时画数值跨度差异大的两组数据时很常用比如气温和温差虽然都是温度但变化幅度不同分开刻度更清晰。4.3 成品效果与优化空间运行后你会看到红蓝两条折线清晰展示了一周的高低温变化橙色半透明柱状图展示每天的温差大小。alpha0.3让柱子半透明折线不会被完全遮住这是双轴图里非常实用的细节处理。如果觉得柱状图太“抢镜”可以把alpha调低到0.2或把柱子的颜色改成更淡的色调。标题、图例位置、网格样式都可以再按口味调整。配合fig.savefig(weather_week.png, dpi300, bbox_inchestight)就能导出高清晰度图片。整个流程看下来你会发现其实就是前面三层架构加五步法的自然组合创建Figure和Axes、用ax画数据、设置Axis标签、展示或保存。5. 常见问题与排查技巧5.1 中文和负号显示乱码怎么办这是Matplotlib中文用户遇到最多的问题。默认字体不包含中文字形所以标题、坐标轴标签中的中文会显示成方框。先看当前可用字体import matplotlib.font_manager as fm fonts [f.name for f in fm.fontManager.ttflist] print(SimHei in fonts) # 是否有黑体如果有中文字体手动指定为默认plt.rcParams[font.sans-serif] [SimHei] # 或用 Microsoft YaHei plt.rcParams[axes.unicode_minus] False # 解决负号显示为方块的问题SimHei在Windows上一般自带macOS上可以用Arial Unicode MS或PingFang SCLinux上如果没有中文字体要先用系统包管理器安装如fonts-wqy-zenhei之类的中文字体。5.2 字体警告font_manager报warning怎么处理很多初学者在import matplotlib时见过类似这样的日志[warning] matplotlib.font_manager: findfont: Font family SimHei not found.这个警告本身不影响代码运行但意味着你指定的中文字体没找到图画出来会显示方框。解决办法有两个方向一是换一个确实存在的字体二是安装中文字体后清理Matplotlib字体缓存import matplotlib matplotlib.font_manager._load_fontmanager(try_read_cacheFalse)或者直接删除缓存目录里的fontlist-*.json文件通常在~/.matplotlib/或~/Library/Caches/matplotlib/下下次启动会自动重建字体缓存。5.3 图不显示或显示空白脚本里写完代码发现运行后什么都没弹出第一反应是检查代码末尾有没有plt.show()。第二个常见原因是后端是Agg这个环境不支持弹窗。可以试试import matplotlib matplotlib.use(TkAgg)再重新导入pyplot。如果是在Jupyter里确认有没有执行过%matplotlib inline没有的话图像不会显示。5.4 图片模糊和线条粗细不协调保存的图片发出去模糊多半是dpi设低了。屏幕浏览建议150以上打印至少300。另外默认线宽1.0在一些显示器上偏细可以统一设置plt.rcParams[lines.linewidth] 2 plt.rcParams[lines.markersize] 6这些全局设置放在绘图代码之前能统一整批图形的风格。5.5 有人问matplotlib能保存动画成gif吗这个确实可以很多人不知道。用matplotlib.animation.FuncAnimation可以逐帧生成动画再用Pillow保存成gif。最简单的方式是用imagemagick作为writer但Windows下经常要额外配置。另一个更省事的方案是用Pillow逐帧拼接示例如下import matplotlib.pyplot as plt import numpy as np from matplotlib.animation import FuncAnimation fig, ax plt.subplots() x np.linspace(0, 2 * np.pi, 100) line, ax.plot(x, np.sin(x)) def update(frame): line.set_ydata(np.sin(x frame / 10)) return line, ani FuncAnimation(fig, update, frames100, interval50, blitTrue) ani.save(sine_wave.gif, writerpillow, fps20)关键点在于writerpillow这样就不依赖额外软件Pillow库本身就是Matplotlib做图像处理时的常见依赖。对于动态数据展示、模型训练过程可视化这类场景这个技巧值得收藏。写在最后Matplotlib真正核心的东西说穿了就是环境、架构、流程这三个板块。环境不干净后面全是坑三层架构搞不明白看再多代码都是散的绘图流程不熟悉遇到需求还得靠翻文档。我个人实际经验是千万别一上来就背API清单把Figure、Axes、Axis这三者的关系在脑子里转清楚再跟着一条完整流程画出三五张图比刷几十个零散教程管用得多。特别是ax开头的写法养成这个习惯以后你碰任何复杂子图布局都不会发怵。画图的乐趣就是从你把第一条会动的曲线画出来之后开始的动手跑一遍比看一百遍都强。