首页 > 解决方案 > 如何在 matplotlib 中使用从值到颜色的非均匀映射来获得颜色条?

问题描述

我正在寻找一个颜色条,其中 0 到 12000 的范围使用 np.interp(x, [0, 100, 1000, 10000, 120000], [0, 0, 0.5, 1, 1]).

这个想法是让从 0 到 100 的波段映射到相同的颜色,然后从最低颜色到中间颜色均匀地映射 10 到 1000 范围,然后从中间颜色到最高颜色映射 1000 到 10000。

我想要这个映射,因为我使用的是发散颜色图RdYlGn_r,并且临界值是 1000,而高于 10000 和 100 的值是异常值。

所以我尝试使用ColorbarBase我自己的子类Normalizersince LogNorm, Normalizer, SymLogNorm,BoundaryNorm并且PowerNorm似乎不适合这项任务。

但情节是空白的(没有错误)

import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np

import traceback
import warnings
import sys


plt.close('all')
fig,ax = plt.subplots(1,1)

class MyNorm(mpl.colors.Normalize):

    def __call__(self, value, clip=True):

        if clip is None:
            clip = self.clip

        clip=False
        result, is_scalar = self.process_value(value)


        self.autoscale_None(result)
        # Convert at least to float, without losing precision.
        (vmin,), _ = self.process_value(self.vmin)
        (vmax,), _ = self.process_value(self.vmax)


        if vmin == vmax:
            result.fill(0)   # Or should it be all masked?  Or 0.5?
        elif vmin > vmax:
            raise ValueError("minvalue must be less than or equal to maxvalue")
        else:
            if clip:
                mask = np.ma.getmask(result)
                result = np.ma.array(np.clip(result.filled(vmax), vmin, vmax),
                                     mask=mask)
            # ma division is very slow; we can take a shortcut
            resdat = result.data        
            resdat = np.interp(resdat, [0,100, 1000, 10000, 120000], [0.00, 0.00, 0.5, 1,1])

            result = np.ma.array(resdat, mask=result.mask, copy=False)


        if is_scalar:
            result = result[0]

        print result

        return result 


norm = MyNorm(vmax=12000, vmin=0, clip=False)
#norm = mpl.colors.Normalize(vmin=0, vmax=12000, clip=True)
cmap = plt.get_cmap('RdYlGn_r')  # From red to green
sm = mpl.cm.ScalarMappable(norm=norm, cmap=cmap)
cb1 = mpl.colorbar.ColorbarBase(ax, cmap=cmap, norm=norm, orientation='vertical',
                                ticks=[100, 1000, 10000])
cb1.set_clim(0,12000)
plt.show()

并不是说我真的不想要由离散颜色制成的颜色条,否则BoundaryNorm会很好用。我需要一个离散颜色的起始区域,然后是渐变和最后的离散色带

标签: matplotlib

解决方案


我不知道这是否是一个错误,ColorbarBase但似乎有一个平坦的起始区域是行不通的。

因此,将范围 0 到 100 映射到颜色 0 到 0 将不起作用,但是将范围 0 到 100 映射到颜色 0 到 0.0001 会正常工作。

因此,通过将np.interpOP 中的替换为

resdat = np.interp(resdat, [0,100, 1000, 10000, 120000], [0.00, 0.00001, 0.5, 1,1])

你得到

彩条

请注意,在中间或末端有一个平坦区域是可以的。


推荐阅读