散点图看起来是Python可视化里最简单的东西,一行plt.plot(x, y, 'o')就能出图,但真正干活的时候,需求往往复杂得多:点要按某个维度变色、点的大小要反映数值大小、有时候还要画出三维的气泡图。这篇文章就把二维散点、带颜色和尺寸映射的气泡图、以及三维气泡图一次性讲透,代码都能直接跑。

一、最基础的二维散点图:plot和scatter该怎么选
画散点图有两个入口,一个是plt.plot(),一个是plt.scatter()。很多人随手就用plot,画出来的效果也差不多,但两者底层实现完全不同。plot把所有点当成一个整体绘制,属性统一,速度快;scatter则允许每个点拥有独立的大小和颜色,代价是当数据量上万时渲染会明显变慢。
经验法则很明确:如果只是看看两个变量的分布关系,数据量又大,用plot(x, y, 'o')就够了;一旦需要让每个点的颜色或大小随数据变化,必须切换到scatter。先看一个基础示例:
import matplotlib.pyplot as plt
import numpy as np
# 解决中文乱码问题,Windows下常用SimHei
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
np.random.seed(42)
x = np.random.randn(300)
y = 0.8 * x + np.random.randn(300) * 0.5
fig, axes = plt.subplots(1, 2, figsize=(11, 4.5))
# 左图:plot方式,速度快,属性统一
axes[0].plot(x, y, 'o', color='steelblue', alpha=0.7)
axes[0].set_title('plot 绘制的散点图')
# 右图:scatter方式,功能强
axes[1].scatter(x, y, color='steelblue', alpha=0.7, edgecolors='none')
axes[1].set_title('scatter 绘制的散点图')
plt.tight_layout()
plt.show()这里有个细节值得注意:alpha=0.7设置透明度在数据密集时非常关键,不透明的点会互相遮挡,看不出堆积密度。加上edgecolors='none'去掉描边后,大规模数据的观感会干净很多。
二、颜色映射:让第三个变量体现在点的颜色上
二维平面只有横纵两个轴,想表达第三个变量,最自然的做法就是让点的颜色随它变化。scatter的c参数接收一个与数据点等长的数组,cmap指定配色方案,再用plt.colorbar()把颜色条加上,读图的人才知道每种颜色对应什么数值。
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(1)
x = np.random.rand(200) * 100
y = np.random.rand(200) * 100
temperature = x * 0.5 + y * 0.3 + np.random.rand(200) * 10 # 第三个变量
fig, ax = plt.subplots(figsize=(8, 6))
sc = ax.scatter(x, y, c=temperature, cmap='coolwarm',
alpha=0.8, edgecolors='white', linewidths=0.5)
cbar = plt.colorbar(sc, ax=ax)
cbar.set_label('温度')
ax.set_xlabel('经度偏移')
ax.set_ylabel('纬度偏移')
ax.set_title('颜色映射第三个变量的散点图')
plt.show()注意colorbar要传入scatter返回的对象sc,而不是直接调用,这样颜色条的刻度范围会自动与数据对齐。如果想让颜色映射固定在某个范围(比如多张图对比时保持一致),可以加vmin和vmax参数:ax.scatter(x, y, c=temperature, vmin=0, vmax=80, ...)。
cmap的选择也有讲究。viridis是matplotlib默认配色,感知均匀且对色盲友好;coolwarm适合表达有正负或冷暖含义的数据;jet虽然经典但不推荐,色阶过渡不均匀容易造成误读。
三、气泡图:用点的大小表达第四个变量
如果还想再塞进一个维度,就用s参数控制点的大小,这就成了气泡图。这里有个非常常见的坑:s指的是点的面积的平方值(点径的平方),不是半径也不是直径。如果直接把原始数据扔进去,数值大的点会大到离谱,所以一般要做归一化处理。
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(7)
city_x = np.random.rand(25) * 100
city_y = np.random.rand(25) * 100
population = np.random.rand(25) * 800 + 50 # 人口:第四个变量
gdp = city_x * 0.6 + np.random.rand(25) * 20 # GDP:第三个变量,用颜色表示
# 关键一步:把人口归一化后映射到合理的面积区间
size = population / population.max() * 1500
fig, ax = plt.subplots(figsize=(9, 7))
sc = ax.scatter(city_x, city_y, s=size, c=gdp, cmap='viridis',
alpha=0.65, edgecolors='black', linewidths=0.8)
plt.colorbar(sc, ax=ax, label='GDP指数')
ax.set_xlabel('东西方向')
ax.set_ylabel('南北方向')
ax.set_title('气泡图:颜色表示GDP,大小表示人口')
plt.show()气泡图的图例是个难点,因为尺寸是连续的,默认图例没法直接表达。常用的解决办法是手动构造几个代表值,用Line2D或者scatter空数据的方式画图例点:
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
# 构造三个档位的图例
legend_vals = [100, 400, 800]
handles = [Line2D([0], [0], marker='o', color='w',
markerfacecolor='gray', alpha=0.65, markersize=np.sqrt(v / 800 * 1500),
label=f'人口 {v:.0f}万') for v in legend_vals]
ax.legend(handles=handles, title='气泡大小', loc='upper left')注意markersize的单位是点径,而s是面积,所以换算时要开平方,这也是很多人画出来的图例点和实际气泡对不上的原因。
四、三维气泡图:mpl_toolkits.mplot3d实战
当数据真的有三个空间维度加一个数值维度时,就轮到三维气泡图登场了。matplotlib自带mpl_toolkits.mplot3d,不需要额外安装,通过projection='3d'创建三维坐标轴即可。三维散点的scatter同样支持c和s参数,逻辑和二维完全一致。
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(20)
fig = plt.figure(figsize=(9, 7))
ax = fig.add_subplot(111, projection='3d')
n = 200
xs = np.random.rand(n) * 10
ys = np.random.rand(n) * 10
zs = np.random.rand(n) * 10
value = xs + ys + zs # 数值维度,决定颜色和大小
p = ax.scatter(xs, ys, zs,
c=value, # 颜色映射数值
s=value * 25, # 大小映射数值
cmap='plasma',
alpha=0.7,
depthshade=True) # 开启深度着色,增强立体感
plt.colorbar(p, ax=ax, shrink=0.6, label='综合数值')
ax.set_xlabel('X 轴')
ax.set_ylabel('Y 轴')
ax.set_zlabel('Z 轴')
ax.set_title('三维气泡图')
ax.view_init(elev=20, azim=45) # 调整视角
plt.show()几个三维图特有的技巧:一是depthshade=True会让远处的点颜色变淡,立体感立刻出来;二是view_init可以调整俯仰角和方位角,找到最能展现数据结构的视角;三是colorbar加shrink=0.6把颜色条压短一点,避免和图形重叠。
需要提醒的是,matplotlib的3D是伪3D,遮挡关系按绘制顺序处理,点特别多时可能出现近点被远点遮挡的假象。如果对交互性要求高,比如需要鼠标旋转查看,建议改用pyecharts或者plotly,其中plotly的px.scatter_3d一行代码就能生成可旋转、可缩放的三维气泡图,浏览器打开即可交互,适合做汇报展示。
总结一下技术路线:数据只有两个变量用plot最快;三个变量加c和colorbar;四个变量用s做气泡图并记得归一化;三个空间维度再加数值就用mplot3d。掌握这几个参数的组合方式,绝大多数散点类的可视化需求都能覆盖。
Python散点图matplotlibbubble chart修改时间:2026-09-06 22:02:41