将alpha添加到现有的matplotlib色彩映射表

Hen*_*dan 21 python matplotlib colormap

我想要叠加几个hexbin图,但是使用内置颜色图只能看到最后一个.我不想重新构建色彩映射.如何在不事先知道色彩图的内部结构的情况下为色彩图添加线性alpha?

Bar*_*art 39

我不太确定这是否符合"不知道色彩图的内部结构",但也许这样的东西可以用来为现有的色彩图添加线性alpha?

import numpy as np
import matplotlib.pylab as pl
from matplotlib.colors import ListedColormap

# Random data
data1 = np.random.random((4,4))

# Choose colormap
cmap = pl.cm.RdBu

# Get the colormap colors
my_cmap = cmap(np.arange(cmap.N))

# Set alpha
my_cmap[:,-1] = np.linspace(0, 1, cmap.N)

# Create new colormap
my_cmap = ListedColormap(my_cmap)

pl.figure()
pl.subplot(121)
pl.pcolormesh(data1, cmap=pl.cm.RdBu)
pl.colorbar()

pl.subplot(122)
pl.pcolormesh(data1, cmap=my_cmap)
pl.colorbar()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

  • 散点图足以在训练营之前定义Alpha。例如plt.scatter(a,b,s = 2,alpha = 0.1,c = c,cmap = cmap)完成了工作。 (2认同)

sco*_*owe 9

Bart 提供的解决方案确实为图形添加了 alpha 通道透明度。该方法的问题是它不能很好地处理连续颜色图或发散颜色图。顺序颜色图尝试近似线性地增加其亮度,从浅色到饱和色,以便颜色的强度随着值强度的增加而增加。在此之上添加 Alpha 通道意味着较浅的阴影大部分是透明的。如果将颜色图渲染在浅色背景上(我认为这是非常典型的),则颜色图在感知上不再均匀,较小的值显得更小。

将现有颜色图转换为具有 Alpha 通道的另一种方法是尽可能多地从原始颜色图的 RGB 颜色中分离白色。通过将“白色分量”转换为透明度,并重新调整 RGB 值以校正 alpha 值,我们可以确保新的透明颜色图在白色背景下呈现时与原始颜色图完全相同。

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

def rgb_white2alpha(rgb, ensure_increasing=False):
    """
    Convert a set of RGB colors to RGBA with maximum transparency.
    
    The transparency is maximised for each color individually, assuming
    that the background is white.
    
    Parameters
    ----------
    rgb : array_like shaped (N, 3)
        Original colors.
    ensure_increasing : bool, default=False
        Ensure that alpha values are strictly increasing.
    
    Returns
    -------
    rgba : numpy.ndarray shaped (N, 4)
        Colors with maximum possible transparency, assuming a white
        background.
    """
    # The most transparent alpha we can use is given by the min of RGB
    # Convert it from saturation to opacity
    alpha = 1. - np.min(rgb, axis=1)
    if ensure_increasing:
        # Let's also ensure the alpha value is monotonically increasing
        a_max = alpha[0]
        for i, a in enumerate(alpha):
            alpha[i] = a_max = np.maximum(a, a_max)
    alpha = np.expand_dims(alpha, -1)
    # Rescale colors to discount the white that will show through from transparency
    rgb = (rgb + alpha - 1) / alpha
    # Concatenate our alpha channel
    return np.concatenate((rgb, alpha), axis=1)
    

def cmap_white2alpha(name, ensure_increasing=False, register=True):
    """
    Convert colormap to have the most transparency possible, assuming white background.
    
    Parameters
    ----------
    name : str
        Name of builtin (or registered) colormap.
    ensure_increasing : bool, default=False
        Ensure that alpha values are strictly increasing.
    register : bool, default=True
        Whether to register the new colormap.

    Returns
    -------
    cmap : matplotlib.colors.ListedColormap
        Colormap with alpha set as low as possible.
    """
    # Fetch the cmap callable
    cmap = plt.get_cmap(name)
    # Get the colors out from the colormap LUT
    rgb = cmap(np.arange(cmap.N))[:, :3]  # N-by-3
    # Convert white to alpha
    rgba = rgb_white2alpha(rgb, ensure_increasing=ensure_increasing)
    # Create a new Colormap object
    cmap_alpha = matplotlib.colors.ListedColormap(rgba, name=name + "_alpha")
    if register:
        matplotlib.cm.register_cmap(name=name + "_alpha", cmap=cmap_alpha)
    return cmap_alpha

# Get original Reds colormap
cmap_og = plt.get_cmap("Reds")

# Get our new version of the colormap with white2alpha
cmap_w2a = cmap_white2alpha("Reds")

# Replicate Bart's method, which adds linear alpha without rescaling RGB values
rgba_lin = cmap(np.arange(cmap_og.N))
rgba_lin[:,-1] = np.linspace(0, 1, cmap_og.N)
cmap_lin_alpha = ListedColormap(rgba_lin)

