如何在 matplotlib 中插入颜色以使其数量加倍

How to interpolate colours to double its number in matplotlib

我有一个包含 9 种颜色的列表:

  colors = [
           [0, 82, 246, 255],
           [0, 196, 196, 255],
           [0, 137, 83, 255],
           [1, 233, 11, 255],
           [234, 255, 31, 255],
           [255, 176, 0, 255],
           [247, 19, 0, 255],
           [193, 0, 76, 255],
           [255, 0, 255, 255]]

我想使用 matplotlib 将插值颜色的数量加倍。我用过 LinearSegmentedColormap.from_list 没有成功:

  cm = LinearSegmentedColormap.from_list('test', np.array(colors) / 255, 
                                         N=len(colors))
  
  colors = cm(np.linspace(0, 1, 2 * len(colors)))
  colors = (colors * 255).astype('uint8')

但是我得到了相同的颜色但重复了:

array([[  0,  82, 246, 255],
       [  0,  82, 246, 255],
       [  0, 196, 196, 255],
       [  0, 196, 196, 255],
       [  0, 137,  83, 255],
       [  0, 137,  83, 255],
       [  1, 233,  11, 255],
       [  1, 233,  11, 255],
       [234, 255,  31, 255],
       [234, 255,  31, 255],
       [255, 176,   0, 255],
       [255, 176,   0, 255],
       [247,  18,   0, 255],
       [247,  18,   0, 255],
       [193,   0,  76, 255],
       [193,   0,  76, 255],
       [255,   0, 255, 255],
       [255,   0, 255, 255]], dtype=uint8)

我怎样才能得到预期的行为,使用我原来的颜色,加上中间的其他颜色?

您的“预期”行为是不可能的:如果您有 9 种颜色,并且您采用 18 个等距内插值,则只有第一个和最后一个值来自您的初始集。要将您的初始集作为列表的一部分,您需要一个倍数减一。

LinearSegmentedColormap.from_list() 的输入不能是 0-255 范围内的 rgb 值:它们必须是 0-1 范围内的浮点值。此外,N= 参数将是内部存储值的数量。如果您将 N 设置为等于原始颜色数,则不会计算任何插值颜色。为了获得最大的灵活性,您可以将 N 设置为 256。

之后,您可以再次将这些值乘以 255 以获得 0-255 范围内的 rgb 值。

from matplotlib.colors import LinearSegmentedColormap
import numpy as np

colors = [[0, 82, 246, 255],
          [0, 196, 196, 255],
          [0, 137, 83, 255],
          [1, 233, 11, 255],
          [234, 255, 31, 255],
          [255, 176, 0, 255],
          [247, 19, 0, 255],
          [193, 0, 76, 255],
          [255, 0, 255, 255]]

cm = LinearSegmentedColormap.from_list('', np.array(colors) / 255, 256)
colors_18 = (cm(np.linspace(0, 1, len(colors) * 2)) * 255).astype(np.uint8)
colors_17 = (cm(np.linspace(0, 1, len(colors) * 2 - 1)) * 255).astype(np.uint8)

colors_18:

array([[  0,  82, 246, 255],
       [  0, 135, 222, 255],
       [  0, 189, 198, 255],
       [  0, 171, 149, 255],
       [  0, 143,  96, 255],
       [  0, 170,  57, 255],
       [  0, 216,  23, 255],
       [ 69, 239,  16, 255],
       [179, 249,  26, 255],
       [238, 236,  23, 255],
       [248, 199,   9, 255],
       [253, 148,   0, 255],
       [249,  74,   0, 255],
       [240,  16,   8, 255],
       [215,   7,  44, 255],
       [196,   0,  86, 255],
       [225,   0, 170, 255],
       [255,   0, 255, 255]], dtype=uint8)

colors_17:

array([[  0,  82, 246, 255],
       [  0, 139, 220, 255],
       [  0, 195, 195, 255],
       [  0, 166, 138, 255],
       [  0, 137,  82, 255],
       [  0, 185,  46, 255],
       [  3, 233,  11, 255],
       [120, 244,  21, 255],
       [234, 253,  30, 255],
       [244, 214,  14, 255],
       [254, 172,   0, 255],
       [250,  94,   0, 255],
       [245,  18,   1, 255],
       [218,   9,  39, 255],
       [194,   0,  80, 255],
       [225,   0, 170, 255],
       [255,   0, 255, 255]], dtype=uint8)

