You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为两个pcolormesh子图设置统一的自定义颜色映射与刻度并共享色条

如何为两个pcolormesh子图设置统一的自定义颜色映射与刻度并共享色条

嗨,我来帮你搞定这个问题!你的核心问题是两个子图没有共用一套统一的颜色数值刻度,导致共享色条只能对应其中一个图。咱们结合你的需求(0计数显示白色、自定义渐变色、共享色条准确对应两个子图)一步步调整代码:

问题根源分析

  1. 你创建了自定义的BoundaryNorm但没有传递给pcolormesh,导致两个子图自动使用各自的数值范围做颜色映射
  2. 固定的bounds没有覆盖两个数据集的最大计数(比如你的pc1计数到50,但bounds只到40)
  3. 自定义色卡的第一个颜色不是白色,没法实现0计数显示白色的需求

解决方案与修改后代码

先看修改后的完整代码,我会在后面解释每一处调整:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import BoundaryNorm, LinearSegmentedColormap

# 加载数据
height, data1, data2 = np.loadtxt('data.txt', unpack=True)

# 简化x轴范围计算(用np.min和np.max直接取两个数组的极值)
x_min = np.min([np.min(data1), np.min(data2)])
x_max = np.max([np.max(data1), np.max(data2)])

# 生成y和x的分箱
y_bins = np.linspace(np.min(height), np.max(height), 100)
x_bins = np.linspace(x_min, x_max, 100)

# 先计算两个数据集的直方图计数(必须先算这个,才能知道全局的计数范围)
counts1, x_edges1, y_edges1 = np.histogram2d(data1, height, bins=[x_bins, y_bins])
counts2, x_edges2, y_edges2 = np.histogram2d(data2, height, bins=[x_bins, y_bins])

# 计算计数的全局最大值(覆盖两个数据集的计数范围)
count_max = max(counts1.max(), counts2.max())

# 制作自定义色卡:0计数用白色,非0用蓝→紫→红→橙的渐变
# 颜色列表长度要和bounds的区间数一致(bounds长度-1)
colors = ['white', 'lightcyan','royalblue', 'darkviolet', 'crimson', 'orangered', 'orange', 'yellow']
# 调整bounds:0作为分界,后续按你原来的间隔,最后覆盖最大计数
bounds = [0, 1, 6, 12, 19, 22, 33, 40, count_max]
# 创建归一化规则,绑定色卡和bounds
norm = BoundaryNorm(bounds, len(colors))
cmap = LinearSegmentedColormap.from_list("custom_gradient", colors, N=len(colors))

# 创建子图
fig, axes = plt.subplots(1, 2, figsize=(15,6))

# 绘制第一个子图
X, Y = np.meshgrid(x_edges1[:-1] + np.diff(x_edges1)/2, y_edges1[:-1] + np.diff(y_edges1)/2)
masked_counts1 = np.ma.masked_where(counts1 == 0, counts1)
# 关键:传递norm参数,强制使用统一的刻度规则
pc1 = axes[0].pcolormesh(X, Y, masked_counts1.T, cmap=cmap, norm=norm, shading='auto')
axes[0].set_title('Height vs Data1')
axes[0].set_ylabel('Height')
axes[0].set_xlabel('Data1')

# 绘制第二个子图
X, Y = np.meshgrid(x_edges2[:-1] + np.diff(x_edges2)/2, y_edges2[:-1] + np.diff(y_edges2)/2)
masked_counts2 = np.ma.masked_where(counts2 == 0, counts2)
# 同样传递norm参数
pc2 = axes[1].pcolormesh(X, Y, masked_counts2.T, cmap=cmap, norm=norm, shading='auto')
axes[1].set_title('Height vs Data2')
axes[1].set_xlabel('Data2')
axes[1].sharey(axes[0])  # 让两个子图共享y轴刻度,更整洁

# 创建共享色条:用统一的norm和cmap创建ScalarMappable,确保色条准确对应两个子图
cbar = fig.colorbar(plt.cm.ScalarMappable(norm=norm, cmap=cmap), 
                    ax=axes, orientation='vertical', 
                    label='Counts', fraction=0.03, aspect=30, pad=0.02)

plt.tight_layout()
plt.show()

关键修改点说明

  1. 先计算直方图计数:必须先拿到两个数据集的计数结果,才能确定全局的最大计数范围,让bounds能覆盖所有数值
  2. 传递norm参数给pcolormesh:这是让两个子图共用同一套刻度的核心,没有这个参数,子图会自动用各自的数值范围做颜色映射
  3. 调整色卡与bounds对应关系:把白色设为0计数对应的颜色,通过bounds的第一个区间[0,1)来匹配,完全满足你“0计数显示白色”的需求
  4. 简化代码逻辑:用np.min([a,b])和np.max([a,b])替代原来的if-else,代码更简洁易读
  5. 共享y轴:加上axes[1].sharey(axes[0])让两个子图的y轴刻度对齐,可视化效果更专业

额外优化建议

  • 如果不想手动设置bounds的间隔,可以用np.linspace动态生成,比如bounds = np.linspace(0, count_max, 8),这样颜色间隔会更均匀
  • 可以用plt.tight_layout()自动调整子图间距,避免标签被截断

备注:内容来源于stack exchange,提问作者user29988411

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.13 19:24:30