简体   繁体   English

非线性色图,matplotlib

[英]nonlinear colormap, matplotlib

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? 是否有任何颜色图或是否有一种简单的方法来转换matplotlib色彩图以提供更接近0.5的更大颜色范围和更小的极端颜色范围? 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. 我正在创建一组子图,其中一个的颜色值大约是其他的10倍,所以它的值占主导地位,其余的图看起来都一样。 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()

There is much more variation in t1 than in t2, however the variation can not be seen because of the high values of t2. t1的变化比t2多得多,但是由于t2的值很高,所以无法看到变化。 What I want is a map the will provide a larger color gradient around the mean of t1 without transforming the data itself. 我想要的是一个地图,它将在t1的平均值周围提供更大的颜色渐变,而不会改变数据本身。 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. 我在这里找到了一个解决方案http://protracted-matter.blogspot.co.nz/2012/08/nonlinear-colormap-in-matplotlib.html但是不能让它适用于我的散点图。

EDIT: 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()

Your link provides quite a good solution for the colormap. 您的链接为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. 我使用了两个以平均值为中心的范围,在样本的标准偏差的+- 4之间。 by changing that to another number you obtain a different local gradient in the color around the two mean values. 通过将其更改为另一个数字,您可以获得围绕两个平均值的颜色的不同局部渐变。

For the colorbar, you 对于colorbar,你

  • either leave the colors nonlinearly spaced with linearly spaced labels 要么是用线性间隔的标签非线性地隔开颜色
  • you have linearly spaced colors with nonlinearly spaced labels. 你有线性间隔的颜色与非线性间隔标签。

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: 在结果中,请注意颜色条的刻度不是等间隔的:

在此输入图像描述

You could use LinearSegmentedColormap : 你可以使用LinearSegmentedColormap

With this, you need to set up a color lookup table within a dictionary eg 'cdict' below. 有了这个,你需要在字典中设置一个颜色查找表,例如下面的'cdict'。

cdict = {'red':   [(0.0,  0.0, 0.0),
                   (0.15,  0.01, 0.01),
                   (0.35,  1.0, 1.0),
                   (1.0,  1.0, 1.0)],

         'green': [(0.0,  0.0, 0.0),
                   (1.0,  0.0, 1.0)],

         'blue':  [(0.0,  0.0, 1.0),
                   (0.9,  0.01, 0.01),
                   (1.0,  0.0, 1.0)]}

This shows the transistions between values. 这显示了值之间的转换。 I have set red to vary a lot around the values of t1/t2_max (0.15 to 0.35) and blue to vary a lot around the values of t2/t2_max (0.9 to 1.0). 我设置红色在t1/t2_max (0.15到0.35)的值附近变化很多,蓝色在t2/t2_max (0.9到1.0)的值附近变化很多。 Green does nothing. 格林什么也没做。 I'd recommend reading the docs to see how this works. 我建议阅读文档 ,看看它是如何工作的。 (Note this could be automated to automatically vary around your values). (注意,这可以自动化,以自动改变您的值)。 I then tweaked your code to show the graph: 然后我调整了你的代码来显示图表:

import matplotlib.colors as col

my_cmap = col.LinearSegmentedColormap('my_colormap', cdict)

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

p = plt.subplot(1,2,1)
colors = my_cmap(t1/t2_max)

p.scatter(x, y, edgecolors=colors, s=15, linewidths=4)

p = plt.subplot(1,2,2)
colors = my_cmap(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=my_cmap, norm=plt.Normalize(vmin=0, vmax=t2_max))
sm._A = []
cbar = plt.colorbar(sm,cax=cbar_ax)

plt.show()

在此输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM