如何用Matplotlib contourf呈现双曲型数据并优化颜色缩放?
问题描述
想用contourf绘制3D函数z=f(x,y)的图像,同时用黑色线条和自定义标签高亮z为常量的等高线。x、y、z数据存储在CSV文件中,用pandas处理,函数缩放关系为$f(x,y) \propto 1/(x \cdot y)$。
当前代码生成的图像颜色缩放效果极差:99%以上的区域颜色一致,无法区分98%-98.5%、98.5%-99%这类区间,色条显示也异常,推测是缩放设置错误。另外,通用场景下希望Z中的NaN区域显示为白色,尽量不新增额外模块。
解决方案
核心问题分析
当前contourf用len(levels)自动生成等高层级,而Z值分布极不均匀(符合1/(x·y)的反比例特性),自动分层会把绝大多数区间压缩到高值段,导致颜色区分度差。
关键修改点
- 指定精确等高层级:直接用自定义的
levels数组作为contourf的层级参数,确保每个目标区间对应独立颜色层 - 处理NaN显示:通过颜色映射的
set_bad方法,将NaN区域设为白色 - 匹配色条与层级:让色条刻度完全对应自定义层级,避免自动生成的混乱
修改后的完整代码
import pandas as pd import numpy as np import matplotlib.pyplot as plt from matplotlib import rcParams rcParams.update({ "text.usetex": True, "font.family": "sans-serif", "font.sans-serif": "Helvetica", }) rcParams['text.latex.preamble'] = r'\usepackage{amsmath}' #for \text command # 自定义格式化函数:去除末尾零并添加百分号 def fmt(x): s = f"{x:.2f}" if s.endswith("0"): s = f"{x:.1f}" if s.endswith("0"): s = f"{x:.0f}" return rf"{s} \%" if plt.rcParams["text.usetex"] else f"{s} %" # 读取数据 contour_data = pd.read_csv('MyData.csv', header=None, names=['x','y','z']) # 重构网格数据 Z = contour_data.pivot_table(index='x', columns='y', values='z', dropna=False).T.values X_unique = np.sort(contour_data.x.unique()) Y_unique = np.sort(contour_data.y.unique()) X, Y = np.meshgrid(X_unique, Y_unique) # 初始化绘图 rcParams['figure.figsize'] = 5, 5 fig = plt.figure() ax = fig.add_subplot(111) # 定义目标等高层级 levels = np.array([98.,98.5,99.,99.5,99.6,99.7,99.8,99.85]) # 配置颜色映射:设置NaN区域为白色 cmap = plt.get_cmap('Reds') cmap.set_bad(color='white') # 生成填充等高线:使用自定义levels确保区间颜色区分 cpf = ax.contourf(X,Y,Z, levels=levels, extend='both', cmap=cmap ) # 色条刻度与自定义层级对齐 fig.colorbar(cpf, ticks=levels, orientation='vertical', format=fmt) # 绘制黑色高亮等高线并添加标签 cp = ax.contour(X, Y, Z, levels=levels, colors='black') ax.clabel(cp, cp.levels, inline=True, fmt=fmt, fontsize=10, colors='black') # 设置坐标轴标签 ax.set_xlabel(r'$X-\text{axis } [\alpha]$') ax.set_ylabel(r'$Y-\text{axis } [\beta]$') # plt.savefig('contour_plot.pdf') # 按需保存图像 plt.show()
修改说明
- 将
contourf的层级参数从len(levels)改为levels,强制Matplotlib使用指定区间划分颜色,解决高值区域颜色扎堆问题 - 通过
cmap.set_bad('white')实现NaN区域显示为白色,适配通用场景 - 色条直接使用
fmt格式化函数,确保刻度显示与等高线标签一致 - 简化等高线颜色设置,直接用
colors='black'替代列表生成,代码更简洁
内容的提问来源于stack exchange,提问作者MttRch
相关产品推荐
相关产品推荐

