Python 使用 matplotlib 创建自己的颜色图并绘制色标
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16834861/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Create own colormap using matplotlib and plot color scale
提问by Trollbrot
I have the following problem, I want to create my own colormap (red-mix-violet-mix-blue) that maps to values between -2 and +2 and want to use it to color points in my plot.
The plot should then have the colorscale to the right.
That is how I create the map so far. But I am not really sure if it mixes the colors.
我有以下问题,我想创建自己的颜色图(红混合紫混合蓝),映射到 -2 和 +2 之间的值,并想用它来为我的绘图中的点着色。然后该图应该具有右侧的色阶。
到目前为止,这就是我创建地图的方式。但我不确定它是否混合了颜色。
cmap = matplotlib.colors.ListedColormap(["red","violet","blue"], name='from_list', N=None)
m = cm.ScalarMappable(norm=norm, cmap=cmap)
That way I map the colors to the values.
这样我将颜色映射到值。
colors = itertools.cycle([m.to_rgba(1.22), ..])
Then I plot it:
然后我绘制它:
for i in range(0, len(array_dg)):
plt.plot(array_dg[i], markers.next(),alpha=alpha[i], c=colors.next())
My problems are:
1. I can't plot the color scale.
2. I am not completely sure if my scale is creating a continues (smooth) colorscale.
我的问题是:
1. 我无法绘制色标。
2. 我不完全确定我的比例是否创建了连续(平滑)的色阶。
采纳答案by unutbu
There is an illustrative example of how to create custom colormaps here.
The docstring is essential for understanding the meaning of
cdict. Once you get that under your belt, you might use a cdictlike this:
这里有一个关于如何创建自定义颜色图的说明性示例。文档字符串对于理解
cdict. 一旦你明白了,你可能会使用cdict这样的:
cdict = {'red': ((0.0, 1.0, 1.0),
(0.1, 1.0, 1.0), # red
(0.4, 1.0, 1.0), # violet
(1.0, 0.0, 0.0)), # blue
'green': ((0.0, 0.0, 0.0),
(1.0, 0.0, 0.0)),
'blue': ((0.0, 0.0, 0.0),
(0.1, 0.0, 0.0), # red
(0.4, 1.0, 1.0), # violet
(1.0, 1.0, 0.0)) # blue
}
Although the cdictformat gives you a lot of flexibility, I find for simple
gradients its format is rather unintuitive. Here is a utility function to help
generate simple LinearSegmentedColormaps:
尽管该cdict格式为您提供了很大的灵活性,但我发现对于简单的渐变,其格式相当不直观。这是一个帮助生成简单 LinearSegmentedColormaps 的实用函数:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
def make_colormap(seq):
"""Return a LinearSegmentedColormap
seq: a sequence of floats and RGB-tuples. The floats should be increasing
and in the interval (0,1).
"""
seq = [(None,) * 3, 0.0] + list(seq) + [1.0, (None,) * 3]
cdict = {'red': [], 'green': [], 'blue': []}
for i, item in enumerate(seq):
if isinstance(item, float):
r1, g1, b1 = seq[i - 1]
r2, g2, b2 = seq[i + 1]
cdict['red'].append([item, r1, r2])
cdict['green'].append([item, g1, g2])
cdict['blue'].append([item, b1, b2])
return mcolors.LinearSegmentedColormap('CustomMap', cdict)
c = mcolors.ColorConverter().to_rgb
rvb = make_colormap(
[c('red'), c('violet'), 0.33, c('violet'), c('blue'), 0.66, c('blue')])
N = 1000
array_dg = np.random.uniform(0, 10, size=(N, 2))
colors = np.random.uniform(-2, 2, size=(N,))
plt.scatter(array_dg[:, 0], array_dg[:, 1], c=colors, cmap=rvb)
plt.colorbar()
plt.show()


By the way, the for-loop
顺便说一下, for-loop
for i in range(0, len(array_dg)):
plt.plot(array_dg[i], markers.next(),alpha=alpha[i], c=colors.next())
plots one point for every call to plt.plot. This will work for a small number of points, but will become extremely slow for many points. plt.plotcan only draw in one color, but plt.scattercan assign a different color to each dot. Thus, plt.scatteris the way to go.
为每次调用绘制一个点plt.plot。这将适用于少量点,但对于许多点会变得非常慢。plt.plot只能绘制一种颜色,但plt.scatter可以为每个点指定不同的颜色。因此,plt.scatter是要走的路。
回答by Steven C. Howell
If you want to automate the creating of a custom divergent colormap commonly used for surface plots, this module combined with @unutbu method worked well for me.
如果你想自动创建一个通常用于表面图的自定义发散颜色图,这个模块结合@unutbu 方法对我来说效果很好。
def diverge_map(high=(0.565, 0.392, 0.173), low=(0.094, 0.310, 0.635)):
'''
low and high are colors that will be used for the two
ends of the spectrum. they can be either color strings
or rgb color tuples
'''
c = mcolors.ColorConverter().to_rgb
if isinstance(low, basestring): low = c(low)
if isinstance(high, basestring): high = c(high)
return make_colormap([low, c('white'), 0.5, c('white'), high])
The high and low values can be either string color names or rgb tuples. This is the result using the surface plot demo:

高值和低值可以是字符串颜色名称或 rgb 元组。这是使用表面图演示的结果:

回答by ImportanceOfBeingErnest
Since the methods used in other answers seems quite complicated for such easy task, here is a new answer:
由于其他答案中使用的方法对于如此简单的任务来说似乎相当复杂,因此这里有一个新答案:
Instead of a ListedColormap, which produces a discrete colormap, you may use a LinearSegmentedColormap. This can easily be created from a list using the from_listmethod.
ListedColormap您可以使用 a代替产生离散颜色图的 a LinearSegmentedColormap。这可以使用该from_list方法轻松地从列表中创建。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
x,y,c = zip(*np.random.rand(30,3)*4-2)
norm=plt.Normalize(-2,2)
cmap = matplotlib.colors.LinearSegmentedColormap.from_list("", ["red","violet","blue"])
plt.scatter(x,y,c=c, cmap=cmap, norm=norm)
plt.colorbar()
plt.show()
More generally, if you have a list of values (e.g. [-2., -1, 2]) and corresponding colors, (e.g. ["red","violet","blue"]), such that the nth value should correspond to the nth color, you can normalize the values and supply them as tuples to the from_listmethod.
更一般地,如果您有一个值列表(例如[-2., -1, 2])和相应的颜色(例如["red","violet","blue"]),使得第nth 个值应该对应于第nth 个颜色,您可以将这些值归一化并将它们作为元组提供给from_list方法。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
x,y,c = zip(*np.random.rand(30,3)*4-2)
cvals = [-2., -1, 2]
colors = ["red","violet","blue"]
norm=plt.Normalize(min(cvals),max(cvals))
tuples = list(zip(map(norm,cvals), colors))
cmap = matplotlib.colors.LinearSegmentedColormap.from_list("", tuples)
plt.scatter(x,y,c=c, cmap=cmap, norm=norm)
plt.colorbar()
plt.show()

