Matplotlib二维绘图核心指南:从基础架构到实战优化

1. 从数据到洞察:为什么二维绘图是数据分析的“第一语言”

干了这么多年数据分析,我越来越觉得,二维图形绘制不是什么花里胡哨的“锦上添花”,而是我们和数据对话的“第一语言”。你想想看,面对一堆冰冷的数字,哪怕你用再精妙的算法算出个结果,如果没法直观地呈现出来,跟老板、跟同事、甚至跟自己都说不清楚。而Matplotlib,就是Python世界里帮你把数据“翻译”成这幅通用语言的最经典、最强大的工具。它可能不是最漂亮的(那是SeabornPlotly的活儿),但它绝对是最底层的、最可控的,你几乎可以用它画出任何你能想象到的二维图形。

很多新手一上来就想搞三维炫图、动态交互,但我总劝他们:先把二维的玩明白了。因为绝大多数业务问题,折线图看趋势、柱状图比大小、散点图找关系、直方图看分布,这四板斧下去,80%的洞见就已经出来了。Matplotlib就像一个功能齐全的机床,从最简单的螺丝钉到复杂的零件都能加工。今天,我就以一个老司机的视角,带你深入Matplotlib的二维世界,不光是教你怎么画,更要讲清楚为什么这么画,以及那些官方文档里不会写的“踩坑实录”。

2. 核心架构与绘图逻辑:理解“画布”、“坐标系”与“艺术家”

在动手写第一行代码之前,我们必须先理解Matplotlib的核心心智模型。很多人画图别扭,就是因为没搞懂它的三层架构:Figure(画布)、Axes(坐标系/子图)和Artist(艺术家元素)。这不是抽象概念,而是你控制图形的实体手柄。

2.1 Figure与Axes:你的画布与绘图区域

你可以把Figure想象成一张空白的物理画布或一张纸。而Axes则是贴在这张画布上的一个或多个带刻度的坐标系。一个Figure可以包含多个Axes,但一个Axes一定只属于一个Figure我们所有的绘图动作,几乎都是在Axes对象上进行的。

为什么区分它们很重要?因为很多全局设置(如图形尺寸、背景色、保存的DPI)是针对Figure的;而数据相关的设置(如X/Y轴范围、标题、图例)是针对Axes的。混用会导致设置无效。

我强烈建议从一开始就使用面向对象(OO)的接口,放弃那些简单的pyplot直接绘图。虽然plt.plot(x, y)写起来快,但当你需要精细控制多个子图时,OO接口的清晰度是无可替代的。

import matplotlib.pyplot as plt import numpy as np # 面向对象(OO)风格 - 推荐 fig, ax = plt.subplots() # 创建一个画布和一个坐标系 x = np.linspace(0, 10, 100) y = np.sin(x) ax.plot(x, y) # 在这个特定的坐标系ax上绘图 ax.set_xlabel('X轴') ax.set_ylabel('Y轴') ax.set_title('一个正弦波') # 对比:简单的pyplot风格(不利于复杂控制) # plt.plot(x, y) # plt.xlabel('X轴') # plt.title('一个正弦波') # plt.show()

plt.subplots()这个函数是黄金搭档。fig, ax = plt.subplots(2, 3)一下子创建了一个2行3列共6个子图的画布,ax变成一个2x3的数组,你可以通过ax[0, 0]ax[1, 2]来精准操作每一个子图。这种控制力是简单接口无法提供的。

2.2 绘图的核心流程与生命周期管理

一个健壮的绘图脚本应该遵循清晰的生命周期,避免内存泄漏和图形错乱:

  1. 准备数据:清洗、转换你的numpy数组或pandasSeries/DataFrame
  2. 创建图形和坐标系:使用plt.subplots()plt.figure()+fig.add_subplot()
  3. 在坐标系上绘图:调用ax.plot(),ax.scatter(),ax.bar()等方法。
  4. 美化图形:设置标题、标签、刻度、图例、网格等。
  5. 显示或保存图形plt.show()用于在交互环境中显示,fig.savefig()用于保存到文件。
  6. 清理:在脚本中,特别是循环创建图形时,使用plt.close('all')关闭所有图形,释放内存。

注意:在Jupyter Notebook中,使用%matplotlib inline魔法命令可以让图形直接嵌入在单元格下方输出。如果你希望有交互功能(缩放、平移),可以使用%matplotlib widget(需安装ipympl)或%matplotlib qt5

3. 五大基础图形深度解析与实战技巧

掌握了架构,我们就可以开始“挥毫泼墨”了。下面我挑最核心的5种二维图形,不仅讲怎么画,更分享参数选择的门道和实战中的坑。

3.1 折线图:趋势分析的基石

折线图用于展示数据随时间或其他连续变量的变化趋势。它的核心是顺序和连续性。

# 示例:绘制两条对比趋势线 fig, ax = plt.subplots(figsize=(10, 6)) # figsize控制画布宽高(英寸) years = np.arange(2015, 2023) sales_a = [20, 22, 25, 28, 30, 33, 31, 35] sales_b = [15, 18, 22, 25, 26, 28, 30, 33] # 绘图,并立即获取线条对象,便于后续设置图例 line_a, = ax.plot(years, sales_a, marker='o', linestyle='-', linewidth=2, color='steelblue', label='产品A') line_b, = ax.plot(years, sales_b, marker='s', linestyle='--', linewidth=2, color='coral', label='产品B') # 精细化设置 ax.set_xlabel('年份', fontsize=12) ax.set_ylabel('销售额 (百万)', fontsize=12) ax.set_title('2015-2022年产品销售额趋势对比', fontsize=14, fontweight='bold') ax.legend(loc='upper left') # 添加图例 ax.grid(True, linestyle=':', alpha=0.7) # 添加网格线,设置样式和透明度 # 设置刻度 ax.set_xticks(years) # 确保每年都显示刻度 ax.set_xticklabels(years, rotation=45) # 刻度标签旋转45度,避免重叠 plt.tight_layout() # 自动调整子图参数,使图形元素不重叠 plt.show()