# Generate some data to plot
data1 = np.random.random((5, 5))
data2 = np.expand_dims(np.arange(25), axis=0)

# Plot the colormap scale bars
plt.figure(figsize=(18, 5), facecolor=[.7, .7, .7])
# Original Reds colormap
plt.subplot(3, 1, 1, facecolor="w")
plt.pcolormesh(data2, cmap=cmap_og)
plt.title("Reds cmap", fontsize=12, rotation=0)
# White converted to alpha
plt.subplot(3, 1, 2, facecolor="w")
plt.pcolormesh(data2, cmap=cmap_w2a)
plt.title("white2alpha", fontsize=12, rotation=0)
# Linear alpha added
plt.subplot(3, 1, 3, facecolor="w")
plt.pcolormesh(data2, cmap=cmap_lin_alpha)
plt.title("linear alpha", fontsize=12, rotation=0)
plt.show()

# Plot randomly generated data
for bg in ["w", "g"]:
    plt.figure(figsize=(20, 5), facecolor=[.7, .7, .7])
    # Plot original Reds colormap
    plt.subplot(1, 3, 1, facecolor=bg)
    plt.pcolormesh(data1, cmap=cmap_og)
    plt.title("Reds cmap")
    plt.colorbar()
    # Plot Reds colormap with white converted to alpha
    plt.subplot(1, 3, 2, facecolor=bg)
    plt.pcolormesh(data1, cmap=cmap_w2a)
    plt.title("Reds white2alpha cmap")
    plt.colorbar()
    # Plot Reds colormap with linear alpha channel
    plt.subplot(1, 3, 3, facecolor=bg)
    plt.pcolormesh(data1, cmap=cmap_lin_alpha)
    plt.title("Reds + linear alpha")
    plt.colorbar()
    # Render
    plt.show()
Run Code Online (Sandbox Code Playgroud)

生成的颜色图如下所示: 颜色条

并分别在白色轴和绿色轴上渲染随机值: 白色背景上的随机值 绿色背景上的随机值

如图所示,与在不重新缩放 RGB 值的情况下添加线性增加的 Alpha 通道相比,将白色转换为 Alpha 产生的结果在感知上更加线性并且具有更丰富的颜色。

将白色转换为 Alpha 的缺点是 Alpha 值不会线性增加,这对您来说可能很重要。

# Plot the alpha values of each of the new colormaps
plt.figure(figsize=(10, 6))
plt.plot(cmap_w2a.colors[:, -1], label="white2alpha")
plt.plot(cmap_lin_alpha.colors[:, -1], label="linear_alpha")
plt.xlabel("Index", fontsize=12)
plt.ylabel("Alpha", fontsize=12)
plt.grid()
plt.legend(fontsize=12)
plt.show()
Run Code Online (Sandbox Code Playgroud)

alpha值比较

如果确实需要 alpha 值线性增加,则可以使用线性增加的 alpha 值,但重新调整 RGB 值以尽可能正确地校正透明度。结果不会很完美,因为颜色图太透明而无法渲染原始颜色,因此需要考虑一些权衡。我在这个colab 笔记本中实现了这个和相关选项。


Tik*_*ik0 8

我想通过修复来扩展 Bart 的答案,消除颜色栏中的线条伪影。一些历史:截至今天,这些线条伪影仍然存在,并且没有得到很好的解决(请参阅Matplotlib:添加一个从全透明到全色运行的自定义颜色条(移除伪影)为什么我的颜色条中有线条?)。但是,带有 Alpha 通道的每种颜色只不过是颜色与其背景的混合。因此,如果知道背景,就可以计算出相应的非 alpha 颜色(参见https://www.viget.com/articles/eqating-color-and-transparency/)。

以下解决方案假设,该图不需要实际透明度。如果在图中使用真正的 alpha 并在需要时使用带有计算出的非 alpha 颜色值的自己的颜色图。

import numpy as np
import matplotlib.pylab as pl
from matplotlib.colors import ListedColormap

# Random data
data1 = np.random.random((4,4))

# Choose colormap which will be mixed with the alpha values
cmap = pl.cm.RdBu

# Get the colormap colors
my_cmap = cmap(np.arange(cmap.N))
# Define the alphas in the range from 0 to 1
alphas = np.linspace(0, 1, cmap.N)
# Define the background as white
BG = np.asarray([1., 1., 1.,])
# Mix the colors with the background
for i in range(cmap.N):
    my_cmap[i,:-1] = my_cmap[i,:-1] * alphas[i] + BG * (1.-alphas[i])
# Create new colormap which mimics the alpha values
my_cmap = ListedColormap(my_cmap)

# Plot
f, axs = pl.subplots(1,2, figsize=(8,3))
h = axs[0].pcolormesh(data1, cmap=pl.cm.RdBu)
cb = f.colorbar(h, ax=axs[0])

h = axs[1].pcolormesh(data1, cmap=my_cmap)
cb = pl.colorbar(h, ax=axs[1])
f.show()
Run Code Online (Sandbox Code Playgroud)

图像 wo 神器