非线性色彩图,matplotlib [英] nonlinear colormap, matplotlib

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

问题描述

是否有任何颜色图或是否有一种简单的方法来转换 matplotlib 颜色图以提供接近 0.5 的更大颜色范围和在极端情况下更小的颜色范围?我正在创建一堆子图,其中一个子图的颜色值约为其他子图的10倍,因此它的值占主导地位,其余所有图看起来都一样.举一个简单的例子,我们有:

Are there any colormaps or is there a simple way to transform a matplotlib colormap to provide a much bigger color range near 0.5 and a smaller one at the extremes? I am creating a bunch of subplots, one of which has color values of about 10 times the others, so it’s values dominate and the rest of the plots all look the same. For a simple example say we have:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(1,10,10)
y = np.linspace(1,10,10)

t1 = np.random.normal(2,0.3,10)
t2 = np.random.normal(9,0.01,10)
t2_max = max(t2)

plt.figure(figsize=(22.0, 15.50))

p = plt.subplot(1,2,1)
colors = plt.cm.Accent(t1/t2_max)
p.scatter(x, y, edgecolors=colors, s=15, linewidths=4)

p = plt.subplot(1,2,2)
colors = plt.cm.Accent(t2/t2_max)
p.scatter(x, y, edgecolors=colors, s=15, linewidths=4)

plt.subplots_adjust(left=0.2)
cbar_ax = plt.axes([0.10, 0.15, 0.05, 0.7])
sm = plt.cm.ScalarMappable(cmap=plt.cm.Accent, norm=plt.Normalize(vmin=0, vmax=t2_max))
sm._A = []
cbar = plt.colorbar(sm,cax=cbar_ax)

plt.show()

t1 中的变化比 t2 中的多得多,但是由于 t2 的值很高,所以无法看到变化.我想要的是一张地图,它将在t1的平均值附近提供更大的颜色渐变,而无需转换数据本身.我在这里找到了一个解决方案 http://protracted-matter.blogspot.co.nz/2012/08/nonlinear-colormap-in-matplotlib.html ,但无法使其适用于我的散点图.

There is much more variation in t1 than in t2, however the variation can not be seen because of the high values of t2. What I want is a map the will provide a larger color gradient around the mean of t1 without transforming the data itself. I have found one solution here http://protracted-matter.blogspot.co.nz/2012/08/nonlinear-colormap-in-matplotlib.html but cant get it to work for my scatter plots.

从下面的答案可以修改类以取负数和固定边界.

From answer below the class can be modified to take negative numbers, and fixed boundaries.

import numpy as np
import matplotlib.pyplot as plt

x = y = np.linspace(1, 10, 10)

t1mean, t2mean = -6, 9
sigma1, sigma2 = .3, .01
t1 = np.random.normal(t1mean, sigma1, 10)
t2 = np.random.normal(t2mean, sigma2, 10)

class nlcmap(object):
    def __init__(self, cmap, levels):
        self.cmap = cmap
        self.N = cmap.N
        self.monochrome = self.cmap.monochrome
        self.levels = np.asarray(levels, dtype='float64')
        self._x = self.levels
        self.levmax = self.levels.max()
        self.levmin = self.levels.min()
        self.transformed_levels = np.linspace(self.levmin, self.levmax,
             len(self.levels))

    def __call__(self, xi, alpha=1.0, **kw):
        yi = np.interp(xi, self._x, self.transformed_levels)
        return self.cmap(yi / (self.levmax-self.levmin)+0.5, alpha)

tmax = 10
tmin = -10
#the choice of the levels depends on the data:
levels = np.concatenate((
    [tmin, tmax],
    np.linspace(t1mean - 2 * sigma1, t1mean + 2 * sigma1, 5),
    np.linspace(t2mean - 2 * sigma2, t2mean + 2 * sigma2, 5),
    ))
levels = levels[levels <= tmax]
levels.sort()
print levels
cmap_nonlin = nlcmap(plt.cm.jet, levels)

fig, (ax1, ax2) = plt.subplots(1, 2)

