1. 别再用Excel画折线图了:从单组到多组数据,matplotlib一步到位
做过数据分析的人都有个体会:数据清洗完,最头疼的不是模型调参,而是怎么把结果快速、准确、好看地画出来。尤其是折线图这种最基础也最常用的图表,很多人第一反应是复制粘贴到Excel里,拖拽几下生成一个默认样式,然后截图贴到报告里。这样做不是不行,但一旦数据量变大、需要批量出图、或者要统一风格,手动操作就成了灾难。更别提多组数据对比时,Excel的默认配色和坐标轴处理经常让人抓狂。
matplotlib作为Python生态里最经典的绘图库,最大的优势就是把画图这件事代码化、可复现、可批量。你只需要把数据整理成列表或数组,几行代码就能生成一张折线图,单组数据和多组数据都能轻松应对。这篇文章面向的是有一定Python基础、但还没系统掌握matplotlib绘图技巧的读者,也适合那些平时用Excel画图、想转向代码化出图的分析师和工程师。我会从最基础的单组数据折线图讲起,逐步过渡到多组数据对比、样式定制、常见坑点排查,把我在实际项目中反复验证过的写法分享出来。
2. 为什么我建议你用代码画折线图而不是手动工具
2.1 手动绘图的三个隐性成本
很多人觉得Excel画图快,拖一下就好了。但我在实际项目里踩过的坑告诉我,手动绘图的成本远不止那几分钟的操作时间。第一个成本是不可复现:三个月后你再看那张图,完全不记得当时是怎么筛选数据、怎么设置坐标轴范围的,想改一个颜色都得重新来一遍。第二个成本是批量困难:如果你有20个城市的销售数据要分别出图,手动操作就是20次重复劳动,而代码只需要一个循环。第三个成本是风格不统一:团队里每个人画图的配色、字体、线宽都不一样,拼到一份报告里显得非常不专业。
代码化绘图的核心价值在于,你把“画图”这件事变成了一个可保存、可修改、可复用的脚本。数据更新了,重新跑一遍脚本就行;想换配色,改一个参数就行;要批量出图,加个for循环就行。这种效率提升,在数据频繁更新的场景下尤其明显。
2.2 matplotlib在折线图场景下的独特优势
Python里能画图的库不少,seaborn、plotly、pyecharts各有千秋。但折线图这个场景,matplotlib依然是最稳妥的选择。原因有三:第一,控制粒度最细,从线宽、线型、标记点样式到坐标轴刻度、图例位置,每一个元素都能精确控制;第二,兼容性最好,不管你是用numpy数组、pandas的DataFrame还是纯Python列表,matplotlib都能直接接收;第三,输出格式灵活,PNG、SVG、PDF随便选,SVG和PDF还是矢量图,放到论文或报告里放大不失真。
seaborn虽然样式更好看,但它本质上是matplotlib的封装,遇到复杂的自定义需求还是得回到matplotlib。plotly适合交互式图表,但静态报告里用不上。所以我的建议是:先把matplotlib的折线图吃透,其他库都是锦上添花。
2.3 单组与多组数据的本质区别
单组数据折线图和多组数据折线图,看起来只是多画几条线的事,但实际处理时有几个关键差异。单组数据时,你只需要关心一条线的x和y;多组数据时,你要考虑每组数据的x轴是否一致、图例怎么区分、颜色怎么搭配、线条重叠时怎么保证可读性。更重要的是,多组数据往往意味着数据结构更复杂,可能是嵌套列表、字典或者DataFrame,怎么把这些结构转换成matplotlib能识别的格式,是很多人卡住的地方。
我在下面会分别用单组和多组的例子,把数据准备、绘图、样式调整的完整流程走一遍。你可以直接把这些代码复制到自己的环境里跑,改改数据就能用。
3. 单组数据折线图:从数据到成图的完整流程
3.1 数据准备:列表、数组还是Series
单组数据折线图的数据准备非常简单,你只需要两个序列:x轴数据和y轴数据。x轴通常是时间、序号或者某个连续变量,y轴是对应的数值。数据格式可以是Python列表、numpy数组或者pandas的Series,matplotlib的plot函数都能直接接收。
我个人的习惯是,如果数据量不大(几百个点以内),直接用列表就行,写起来最直观。如果数据量上千,建议用numpy数组,运算效率更高。如果数据本身就在DataFrame里,直接取某一列传进去也可以,但要注意索引问题。
import matplotlib.pyplot as plt # 方式一:纯列表 x = [1, 2, 3, 4, 5, 6, 7] y = [12, 15, 13, 18, 22, 19, 25] # 方式二:numpy数组 import numpy as np x = np.arange(1, 8) y = np.array([12, 15, 13, 18, 22, 19, 25]) # 方式三:pandas Series import pandas as pd df = pd.DataFrame({'day': [1,2,3,4,5,6,7], 'value': [12,15,13,18,22,19,25]}) x = df['day'] y = df['value']三种方式画出来的图是一样的,区别只在于数据操作的便利性。如果你后续还要做数据筛选、分组聚合,用pandas会更方便;如果只是单纯画图,列表就够了。
3.2 最简绘图代码与参数解读
单组数据折线图的核心代码就一行:plt.plot(x, y)。但这一行背后有很多默认行为,理解这些默认值能帮你少走弯路。
import matplotlib.pyplot as plt x = [1, 2, 3, 4, 5, 6, 7] y = [12, 15, 13, 18, 22, 19, 25] plt.plot(x, y) plt.show()这段代码会生成一张默认样式的折线图:蓝色实线,线宽1.5,没有标记点,坐标轴范围自动根据数据调整。plt.show()在脚本里会弹出一个窗口显示图像,在Jupyter Notebook里会直接内嵌显示。
这里有几个默认行为值得注意。第一,坐标轴范围是自动计算的,matplotlib会根据数据的最大值和最小值留出一定的边距,通常是数据范围的5%。第二,x轴和y轴的刻度也是自动生成的,它会尽量选择“好看”的刻度值,比如整数或者0.5的倍数。第三,没有图例,因为单组数据不需要区分。第四,没有标题和轴标签,这些都需要你手动添加。
3.3 让图表可读性翻倍的五个设置
默认样式能用,但离“好看”还差得远。我每次画图都会加上这五个设置,基本上能让图表的可读性提升一个档次。
第一个是设置图片尺寸。默认的图片尺寸是6.4x4.8英寸,在报告里显得有点小。我一般用plt.figure(figsize=(10, 6)),宽10英寸、高6英寸,比例更舒服。
第二个是添加标题和轴标签。标题用plt.title(),x轴标签用plt.xlabel(),y轴标签用plt.ylabel()。标签要写清楚单位,比如“销售额(万元)”,不要只写“销售额”。
第三个是设置中文字体。matplotlib默认不支持中文,直接写中文会显示成方框。需要设置plt.rcParams['font.sans-serif'] = ['SimHei'],SimHei是黑体,Windows系统自带。Mac系统可以用['Arial Unicode MS']。
第四个是添加网格线。plt.grid(True, linestyle='--', alpha=0.5),虚线网格、透明度0.5,既能辅助读数又不会喧宾夺主。
第五个是调整坐标轴范围。如果数据从0开始有意义,就用plt.ylim(bottom=0)让y轴从0开始;如果数据集中在某个区间,可以手动设置plt.ylim(10, 30)让差异更明显。
import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False x = [1, 2, 3, 4, 5, 6, 7] y = [12, 15, 13, 18, 22, 19, 25] plt.figure(figsize=(10, 6)) plt.plot(x, y, linewidth=2, marker='o', markersize=6) plt.title('一周销售额变化趋势', fontsize=16) plt.xlabel('日期(天)', fontsize=12) plt.ylabel('销售额(万元)', fontsize=12) plt.grid(True, linestyle='--', alpha=0.5) plt.ylim(bottom=0) plt.show()这里我加了marker='o'和markersize=6,在每个数据点上画一个圆点。数据点少于20个的时候,加标记点能让读者更清楚地看到具体数值位置。数据点多的时候就不要加了,否则线会显得很乱。
注意:
plt.rcParams['axes.unicode_minus'] = False这行代码是为了解决负号显示成方框的问题,只要用了中文字体就建议加上。
4. 多组数据折线图:对比分析的正确打开方式
4.1 多组数据的三种组织方式
多组数据折线图的核心需求是对比。比如对比三个产品过去一年的销量走势,或者对比两个城市的气温变化。数据组织方式直接决定了代码怎么写,我常用的是三种:嵌套列表、字典和DataFrame。
嵌套列表适合数据量小、结构简单的情况。比如三组数据,每组7个点:
x = [1, 2, 3, 4, 5, 6, 7] y1 = [12, 15, 13, 18, 22, 19, 25] y2 = [8, 11, 14, 12, 16, 18, 20] y3 = [20, 18, 22, 25, 21, 24, 28]字典适合给每组数据起名字,方便后续设置图例:
data = { '产品A': [12, 15, 13, 18, 22, 19, 25], '产品B': [8, 11, 14, 12, 16, 18, 20], '产品C': [20, 18, 22, 25, 21, 24, 28] }DataFrame适合数据本身就在表格里的情况,比如从CSV读进来的数据:
import pandas as pd df = pd.DataFrame({ 'day': [1,2,3,4,5,6,7], '产品A': [12,15,13,18,22,19,25], '产品B': [8,11,14,12,16,18,20], '产品C': [20,18,22,25,21,24,28] })三种方式都能画图,区别在于代码的简洁程度和可扩展性。我一般推荐用字典或DataFrame,因为图例的标签可以直接从键名或列名取,不用手动写。
4.2 循环绘图与图例自动生成
多组数据绘图最忌讳的就是把plt.plot()写三遍,然后手动设置颜色和图例。正确的做法是用循环,代码简洁且容易扩展。
import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False x = [1, 2, 3, 4, 5, 6, 7] data = { '产品A': [12, 15, 13, 18, 22, 19, 25], '产品B': [8, 11, 14, 12, 16, 18, 20], '产品C': [20, 18, 22, 25, 21, 24, 28] } plt.figure(figsize=(10, 6)) for label, y in data.items(): plt.plot(x, y, linewidth=2, marker='o', markersize=5, label=label) plt.title('三款产品一周销量对比', fontsize=16) plt.xlabel('日期(天)', fontsize=12) plt.ylabel('销量(件)', fontsize=12) plt.legend(fontsize=12) plt.grid(True, linestyle='--', alpha=0.5) plt.show()这段代码的关键是label=label和plt.legend()的配合。label参数给每条线打上标签,plt.legend()负责把标签渲染成图例。matplotlib会自动为每条线分配不同的颜色,默认的颜色循环是蓝、橙、绿、红、紫、棕、粉、灰、黄、青,十条线以内都能区分开。
4.3 颜色、线型和标记点的搭配策略
自动分配的颜色在三条线以内没问题,但超过五条线就容易混淆。这时候需要手动指定颜色和线型,让每条线都有独特的视觉特征。
我常用的策略是:颜色区分主要类别,线型区分次要类别。比如对比三个产品,用三种颜色;每个产品又有实际值和预测值两条线,就用实线和虚线区分。
colors = ['#1f77b4', '#ff7f0e', '#2ca02c'] linestyles = ['-', '--', '-.'] markers = ['o', 's', '^'] plt.figure(figsize=(10, 6)) for i, (label, y) in enumerate(data.items()): plt.plot(x, y, color=colors[i], linestyle=linestyles[i], marker=markers[i], markersize=5, linewidth=2, label=label) plt.title('三款产品一周销量对比', fontsize=16) plt.xlabel('日期(天)', fontsize=12) plt.ylabel('销量(件)', fontsize=12) plt.legend(fontsize=12) plt.grid(True, linestyle='--', alpha=0.5) plt.show()颜色我推荐用十六进制色值,比英文颜色名更精确。上面用的三个颜色是matplotlib默认色环的前三个,分别是蓝色、橙色、绿色,对比度足够且对色盲友好。线型方面,实线表示主要数据,虚线表示次要数据,点划线表示参考数据,这是行业惯例。标记点用圆形、方形、三角形区分,形状差异比颜色差异更容易在黑白打印时辨认。
提示:如果线条超过五条,建议考虑拆成多张子图,或者只突出显示最重要的两三条,其余的用灰色细线作为背景。一张图里塞太多线,读者根本看不清。
5. 样式定制:让你的折线图直接达到报告级别
5.1 坐标轴与刻度的精细控制
默认的坐标轴刻度是matplotlib自动生成的,大多数时候够用,但有些场景需要手动干预。比如x轴是日期时,自动刻度可能会显示成“1.5”这种没有意义的小数;或者y轴数据范围是0.001到0.002,自动刻度显示成科学计数法,读者看不懂。
手动设置刻度用plt.xticks()和plt.yticks():
plt.xticks([1, 2, 3, 4, 5, 6, 7], ['周一', '周二', '周三', '周四', '周五', '周六', '周日']) plt.yticks([0, 5, 10, 15, 20, 25, 30])第一个参数是刻度位置,第二个参数是刻度标签。如果只传第一个参数,标签就用数值本身。这个功能在x轴是分类变量时特别有用,比如把1到7映射成星期几。
坐标轴范围用plt.xlim()和plt.ylim()控制。我一般会留一点边距,不要让数据点紧贴边界:
plt.xlim(0.5, 7.5) plt.ylim(0, 32)如果y轴数据从0开始有意义(比如销量、人数),一定要用plt.ylim(bottom=0)让y轴从0开始,否则会夸大数据之间的差异,造成误导。这是数据可视化的基本原则,但很多人会忽略。
5.2 图例位置与样式的调整技巧
图例默认放在图表的右上角,但有时候会挡住数据线。plt.legend()的loc参数可以控制位置,常用的值有'upper right'、'upper left'、'lower right'、'lower left'、'center'、'best'。'best'会让matplotlib自动选择遮挡最少的位置,但计算需要时间,数据量大时可能会慢。
plt.legend(loc='upper left', fontsize=12, frameon=True, shadow=True)frameon=True给图例加边框,shadow=True加阴影,让图例从背景中凸显出来。如果图例内容比较多,可以用ncol参数分成多列:
plt.legend(loc='upper center', ncol=3, fontsize=11)ncol=3表示图例分三列显示,适合类别较多的情况。图例的标题可以用title参数设置,比如plt.legend(title='产品名称')。
5.3 保存图片的格式选择与分辨率设置
画完图最后一步是保存。plt.savefig()支持多种格式,常用的有PNG、SVG、PDF。PNG适合网页和PPT,SVG和PDF适合论文和印刷品,因为它们是矢量格式,放大不失真。
plt.savefig('sales_trend.png', dpi=300, bbox_inches='tight') plt.savefig('sales_trend.svg', bbox_inches='tight') plt.savefig('sales_trend.pdf', bbox_inches='tight')dpi=300表示每英寸300个像素点,这是印刷品的标准分辨率。屏幕显示用72或96就够了,但报告和论文建议用300。bbox_inches='tight'会自动裁剪图片周围的空白边距,让图表更紧凑。
注意:
plt.savefig()必须在plt.show()之前调用。因为plt.show()会清空当前图形,之后再保存就是一张白图。这个坑我踩过不止一次,尤其是在Jupyter Notebook里,plt.show()之后图形就没了。
6. 实操中踩过的坑与排查技巧
6.1 中文显示方框的三种解决方案
中文显示成方框是matplotlib最常见的问题,没有之一。根本原因是matplotlib默认的字体不支持中文字符。解决方案有三种,我按推荐程度排序。
第一种是设置全局字体,一劳永逸:
plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = FalseSimHei是Windows自带的黑体,Mac系统可以用['Arial Unicode MS']或['PingFang SC']。这行代码要放在所有绘图代码之前。
第二种是给单个文本元素指定字体:
plt.title('销售额趋势', fontproperties='SimHei')这种方式适合只改标题或轴标签的情况,但每个文本元素都要加,比较麻烦。
第三种是下载中文字体文件,手动注册到matplotlib。这种方法最灵活,但步骤最多,适合需要特定字体的情况。我一般用第一种就够了。
6.2 数据点重叠与线条遮挡的处理
多组数据画在一起时,线条重叠是常有的事。如果两条线数值接近,后画的线会盖住先画的线,导致读者看不清。解决办法有三个。
第一个是调整透明度。plt.plot(x, y, alpha=0.7),让线条半透明,重叠部分能看出颜色叠加。但透明度太低会影响单条线的清晰度,0.6到0.8之间比较合适。
第二个是调整绘制顺序。把最重要的数据放在最后画,这样它会显示在最上层。在循环里调整字典的顺序就行。
第三个是错开数据点。如果x轴是分类变量,可以给不同组的数据加一个微小的偏移,比如第一组x=1,第二组x=1.1,第三组x=1.2。这样线条不会完全重叠,但要注意偏移量不能太大,否则x轴刻度会对不上。
6.3 常见报错与快速排查表
| 报错信息 | 原因 | 解决方法 |
|---|---|---|
ValueError: x and y must have same first dimension | x和y长度不一致 | 检查数据长度,用len()确认 |
TypeError: unsupported operand type(s) | 数据类型不对,比如字符串和数字混用 | 用astype(float)转换数据类型 |
| 中文显示成方框 | 字体不支持中文 | 设置plt.rcParams['font.sans-serif'] |
| 负号显示成方框 | 字体不支持负号 | 设置plt.rcParams['axes.unicode_minus'] = False |
| 保存的图片是空白 | plt.show()在plt.savefig()之前调用 | 调整顺序,先保存再显示 |
| 图例不显示 | 没有设置label参数 | 在plt.plot()里加label='名称' |
| 线条太细看不清 | 默认线宽1.5 | 设置linewidth=2或更大 |
这张表里的问题我基本都遇到过,尤其是第一个和第五个,新手很容易卡住。记住一个原则:报错信息里提到什么,就去检查什么。x and y must have same first dimension就是告诉你x和y长度不一样,去检查数据源就行。
6.4 批量出图的效率技巧
如果你需要为多个数据集分别出图,比如20个城市各画一张折线图,手动改代码肯定不行。用循环批量生成:
cities = ['城市A', '城市B', '城市C'] for city in cities: plt.figure(figsize=(10, 6)) plt.plot(x, data[city], linewidth=2, marker='o') plt.title(f'{city}销售额趋势', fontsize=16) plt.xlabel('日期(天)', fontsize=12) plt.ylabel('销售额(万元)', fontsize=12) plt.grid(True, linestyle='--', alpha=0.5) plt.savefig(f'{city}_trend.png', dpi=300, bbox_inches='tight') plt.close()关键点是每次循环都要新建一个figure,画完后用plt.close()关闭,否则内存会越占越多。plt.close()这行很多人会忘,数据量大的时候会导致内存溢出。
提示:批量出图时建议把图片保存到单独的文件夹里,用
os.makedirs()创建文件夹,文件名加上日期或版本号,方便后续查找。
7. 从单组到多组:我的实际项目经验总结
7.1 数据量不同时的策略选择
单组数据和多组数据在数据量上的处理策略完全不同。单组数据如果超过1000个点,线条会变得非常密集,标记点就不要加了,线宽也要调细,否则图看起来像一团色块。这时候可以考虑用plt.plot(x, y, linewidth=0.8),或者对数据进行降采样,每10个点取一个。
多组数据时,如果每组都超过500个点,一张图里塞三组就是1500个点,可读性会急剧下降。我的做法是:要么拆成多张子图,要么只画趋势线(比如用滑动平均后的数据),要么用透明度区分。子图用plt.subplot()实现,比如plt.subplot(1, 3, 1)表示一行三列的第一个位置。
7.2 图例太多时的布局方案
多组数据超过五组时,图例会占很大空间。我常用的方案是把图例放在图表外面:
plt.legend(loc='upper left', bbox_to_anchor=(1.02, 1), borderaxespad=0)bbox_to_anchor把图例定位到坐标轴外侧,(1.02, 1)表示在坐标轴右边缘稍微偏右的位置。这样图例不会遮挡数据,但需要调整plt.subplots_adjust()给图例留出空间:
plt.subplots_adjust(right=0.75)right=0.75表示坐标轴右边缘占图片宽度的75%,剩下的25%留给图例。这个比例根据图例的宽度调整,图例越宽,right的值越小。
7.3 代码复用的封装思路
每次画图都写一遍plt.figure()、plt.plot()、plt.title()太啰嗦。我一般会封装一个函数:
def plot_lines(x, data_dict, title, xlabel, ylabel, figsize=(10, 6)): plt.figure(figsize=figsize) for label, y in data_dict.items(): plt.plot(x, y, linewidth=2, marker='o', markersize=5, label=label) plt.title(title, fontsize=16) plt.xlabel(xlabel, fontsize=12) plt.ylabel(ylabel, fontsize=12) plt.legend(fontsize=12) plt.grid(True, linestyle='--', alpha=0.5) plt.tight_layout() return plt.gcf()这个函数接收x轴数据、数据字典、标题和轴标签,返回当前的figure对象。调用的时候只需要一行:
fig = plot_lines(x, data, '产品销量对比', '日期(天)', '销量(件)') fig.savefig('comparison.png', dpi=300, bbox_inches='tight')封装的好处是,所有图表的样式统一,改样式只需要改函数里的代码,不用每张图都改。plt.tight_layout()会自动调整子图间距,避免标签被截断。
7.4 几个让我少走弯路的习惯
第一个习惯是先画草图再调样式。不要一开始就纠结颜色和线型,先用默认样式把图跑出来,确认数据没问题,再慢慢调样式。我见过很多人卡在颜色选择上半小时,结果发现数据本身就有问题。
第二个习惯是把绘图代码和数据分开。数据从CSV或数据库读,绘图代码单独一个文件。这样数据更新了不用改代码,代码改了也不影响数据。
第三个习惯是保存绘图脚本。每张图对应的脚本都存下来,命名清晰,比如plot_sales_trend.py。三个月后要改图,直接找到脚本改一行就行,不用从头写。
第四个习惯是用版本号管理图片。sales_trend_v1.png、sales_trend_v2.png,不要覆盖旧图。有时候领导会说“还是上一版好看”,这时候旧图就派上用场了。
这些习惯看起来不起眼,但在实际项目里能省下大量时间。尤其是第三个和第四个,我在多个项目里都因为没保存脚本或覆盖了旧图而重新做过,教训深刻。
8. 进阶技巧:让折线图表达更多信息
8.1 添加参考线与标注
折线图有时候需要标注特殊事件,比如某天做了促销活动,销量突然上升。用plt.axvline()画竖线,用plt.annotate()加文字标注:
plt.axvline(x=4, color='red', linestyle='--', alpha=0.5) plt.annotate('促销活动', xy=(4, 18), xytext=(4.5, 24), arrowprops=dict(arrowstyle='->', color='red'), fontsize=12, color='red')axvline在x=4的位置画一条红色虚线,annotate在(4.5, 24)的位置写“促销活动”,并用箭头指向(4, 18)。这样读者一眼就能看出销量变化的原因。
水平参考线用plt.axhline(),比如画一条平均线:
avg = np.mean(y) plt.axhline(y=avg, color='gray', linestyle=':', alpha=0.7) plt.text(7.1, avg, f'平均: {avg:.1f}', fontsize=10, color='gray')8.2 双y轴折线图的实现
有时候两组数据的量纲不同,比如一组是销量(件),另一组是增长率(%),画在同一张图上需要双y轴。用plt.twinx()创建第二个y轴:
fig, ax1 = plt.subplots(figsize=(10, 6)) ax1.plot(x, sales, color='#1f77b4', linewidth=2, marker='o', label='销量') ax1.set_xlabel('日期(天)', fontsize=12) ax1.set_ylabel('销量(件)', fontsize=12, color='#1f77b4') ax1.tick_params(axis='y', labelcolor='#1f77b4') ax2 = ax1.twinx() ax2.plot(x, growth, color='#ff7f0e', linewidth=2, marker='s', label='增长率') ax2.set_ylabel('增长率(%)', fontsize=12, color='#ff7f0e') ax2.tick_params(axis='y', labelcolor='#ff7f0e') plt.title('销量与增长率对比', fontsize=16) fig.tight_layout() plt.show()双y轴的关键是twinx()创建共享x轴的第二个y轴,然后分别设置两个y轴的颜色和标签。图例需要合并两个轴的图例:
lines1, labels1 = ax1.get_legend_handles_labels() lines2, labels2 = ax2.get_legend_handles_labels() ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left')8.3 子图布局:一页展示多张折线图
如果有多组数据需要分别展示,但又想放在一张大图里对比,用子图布局。plt.subplots()可以创建网格状的子图:
fig, axes = plt.subplots(2, 2, figsize=(12, 10)) axes[0, 0].plot(x, data['产品A'], linewidth=2, marker='o') axes[0, 0].set_title('产品A', fontsize=14) axes[0, 1].plot(x, data['产品B'], linewidth=2, marker='s', color='#ff7f0e') axes[0, 1].set_title('产品B', fontsize=14) axes[1, 0].plot(x, data['产品C'], linewidth=2, marker='^', color='#2ca02c') axes[1, 0].set_title('产品C', fontsize=14) axes[1, 1].plot(x, data['产品A'], label='产品A') axes[1, 1].plot(x, data['产品B'], label='产品B') axes[1, 1].plot(x, data['产品C'], label='产品C') axes[1, 1].set_title('三者对比', fontsize=14) axes[1, 1].legend() plt.tight_layout() plt.show()subplots(2, 2)返回一个2x2的axes数组,用axes[行, 列]访问每个子图。tight_layout()自动调整间距,避免标题和标签重叠。这种布局适合在报告里一页展示多个维度的数据,比堆在一张图里清晰得多。
9. 关于折线图的一些个人体会
画折线图这件事,说简单也简单,plt.plot(x, y)一行代码就能出图。但要说画好,里面有不少细节值得琢磨。我刚开始用matplotlib的时候,觉得默认样式太丑,到处找教程调样式,结果调了半天发现数据本身有问题。后来才明白,图表的本质是传达信息,样式是辅助,数据才是核心。先把数据搞清楚,再考虑怎么画得好看。
另一个体会是,代码化绘图的优势在长期项目中才会显现。如果你只是偶尔画一张图,Excel确实更快。但如果你每周都要出报表,或者数据频繁更新,花一个小时把绘图脚本写好,后面能省下几十个小时。这个投入产出比是很划算的。
最后说一个我常用的检查方法:画完图之后,把图片缩小到50%看一遍。如果缩小后还能看清趋势和关键数据,说明图表的可读性没问题;如果缩小后一团糟,说明信息密度太高,需要简化。这个方法帮我避免了很多“自嗨型”图表,就是那种自己觉得画得很详细、但读者根本看不清的图。