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

Proplot调用contourf绘图报错DiscreteNorm无'_vmin'属性

ProPlot调用contourf绘图触发DiscreteNorm缺少_vmin属性报错

问题现象

  • 使用ProPlot(Matplotlib高级封装绘图库)调用contourf绘制填充等高线时触发属性错误,即便是运行官方文档提供的2dplots章节对应示例代码,也会复现完全相同的报错。
  • 正常依赖配置的环境下上述官方示例可正常输出图像,初步排查ProPlot源码未定位到根因。

测试数据构造代码

import xarray as xr
import numpy as np
import pandas as pd
import proplot as pp

# 构造DataArray格式测试数据
state = np.random.RandomState(51423)
linspace = np.linspace(0, np.pi, 20)
data = 50 * state.normal(1, 0.2, size=(20, 20)) * (
    np.sin(linspace * 2) ** 2
    * np.cos(linspace + np.pi / 2)[:, None] ** 2
)
lat = xr.DataArray(
    np.linspace(-90, 90, 20),
    dims=('lat',),
    attrs={'units': '\N{DEGREE SIGN}N'}
)
plev = xr.DataArray(
    np.linspace(1000, 0, 20),
    dims=('plev',),
    attrs={'long_name': 'pressure', 'units': 'hPa'}
)
da = xr.DataArray(
    data,
    name='u',
    dims=('plev', 'lat'),
    coords={'plev': plev, 'lat': lat},
    attrs={'long_name': 'zonal wind', 'units': 'm/s'}
)

# 构造DataFrame格式测试数据
data = state.rand(12, 20)
df = pd.DataFrame(
    (data - 0.4).cumsum(axis=0).cumsum(axis=1)[::1, ::-1],
    index=pd.date_range('2000-01', '2000-12', freq='MS')
)
df.name = 'temperature (\N{DEGREE SIGN}C)'
df.index.name = 'date'
df.columns.name = 'variable (units)'

绘图复现代码

fig = pp.figure(refwidth=2.5, share=False, suptitle='Automatic subplot formatting')

# 绘制DataArray填充等高线
cmap = pp.Colormap('PuBu', left=0.05)
ax = fig.subplot(121, yreverse=True)
ax.contourf(da, cmap=cmap, colorbar='t', lw=0.7, ec='k')

# 绘制DataFrame填充等高线
ax = fig.subplot(122, yreverse=True)
ax.contourf(df, cmap='YlOrRd', colorbar='t', lw=0.7, ec='k')
ax.format(xtickminor=False, yformatter='%b', ytickminor=False)

完整报错信息

AttributeError                            Traceback (most recent call last)
Input In [780], in <module>
      4 cmap = pp.Colormap('PuBu', left=0.05)
      5 ax = fig.subplot(121, yreverse=True)
----> 6 ax.contourf(da, cmap=cmap, colorbar='t', lw=0.7, ec='k')
      8 # Plot DataFrame
      9 ax = fig.subplot(122, yreverse=True)

File /opt/anaconda3/envs/argopy-tests/lib/python3.8/site-packages/proplot/internals/process.py:284, in _preprocess_args.<locals>.decorator.<locals>._redirect_or_standardize(self, *args, **kwargs)
    281             ureg.setup_matplotlib(True)
    283 # Call main function
--> 284 return func(self, *args, **kwargs)

File /opt/anaconda3/envs/argopy-tests/lib/python3.8/site-packages/proplot/axes/plot.py:3861, in PlotAxes.contourf(self, x, y, z, **kwargs)
   3859 x, y, z, kw = self._parse_plot2d(x, y, z, **kwargs)
   3860 kw.update(_pop_props(kw, 'collection'))
-> 3861 kw = self._parse_cmap(x, y, z, plot_contours=True, **kw)
   3862 contour_kw = _pop_kwargs(kw, 'edgecolors', 'linewidths', 'linestyles')
   3863 edgefix_kw = _pop_params(kw, self._apply_edgefix)

File /opt/anaconda3/envs/argopy-tests/lib/python3.8/site-packages/proplot/internals/warnings.py:96, in _rename_kwargs.<locals>.decorator.<locals>._deprecate_kwargs(*args, **kwargs)
     91         key_new = key_new.format(value)
     92     _warn_proplot(
     93         f'Keyword {key_old!r} was deprecated in version {version} and will '
     94         f'be removed in a future release. Please use {key_new!r} instead.'
     95     )
---> 96 return func_orig(*args, **kwargs)