关键参数与避坑指南:

  • marker:‘o’(圆点),‘s’(方块),‘^’(三角)。数据点稀疏时建议加上,密集时可省略。
  • linestyle:‘-’(实线),‘--’(虚线),‘:’(点线),‘-.’(点划线)。用于区分不同线条。
  • linewidth(或lw): 线条粗细。印刷或海报展示时需加粗(如2.5),屏幕显示1.5-2即可。
  • color: 可直接用颜色名(如‘red’)、十六进制码(如‘#FF5733’)或RGB元组。避坑:不要用太浅的颜色(如亮黄)做线条,在白色背景上根本看不清。
  • plt.tight_layout(): 这是一个神器!它能自动调整子图之间的间距和画布边距,解决标签、标题被截断的问题。在图形元素复杂时务必调用。

3.2 散点图:探索变量关系的显微镜

散点图是发现两个连续变量之间相关性、聚类或异常值的利器。它的核心是分布和密度。

# 示例:探索身高与体重的相关性,并按性别着色 np.random.seed(42) n_samples = 200 # 模拟数据 male_height = np.random.normal(175, 7, n_samples//2) male_weight = male_height * 0.6 + np.random.normal(0, 5, n_samples//2) + 50 female_height = np.random.normal(162, 6, n_samples//2) female_weight = female_height * 0.5 + np.random.normal(0, 4, n_samples//2) + 45 height = np.concatenate([male_height, female_height]) weight = np.concatenate([male_weight, female_weight]) gender = np.array(['男']*(n_samples//2) + ['女']*(n_samples//2)) fig, ax = plt.subplots(figsize=(9, 6)) # 分别绘制不同性别的散点 for g in ['男', '女']: idx = gender == g ax.scatter(height[idx], weight[idx], label=g, alpha=0.6, # 透明度,解决点重叠问题 edgecolors='w', # 点边缘白色,使密集处更清晰 s=50) # 点的大小 ax.set_xlabel('身高 (cm)') ax.set_ylabel('体重 (kg)') ax.set_title('身高与体重关系散点图(按性别区分)') ax.legend() ax.grid(True, alpha=0.3) # 添加趋势线(以全部数据为例) z = np.polyfit(height, weight, 1) # 一次多项式拟合 p = np.poly1d(z) ax.plot(height, p(height), “r--”, lw=1.5, label=f‘趋势线: y={z[0]:.2f}x+{z[1]:.2f}’) ax.legend() plt.tight_layout() plt.show()

核心技巧与问题排查:

  • 解决点重叠(Overplotting):这是散点图最常见的问题。解决方法:
    1. 设置透明度 (alpha): 如alpha=0.5,重叠区域颜色会加深,直观显示密度。
    2. 使用边缘色 (edgecolors): 设为白色(‘w’)或浅灰色,能让密集区域的点轮廓更清晰。
    3. 减小点大小 (s): 点特别多时,将s从50降到20或10。
    4. 采样或使用蜂群图/二维密度图:如果数据量极大(>10万点),考虑先采样,或使用ax.hexbin()seaborn.kdeplot绘制密度图。
  • s参数:可以是一个标量,所有点一样大;也可以是一个与数据长度相同的数组,用于让点的大小代表第三个变量(气泡图的雏形)。
  • 拟合趋势线:使用np.polyfit进行多项式拟合,再用np.poly1d生成函数并绘图,是快速观察相关性强弱的实用方法。

3.3 柱状图:分类比较的标尺

柱状图用于比较不同类别之间的数值差异。分为普通柱状图和分组/堆叠柱状图。

# 示例:分组柱状图 fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6)) # 数据 categories = ['Q1', 'Q2', 'Q3', 'Q4'] product_x = [120, 135, 148, 165] product_y = [90, 115, 130, 140] x_index = np.arange(len(categories)) # 类别索引 [0, 1, 2, 3] bar_width = 0.35 # 柱子的宽度 # 子图1:分组柱状图 bars1 = ax1.bar(x_index - bar_width/2, product_x, width=bar_width, label='产品X', color='lightblue', edgecolor='black') bars2 = ax1.bar(x_index + bar_width/2, product_y, width=bar_width, label='产品Y', color='lightcoral', edgecolor='black') ax1.set_xlabel('季度') ax1.set_ylabel('销售额 (万)') ax1.set_title('产品季度销售额对比(分组)') ax1.set_xticks(x_index) ax1.set_xticklabels(categories) ax1.legend() # 在柱子上方添加数值标签 for bar in bars1: height = bar.get_height() ax1.text(bar.get_x() + bar.get_width()/2., height + 3, f‘{height}’, ha=‘center’, va=‘bottom’, fontsize=9) for bar in bars2: height = bar.get_height() ax1.text(bar.get_x() + bar.get_width()/2., height + 3, f‘{height}’, ha=‘center’, va=‘bottom’, fontsize=9) ax1.grid(axis=‘y’, alpha=0.4) # 子图2:堆叠柱状图 ax2.bar(categories, product_x, label='产品X', color='lightblue', edgecolor='black') ax2.bar(categories, product_y, bottom=product_x, label='产品Y', color='lightcoral', edgecolor='black') # 关键参数 bottom ax2.set_xlabel('季度') ax2.set_ylabel('总销售额 (万)') ax2.set_title('产品季度销售额对比(堆叠)') ax2.legend(loc=‘upper left’) ax2.grid(axis=‘y’, alpha=0.4) plt.tight_layout() plt.show()

分组与堆叠的选择逻辑:

  • 分组柱状图:适合比较同一类别下不同分组的绝对数值。例如,比较每个季度产品X和产品Y各自的销售额。
  • 堆叠柱状图:适合展示同一类别下各分组的构成比例,以及总量的对比。例如,展示每个季度总销售额中,产品X和产品Y分别贡献了多少。
  • 避坑:如果分组的数值有正有负,堆叠图会变得难以阅读,此时应使用分组图。

添加数据标签的细节:

  • bar.get_height()获取柱子的高度(值)。
  • bar.get_x()bar.get_width()获取柱子的左下角x坐标和宽度。
  • text()函数中,ha=‘center’(水平对齐)和va=‘bottom’(垂直对齐)是让标签居中显示在柱子上方的关键。
  • 标签的y坐标是height + 3,这里的3是一个偏移量,让标签略高于柱子,避免重叠。

3.4 直方图与密度图:分布形态的透视镜

直方图将连续数据分箱,用柱子的高度表示频数,是观察数据分布形状(是否正态、是否偏态)的首选工具。密度图(KDE)则是直方图的平滑版本。

# 示例:直方图与密度图叠加 fig, ax = plt.subplots(figsize=(10, 6)) # 生成偏态数据 data_skewed = np.random.gamma(shape=2, scale=2, size=1000) # 绘制直方图(归一化到密度) counts, bins, patches = ax.hist(data_skewed, bins=30, density=True, alpha=0.6, color='skyblue', edgecolor='black', label='直方图 (密度)') # 绘制核密度估计(KDE)曲线 from scipy.stats import gaussian_kde kde = gaussian_kde(data_skewed) x_range = np.linspace(bins[0], bins[-1], 500) ax.plot(x_range, kde(x_range), ‘r-’, linewidth=2, label=‘核密度估计 (KDE)’) # 添加理论分布曲线(例如Gamma分布)作为参考 shape, loc, scale = 2, 0, 2 x = np.linspace(bins[0], bins[-1], 500) pdf = (x**(shape-1) * np.exp(-x/scale)) / (scale**shape * gamma(shape)) ax.plot(x, pdf, ‘g--’, linewidth=1.5, label=‘理论Gamma分布’) ax.set_xlabel(‘数据值’) ax.set_ylabel(‘密度’) ax.set_title(‘数据分布分析:直方图 vs. KDE vs. 理论分布’) ax.legend() ax.grid(True, alpha=0.3) plt.tight_layout() plt.show()

关于bins(分箱数)的选择:这是直方图最关键的参数,没有固定答案。太少会丢失细节,太多会产生噪音。

  • 经验法则bins = int(np.sqrt(len(data)))bins = int(np.ceil(2 * (len(data) ** (1/3))))
  • 常用策略:使用‘auto’‘fd’(Freedman-Diaconis准则)、‘sturges’等字符串,让Matplotlib自动选择。‘fd’对于异常值较多的数据更稳健。
  • 实操心得:多试几个bins值,选择那个最能清晰展示数据主要特征(如单峰/双峰、偏度、尾部)且不会过于破碎的值。

density=True参数:这会将直方图归一化,使得所有柱子的面积之和为1。这样,直方图就可以和概率密度函数(如KDE曲线、理论分布曲线)在同一尺度下进行比较,非常有用。

3.5 饼图与箱线图:比例与统计的利器

  • 饼图:用于显示一个整体中各组成部分的比例。慎用,因为人眼对角度差异不敏感。类别过多(>5个)或比例接近时,建议改用堆叠柱状图。

    fig, ax = plt.subplots(figsize=(8, 8)) sizes = [35, 25, 20, 15, 5] labels = [‘A类’, ‘B类’, ‘C类’, ‘D类’, ‘其他’] explode = (0.05, 0, 0, 0, 0) # 突出第一块 ax.pie(sizes, explode=explode, labels=labels, autopct=‘%1.1f%%’, startangle=90, colors=plt.cm.Set3(np.arange(len(sizes))/len(sizes))) ax.set_title(‘市场份额分布’) ax.axis(‘equal’) # 确保饼图是正圆 plt.show()

    关键点autopct格式化百分比,startangle设置起始角度,explode使某部分突出。务必使用ax.axis(‘equal’)

  • 箱线图:用于展示一组数据的中位数、四分位数、异常值。是数据探索性分析(EDA)的必备工具,能快速了解数据的集中趋势、离散程度和偏态。

    fig, ax = plt.subplots(figsize=(8, 6)) # 生成多组数据 data_to_plot = [np.random.normal(0, std, 100) for std in range(1, 5)] bp = ax.boxplot(data_to_plot, patch_artist=True, labels=[f‘组{i+1}’ for i in range(4)]) # 美化箱子颜色 for box in bp[‘boxes’]: box.set(facecolor=‘lightblue’, alpha=0.6) ax.set_ylabel(‘观测值’) ax.set_title(‘多组数据箱线图对比’) ax.grid(True, axis=‘y’, alpha=0.4) plt.show()

    解读箱线图:箱子中间的线是中位数;箱子的上下边是上四分位数(Q3)和下四分位数(Q1);箱子的高度是四分位距(IQR);上下“须”通常延伸到Q1 - 1.5*IQRQ3 + 1.5*IQR;之外的单个点被视为异常值

4. 图形美化的艺术:从“能看”到“专业”

一张专业的图表,细节决定成败。Matplotlib的默认样式比较基础,我们需要手动调整。

4.1 全局样式设置:一键切换专业风格

在绘图前设置全局样式,可以统一所有图形的外观。

import matplotlib.pyplot as plt # 设置全局样式 plt.style.use(‘seaborn-v0_8-darkgrid’) # 使用seaborn的深色网格样式,经典美观 # 其他优秀样式:’ggplot‘, ’fivethirtyeight‘, ’grayscale‘ plt.rcParams[‘font.sans-serif’] = [‘SimHei’, ‘Arial Unicode MS’] # 解决中文显示问题 plt.rcParams[‘axes.unicode_minus’] = False # 解决负号显示为方块的问题 plt.rcParams[‘figure.dpi’] = 150 # 提高图形显示分辨率 plt.rcParams[‘savefig.dpi’] = 300 # 保存图片时的分辨率,用于出版或打印 plt.rcParams[‘savefig.bbox’] = ‘tight’ # 保存时自动裁剪白边

4.2 颜色与色彩映射

颜色是传递信息的重要手段。

  • 定性配色:用于区分不同类别,如折线图中的多条线。使用plt.cm.tab10plt.cm.Set2等。
    colors = plt.cm.tab10(np.arange(5)/5) # 生成5个区分度好的颜色
  • 顺序配色:用于表示数值大小,如热力图。使用plt.cm.viridisplt.cm.plasma(对色盲友好)。
  • 发散配色:用于表示相对中点的正负偏差,如相关性矩阵。使用plt.cm.RdBuplt.cm.coolwarm
  • 在绘图函数中指定color=‘#2E86AB’(十六进制),color=(0.1, 0.2, 0.5)(RGB元组,值在0-1之间)。

4.3 刻度、标签与图例的精细化控制

这是让图表清晰易读的关键。

fig, ax = plt.subplots() # ... 绘图代码 ... # 1. 刻度设置 ax.set_xlim(0, 100) # 设置X轴范围 ax.set_ylim(-1.5, 1.5) # 设置Y轴范围 ax.set_xticks([0, 20, 40, 60, 80, 100]) # 设置X轴刻度位置 ax.set_xticklabels([‘起点’, ‘20%’, ‘40%’, ‘60%’, ‘80%’, ‘终点’], rotation=30) # 设置刻度标签并旋转 ax.tick_params(axis=‘both’, which=‘major’, labelsize=9) # 设置主刻度标签大小 # 2. 轴标签和标题 ax.set_xlabel(‘时间进度’, fontsize=12, fontweight=‘bold’) ax.set_ylabel(‘性能指标’, fontsize=12) ax.set_title(‘项目性能随时间变化图’, fontsize=14, pad=15) # pad增加标题与图的间距 # 3. 图例高级设置 # 假设lines是之前plot返回的线条对象列表 ax.legend(lines, [‘模型A’, ‘模型B’], loc=‘upper left’, frameon=True, # 显示图例边框 fancybox=True, # 边框圆角 shadow=True, # 添加阴影 fontsize=10, ncol=2) # 图例分两列显示 # 4. 添加文本和箭头注释 ax.text(50, 0.5, ‘关键节点’, fontsize=11, style=‘italic’, ha=‘center’) ax.annotate(‘峰值出现’, xy=(65, 1.2), xytext=(40, 1.0), arrowprops=dict(arrowstyle=‘->’, connectionstyle=‘arc3,rad=.2’), fontsize=10)

4.4 多子图布局与组合图形

将多个相关图形组合在一张大图中,是进行综合对比分析的常用手段。

fig = plt.figure(figsize=(12, 10)) # 使用GridSpec进行复杂布局 gs = fig.add_gridspec(3, 4) # 3行4列 # 左上角:一个大图占两行两列 ax_main = fig.add_subplot(gs[0:2, 0:2]) ax_main.plot(...) # 主图内容 # 右上角:两个小图上下排列 ax_sub1 = fig.add_subplot(gs[0, 2]) ax_sub1.hist(...) # 子图1 ax_sub2 = fig.add_subplot(gs[1, 2]) ax_sub2.scatter(...) # 子图2 # 底部:一个长图占一行四列 ax_bottom = fig.add_subplot(gs[2, :]) ax_bottom.bar(...) # 底部图 # 共享坐标轴(常用于对比) fig2, (ax_left, ax_right) = plt.subplots(1, 2, sharey=True) # 共享Y轴 ax_left.plot(...) ax_right.plot(...) # 此时只需设置左边图的Y轴标签即可 ax_left.set_ylabel(‘共享的Y轴’) plt.tight_layout() plt.show()

5. 高级技巧与性能优化

当数据量变大或图形复杂度增加时,你需要这些技巧。

5.1 大量数据的高效绘制

绘制数十万甚至上百万个数据点时,直接使用plotscatter会极其缓慢。

  • 对于折线图:使用ax.plot(x, y, ‘-’, linewidth=0.5),线条比标记点快得多。如果数据是排序好的,可以尝试用ax.fill_between填充区域来代替细线。
  • 对于散点图
    1. 使用ax.plot代替ax.scatterplot在绘制纯色、固定大小点时效率远高于scatterax.plot(x, y, ‘o’, markersize=1, alpha=0.5)
    2. 下采样:在绘图前对数据进行随机采样或等间隔采样。
    3. 使用rasterized=True:在scatterplot中设置此参数,会将这部分图形在保存为矢量图(如PDF)时进行栅格化,大幅减小文件体积。ax.scatter(x, y, s=1, alpha=0.2, rasterized=True)
  • 终极方案:对于超大数据集,考虑使用专门库,如Datashader(先栅格化再可视化)。

5.2 图形保存与格式选择

fig.savefig()是保存图形的标准方法。

fig.savefig(‘my_plot.png’, dpi=300, bbox_inches=‘tight’, facecolor=‘white’, edgecolor=‘none’)
  • 格式选择
    • .png:位图,支持透明度,适用于网页、报告。文件大小和分辨率(DPI)相关。
    • .jpg/.jpeg:有损压缩位图,文件小,不支持透明度。适用于照片类图像。
    • .pdf:矢量图,无限缩放不失真,适用于学术出版、打印。文件可能较大。
    • .svg:矢量图,适用于网页前端交互。可被代码编辑器编辑。
  • bbox_inches=‘tight’:自动计算并裁剪图形周围的空白区域,强烈推荐。
  • facecolor/edgecolor:设置画布的背景色和边框色。

5.3 自定义绘图样式与复用

你可以创建自己的样式文件,实现公司或个人的图表风格统一。

  1. 创建一个mystyle.mplstyle文件,内容如下:
    figure.figsize: 8, 6 figure.dpi: 150 font.size: 11 axes.titlesize: 13 axes.labelsize: 11 lines.linewidth: 2 lines.markersize: 6 legend.fontsize: 10 grid.alpha: 0.3 savefig.dpi: 300 savefig.bbox: tight
  2. 在代码中使用:plt.style.use(‘./mystyle.mplstyle’)

6. 常见问题排查与调试心得

绘图时总会遇到各种奇怪的问题,这里记录几个最常遇到的。

问题1:中文显示为方框

  • 原因:系统缺少中文字体或Matplotlib未配置中文字体。
  • 解决
    # 方法一:临时指定(推荐) plt.rcParams[‘font.sans-serif’] = [‘SimHei’, ‘Microsoft YaHei’, ‘Arial Unicode MS’] # Windows # plt.rcParams[‘font.sans-serif’] = [‘Heiti TC’, ‘Arial Unicode MS’] # Mac plt.rcParams[‘axes.unicode_minus’] = False
    • 如果上述字体无效,找到你系统里的中文字体文件(如C:\Windows\Fonts\msyh.ttc微软雅黑),并将其路径添加到Matplotlib的字体管理中。

问题2:保存的图片分辨率低,文字模糊

  • 原因:保存时DPI设置过低,或显示DPI与保存DPI混淆。
  • 解决
    1. 在保存时明确指定高DPI:fig.savefig(‘output.png’, dpi=300)
    2. 设置全局保存DPI:plt.rcParams[‘savefig.dpi’] = 300
    3. 确保画布尺寸(figsize)足够大。一个figsize=(8,6)英寸,dpi=300的图片,像素尺寸是2400x1800,足够清晰。

问题3:图例显示不正确或出现重复项

  • 原因:重复调用ax.plot且未正确处理返回的线条对象,或在循环中错误添加标签。
  • 解决
    • 在绘图时明确指定label参数,并确保每个label唯一。
    • 调用一次ax.legend()即可。如果图例项不对,可以手动指定:
      line1, = ax.plot(x1, y1, label=‘Line 1’) line2, = ax.plot(x2, y2, label=‘Line 2’) ax.legend([line1, line2], [‘自定义名1’, ‘自定义名2’])

问题4:图形在Notebook中显示不正常或太小

  • 原因figsize设置不当或未使用%matplotlib inline魔法命令。
  • 解决
    1. 在Jupyter单元格开头运行%matplotlib inline
    2. 创建图形时设置合适的figsize,如plt.subplots(figsize=(12, 8))
    3. 使用plt.tight_layout()自动调整布局。
    4. 可以尝试%config InlineBackend.figure_format = ‘retina’来获得更高清的显示(如果系统支持)。

问题5:绘制速度慢,卡顿

  • 原因:数据量过大;图形元素过多(如大量散点、文本);使用了抗锯齿等高性能消耗特性。
  • 解决
    1. 对大数据进行下采样。
    2. 简化图形:减少不必要的网格、图例、注释。
    3. 关闭抗锯齿:在绘图函数中加入antialiased=False参数(对线条有效)。
    4. 使用更高效的绘图方法(如前文所述,用plot代替scatter)。
    5. 考虑使用Matplotlib的交互式后端(如%matplotlib widget)进行数据探索,但最终出版图形用静态后端渲染。

绘图就像做菜,Matplotlib给了你最齐全的厨房和食材,但一道好菜需要你对火候(参数)、刀工(数据处理)、摆盘(美化)都有深刻的理解。最好的学习方式就是“临摹”——找到你觉得专业的图表,用Matplotlib尝试复现它,在这个过程中,你会被迫去查每一个细节的实现方法,这才是最快的学习路径。当你能够不假思索地调出合适的颜色、设置完美的布局、一眼看出图形中的问题所在时,你就真正掌握了用二维图形讲述数据故事的能力。