使用 Matplotlib 的任意非线性颜色条

Ach*_*aün 5 python matplotlib networkx colorbar

我想使用 Networkx 和 Matplotlib 为网络的边缘着色,其中每个边缘(i,j)的值都G[i][j]['label']在 0 和 1 之间。

但是,通常,这些值要么非常接近于零,要么非常接近于 1。因此很难将颜色的变化可视化,因为所有东西要么非常红,要么非常蓝(使用coolwarm颜色图)。

然后,我的想法是应用filtR像以下过滤器之一:

在此处输入图片说明

它只是一个多项式函数,它提供从 [0,1] 到 [0,1] 的双射,并在 0 或 1 附近拉伸更多值。如果需要,逆是可以处理的。

现在,我只是将它应用于边缘的值,以定义它的颜色:

cm        = plt.get_cmap('coolwarm') 
cNorm     = colors.Normalize(vmin=0., vmax=1.)
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=cm)
colorList = []

# The color is defined by filtR(G[i][j]['label'])
val_map   = {(i,j): filtR(G[i][j]['label']) for (i,j) in G.edges()}
values    = [scalarMap.to_rgba(val_map[e]) for e in G.edges()]
edges     = nx.draw_networkx_edges(G,edge_color=values,edge_cmap=plt.get_cmap('coolwarm'))


# Definition of the colorbar :-(
sm = cmx.ScalarMappable(cmap=cmx.coolwarm)
sm.set_array(values)
plt.colorbar(sm)
Run Code Online (Sandbox Code Playgroud)

现在的问题是:我想定义相应的颜色条。

目前,它显示了filtR函数对我的边的评估,这是没有意义的:过滤器的唯一目的是修改 [0,1] 区间上的颜色重新分配,以提高图形的可读性。

例如,我得到:

在此处输入图片说明

我对左侧部分感到满意​​,但对右侧部分不满意,其中颜色条应该是这样的:

在此处输入图片说明

这里的过滤功能显然不是最好的,但它应该为您提供更好的说明。

我试图values在 colorbar定义之前重新定义:

# Definition of the colorbar :-(

new_val_map = {(i,j): filtR(G[i][j]['label']) for (i,j) in G.edges()}
new_values  = [scalarMap.to_rgba(val_map[e]) for e in G.edges()]

sm = cmx.ScalarMappable(cmap=cmx.coolwarm)
sm.set_array(new_values)
plt.colorbar(sm)
Run Code Online (Sandbox Code Playgroud)

但什么都没有改变。

我对 Matplotlib 的理解是有限的,并且呈现的代码已经是堆栈溢出答案的拼凑而成。

Imp*_*est 5

本质上,您根本不想更改颜色图。您想要创建自定义规范化。为此,您可以子类化matplotlib.colors.Normalize并让它返回自定义函数的值。该函数需要采用vmin和之间的值vmax作为输入,并返回 [0,1] 范围内的值。

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


class MyNormalize(mcolors.Normalize):
    def __call__(self, value, clip=None):
        # function to normalize any input between vmin and vmax linearly to [0,1]
        n = lambda x: (x-self.vmin)/(self.vmax-self.vmin)
        # nonlinear function between [0,1] and [0,1]
        f = lambda x,a: (2*x)**a*(2*x<1)/2. +(2-(2*(1-1*x))**a)*(2*x>=1)/2.
        return np.ma.masked_array(f(n(value),0.5))


fig, (ax,ax2) = plt.subplots(ncols=2)

x = np.linspace(-0.3,1.2, num=101)
X = (np.sort(np.random.rand(100))*1.5-0.3)

norm=  MyNormalize(vmin=-0.3, vmax=1.2)

ax.plot(x,norm(x))
im = ax2.imshow(X[::-1,np.newaxis], norm=norm, cmap="coolwarm", aspect="auto")
fig.colorbar(im)

plt.show()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

所需颜色条的图像更建议使用部分线性函数,如下所示。

class MyNormalize2(mcolors.Normalize):
    def __call__(self, value, clip=None):
        n = lambda x: self.vmin+(self.vmax-self.vmin)*x
        x, y = [self.vmin, n(0.2), n(0.8), self.vmax], [0, 0.48,0.52, 1]
        return np.ma.masked_array(np.interp(value, x, y))
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述