File /opt/anaconda3/envs/argopy-tests/lib/python3.8/site-packages/proplot/axes/plot.py:2703, in PlotAxes._parse_cmap(self, cmap, cmap_kw, c, color, colors, default_cmap, norm, norm_kw, extend, vmin, vmax, discrete, default_discrete, skip_autolev, plot_lines, plot_contours, min_levels, *args, **kwargs)
   2700 # Create the discrete normalizer
   2701 # Then finally warn and remove unused args
   2702 if levels is not None:
-> 2703     norm, cmap, kwargs = self._parse_discrete(
   2704         levels, norm, cmap, extend=extend, min_levels=min_levels, **kwargs
   2705     )
   2706 methods = (self._parse_levels, self._parse_autolev, self._parse_vlim)
   2707 params = _pop_params(kwargs, *methods, ignore_internal=True)

File /opt/anaconda3/envs/argopy-tests/lib/python3.8/site-packages/proplot/axes/plot.py:2529, in PlotAxes._parse_discrete(self, levels, norm, cmap, extend, min_levels, **kwargs)
   2526 # Generate DiscreteNorm and update "child" norm with vmin and vmax from
   2527 # levels. This lets the colorbar set tick locations properly!
   2528 if not isinstance(norm, mcolors.BoundaryNorm) and len(levels) > 1:
-> 2529     norm = pcolors.DiscreteNorm(levels, norm=norm, unique=unique, step=step)
   2531 return norm, cmap, kwargs

File /opt/anaconda3/envs/argopy-tests/lib/python3.8/site-packages/proplot/internals/warnings.py:96, in _rename_kwargs.<locals>.decorator.<locals>._deprecate_kwargs(*args, **kwargs)
     91         key_new = key_new.format(value)
     92     _warn_proplot(
     93         f'Keyword {key_old!r} was deprecated in version {version} and will '
     94         f'be removed in a future release. Please use {key_new!r} instead.'
     95     )
---> 96 return func_orig(*args, **kwargs)

File /opt/anaconda3/envs/argopy-tests/lib/python3.8/site-packages/proplot/colors.py:2459, in DiscreteNorm.__init__(self, levels, norm, unique, step, clip)
   2457 self._dest = dest
   2458 self._norm = norm
-> 2459 self.vmin = vmin
   2460 self.vmax = vmax
   2461 self.boundaries = levels

File /opt/anaconda3/envs/argopy-tests/lib/python3.8/site-packages/matplotlib/colors.py:1148, in Normalize.vmin(self, value)
   1145 @vmin.setter
   1146 def vmin(self, value):
   1147     value = _sanitize_extrema(value)
-> 1148     if value != self._vmin:
   1149         self._vmin = value
   1150         self._changed()

AttributeError: 'DiscreteNorm' object has no attribute '_vmin'

问题根因

该报错由ProPlot与Matplotlib版本不兼容导致:

  • 当前环境安装的Matplotlib版本≥3.6.0,新版本调整了Normalize基类的初始化逻辑,_vmin、_vmax这类私有属性必须先通过父类构造方法初始化,才能通过setter给vmin、vmax属性赋值。
  • 环境中安装的ProPlot为≤0.9.7的正式稳定版,该版本中DiscreteNorm类的__init__方法没有先调用父类构造方法完成基础属性初始化,就直接执行self.vmin = vmin的赋值操作,触发属性不存在的错误。
  • 官方示例代码本身没有逻辑问题,是本地环境依赖版本不匹配导致运行失败。

解决方案

可根据自身需求选择以下任意一种方案修复:

  • 方案1:降级Matplotlib到兼容版本(最稳定)
    将Matplotlib版本固定到3.5.x系列,该版本与0.9.7版ProPlot适配性最好,不会出现兼容问题。执行对应包管理命令即可:
    # pip环境
    pip install matplotlib==3.5.3
    # conda环境
    # conda install matplotlib=3.5.3
    
  • 方案2:安装修复了兼容问题的ProPlot开发版
    ProPlot官方开发分支已经适配了Matplotlib 3.6+版本的接口变更,可直接安装最新开发版替换现有稳定版。
  • 方案3:临时手动修改ProPlot源码修复
    如果不想调整现有依赖版本,可以找到环境中ProPlot安装路径下的proplot/colors.py文件,定位到DiscreteNorm类的__init__方法,在所有self.xxx属性赋值前,添加一行父类初始化代码:
    super().__init__(vmin=None, vmax=None, clip=clip)
    
    修改保存后重启Python内核,即可正常运行绘图代码。

内容的提问来源于stack exchange,提问作者Only god knows

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 03:06:11