如何为Matplotlib散点图标记添加渐变阴影以展示不确定性?
实现带左右渐变阴影的不确定性散点图(Matplotlib)
核心解决方案
你可以直接使用带线性渐变填充的圆形Patch替代imshow的方案,这种方法基于Matplotlib的矢量图形系统,能完美保持圆形的宽高比,且不会导致轴范围异常变动,同时实现左右渐变来展示z±sigma的不确定性范围。
改进后的代码
import numpy as np import matplotlib.pyplot as plt from matplotlib.colors import Normalize from matplotlib.patches import Circle from matplotlib.colors import LinearSegmentedColormap def scatter_uncertainty_circles(ax, x, y, z, sigma, cmap, radius=0.2): x, y, z, sigma = map(np.asarray, (x, y, z, sigma)) norm = Normalize((z - sigma).min(), (z + sigma).max()) for xi, yi, zi, si in zip(x, y, z, sigma): # 定义左右渐变的颜色:左(z-sigma) -> 右(z+sigma) left_color = cmap(norm(zi - si)) right_color = cmap(norm(zi + si)) # 创建水平方向的线性渐变 grad = LinearSegmentedColormap.from_list( f"grad_{xi}_{yi}", [left_color, right_color] ) # 创建带渐变填充的圆形Patch circle = Circle( (xi, yi), radius, edgecolor='black', facecolor='none' ) circle.set_fill(True) circle.set_gradient("horizontal", grad) ax.add_patch(circle) # Demo np.random.seed(0) x = np.linspace(-2, 2, 7) y = np.linspace(-2, 0, 4) X, Y = np.meshgrid(x, y) X = X.ravel() Y = Y.ravel() Z = np.sin(X ** 2 + Y ** 2) sigma = 0.1 + 0.7 * np.random.rand(len(X)) cmap = plt.get_cmap('viridis') fig, ax = plt.subplots() scatter_uncertainty_circles(ax, X, Y, Z, sigma, cmap) sm = plt.cm.ScalarMappable(norm=Normalize((Z - sigma).min(), (Z + sigma).max()), cmap=cmap) fig.colorbar(sm, ax=ax) ax.set_aspect('equal') # 强制保持圆形比例 ax.set_xlim(-2.5, 2.5) ax.set_ylim(-2.5, 0.5) plt.show()
关键改进点
- 基于矢量图形的
CirclePatch绘制,完全匹配数据坐标系统,不会受轴宽高比影响,ax.set_aspect('equal')可进一步确保圆形不被拉伸。 - 避免了
imshow自动调整轴范围的问题,所有元素的位置和尺寸都完全可控。 - 代码逻辑更简洁,性能比逐点绘制图像更高。
补充说明
如果需要调整渐变的细节(比如偏移量、渐变方向),可以修改set_gradient的参数,例如circle.set_gradient("horizontal", grad, offset=0.2)来微调渐变的起始位置。
内容的提问来源于stack exchange,提问作者Heisenbugs
相关产品推荐
相关产品推荐

