使用Matplotlib的Arbirtrary非线性颜色条 [英] Arbirtrary non-linear colorbar using Matplotlib

查看:352
本文介绍了使用Matplotlib的Arbirtrary非线性颜色条的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用Networkx和Matplotlib为网络的边缘着色,其中为每个边缘(i,j)赋予一个介于0和1之间的值G[i][j]['label'].

I want to color edges of networks using Networkx and Matplotlib, where each edge (i,j) is given a value G[i][j]['label'] between 0 and 1.

但是,这些值通常非常接近于零,或者非常接近于1.由于所有内容都是非常红色或非常蓝色(使用coolwarm色彩映射表),因此很难形象化颜色的变化.

However, often, these values are either very close to zero, or very close to 1. It's then difficult to visualize the variations of color, since everything is either very red or very blue (using a coolwarm colormap).

然后,我的想法是像这样一个过滤器那样应用过滤器filtR:

Then, my idea is to apply a filter filtR like one of these ones :

它只是一个多项式函数,提供从[0,1]到[0,1]的双射,并在0或1周围扩展更多的值.如果需要,则逆是易处理的.

It's simply a polynomial function which provides a bijection from [0,1] to [0,1], and stretches more values around 0 or 1. If needed, the inverse is tractable.

现在,我仅将其应用于边缘的值,以定义其颜色:

For now, I just apply it to the value of the edge, in order to define its color :

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)

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

The question is now : I would like to define the corresponding colorbar.

现在,它显示了filtR函数对我的边缘的评估,这是没有意义的:滤镜的唯一目的是修改[0,1]间隔上的颜色重新分配,以改善图的可读性.

For now, it shows the evaluation of my edges by the filtR function, which is meaningless : the only purpose of the filter is to modify the repartition of colors on the [0,1] interval in order to improve the readibility of the graph.

例如,我得到了:

我对左边的部分感到满意​​,但对右边的部分不满意,其中的颜色条应类似于:

I'm happy with the left part, but not the right one, where the colorbar should be something like:

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

我试图在定义颜色条之前重新定义values:

I tried to redefine values just before the definition of the 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)

但是什么都没有改变.

But nothing changes.

我对Matplotlib的理解是有限的,给出的代码已经是堆栈溢出答案的拼凑而成.

My understanding of Matplotlib is kind of limited, and the presented code is already a patchwork of stack overflow answers.

推荐答案

基本上,您根本不想更改颜色图.想要创建自定义规范化.为此,您可以将matplotlib.colors.Normalize子类化,并使其返回自定义函数的值.该函数需要将vminvmax之间的值作为输入,并返回[0,1]范围内的值.

Essentially you do not want to change the colormap at all. Instaed you want to create your custom normalization. To this end, you can subclass matplotlib.colors.Normalize and let it return the values of your custom function. The function would need to take values between vmin and vmax as input and return values in the range [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()

所需色条的图像建议使用部分线性函数,例如使用以下蜜蜂.

The image of the desired colorbar rather suggests a partially linear function like the following beeing used.

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))

这篇关于使用Matplotlib的Arbirtrary非线性颜色条的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