数据有了也分析完了,但拿一堆表格数字给人看,没人看得进去——得画图。
一说到画图很多人就头疼:参数太多。其实不用。Matplotlib 的逻辑跟纸上画画一模一样,就三层:
- 第一层:得有张纸——画布(Figure)
- 第二层:纸上得有个画的区域——坐标系(Axes)
- 第三层:在区域里画东西——图表元素(线、柱、点)
理解了这三层,所有参数都有地方放。今天把最常用的三种图一次搞定:折线图、柱状图、散点图。
一、先搞清楚那三层关系
把 Matplotlib 想象成一个画室:
- Figure 就是画纸:纸多大、横版竖版归它管
- Axes 就是画框:一张纸可以放一个或多个画框(比如 2 行 2 列四张图),每个画框有自己的坐标系、标题、标签
- 图表元素 就是画的内容:线条、柱子、散点、标注都在画框里
记住一句:Figure 是纸,Axes 是纸上的一块画图区域。我们从一开始就用面向对象的写法(围绕ax操作),逻辑最清楚,后面画复杂图也不会乱。
importmatplotlib.pyplotaspltimportmatplotlib matplotlib.rcParams['font.sans-serif']=['SimHei','Microsoft YaHei']matplotlib.rcParams['axes.unicode_minus']=Falsedays=['周一','周二','周三','周四','周五','周六','周日']temp=[22,24,23,26,25,27,26]fig,ax=plt.subplots(figsize=(8,4))ax.plot(days,temp,marker='o',color='#ff4d4f',linewidth=2)ax.set_title('本周气温变化',fontsize=14)ax.set_xlabel('日期')ax.set_ylabel('温度(℃)')ax.grid(axis='y',alpha=0.3)plt.tight_layout()plt.show()代码结构就是那三层:plt.subplots()同时创建画纸(fig)和画框(ax),ax.plot()在画框里画线,ax.set_title()加文字说明。所有操作都围绕ax来。
二、折线图:看趋势
折线图用得最多,看趋势、看变化、看走势,时间序列和连续变化的数据首选。
importmatplotlib.pyplotaspltimportmatplotlib matplotlib.rcParams['font.sans-serif']=['SimHei','Microsoft YaHei']matplotlib.rcParams['axes.unicode_minus']=Falsemonths=['1月','2月','3月','4月','5月','6月']sales_A=[120,150,135,180,200,220]sales_B=[80,95,110,130,125,150]fig,ax=plt.subplots(figsize=(9,5))ax.plot(months,sales_A,marker='o',color='#ff4d4f',linewidth=2,label='产品A')ax.plot(months,sales_B,marker='s',color='#1890ff',linewidth=2,label='产品B')ax.set_title('上半年产品销售趋势',fontsize=15)ax.set_xlabel('月份')ax.set_ylabel('销售额(万元)')ax.legend(loc='upper left')ax.grid(axis='y',alpha=0.3,linestyle='--')ax.spines['top'].set_visible(False)ax.spines['right'].set_visible(False)plt.tight_layout()plt.show()几个关键点:
- 多条线就多次调用
plot(),每次传不同数据和颜色 - marker是数据点标记:圆圈
o、方块s、三角^ - 图例用
legend(),自动读取每条线的label - 去掉上右边框是提升图品质感的小技巧,专业图表大多这么做
想突出体量感还能画填充面积:ax.fill_between(months, sales_A, alpha=0.2, color='#ff4d4f'),alpha越小越透明。
三、柱状图:比大小
柱状图用来对比、排名、看多少,不同类别比大小最直观。
importmatplotlib.pyplotaspltimportmatplotlib matplotlib.rcParams['font.sans-serif']=['SimHei','Microsoft YaHei']matplotlib.rcParams['axes.unicode_minus']=Falsecategories=['食品','服装','数码','家居','美妆']revenue=[320,280,450,180,220]fig,ax=plt.subplots(figsize=(9,5))bars=ax.bar(categories,revenue,color='#ff4d4f',width=0.6)ax.set_title('各品类销售额对比',fontsize=15)ax.set_ylabel('销售额(万元)')forbarinbars:h=bar.get_height()ax.text(bar.get_x()+bar.get_width()/2,h+5,f'{h}',ha='center',va='bottom')ax.spines['top'].set_visible(False)ax.spines['right'].set_visible(False)ax.grid(axis='y',alpha=0.3,linestyle='--')plt.tight_layout()plt.show()最实用的技巧是在柱子顶上加数字,别人不用对着 Y 轴猜。类别名字长时用横向柱状图ax.barh(categories, revenue)。
两组数据放一起对比用分组柱状图,核心是用x - width/2和x + width/2把两组柱子错开,就不会叠在一起:
importnumpyasnp categories=['食品','服装','数码','家居','美妆']last_year=[280,260,380,150,190]this_year=[320,280,450,180,220]x=np.arange(len(categories))width=0.35fig,ax=plt.subplots(figsize=(9,5))ax.bar(x-width/2,last_year,width,label='去年',color='#91d5ff')ax.bar(x+width/2,this_year,width,label='今年',color='#ff4d4f')ax.set_xticks(x)ax.set_xticklabels(categories)ax.set_title('各品类今年vs去年销售额',fontsize=15)ax.legend()ax.spines['top'].set_visible(False)ax.spines['right'].set_visible(False)plt.tight_layout()plt.show()四、散点图:看关系
散点图用来看两个变量的关系、分布、聚类,比如身高体重、广告费和销售额、学习时间和分数。
importmatplotlib.pyplotaspltimportmatplotlibimportnumpyasnp matplotlib.rcParams['font.sans-serif']=['SimHei','Microsoft YaHei']matplotlib.rcParams['axes.unicode_minus']=Falsenp.random.seed(42)ad_spend=np.random.uniform(10,100,50)sales=50+3*ad_spend+np.random.normal(0,20,50)fig,ax=plt.subplots(figsize=(8,6))ax.scatter(ad_spend,sales,c='#ff4d4f',alpha=0.6,s=60,edgecolors='white')ax.set_title('广告费投入 vs 销售额',fontsize=15)ax.set_xlabel('广告费投入(万元)')ax.set_ylabel('销售额(万元)')ax.spines['top'].set_visible(False)ax.spines['right'].set_visible(False)plt.tight_layout()plt.show()散点图里每个点代表一条记录,点的分布形态就是两个变量的关系:
- 左下往右上走 → 正相关(一个涨另一个也涨)
- 左上往右下走 → 负相关
- 一团散点 → 没什么关系
- 弯弯曲曲 → 可能是非线性关系
还能用点的大小和颜色再加两个维度(比如点大小表利润、颜色表转化率),但初学别加太多,容易乱。
五、一张纸上画多张图
用plt.subplots(行数, 列数)就行,比如 2 行 2 列:
importmatplotlib.pyplotaspltimportmatplotlibimportnumpyasnp matplotlib.rcParams['font.sans-serif']=['SimHei','Microsoft YaHei']matplotlib.rcParams['axes.unicode_minus']=Falsemonths=['1月','2月','3月','4月','5月','6月']sales=[120,150,135,180,200,220]categories=['食品','服装','数码','家居','美妆']revenue=[320,280,450,180,220]fig,axes=plt.subplots(2,2,figsize=(12,9))axes[0,0].plot(months,sales,marker='o',color='#ff4d4f')axes[0,0].set_title('销售趋势')axes[0,1].bar(categories,revenue,color='#1890ff')axes[0,1].set_title('品类对比')axes[1,0].scatter(months,sales,c='#52c41a',s=50)axes[1,0].set_title('月度散点')axes[1,1].fill_between(months,sales,alpha=0.3,color='#722ed1')axes[1,1].plot(months,sales,color='#722ed1')axes[1,1].set_title('销售面积图')foraxinaxes.flat:ax.spines['top'].set_visible(False)ax.spines['right'].set_visible(False)plt.tight_layout()plt.show()这里的axes是二维数组,axes[0,0]是左上角,axes[0,1]是右上角,以此类推;axes.flat把二维数组展开成一维,方便统一设置样式。
真实运行效果
把第一节那段三层逻辑的折线图代码直接跑一遍(开头先设好 SimHei 中文字体),终端输出如下:
可以看到一周气温的最高 27℃、最低 22℃、均值 24.71℃ 都是代码实时算出的数字,折线图按“画布→坐标系→画线”三层画好并保存成图片,全程无报错、中文也没有乱码。
六、总结一下
今天的核心不是记了多少参数,而是搞懂那个三层逻辑:
画纸(Figure)→ 画框(Axes)→ 画面内容(plot/bar/scatter)
以后不管画什么图,先想:要多大一张纸?纸上分几个区域?每个区域里画什么?加不加标题、标签、图例?按这个顺序来,永远不会乱。
折线图看趋势、柱状图比大小、散点图看关系——三个基础图,就能应付绝大多数日常数据分析需求。
下一篇聊个更根本的问题:面对一份数据,到底该选什么图来表达?
梅雅达编程工作室 · Python数据实战系列第11篇
所有代码均可直接复制运行。建议动手敲一遍,比看十遍都管用。