ax1.scatter(x, y, edgecolors=cmap_nonlin(t1), s=15, linewidths=4)
ax2.scatter(x, y, edgecolors=cmap_nonlin(t2), s=15, linewidths=4)

fig.subplots_adjust(left=.25)
cbar_ax = fig.add_axes([0.10, 0.15, 0.05, 0.7])

#for the colorbar we map the original colormap, not the nonlinear one:
sm = plt.cm.ScalarMappable(cmap=plt.cm.jet, 
                norm=plt.Normalize(vmin=tmin, vmax=tmax))
sm._A = []

cbar = fig.colorbar(sm, cax=cbar_ax)
#here we are relabel the linear colorbar ticks to match the nonlinear ticks
cbar.set_ticks(cmap_nonlin.transformed_levels)
cbar.set_ticklabels(["%.2f" % lev for lev in levels])

plt.show()

推荐答案

您的 link 为颜色图提供了很好的解决方案.我编辑了一点,但它包含了所有必要的内容.您需要为非线性色彩图选择一些合理的级别.我使用了两个以平均值为中心的范围,在 +-4 样本的标准偏差之间.通过将其更改为另一个数字,可以在两个平均值附近获得不同的颜色局部梯度.

Your link provides quite a good solution for the colormap. I edited a bit, but it contained al the necessary. You need to pick some sensible levels for your nonlinear colormap. I used two ranges centered around the mean values, between +- 4 the standard deviation of your sample. by changing that to another number you obtain a different local gradient in the color around the two mean values.

对于颜色栏,您

  • 要么使用线性间隔的标签使颜色非线性间隔
  • 您有线性间隔的颜色和非线性间隔的标签.

第二个在查看数据时可以提供更高的分辨率,看起来更好,并且在以下实现:

The second allows greater resolution when looking at the data, looks nicer and is implemented below:

import numpy as np
import matplotlib.pyplot as plt

x = y = np.linspace(1, 10, 10)

t1mean, t2mean = 2, 9
sigma1, sigma2 = .3, .01
t1 = np.random.normal(t1mean, sigma1, 10)
t2 = np.random.normal(t2mean, sigma2, 10)

class nlcmap(object):
    def __init__(self, cmap, levels):
        self.cmap = cmap
        self.N = cmap.N
        self.monochrome = self.cmap.monochrome
        self.levels = np.asarray(levels, dtype='float64')
        self._x = self.levels
        self.levmax = self.levels.max()
        self.transformed_levels = np.linspace(0.0, self.levmax,
             len(self.levels))

    def __call__(self, xi, alpha=1.0, **kw):
        yi = np.interp(xi, self._x, self.transformed_levels)
        return self.cmap(yi / self.levmax, alpha)

tmax = max(t1.max(), t2.max())
#the choice of the levels depends on the data:
levels = np.concatenate((
    [0, tmax],
    np.linspace(t1mean - 4 * sigma1, t1mean + 4 * sigma1, 5),
    np.linspace(t2mean - 4 * sigma2, t2mean + 4 * sigma2, 5),
    ))

levels = levels[levels <= tmax]
levels.sort()

cmap_nonlin = nlcmap(plt.cm.jet, levels)

fig, (ax1, ax2) = plt.subplots(1, 2)

ax1.scatter(x, y, edgecolors=cmap_nonlin(t1), s=15, linewidths=4)
ax2.scatter(x, y, edgecolors=cmap_nonlin(t2), s=15, linewidths=4)

fig.subplots_adjust(left=.25)
cbar_ax = fig.add_axes([0.10, 0.15, 0.05, 0.7])

#for the colorbar we map the original colormap, not the nonlinear one:
sm = plt.cm.ScalarMappable(cmap=plt.cm.jet, 
                norm=plt.Normalize(vmin=0, vmax=tmax))
sm._A = []

cbar = fig.colorbar(sm, cax=cbar_ax)
#here we are relabel the linear colorbar ticks to match the nonlinear ticks
cbar.set_ticks(cmap_nonlin.transformed_levels)
cbar.set_ticklabels(["%.2f" % lev for lev in levels])

plt.show()

在结果中,请注意颜色条的刻度不是等距的:

In the result, notice that the ticks of the colorbar are NOT equispaced:

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

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