先得把话说清楚Matplotlib里真正让你“掌控绘图”的不是plt.plot()这种快捷方式而是藏在背后的axes API。很多初学者用Matplotlib画图永远只停留在plt.开头的函数上画个折线没问题一旦想画子图、想精细控制坐标轴、想做雷达图就会卡壳。原因很简单——你没搞清楚figure、axes、axis这三个概念到底谁管谁。这篇文章就是要把axes API彻底讲透从核心概念到实操代码让那些“只会plt.plot”的人也能写出结构化、可复用的绘图代码。无论是做数据分析、写论文插图还是开发可视化组件这部分能力迟早要用到。先说结论性的一句话figure是画板axes是画纸axis是画纸上的刻度线。理解这三层关系Matplotlib的绝大多数坑都能避开而axes API就是你在“画纸”上精准作画的那支笔。下面我按自己实际使用的路径一层一层拆开讲。1. 先把figure、axes、axis三者的关系彻底捋清1.1 figure整张画板figure是Matplotlib绘图的顶层容器相当于你摊开在桌面上的一张白纸。它管理整个图像窗口的大小、背景色、分辨率以及所有子图axes的布局关系。在代码层面plt.figure(figsize(8, 6), dpi100)创建的就是一个figure对象你可以理解成“一块8x6英寸、100dpi分辨率的面板”。figure本身不直接画任何数据图形它只负责提供舞台。数据画在哪里画在它内部的axes上。一个figure可以承载一个axes也可以承载多个axes就像一块大画板可以贴好几张画纸。有些人在代码里频繁调用plt.figure()却不保存返回值这很容易埋坑。比如你写完第一个图想在同一个figure里再画一个子图却不知道要去哪里找这个figure对象最后只能被迫用plt.gcf()去猜当前figure代码一旦复杂就会失控。1.2 axes真正的绘图区axes才是你画数据的“纸”。每个axes都有一个x轴、一个y轴、还有整个绘图区域。你看到的坐标轴刻度、网格线、数据曲线、散点、图例全都挂在axes下面。官方文档对axes的定义是“数据坐标系”我更愿意把它理解为“一块自带坐标系的小画纸”。在代码中最常见创建axes的方式是fig, ax plt.subplots()这里的ax就是axes对象。你在ax.plot()、ax.scatter()、ax.set_xlabel()上做的所有操作都会精确作用在这张“画纸”上不会影响其他子图。这也是axes API和pyplot接口最大的区别pyplot接口依赖“当前axes”的隐式状态而axes API把每一张画纸清清楚楚地握在你手里。1.3 axis坐标轴对象axis是最容易被忽略的一层。它指的是具体的x轴或y轴对象包含刻度线、刻度标签、轴标签以及它们的显示范围。当你调用ax.set_xlim(0, 10)时实际上就是在调整x轴这个对象的显示范围ax.tick_params(rotation45)则是在设置x轴或y轴刻度标签的旋转角度。需要注意axis在Matplotlib里既可以表示“x轴/y轴”这种抽象概念也可以指matplotlib.axis.Axis这个具体类。在阅读代码时看到ax.xaxis、ax.yaxis这样的写法就是在直接操作axis对象。比如你想隐藏刻度线可以写ax.xaxis.set_visible(False)想设置刻度格式可以写ax.xaxis.set_major_formatter()。1.4 三者的关系与日常对应的代码模式关系捋顺了代码自然就懂了plt.figure()创建画板返回figure对象。fig.add_subplot(row, col, index)在画板上添加一张画纸返回axes对象。ax.xaxis、ax.yaxis是这张画纸上的两条坐标轴返回axis对象。ax.plot()、ax.scatter()把数据画在画纸上。对比一下两种写法# pyplot风格隐式操作 import matplotlib.pyplot as plt plt.plot([1, 2, 3], [4, 5, 6]) plt.xlabel(x) plt.ylabel(y) plt.title(demo) # axes API风格显式操作 fig, ax plt.subplots() ax.plot([1, 2, 3], [4, 5, 6]) ax.set_xlabel(x) ax.set_ylabel(y) ax.set_title(demo)两种写法在单图场景下结果一样但一旦涉及多子图、动态更新、函数封装pyplot风格就非常容易串状态。我自己的习惯是从一开始就只用axes API省得后面回头重构。想验证自己是否真的理解了这三者的区别可以试试这个问题如果fig.add_subplot(2, 2, 3)创建的是哪个位置的子图答案是2行2列布局中的第3个位置也就是左下角因为Matplotlib的子图编号是按行优先从左到右、从上到下排列的。2. 创建figure和axes的四种方式选对入口就成功了一半2.1plt.subplots()日常首选fig, ax plt.subplots()是最推荐的方式没有之一。它一次性返回figure和axes两个对象参数丰富到可以覆盖90%的需求fig, ax plt.subplots( nrows2, ncols3, figsize(12, 8), dpi100, sharexTrue, shareyFalse, constrained_layoutTrue )nrows和ncols决定子图网格的行列数。figsize是画板尺寸单位是英寸。做论文插图时常见figsize(8, 4)这种比例但要结合最终成品尺寸和dpi来定。sharexTrue会让所有子图共享x轴刻度时间序列对比图尤其好用能大幅压缩纵向空间。constrained_layoutTrue是比tight_layout()更现代的布局方案它会在绘制时自动调整子图间距避免标签互相遮挡后面我会专门提到。当nrows和ncols都大于1时ax是一个二维数组比如ax[0, 1]表示第0行第1列的子图。访问时要小心不要和数组索引搞混。2.2plt.figure()fig.add_subplot()灵活拼接如果你不是规整的矩形网格布局而是想要“左边一个大图右边两个小图”这种不规则布局subplots()就不那么顺手了。这时可以用plt.figure()先创建画板再用fig.add_subplot()自由指定子图位置fig plt.figure(figsize(10, 6)) ax_left fig.add_subplot(1, 2, 1) # 左侧大图 ax_right_top fig.add_subplot(2, 2, 2) # 右上小图 ax_right_bottom fig.add_subplot(2, 2, 4) # 右下小图思路很简单先把画板想象成网格然后用add_subplot在不同网格位置放置不同大小的画纸。注意add_subplot(1, 2, 1)和add_subplot(2, 2, 2)可以混用Matplotlib会自动协调位置。如果你需要更复杂的比例控制比如左图占1/3、右图占2/3那就得上GridSpec了那是进阶话题这里先不展开。2.3plt.subplot_mosaic()复杂布局的懒人方案Matplotlib 3.3之后提供了subplot_mosaic我用过一次就离不开了。它用类似ASCII画图的字符串语法来定义布局可读性极高fig, ax_dict plt.subplot_mosaic( [[left, right_top], [left, right_bottom]], figsize(8, 6) )返回的ax_dict是字典键是字符串值是对应的axes对象。比如ax_dict[left]直接拿到左边大图不需要记ax[0, 0]这种索引。布局再复杂也不会搞混强烈推荐需要做仪表盘式图表的场景。2.4 直接操作plt.axes()画中画场景还有一种场景是在已有axes内部再嵌入一个小坐标轴比如画一个放大的局部图。这时候可以用plt.axes([left, bottom, width, height])四个参数都是0到1之间的相对坐标fig, ax_main plt.subplots() ax_zoom fig.add_axes([0.55, 0.55, 0.3, 0.3])注意这里用的是fig.add_axes四个位置参数以figure为参考系[0.55, 0.55, 0.3, 0.3]表示x方向起点在figure宽度55%处y方向起点在高度55%处宽和高各占30%。这种画中画技术在做数据对比局部细节时特别实用。2.5 为什么我只用axes API而不用纯pyplot写法直接说原因pyplot的隐式状态在单文件、单图脚本里没问题但一旦代码超过50行或者需要把绘图逻辑包装成函数它的“当前axes”状态就会成为定时炸弹。比如你写了一个自定义绘图函数函数内部用了plt.xlabel()它设置的永远是“当前axes”的x轴标签。如果你在另一个地方想画两张独立子图没有正确切换当前axes标签就会跑到错误的位置上去。用axes API则完全不会有这个问题ax对象是显式传递的想画哪张纸就碰哪个ax。这种代码天然适合复用和调试。这也是为什么Matplotlib官方文档现在的主线示例几乎全部基于axes API。3. 在axes API里核心绘图环节逐个击破3.1 从ax.plot()到ax.scatter()数据层的基本功一切绘图最终还是落在数据层。axes对象提供了大量绘图方法最常用的几个是ax.plot(x, y)折线图。ax.scatter(x, y, s, c, alpha)散点图。ax.bar(x, height)柱状图。ax.hist(x, bins)直方图。ax.pcolormesh(X, Y, C)伪彩色图。这些方法的共同点在于它们都直接作用在当前的axes对象上返回的Line2D、PathCollection等对象可以继续用来做精细控制。比如你想把画出来的折线存下来后面修改它的颜色line, ax.plot(x, y) line.set_color(red) line.set_linewidth(2)这里返回的是Line2D对象解包时要带上逗号因为ax.plot()返回的是一个列表即使只有一条线。3.2 散点图的透明度和网格alpha和grid是亲兄弟散点图一多就会叠在一起这时候透明度是救命稻草。alpha参数范围是0到10表示完全透明1表示完全不透明。实际作图时我一般先设alpha0.6试跑一次看重叠情况再微调。但如果只是想表达密度更专业的是用c参数配合cmap把第三个变量的数值映射到颜色上sc ax.scatter( x, y, spoints_size, # 点大小 cthird_variable, # 颜色映射数据 cmapviridis, # 颜色映射表 alpha0.6, # 透明度 edgecolorswhite, # 点边缘颜色 linewidths0.5 # 边缘线宽 )网格线的作用则是给数值定位提供参照系。ax.grid()是控制网格的入口参数有几个常用组合ax.grid(True, whichmajor, axisboth, linestyle--, linewidth0.6, alpha0.7)which参数可以选major、minor或both表示显示主刻度网格线还是次刻度网格线。默认情况下Matplotlib只显示主网格线。如果你要显示次网格线得先让坐标轴开启次刻度比如ax.xaxis.set_minor_locator(AutoMinorLocator())。axis参数控制是x轴、y轴还是全部显示。很多新手只写ax.grid(True)出来的网格线又粗又密其实调成linestyle--和alpha0.5颜值会立刻提升一个档次。3.3 颜色设置不止是colorred这么简单Matplotlib的颜色体系分几个层级。最简单的是直接用英文颜色名比如colorred、colorblue。其次是十六进制颜色码color#FF5733这种自由度更高。还可以用RGB元组取值范围0到1比如color(0.2, 0.4, 0.6)。如果你有HTML颜色背景可能会更习惯写color(0.8, 0.4, 0.4)对应#CC6666注意Matplotlib的RGB分量是0到1的浮点数不是0到255。当颜色需要对应连续数据时用cmap色彩映射表。常见的cmap包括viridis、plasma、inferno这些都是感知均匀的颜色映射色盲友好度也高。设置方法sc ax.scatter(x, y, cz, cmapviridis) fig.colorbar(sc, axax)colorbar会自动从散点图对象中提取颜色映射关系生成一个颜色条方便读者把颜色对应回数值。要注意colorbar接收的第一个参数是绘图返回的对象不是axes对象。很多人写成fig.colorbar(ax)会报错这是一个高频错误。3.4 图例设置ax.legend()的完整控制力图例是绘图中最折磨人的环节之一。ax.legend()支持几个关键参数loc图例位置可以是字符串如upper right、lower left也可以是数字代码如1、2。推荐用字符串可读性好。ncol图例列数当图例项目很多时设为2可以节省空间。frameon是否显示图例边框简洁风格通常设False。fontsize图例字体大小。title给图例加标题分组的图例尤其有用。图例的数据来源有两个途径。一是在绘图方法中直接传label参数二是在ax.legend()里手动传入图例句柄和标签列表。第一种更常见ax.plot(x, y, labelseries A) ax.plot(x, z, labelseries B) ax.legend(locupper right, frameonFalse)第二种适合你想修改图例文字、却不希望改动原始绘图代码的场景。比如图例里你想写成中文标签而绘图代码里用的是英文内部标签就可以line_a, ax.plot(x, y) line_b, ax.plot(x, z) ax.legend(handles[line_a, line_b], labels[序列A, 序列B])还有一个细节图例会遮挡数据。实际作图时我常把loc设为center left再把bbox_to_anchor(1.02, 0.5)这样图例就被挪到坐标轴外面去了彻底不挡数据。代价是副图的宽度会被压缩需要配合fig.tight_layout()或constrained_layoutTrue来调整空白。3.5 坐标轴范围、刻度和tick_params从宏观到微观控制坐标轴范围是ax.set_xlim(left, right)和ax.set_ylim(bottom, top)这里不做过多解释。更值得关注的是刻度控制因为刻度决定了读者对数据的感知精细度。ax.set_xticks([0, 1, 2, 3])手动指定希望显示哪些主刻度位置。ax.set_xticklabels([零, 一, 二, 三])则设置刻度标签的内容。两个要成对使用否则标签数量对不上会报错。ax.tick_params(axisx, rotation45)是控制刻度外观的万能方法。常用参数包括labelsize标签字号、colors标签颜色、directionin刻度线向内、length刻度线长度、pad标签与刻度线的距离。当坐标轴标题或标签过长时rotation是第一优先级要调的参数否则文字叠在一起直接毁掉整张图。日期坐标轴是另一个常见痛点。如果你用ax.plot(dates, values)默认刻度可能稀疏或者拥挤。此时需要ax.xaxis.set_major_locator和ax.xaxis.set_major_formatter配合比如每周一个主刻度、显示为“月-日”格式。Matplotlib提供了dates模块import matplotlib.dates as mdates然后ax.xaxis.set_major_locator(mdates.WeekdayLocator(interval1)) ax.xaxis.set_major_formatter(mdates.DateFormatter(%m-%d))这是处理时间序列绕不开的组合拳。3.6 雷达图极坐标axes的典型应用雷达图在Matplotlib里不是独立图表类型而是把axes的坐标系切换成极坐标polar之后再用折线或散点填充来模拟出来的。创建方式很简单fig, ax plt.subplots(subplot_kw{projection: polar})subplot_kw是关键参数它把子图创建时的参数透传给add_subplot。也可以写成ax fig.add_subplot(111, projectionpolar)极坐标axes的坐标系和直角坐标完全不同。横方向变成了角度θ纵方向变成了半径r。默认情况下θ从0度开始逆时针增大每周360度。雷达图的经典做法是让多个类别均匀分布在360度之内首尾相连。代码实现通常是import numpy as np categories [速度, 力量, 耐力, 敏捷, 柔韧] values [4, 3.5, 5, 4.2, 3.8] angles np.linspace(0, 2 * np.pi, len(categories), endpointFalse) # 封闭首尾 angles np.concatenate((angles, [angles[0]])) values_closed np.concatenate((values, [values[0]])) ax.plot(angles, values_closed, linewidth2) ax.fill(angles, values_closed, alpha0.25) ax.set_xticks(angles[:-1]) ax.set_xticklabels(categories)这里np.linspace(0, 2 * np.pi, len(categories), endpointFalse)保证了每个分类的角度均分一圈且最后一个点不与第一个点重合然后再手动拼接形成闭环。fill函数用半透明色填充雷达图内部视觉上更好看。雷达图有个要命的问题当不同维度的数值尺度差异过大时半径轴的范围会自动适应最大值导致小数值维度“凹陷”得很夸张。解决办法是显式固定半径轴范围比如ax.set_ylim(0, 5)让所有类别用同一把尺子衡量。另外如果分类超过8个雷达图就会变成一团乱麻不如直接放弃雷达图改条形图。4. 完整实战用axes API从零绘制一张高质量散点图和雷达图4.1 场景设定假设我们有这样一份数据每个城市有“人均GDP”、“幸福感指数”、“环境质量”、“医疗资源”四个维度的评分同时还有人均GDP和一个外部变量的关系需要观察。我们要在一张图上同时展示两组信息于是决定做一张2x1布局的子图上图是带网格、透明度的散点图下图是四个城市的雷达图对比。4.2 代码实现import numpy as np import matplotlib.pyplot as plt # 数据准备 cities [北京, 上海, 广州, 深圳] dimensions [人均GDP, 幸福感指数, 环境质量, 医疗资源] data np.array([ [9, 7.5, 6.8, 8.9], [9.2, 7.8, 6.5, 9.0], [8.5, 8.0, 7.2, 8.2], [9.1, 7.2, 6.9, 8.7] ]) fig, axes plt.subplots( nrows2, ncols1, figsize(8, 10), constrained_layoutTrue ) # 第一个子图散点图 网格 透明度 颜色映射 sc axes[0].scatter( data[:, 0], data[:, 2], s200, # 点大小 cdata[:, 1], # 用幸福感指数做颜色映射 cmapplasma, alpha0.7, edgecolorsblack, linewidths0.3 ) axes[0].set_xlabel(人均GDP评分) axes[0].set_ylabel(环境质量评分) axes[0].set_title(城市人均GDP与环境质量关系) axes[0].grid(True, linestyle--, linewidth0.6, alpha0.5) axes[0].set_xlim(7.5, 10) axes[0].set_ylim(6, 8) fig.colorbar(sc, axaxes[0], label幸福感指数) # 第二个子图雷达图极坐标 ax_radar fig.add_subplot(2, 1, 2, projectionpolar) angles np.linspace(0, 2 * np.pi, len(dimensions), endpointFalse) angles np.concatenate((angles, [angles[0]])) colors [#e74c3c, #3498db, #2ecc71, #f39c12] for idx, city in enumerate(cities): values np.concatenate((data[idx], [data[idx][0]])) ax_radar.plot(angles, values, labelcity, colorcolors[idx], linewidth2) ax_radar.fill(angles, values, colorcolors[idx], alpha0.15) ax_radar.set_xticks(angles[:-1]) ax_radar.set_xticklabels(dimensions, fontsize10) ax_radar.set_ylim(0, 10) ax_radar.set_title(四城市多维度能力雷达图, pad20) ax_radar.legend(locupper right, bbox_to_anchor(1.3, 1.1), frameonFalse) plt.show()4.3 代码里的几个关键细节第一个子图用data[:, 0]、data[:, 1]、data[:, 2]做散点图的三个维度s参数固定点大小c参数控制颜色映射edgecolorsblack给散点描了黑边在浅色背景下能让重叠的点更清晰。grid(True, linestyle--, linewidth0.6, alpha0.5)设置半透明虚线网格既不干扰散点识别又提供定位参照。第二个子图的创建方式要注意我在subplots()创建好一个2行1列的axes数组之后又用fig.add_subplot(2, 1, 2, projectionpolar)覆盖了第二个位置的axes。这种写法不算最优雅但可以避免在subplots()里通过subplot_kw统一指定极坐标。如果一开始就用plt.subplots(2, 1, subplot_kw{projection: polar})会导致所有子图都变成极坐标所以务实方案是先用普通axes再单独覆盖。雷达图填充用alpha0.15透明度很低只是为了给多组数据之间做区域区分不至于互相遮盖到看不清边界。legend放在坐标轴外部时用bbox_to_anchor(1.3, 1.1)把图例从图形右侧“拖”出去避免图表内容被挤占。4.4savefig保存图表的几个坑plt.show()之后如果还要保存图片应该用fig.savefig()而不是plt.savefig()虽然两者在单figure场景下等价但用fig.savefig()显式指定对象更安全。保存参数方面有三点经验fig.savefig(output.png, dpi300, bbox_inchestight, facecolorwhite)dpi300是投稿级分辨率文档插图常用150到200屏幕阅读用100足够。bbox_inchestight会自动裁剪掉多余的空白保存出来的图片“刚好套住内容”不会出现大片留白。facecolorwhite很重要如果你的figure背景是透明的在某些白底背景上图片会显示灰色网格线条贴上白色背景层能避免这种问题。还有一个坑是中文乱码。plt.savefig中文乱码本质上是字体问题和保存图片没有直接关系但很多人是保存之后才发现中文变成方框。最简单的处理在代码开头加上plt.rcParams[font.sans-serif] [SimHei] # Windows黑体 plt.rcParams[axes.unicode_minus] False # 解决负号显示为方块的问题macOS上可以把SimHei换成Arial Unicode MS或PingFang SCLinux上一般用Noto Sans CJK SC。具体字体能不能生效取决于你的系统里是否安装了这些字体。要是临时不想改全局配置也可以在ax.set_xlabel()里显式指定fontproperties参数但那样写起来太啰嗦日常用rcParams更省事。5. 常见问题与排查技巧实录5.1 运行时图形窗口不弹出很多人用PyCharm跑Matplotlib代码执行完什么窗口都没看到。这通常不是逻辑错误而是后端显示方式的问题。解决办法是在代码里加import matplotlib matplotlib.use(TkAgg) import matplotlib.pyplot as plt这行use(TkAgg)要放在import matplotlib.pyplot之前手动指定后端。不同环境下可用的后端不一样比较常见的有TkAgg、QtAgg、macOSX。如果你在PyCharm里用科学模式可以打开“SciView”面板图形会显示在独立的变量查看器里这时候plt.show()未必需要图形会自动展示。还有一种情况是脚本一次性执行完所有代码图形窗口闪一下立刻就关闭了。解决方法是执行到plt.show()时让Python保持阻塞状态或者在脚本末尾加上input(Press Enter to exit...)这样窗口会一直停着等你操作。5.2 图例只显示一半或完全不显示图例不显示最常见的原因是绘图时忘了传label参数。ax.legend()默认收集当前axes里带label的绘图对象如果所有绘图对象都没有label图例自然为空。但也别急着把所有label都补上——如果你只想要其中一部分曲线出现在图例里可以用ax.legend(handles[line1])手动指定。我遇到过更隐蔽的坑画了多条曲线每条都加了label但图例只显示了第一条。排查之后发现是某个label字符串里有重复值被Matplotlib自动去重了。解决办法是确保label唯一或者手动传入句柄列表。5.3 坐标轴标签和标题被截断plt.show()输出的图形里x轴标签经常会显示不完全“被切掉一半”。这是布局管理器没调整好导致的。两个方案第一种在代码最后加fig.tight_layout()。它会在绘图完成后自动调整子图间距让所有标签、标题都完整显示。注意tight_layout()必须在所有绘图操作之后调用而且不要和constrained_layoutTrue同时使用否则会冲突。第二种使用constrained_layoutTrue。我在前面已经推荐过它会在绘图过程中自动预留空间。如果选择这个方案就不要再用tight_layout()了二选一即可。5.4 散点图颜色条colorbar位置错乱当你用fig.colorbar(sc, axax)在子图上添加颜色条时默认情况下它会“偷走”当前子图的一部分宽度导致子图左右不对称。如果存在多个子图每个子图都有颜色条布局会非常丑陋。解决办法是给colorbar指定ax参数fig.colorbar(sc, ax[ax1, ax2], locationright)ax可以传一个列表这样颜色条会横跨两个子图的高度视觉上更整齐。5.5 雷达图刻度标签重叠或显示不全极坐标axes的刻度标签位置比较特殊如果不做调整类别名称会叠在一起。常用的处理方式调小字体ax.tick_params(labelsize8)。调整刻度标签与圆心的距离ax.tick_params(pad10)。手动设置标签位置ax.set_xticklabels(dimensions, position(x, y))但这种方式太麻烦实际很少用。增加figure尺寸figsize(8, 8)让雷达图占据更大的空间。如果类别超过6个我的建议是直接放弃雷达图改用水平条形图每个类别一行方向统一阅读效率高得多。5.6 常见问题速查表问题现象可能原因处理方式图形窗口不显示后端配置错误matplotlib.use(TkAgg)中文显示为方框字体缺失rcParams[font.sans-serif][SimHei]坐标轴标签被截断布局未调整fig.tight_layout()图例为空未传label绘图时加label参数雷达图标签重叠极坐标标签过多调小字体或figsize保存图片有白边bbox_inches未设置savefig(..., bbox_inchestight)多条曲线线条难以区分线型颜色太接近使用color列表linestyle组合这表格里的问题我基本都踩过一遍尤其是中文乱码和后端问题几乎在每次换环境、换电脑时都会遇到。提前在代码模板里设置好能省掉很多重复排查时间。6. 一些实际操作中的经验体会写到这里我想分享几个不太会写在官方文档里的经验。第一个是关于代码结构只要画的图超过一个我就一定会把绘图逻辑封装成函数用fig和ax作为输入输出而不是让函数内部创建figure。这样测试和复用都会方便很多。第二个是使用ax.set(… )批量设置参数。ax.set_xlabel()、ax.set_ylabel()、ax.set_title()、ax.set_xlim()这些方法可以一次性合并成ax.set(xlabel..., ylabel..., title..., xlim(0, 10))代码精简不少也让视觉上更整齐。官方也推荐这种写法。第三个是关于axes命名风格。我发现很多新手会把变量名写成axs而不是ax这是从plt.subplots(2, 2)返回二维数组的习惯来的。但注意如果你只有一个子图变量名用ax如果有多个子图变量名用axes或者axs千万别混用。避免给未来阅读代码的自己挖坑。第四个经验是关于异常排错的顺序。如果你的绘图代码报错第一步不是看代码逻辑而是先看是否在正确的位置创建了axes。大量报错、空白、标签错乱根源都在于“在没有axes的地方去调用axes方法”。比如直接在figure对象上调用plot()就会报AttributeError。记住数据画在axes上axes由figure管理figure只是容器。最后说一个我最近常用的技巧利用fig.autofmt_xdate()自动旋转日期刻度标签。如果你用ax.plot()画时间序列调用这个方法会自动把x轴刻度标签旋转30度并调整对齐方式比手动tick_params省心得多。Matplotlib的axes API真正强大之处就在这里它把画图的每个环节都变成可控对象你知道每个部件在哪里就总能找到相应的控制方法。遇到问题去翻一下Axes类的文档比到处搜代码片段高效得多。
