楼层: 首页/ 软件技术/ Python AI 数据科学/ Matplotlib:把数据画出来
4

Matplotlib:把数据画出来

Matplotlib & Seaborn

"一图胜千言"。数据表格看三行就眼花,画成折线图趋势一目了然。Matplotlib 是 Python 画图的祖师爷,简单直接;Seaborn 在它之上封装了更漂亮的统计图表。

基本图表:折线、散点、柱状、饼图

import matplotlib.pyplot as plt # 折线图 x = [1, 2, 3, 4, 5] y = [2, 4, 1, 5, 3] plt.plot(x, y, label="趋势", color="#2E4B3D", marker="o") plt.title("我的折线图") plt.xlabel("X 轴") plt.ylabel("Y 轴") plt.legend() plt.savefig("line.png", dpi=150) plt.show() # 散点图 plt.scatter(x, y, c="red", s=50) # 柱状图 names = ["张三", "李四", "王五"] scores = [90, 85, 78] plt.bar(names, scores, color="#B98A2F") # 饼图 plt.pie(scores, labels=names, autopct="%1.1f%%") # 直方图:看分布 data = [1,2,2,3,3,3,4,5] plt.hist(data, bins=5)

子图 subplots

# 2 行 2 列,画 4 张图 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[1][0].bar(names, scores) axes[1][1].hist(data, bins=5) plt.tight_layout() plt.show()
Matplotlib 中文乱码

默认字体不支持中文,标题写中文会变成方块。在最开头加这几行:

import matplotlib.pyplot as plt plt.rcParams["font.sans-serif"] = ["PingFang SC", "SimHei", "Arial Unicode MS"] plt.rcParams["axes.unicode_minus"] = False # 负号也正常显示

Seaborn:更美观的统计图表

import seaborn as sns # 箱线图:看一组数据的分布、离群点 sns.boxplot(data=df, x="部门", y="工资") # 热力图:看相关性矩阵 corr = df.corr(numeric_only=True) sns.heatmap(corr, annot=True, cmap="YlGnBu")

更多常用图:箱线图、小提琴图

# 箱线图:看分布、中位数、离群点(须外的点就是异常值) sns.boxplot(data=df, x="部门", y="工资") # 小提琴图:箱线图 + 密度估计,更好看 sns.violinplot(data=df, x="部门", y="工资") # 散点图矩阵:两两看关系(小数据集) sns.pairplot(df[["成绩", "年龄", "出勤率"]]) # 保存图片:savefig 要在 show() 之前 plt.savefig("result.png", dpi=200, bbox_inches="tight")

ROC 曲线:画出来看模型好坏

from sklearn.metrics import roc_curve, auc # y_score 是模型对正例的"信心分数",不是 0/1 预测 fpr, tpr, thresholds = roc_curve(y_test, y_score) roc_auc = auc(fpr, tpr) plt.plot(fpr, tpr, label=f"ROC (AUC={roc_auc:.2f})") plt.plot([0, 1], [0, 1], "--", color="gray") # 对角线=瞎猜 plt.xlabel("假正例率") plt.ylabel("真正例率") plt.legend() plt.show()

子图布局进阶:subplots / GridSpec

import matplotlib.pyplot as plt import numpy as np x = np.linspace(0, 10, 100) # 1. subplots 简单布局:2 行 2 列 fig, axes = plt.subplots(2, 2, figsize=(10, 7)) axes[0,0].plot(x, np.sin(x)); axes[0,0].set_title("sin") axes[0,1].plot(x, np.cos(x)); axes[0,1].set_title("cos") axes[1,0].scatter(x, np.random.rand(100)) axes[1,1].hist(np.random.randn(1000), bins=30) fig.tight_layout() # 自动调整子图间距 # 2. GridSpec:不规则布局(如第一行跨两列) from matplotlib.gridspec import GridSpec fig = plt.figure(figsize=(10, 8)) gs = GridSpec(3, 3, figure=fig) ax1 = fig.add_subplot(gs[0, :]) # 第0行跨全部3列 ax2 = fig.add_subplot(gs[1, :2]) # 第1行前2列 ax3 = fig.add_subplot(gs[1, 2]) # 第1行第3列 ax4 = fig.add_subplot(gs[2, :]) # 第2行跨全部3列 ax1.plot(x, np.sin(x)) ax2.hist(np.random.randn(1000)) ax3.scatter(x, np.cos(x)) ax4.plot(x, np.tan(x)) fig.tight_layout() plt.show()

