在给定的时间间隔内循环或包装颜色图

Looping or wrapping a colormap over a given interval

我最近 运行 遇到了一个问题,我希望在给定的时间间隔内循环颜色图 'wrapped',因为需要一个更好的词。在下面的示例中,我在区间 [-5, 5] 上绘制值,并且我想在每个区间 [-1, 1] 上重复颜色图。我开始使用 matplotlib.colors.Normalize,但虽然我打算将数字标准化到区间 [0, 1],但给定 vminvmax 参数之外的数字被映射到该区间之外:

>>> norm = mpl.colors.Normalize(vmin=-1, vmax=1)
>>> norm(2)
1.5

当此值传递给颜色图时,返回值默认为 cmap(1),但可以使用 cmap.set_over()/cmap.set_under() 更改。但是,据我所知,这只能设置为静态颜色。

我想出的不令人满意的解决方案是定义一个函数,将我的 norm 函数应用于数组 mod 1,然后将其作为我的数据传递给 imshow() , 而无需将 norm 作为参数传递。到目前为止,我的尝试如下:

代码:

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

# Plot values between -5 and 5
x = np.linspace(-5,5,1000).reshape(1, -1)

# Normalize values to between -1 and 1
norm = mpl.colors.Normalize(vmin=-1, vmax=1)

# Function to apply norm cyclicly
def f(x):
    return norm(x)%1

# Use a cyclic cmap
cmap=plt.cm.hsv

# Plot image
fig, axs = plt.subplots(3, 1)

# Attempt using just cmap, no norm
axs[0].imshow(x, cmap=cmap, extent=[-5,5,0,1])

# Attempt applying norm, no application of modulus function
axs[1].imshow(x, cmap=cmap, norm=norm, extent=[-5,5,0,1])

# Correct output, applying norm%1 to data before passing to cmap
axs[2].imshow(f(x), cmap=cmap, extent=[-5,5,0,1])

输出:

问题:

是否有 better/built 方式 loop/wrap 颜色图而无需定义自定义函数,如底部子图所示?

一个想法可能是调整来自 tutorial 的自定义范数以获得循环范数:

import matplotlib.pyplot as plt
from matplotlib import colors
import numpy as np

class CyclicNormalize(colors.Normalize):
    def __init__(self, cmin=0, cmax=1, vmin=0, vmax=1, clip=False):
        self.cmin = cmin
        self.cmax = cmax
        colors.Normalize.__init__(self, vmin, vmax, clip=clip)

    def __call__(self, value, clip=False):
        x, y = [self.cmin, self.cmax], [0, 1]
        return np.ma.masked_array(np.interp(value, x, y, period=self.cmax - self.cmin))

x = np.linspace(-5, 5, 1000).reshape(1, -1)
cmap = plt.cm.hsv

cyclicnorm = CyclicNormalize(cmin=-1, cmax=1, vmin=-5, vmax=5)

fig, ax = plt.subplots()
pcm = ax.imshow(x, cmap=cmap, norm=cyclicnorm, extent=[-5, 5, 0, 1])
plt.show()