为了在其他应用程序中使用颜色,matplotlib 还提供了一个 to_hex 函数(不适用于数组,仅适用于单个颜色):

from matplotlib.colors import to_hex
colors_18_hex = [to_hex(cm(v)) for v in np.linspace(0, 1, len(colors) * 2)]
# ['#0052f6', '#0088de', '#00bdc7', '#00ac95', '#009060', '#00ab3a', '#01d818', '#46ef11', '#b3fa1a', '#efec18', '#f9c709', '#fe9400', '#fa4a00', '#f11109', '#d7082d', '#c50057', '#e200ab', '#ff00ff']"

这是一个图表,展示了插值是如何进行的:

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

colors = np.array([[0, 82, 246, 255], [0, 196, 196, 255], [0, 137, 83, 255], [1, 233, 11, 255], [234, 255, 31, 255], [255, 176, 0, 255], [247, 19, 0, 255], [193, 0, 76, 255], [255, 0, 255, 255]])

fig, axs = plt.subplots(nrows=3, figsize=(15, 5))

plt.colorbar(ScalarMappable(cmap=LinearSegmentedColormap.from_list('', colors / 255, len(colors))),
             ticks=np.linspace(0, 1, len(colors)), orientation='horizontal', cax=axs[0])
axs[0].set_title("9 colors, no interpolation")

plt.colorbar(ScalarMappable(cmap=LinearSegmentedColormap.from_list('', colors / 255, 256)),
             ticks=np.linspace(0, 1, len(colors) * 2 - 1), orientation='horizontal', cax=axs[1])
axs[1].set_title("positions of 17 colors")
axs[1].xaxis.grid(True, ls='--')

plt.colorbar(ScalarMappable(cmap=LinearSegmentedColormap.from_list('', colors / 255, 256)),
             ticks=np.linspace(0, 1, len(colors) * 2), orientation='horizontal', cax=axs[2])
axs[2].set_title("positions of 18 colors")
axs[2].xaxis.grid(True, ls='--')

plt.tight_layout()
plt.show()

我的解决方案类似,但可能更简单。

我有这个 numpy 数组 colvals:

array([[0.90588235, 0.96078431, 1.        , 1.        ],
       [0.81568627, 0.92156863, 1.        , 1.        ],
       [0.64705882, 0.84705882, 1.        , 1.        ],
       [0.45490196, 0.75294118, 0.98823529, 1.        ],
       [0.30196078, 0.67058824, 0.96862745, 1.        ],
       [0.2       , 0.60392157, 0.94117647, 1.        ],
       [0.13333333, 0.54509804, 0.90196078, 1.        ],
       [0.10980392, 0.49411765, 0.83921569, 1.        ],
       [0.09803922, 0.44313725, 0.76078431, 1.        ],
       [0.09411765, 0.39215686, 0.67058824, 1.        ]])

它是 rgba 格式。

转换为颜色图如下所示:

cmp_blue = ListedColormap(colvals)
cmp_blue

现在我让它更细化

inbetween_color_amount = 10

# the 10 is from the original 10 colors, the 4 is for R, G, B, A
newcolvals = np.zeros(shape=(10 * (inbetween_color_amount) - (inbetween_color_amount - 1), 4))

# add first one already
newcolvals[0] = colvals[0]

for i, (rgba1, rgba2) in enumerate(zip(colvals[:-1], np.roll(colvals, -1, axis=0)[:-1])):
    for j, (p1, p2) in enumerate(zip(rgba1, rgba2)):
        flow = np.linspace(p1, p2, (inbetween_color_amount + 1))
        # discard first 1 since we already have it from previous iteration
        flow = flow[1:]
        newcolvals[ i * (inbetween_color_amount) + 1 : (i + 1) * (inbetween_color_amount) + 1, j] = flow
    
newcolvals

这次:

cmp_blue = ListedColormap(newcolvals)
cmp_blue

我得到: