
刚接触数据可视化的人十有八九都听过Matplotlib这个库的名字。它长期霸占着Python绘图工具的第一梯队位置无论是折线图、曲线图、柱状图还是散点图几乎你能想到的静态图表它都能画出来。我最早用这个库的时候还在上学当时只觉得它能出图很神奇后来做了这么多项目才发现Matplotlib真正厉害的地方不在于“能画”而在于“什么都能调”。说它是画图的神真不算夸张。这篇文章我会从底层的绘图逻辑开始讲把折线图、曲线图以及各种常见图表的绘制原理和实操细节拆开揉碎再把我在实际项目中踩过的坑和积累的经验一并写出来。不管你是刚上手Python的小白还是已经能写业务代码但绘图总差一口气的开发者这篇文章都能让你少走很多弯路。1. Matplotlib到底解决什么问题先明白它的设计风格1.1 它是“状态机思维”的绘图库很多人学Matplotlib一开始就晕是因为没理解它的核心逻辑。它和那种“一行代码出图”的库不一样它的工作方式更像一个画师在画板上逐笔作画。你把画板准备好拿笔画一条线再加点颜色标注几个点最后把画展示出来或者保存成图片文件。每一步操作会作用于同一个“当前画布”这就是所谓的状态机思维。import matplotlib.pyplot as plt plt.plot([1, 2, 3], [4, 5, 6]) plt.title(简单折线图) plt.show()在这个最简单的例子里plt.plot()往当前画布上加了一条线plt.title()加了个标题plt.show()把画布展示出来。你不用显式地说“我要创建一个画板”因为plt模块已经帮你默认创建好了。这种设计的好处是写起来非常顺手代码短小精悍特别适合快速探索数据。但如果你要做稍微复杂一点的图比如一张画布上排列多个子图、每个子图有自己的坐标轴范围状态机的写法就会变得混乱。这时候就需要切换到Matplotlib的面向对象接口这是每个进阶用户必须迈过的一关。1.2 先分清Figure和AxesMatplotlib最核心的两个概念就是Figure和Axes。你可以把Figure理解成一张完整的画布它包含标题、图例、坐标轴等所有元素而Axes是画布上的一块绘图区域也就是真正画数据图的那个坐标系。一个Figure上可以有好几个Axes就像一张纸上可以画好几幅图一样。fig, ax plt.subplots() ax.plot([1, 2, 3], [4, 5, 6]) ax.set_title(使用Axes绘图) plt.show()plt.subplots()返回两个对象fig是画布ax是子图区域。之后所有的绘图操作都在ax上进行设置标题也是ax.set_title()。这种写法看起来比状态机模式冗长一点但它清晰、可控、不易出错。我强烈建议新手在学习初期就习惯用这种写法因为后续所有复杂的布局、坐标轴共享、动画更新都是以Figure和Axes为基石的。理解了这两个概念你就已经掌握了Matplotlib的骨架剩下的都是往骨架上填充肌肉和皮肤。2. 环境准备与第一张图别急着画图先搭好地基2.1 安装和基本导入Matplotlib的安装非常简单直接用pip命令即可pip install matplotlib如果你用的是Anaconda发行版那它已经预装好了不需要额外安装。导入的时候有一个约定俗成的习惯几乎所有资料都会写成import matplotlib.pyplot as plt import numpy as nppyplot是Matplotlib提供的一个快捷接口集合它内部维护着当前Figure和Axes的状态方便我们快速绘图。而numpy几乎是数据处理的标配因为Matplotlib的绘图数据通常以numpy数组的形式传入。我自己的习惯是还会加一句plt.rcParams[figure.dpi] 100把默认图片分辨率调高一点这样在屏幕上预览时不会因为模糊而忽略细节。当然这纯粹是个人偏好不影响功能。2.2 画一个最简单的折线图第一张图不必复杂用一组简单的数据感受一下绘图流程x np.linspace(0, 10, 20) y x ** 2 fig, ax plt.subplots() ax.plot(x, y) ax.set_xlabel(x) ax.set_ylabel(y) ax.set_title(y x^2 折线图) plt.show()np.linspace(0, 10, 20)生成了从0到10均匀分布的20个点x ** 2得到对应的平方值。用ax.plot()画线后设置x轴标签、y轴标签和标题一张完整的折线图就出来了。可能有人会问明明数据是离散的20个点为什么画出来是连续的曲线这是因为Matplotlib默认会把这些点用线段依次连接起来形成一个折线图效果。你传入的点数越多折线就越接近一条光滑的曲线。这也是折线图和曲线图在Matplotlib里其实用的是同一个函数的原因——plot()区别只在于数据密度和是否做了平滑处理。2.3 中文乱码问题必须第一时间处理初次使用中文标题时大概率会看到一个个方框这是因为Matplotlib的默认字体不支持中文。这是中文用户绕不过去的一个坎解决办法也很简单指定一个支持中文的字体即可plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False第一行把默认无衬线字体改成黑体这是Windows自带的字体如果你在macOS上使用可以改成[PingFang SC]或[Arial Unicode MS]Linux环境则可能需要指定[WenQuanYi Zen Hei]或[Noto Sans CJK SC]等。axes.unicode_minus这个设置是为了解决坐标轴负号显示为方块的问题。这个配置建议放在脚本开头统一设置否则每张图都要重复处理。我在团队里见过不少同学写完代码才发现中文乱码然后逐张修改非常浪费时间。3. 从折线图到“画图的神”常见图表逐个拆解3.1 折线图plot()最基础也最灵活折线图的核心目的是展示数据随时间或某个连续变量的变化趋势。plot()函数的完整签名里有大量的可选参数但日常使用最频繁的是下面几个color颜色可以用英文名、十六进制色值或RGB元组linestyle线型比如实线-、虚线--、点线:linewidth线宽数值越大线越粗marker数据点标记形状比如圆点o、方形s、星形*markersize标记大小举个例子fig, ax plt.subplots() ax.plot(x, y, color#FF6B6B, linestyle--, linewidth2.5, markero, markersize6) ax.set_title(带标记的虚线折线图) plt.show()这里用的是十六进制色值#FF6B6B一种偏珊瑚红的颜色屏幕显示效果比默认的蓝色更醒目。新手可以大胆尝试不同参数组合这些视觉细节直接影响图表的专业感。我在实际项目中有一个小经验如果数据点本身很重要比如每月销售额、每周用户数一定要加上marker参数如果数据点密集到已经无法分辨就不需要加否则线条会显得杂乱。3.2 曲线图进阶平滑曲线怎么实现数据点足够密集时直接用plot()画出来就已经接近曲线效果。但现实中的数据往往很稀疏比如一周只有7个采样点直接连线会得到一条生硬的折线。这时候就需要做平滑处理。最简单的方案是插值。用scipy.interpolate中的make_interp_spline方法from scipy.interpolate import make_interp_spline x_new np.linspace(x.min(), x.max(), 200) spl make_interp_spline(x, y, k3) y_smooth spl(x_new) fig, ax plt.subplots() ax.plot(x, y, o, label原始数据) ax.plot(x_new, y_smooth, -, label平滑曲线) ax.legend() plt.show()k3表示使用三次样条插值这是最常用的阶数。x_new是插值后的新横坐标序列点数越多曲线越平滑。注意保留原始散点作为参照否则容易给人一种“数据本就如此平滑”的错觉这在做汇报展示时是需要避免的。还有一种场景是数据本身带有噪声比如传感器采集的温度值这时候简单的插值反而会把噪声也放大。更合适的做法是先用滑动平均或Savitzky-Golay滤波器去噪再绘图。我一般在时序数据处理中优先用Savitzky-Golayfrom scipy.signal import savgol_filter y_smooth savgol_filter(y, window_length7, polyorder2)窗口长度window_length必须是奇数polyorder是多项式阶数通常2或3足够。3.3 柱状图bar()与对比需求柱状图的主要用途是比较不同类别之间的数值大小。比如对比几个商品线的月销量、不同地区的用户增长情况柱状图是最直观的选择。categories [A产品, B产品, C产品] sales [125, 312, 287] fig, ax plt.subplots() ax.bar(categories, sales, color[#5B8FF9, #61DDAA, #65789B]) ax.set_ylabel(销量) ax.set_title(各产品线销量对比) ax.bar_label(ax.containers[0], label_typeedge) plt.show()ax.bar()传入类别名称和对应的数值。我特意加了一行ax.bar_label(ax.containers[0], label_typeedge)这是Matplotlib 3.4.0之后提供的方法可以直接在柱状图顶端标注数值省去了手动写text()的麻烦。柱状图有几个容易忽略的细节一是颜色数量不要太多三到五个即可过多会让人眼花缭乱二是如果柱子之间存在横向比较关系建议把最大值和最小值用不同颜色突出显示三是当分类轴有明确顺序时比如月份不要随意打乱除非核心目的是比较而非趋势。需要展示多个系列对比时可以改成分组柱状图import numpy as np months np.arange(1, 7) product_a [20, 35, 30, 42, 38, 50] product_b [15, 22, 28, 30, 35, 40] width 0.35 fig, ax plt.subplots() ax.bar(months - width/2, product_a, width, labelA产品) ax.bar(months width/2, product_b, width, labelB产品) ax.set_xticks(months) ax.legend() plt.show()关键在于手动调整每个柱子的x坐标位置用一个width控制柱子宽度让两个系列错开排列。这里要特别注意set_xticks把刻度放回整数月份位置否则整个图会偏斜。3.4 散点图scatter()观察分布关系散点图用点的位置来展示两个变量之间的相互关系。它和折线图最大的区别是不会有连接线每个数据点都是独立的。np.random.seed(42) n 100 x np.random.normal(50, 10, n) y 0.6 * x np.random.normal(0, 5, n) fig, ax plt.subplots() ax.scatter(x, y, alpha0.7, c#5B8FF9, edgecolorswhite, linewidths0.5) ax.set_xlabel(广告投入) ax.set_ylabel(销售额) ax.set_title(广告投入与销售额关系散点图) plt.show()alpha控制透明度当点数量很多、彼此重叠时透明度的效果尤其明显——重叠区域颜色更深能体现出密度分布。edgecolors和linewidths给点加上一个白色描边让点在重叠时依然可分辨这是科研绘图里常用的小技巧。散点图还可以通过颜色映射colormap增加一个第三维度的信息点的颜色对应某个分组或某种连续数值。这在分析用户分群时非常实用sizes np.random.uniform(20, 100, n) fig, ax plt.subplots() sc ax.scatter(x, y, csizes, cmapviridis, alpha0.8) fig.colorbar(sc) plt.show()c参数传入一个和x等长度的数组cmap选择颜色映射方案fig.colorbar(sc)把色条画出来。这样一张图就能同时传达三个维度的信息信息密度一下子提升不少。3.5 直方图hist()统计分布的利器直方图用于展示数据的分布形态比如某地区人口的年龄分布、用户日活跃时长的分布。它的本质是把数据按区间切分统计每个区间内的数据个数。data np.random.normal(170, 8, 1000) fig, ax plt.subplots() ax.hist(data, bins30, color#61DDAA, edgecolorwhite, alpha0.8) ax.set_xlabel(身高/cm) ax.set_ylabel(频数) ax.set_title(身高分布直方图) plt.show()bins参数决定切分多少个区间这个值对直方图形态影响非常大。bins太小会丢失细节太大又会引入噪声。我通常先试十几个值找到既能看清趋势又不过于细碎的区间数。如果想要展示概率密度而不是频数可以加densityTrue让纵轴变成概率密度。直方图和柱状图的区别值得说清楚柱状图的横轴是离散类别柱子之间互不相连直方图的横轴是连续数值的分组柱子在边界处紧密相邻。这两种图在业务汇报里经常被混用搞清楚了才不会画错类型。3.6 饼图pie()占比展示的注意事项饼图是流传度很高但也很容易被批评的图表类型。它的适用场景是展示各个部分占整体的比例通常不超过6个部分否则扇区太小很难辨认。sizes [35, 25, 20, 20] labels [产品A, 产品B, 产品C, 产品D] fig, ax plt.subplots() ax.pie(sizes, labelslabels, autopct%.1f%%, startangle90, explode[0.05, 0, 0, 0]) ax.axis(equal) plt.show()autopct%.1f%%在扇区内部显示百分比保留一位小数。startangle90让饼图从90度方向开始画视觉上更整齐。explode参数可以把某个扇区“炸开”一点用于突出该部分比如这里把产品A的扇区向外偏移5%。ax.axis(equal)这行不能省它强制x轴和y轴的比例相等保证饼图是正圆形而不是椭圆形。我见过太多人因为漏掉这行代码画出一个难看的椭圆饼图。4. 图表美化和定制让图真正“能打”数据和内容固然重要但同一份数据用默认样式画出来和经过精心调色后画出来效果天差地别。图表美化是Matplotlib进阶中性价比最高的投入。4.1 颜色、线型、标记的组合Matplotlib有一个完整的颜色系统支持英文颜色名red、单个字母缩写r、十六进制色值#FF6B6B、RGB元组(1, 0.4, 0.4)还有灰度表示方法0.7表示浅灰。我的经验是如果图要用于正式报告不要用默认的蓝色和橙色选一些经过设计师调校的颜色组合会更耐看。一套我经常沿用的配色是主色#5B8FF9柔和蓝对比色#61DDAA薄荷绿强调色#F6BD16暖黄警示色#E8684A砖红这些颜色饱和度适中打印和屏幕播放都不会失真。线型方面最常用的是实线-和虚线--偶尔用点线:和点划线-.。在同一张图上画多条曲线时优先用颜色区分如果还需要更强的区分度比如黑白打印就同时改线型。4.2 标注与文字把关键信息说清楚单纯把线画出来只是第一步真正有价值的是告诉读者“看这里这个点很重要”。Matplotlib提供了ax.annotate()专门用来给关键位置添加注释。x_peak 7 y_peak 7 ** 2 fig, ax plt.subplots() ax.plot(x, y) ax.annotate(峰值点, xy(x_peak, y_peak), xytext(4, 80), arrowpropsdict(arrowstyle-, color#E8684A), fontsize12) plt.show()xy是待标注数据点的位置xytext是注释文字的位置arrowprops把两者用箭头连起来。我每次做这种标注时都会多试几个xytext位置避免箭头穿过数据线或者在角落挤压变形。如果要在图中添加一行或多行文字说明用ax.text()ax.text(0.5, 0.5, 说明文字, transformax.transAxes)transformax.transAxes是一个很常用的技巧它会将坐标原点从数据坐标系切换到轴坐标系范围内这样注释位置就不会随着数据范围的变化而漂移。坐标(0, 0)是左下角(1, 1)是右上角。4.3 子图布局一张画布讲多个故事实际业务场景中经常需要把多个相关图表放在一起对照展示比如同一个指标的不同分组、同一组数据的原始形态和分布情况。用plt.subplots()创建多个子图并指定布局fig, axes plt.subplots(2, 2, figsize(10, 8)) axes[0, 0].plot(x, y) axes[0, 0].set_title(折线图) axes[0, 1].scatter(x, y) axes[0, 1].set_title(散点图) axes[1, 0].hist(y, bins20) axes[1, 0].set_title(直方图) axes[1, 1].boxplot(y) axes[1, 1].set_title(箱线图) plt.tight_layout() plt.show()subplots(2, 2)创建了一个两行两列的子图网格axes是一个二维数组分别索引即可。figsize(10, 8)控制整个画布的大小单位是英寸。plt.tight_layout()会自动调整子图之间的间距避免标题和坐标轴标签互相重叠这一行我几乎每次都会加。如果你希望某个子图比其他子图宽或高可以用gridspec或者subplot_mosaic。subplot_mosaic是Matplotlib 3.3引入的新特性语法更直观fig, axes plt.subplot_mosaic([ [left, right_top], [left, right_bottom] ]) axes[left].plot(x, y)通过传入一个二维列表字母相同的区域会合并成一个子图。这种布局自由度很高适合做复杂仪表盘式的综合图。4.4 样式方案几行代码切换风格Matplotlib内置了多套样式可以通过plt.style.use()一键切换。常见的包括seaborn-v0_8、ggplot、bmh、fivethirtyeight。plt.style.use(seaborn-v0_8)我比较喜欢seaborn-v0_8的默认网格线和配色它能让图表呈现一种近似专业统计软件输出的质感。ggplot的风格则更接近R语言生态下的经典审美。这些样式方案适合快速出图但如果你需要多张图风格统一我建议还是自定义一套自己的sans-serif字体、配色循环和坐标轴线条粗细通过rcParams一次性配置plt.rcParams.update({ font.sans-serif: [SimHei], axes.unicode_minus: False, axes.spines.top: False, axes.spines.right: False, axes.grid: True, grid.alpha: 0.4, figure.figsize: (9, 6), })隐藏顶部和右侧的坐标轴线让图看起来更干净打开网格线并降低透明度辅助读图又不喧宾夺主。这套配置我已经用了很多年几乎所有图都基于它再微调。5. 常用高阶操作与实战场景5.1 多子图组合案例一份数据多种视角下面我用一份模拟的电商订单数据把前面介绍的几个核心图表串起来。import numpy as np import matplotlib.pyplot as plt np.random.seed(7) days np.arange(1, 31) daily_orders np.random.poisson(lam120, size30).astype(float) daily_orders np.sin(days / 3) * 15 fig, axes plt.subplots(2, 3, figsize(14, 8)) axes[0, 0].plot(days, daily_orders, -o, color#5B8FF9) axes[0, 0].set_title(每日订单量趋势) axes[0, 0].set_xlabel(日期) axes[0, 1].hist(daily_orders, bins10, color#61DDAA, edgecolorwhite) axes[0, 1].set_title(订单量分布直方图) axes[0, 2].boxplot(daily_orders, patch_artistTrue, boxpropsdict(facecolor#F6BD16)) axes[0, 2].set_title(订单量箱线图) axes[0, 2].set_xticklabels([订单量]) axes[1, 0].plot(days, daily_orders, color#65789B) axes[1, 0].fill_between(days, daily_orders.min(), daily_orders, color#61DDAA, alpha0.3) axes[1, 0].set_title(订单量面积图) cumsum_orders np.cumsum(daily_orders) axes[1, 1].plot(days, cumsum_orders, color#E8684A, linewidth2) axes[1, 1].set_title(累计订单量) sorted_orders np.sort(daily_orders)[::-1] axes[1, 2].bar(days[:5], sorted_orders[:5], color#5B8FF9) axes[1, 2].set_title(订单量Top5) axes[1, 2].set_xticks(days[:5]) plt.tight_layout() plt.show()这六张子图从趋势、分布、离群值、累计量、排序等多个角度展示同一份数据。fill_between()画出了面积图效果np.cumsum()快速算累计值np.sort()[::-1]实现降序排序提取Top5。这种“一数多图”的展示方式在数据分析报告里非常受欢迎比单纯贴一张大折线图信息量大得多。5.2 时间序列坐标处理处理时间序列时Matplotlib的默认刻度往往不是最优的。比如数据横跨一整年默认刻度可能落到每个数据点标签密密麻麻。更合理的方式是用matplotlib.dates模块设置刻度定位器和格式器。import matplotlib.dates as mdates from datetime import datetime, timedelta dates [datetime(2024, 1, 1) timedelta(daysi) for i in range(180)] values np.random.randn(180).cumsum() fig, ax plt.subplots() ax.plot(dates, values) locator mdates.MonthLocator() formatter mdates.DateFormatter(%Y-%m) ax.xaxis.set_major_locator(locator) ax.xaxis.set_major_formatter(formatter) plt.xticks(rotation30) plt.show()MonthLocator()让主刻度只显示在每个月的起始位置DateFormatter(%Y-%m)把刻度标签格式化成年-月的形式。plt.xticks(rotation30)让标签旋转30度避免拥挤。时间序列还有一个常见的坑如果你传入的是字符串日期Matplotlib不一定能正确解析为时间轴画出来的图可能在坐标轴间距上不对。最好提前用pd.to_datetime()或者datetime.strptime()转换成datetime对象。5.3 动态数据更新与动画如果你做的是实时数据监控比如服务器CPU使用率、股票行情Matplotlib也支持动态更新。核心原理是在一个循环中清除旧数据、绘制新数据然后用plt.pause()短暂刷新界面。fig, ax plt.subplots() x_data, y_data [], [] for i in range(100): x_data.append(i) y_data.append(np.random.randn()) ax.clear() ax.plot(x_data, y_data, color#5B8FF9) ax.set_title(f实时数据更新 - {i}) plt.pause(0.05) plt.show()ax.clear()清空当前子图的所有绘图内容然后重新ax.plot()。plt.pause(0.05)让界面有0.05秒的时间刷新同时保持GUI事件循环不卡死。如果想要更专业的动画控制可以用matplotlib.animation.FuncAnimation它的效率更高适合做真正的成片动画或GIF导出。这里先不展开等你有需要时再去翻官方文档也会很容易上手因为核心思路和上面的循环是一致的。6. 高频报错与排坑实录6.1 常见报错速查表我把这些年遇到的Matplotlib高频报错整理成了一个表格方便大家在遇到问题时快速定位。报错或异常常见原因解决办法中文显示为方块当前字体不支持中文设置rcParams[font.sans-serif]负号显示为方块字体不支持负号设置rcParams[axes.unicode_minus] FalseValueError: x and y must have same first dimensionx和y数组长度不一致检查数据长度绘图前打印len()逐一确认TypeError: list object is not callable变量名覆盖了内置函数或方法检查是否把plot等名称重新赋值了图形显示空白调用了plt.show()后清空画布保存图片要在plt.show()之前用plt.savefig()AttributeError: NoneType object has no attribute get_...Axes对象为None通常是因为使用了plt.subplots()没解包或索引错误图例不显示没有给绘图对象添加label参数在plot()等函数中加label名称再调用ax.legend()子图重叠严重没有调整间距在plt.show()之前加plt.tight_layout()图片保存后模糊不清默认dpi较低plt.savefig(out.png, dpi300)饼图不是圆形X轴和Y轴比例不一致加ax.axis(equal)这表格里的每一个都是真实出现过的报错其中“中文显示为方块”和“负号显示为方块”出现的频率最高也是新手最容易卡住的地方。6.2 我自己踩过的一些坑第一个坑是plt.show()和plt.savefig()的调用顺序。早期我经常在代码里先调plt.show()看一下效果确认没问题后想在后面加上plt.savefig()保存图片结果保存下来的是一张空白图。原因是plt.show()在默认后端中会清空当前画布后续保存自然什么都没有。正确的做法是保存操作放在show()之前。第二个坑是在绘图之前没有检查数据中是否存在NaN或无穷值。有一次我画折线图发现图形中间出现一条奇怪的垂直线段排查了小半天才发现是传入数据中有一个np.nanMatplotlib在遇到NaN时会断开线段那个异常就来自另一个数据点的异常跳跃。处理办法很简单绘图前用pd.isna()或np.isfinite()过滤mask np.isfinite(x) np.isfinite(y) x, y x[mask], y[mask]第三个坑是图例的重复标签。如果在一个循环中多次调用ax.plot()给同一个曲线迭代调色并且每次调用都传了相同的label图例会重复出现多条标目。解决办法是只在第一条线上设置label其余设置_nolegend_这是一个隐藏标记for i, color in enumerate(colors): if i 0: ax.plot(x, y, colorcolor, label曲线1) else: ax.plot(x, y, colorcolor, label_nolegend_)第四个坑和子图坐标轴共享有关。如果两个子图的数据量级差异很大却没有设置共享比例那对比效果会被压缩或者拉伸。比如一个子图显示0到1的小数另一个显示几千上万的大数并把两个图并列对照观察者很容易被误导。subplots支持sharex和sharey参数可以让多个子图共用一组坐标轴范围。6.3 如何让图表导出清晰工作中做出来的图大概率要放进报告里可能是Word文档、PPT或者网页。不同的载体对图片的规格要求不同有几个全局配置我很早就固定了下来。放在屏幕演示的图分辨率150到200dpi就够了打印输出或提交给期刊的图至少300dpi。fig.savefig(report.png, dpi300, bbox_inchestight)bbox_inchestight会自动裁剪白边让图片内容紧凑展示时不会被大块空白占据注意力。如果希望保存透明背景加transparentTrue这在叠加到其他设计图上时非常方便。矢量图格式也值得推荐。把图片保存为PDF或SVG放大多少倍都不会模糊适合印刷和UI设计场景。网页端用WebAgg后端还能交互式查看图形鼠标悬浮时显示具体坐标值。7. 写在最后一点个人体会掌握Matplotlib的节奏和掌握别的技能不太一样它不需要背太多东西关键是建立一个“绘图流程”的直觉——先想好画什么类型、数据是什么结构、需要哪些配置再动手。我在实际使用中最大的体会是最高频的操作其实就那么二十来个plot()、scatter()、hist()、bar()、pie()再加上set_title()、set_xlabel()、legend()这些配套方法。把这些做到条件反射级别的熟练工具层面的“不会”基本就不存在了。之后再遇到新需求靠的是对数据本身的思考而不是对函数用法的搜索。最后再分享一个小技巧每次拿到一组新数据不要急着一次性写完整绘图代码。先画最基础的图确认数据范围和形态合理再逐渐调整样式、加标注、调布局。一步一步叠加出问题的概率会小很多。这个过程听起来很笨但真的是我做了无数个图之后最实用的方法。Matplotlib给你足够大的自由去表达数据同样的数据、不同的参数组合可以讲出完全不同的故事。画图不是炫技是把话讲清楚。