使用 matplotlib 创建自己的颜色图并绘制颜色比例
- 2024-12-26 08:43:00
- admin 原创
- 115
问题描述:
我有以下问题,我想创建自己的颜色图(红色混合紫色混合蓝色),该颜色图映射到 -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())
我的问题是:
我无法绘制颜色标尺。2
. 我不完全确定我的标尺是否正在创建连续(平滑)的颜色标尺。
解决方案 1:
由于其他答案中使用的方法对于如此简单的任务来说似乎相当复杂,因此这里有一个新的答案:
您可以使用来代替ListedColormap
,因为它会生成离散颜色图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()
更一般地,如果您有一个值列表(例如[-2., -1, 2]
)和对应颜色(例如["red","violet","blue"]
),使得n
第个值应该对应于n
第个颜色,则可以规范化这些值并将它们作为元组提供给方法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()
解决方案 2:
这里有一个关于如何创建自定义颜色图的示例。文档字符串对于理解的含义至关重要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
这是可行的方法。
解决方案 3:
如果您想自动创建常用于表面图的自定义发散色彩图,那么该模块与@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 元组。这是使用表面图演示的结果:
解决方案 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' ] )