双 Y 轴:同一图画两个不同量纲

# 比如同时画"销售额(元)"和"订单数(单)" fig, ax1 = plt.subplots(figsize=(10,5)) ax1.plot(x, sales, color="#2E4B3D", label="销售额") ax1.set_xlabel("月份") ax1.set_ylabel("销售额(万元)", color="#2E4B3D") ax2 = ax1.twinx() # 共享 x 轴,新建一个 y 轴 ax2.plot(x, orders, color="#B98A2F", label="订单数") ax2.set_ylabel("订单数(单)", color="#B98A2F") plt.title("销售额与订单数") plt.show()

3D 图与动画

from mpl_toolkits.mplot3d import Axes3D # 3D 散点图:看三维数据分布 fig = plt.figure(figsize=(8,6)) ax = fig.add_subplot(111, projection="3d") xs = np.random.rand(100) ys = np.random.rand(100) zs = np.random.rand(100) ax.scatter(xs, ys, zs, c="#B98A2F") ax.set_xlabel("X"); ax.set_ylabel("Y"); ax.set_zlabel("Z") plt.show() # 动画:sin 波传播(需要保存为 mp4/gif) from matplotlib.animation import FuncAnimation fig, ax = plt.subplots() line, = ax.plot([], [], lw=2) ax.set_xlim(0, 2*np.pi) ax.set_ylim(-1.5, 1.5) def update(frame): y = np.sin(x + frame/10) line.set_data(x, y) return line, ani = FuncAnimation(fig, update, frames=100, interval=50) ani.save("wave.gif", writer="pillow", fps=20) plt.show()

Seaborn 高级统计图

import seaborn as sns sns.set_theme(style="whitegrid", font="PingFang SC") # 1. 分面图(FacetGrid):按类别拆成小图 # 比如按"性别"分两列,看不同组的年龄分布 g = sns.FacetGrid(df, col="性别", hue="是否在职") g.map(sns.histplot, "年龄", bins=20) # 2. 联合分布图:散点 + 边缘直方图 sns.jointplot(data=df, x="工资", y="工龄", kind="reg") # 3. 成对关系图:所有数值列两两画散点/分布 sns.pairplot(df[["工资", "年龄", "工龄"]], hue="性别") # 4. 线性回归拟合 + 置信区间 sns.lmplot(data=df, x="广告投入", y="销售额") # 5. 热力图:相关性矩阵(EDA 必备) corr = df.corr(numeric_only=True) sns.heatmap(corr, annot=True, cmap="YlGnBu", center=0) # 6. 聚类热图:行列都按相似性排序 sns.clustermap(corr, cmap="RdBu_r", center=0)

Matplotlib 章节面试题

面试 · Matplotlib

Q1. plt.show() 和 plt.savefig() 的顺序?

查看答案

savefig 必须在 show() 之前。show() 会清空画布,先 show 再 savefig 保存出来是空白图。

Q2. 怎么解决中文乱码?

查看答案

开头加 plt.rcParams["font.sans-serif"] = ["PingFang SC", "SimHei", "Arial Unicode MS"] 和 plt.rcParams["axes.unicode_minus"] = False(修负号显示)。

Q3. plt.subplots 和 plt.add_subplot 区别?

查看答案

plt.subplots(n,m) 一次性创建 n×m 个子图,返回 (fig, axes);fig.add_subplot(gs[...]) 用于 GridSpec 不规则布局,一次加一个。

Q4. 双 Y 轴怎么画?

查看答案

ax2 = ax1.twinx(),然后 ax1 画左边量纲、ax2 画右边量纲。共享 x 轴。

Q5. Seaborn 和 Matplotlib 的关系?

查看答案

Seaborn 是 Matplotlib 的高级封装,底层还是 Matplotlib 对象。Seaborn 提供更漂亮的默认样式和现成的统计图表(箱线图、热力图、pairplot);需要精细控制时还是要回到 Matplotlib API。