使用 matplotlib 创建自己的颜色图并绘制颜色比例
Posted
技术标签:
【中文标题】使用 matplotlib 创建自己的颜色图并绘制颜色比例【英文标题】:Create own colormap using matplotlib and plot color scale 【发布时间】:2013-05-25 22:49:59 【问题描述】:我有以下问题,我想创建自己的颜色图 (red-mix-violet-mix-blue),它映射到 -2 和 +2 之间的值,并想用它来为我的绘图中的点着色。 然后,该图应具有右侧的色标。 到目前为止,这就是我创建地图的方式。但我不确定它是否会混合颜色。
cmap = matplotlib.colors.ListedColormap(["red","violet","blue"], name='from_list', N=None)
m = cm.ScalarMappable(norm=norm, cmap=cmap)
这样我将颜色映射到值。
colors = itertools.cycle([m.to_rgba(1.22), ..])
然后我绘制它:
for i in range(0, len(array_dg)):
plt.plot(array_dg[i], markers.next(),alpha=alpha[i], c=colors.next())
我的问题是: 1. 我无法绘制色标。 2. 我不完全确定我的比例是否正在创建一个连续(平滑)的色阶。
【问题讨论】:
你能澄清一下你的问题吗?例如,c=
指定线条颜色,而您正在谈论点。你只能指定一个markerfacecolor
,如果你真的想要积分,分散可能是一个更好的选择。确实ListedColormap
已列出,而不是连续的,请参阅LinearSegmentedColormap
。
这很奇怪,应该是点,看起来像点。
你当然可以,但这就是你应该澄清的。我们看不到您使用的是什么情节风格。如果您使用plt.plot(values, 'o')
,您将只绘制标记而不绘制线条,但标记将具有一种固定颜色,不会(也不能)随值变化。
【参考方案1】:
有一个how to create custom colormaps here 的说明性示例。
文档字符串对于理解
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
虽然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()
顺便说一句,for-loop
for i in range(0, len(array_dg)):
plt.plot(array_dg[i], markers.next(),alpha=alpha[i], c=colors.next())
为每次调用plt.plot
绘制一个点。这将适用于少数点,但对于许多点会变得非常慢。 plt.plot
只能绘制一种颜色,但plt.scatter
可以为每个点分配不同的颜色。因此,plt.scatter
是要走的路。
【讨论】:
现在我遇到了问题。我还想根据颜色获得不同的标记符号(我有 13 种不同的颜色)。但是散点图每个图只允许一个标记,还是我错过了什么? 在这种情况下,您需要为每种颜色/标记组合调用一次plt.scatter
(或plt.plot
)。
为什么我不能在 plt.set_cmap() 中使用用这个很棒的函数创建的颜色图?错误很长,最后一行是ValueError: Colormap CustomMap is not识别。
@Ilya:先注册颜色图:plt.register_cmap(name=rvb.name, cmap=rvb)
,然后调用plt.set_cmap(rvb)
。
@As3adTintin: rvb
上面是一个完整的颜色图,就像plt.cm.cool
。所以它们是可替代的:color = rvb(x/y)
.【参考方案2】:
由于其他答案中使用的方法对于如此简单的任务似乎相当复杂,所以这里有一个新答案:
您可以使用LinearSegmentedColormap
,而不是生成离散颜色图的ListedColormap
。这可以使用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()
更一般地说,如果您有一个值列表(例如[-2., -1, 2]
)和相应的颜色(例如["red","violet","blue"]
),那么n
th 值应该对应于n
th 颜色,您可以标准化这些值并将它们作为元组提供给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()
【讨论】:
您现在如何将自己定义的范围传递给此,例如red
对应于-5
,violet
对应于1
和blue
对应于100
?如果你能看看我问的问题here,我将不胜感激。
使用各自绘图方法的vmin
和vmax
或norm
参数。
这可能不如接受的答案中的完整自定义地图灵活,但这非常复杂,我认为这个答案正是大多数人想要自定义颜色图时所需要的。
@Notso LinearSegmentedColormap.from_list("", [(0,"red"), (.1,"violet"), (.5, "blue"), (1.0, "green")])
。我更新了答案,希望能更清楚地说明这一点。
@ShaunLowis 在这种特定情况下,您可以自己插入 RGB 值。更一般地说,您可以先创建一个颜色图,然后以非等距的步骤获取该图的颜色。例如。如果cmap
是原始颜色图,那么cvals=[-12, -2,0,2,12]; colors = cmap(plt.Normalize(-12,12)(np.array(cvals)))
将为您提供压缩图的新颜色。【参考方案3】:
如果您想自动创建通常用于surface plots 的自定义发散颜色图,此模块与@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])
高低值可以是字符串颜色名称或 rgb 元组。这是使用surface plot demo 的结果:
【讨论】:
【参考方案4】:这似乎对我有用。
def make_Ramp( ramp_colors ):
from colour import Color
from matplotlib.colors import LinearSegmentedColormap
color_ramp = LinearSegmentedColormap.from_list( 'my_list', [ Color( c1 ).rgb for c1 in ramp_colors ] )
plt.figure( figsize = (15,3))
plt.imshow( [list(np.arange(0, len( ramp_colors ) , 0.1)) ] , interpolation='nearest', origin='lower', cmap= color_ramp )
plt.xticks([])
plt.yticks([])
return color_ramp
custom_ramp = make_Ramp( ['#754a28','#893584','#68ad45','#0080a5' ] )
【讨论】:
以上是关于使用 matplotlib 创建自己的颜色图并绘制颜色比例的主要内容,如果未能解决你的问题,请参考以下文章
python使用matplotlib绘制水平条形图并在条形图上添加实际数值标签实战
简单的Python项目——可视化数据入门(关键词:matplotlib,pyolot,pygal)
python使用matplotlib可视化使用subplots子图subplots绘制子图并为可视化的子图添加主标题(subplots main title)
python使用matplotlib可视化subplots子图subplots绘制子图并为可视化的多个子图设置共享的X轴
python使用matplotlib可视化subplots子图subplots绘制子图并为可视化的多个子图设置共享的Y轴
python使用matplotlib可视化使用subplots子图subplots绘制子图并为可视化的每个子图添加标题(title for each subplots)