从 matplotlib 中的颜色图中获取单独的颜色
- 2025-03-18 08:54:00
- admin 原创
- 47
问题描述:
如果你有一个Colormap cmap
,例如:
cmap = matplotlib.cm.get_cmap('Spectral')
如何从 0 到 1 之间获取特定颜色,其中 0 是地图中的第一个颜色,而 1 是地图中的最后一种颜色?
理想情况下,我可以通过执行以下操作来获取地图中的中间颜色:
>>> do_some_magic(cmap, 0.5) # Return an RGBA tuple
(0.1, 0.2, 0.3, 1.0)
解决方案 1:
您可以使用下面的代码执行此操作,并且问题中的代码实际上非常接近您需要的,您所要做的就是调用cmap
您拥有的对象。
import matplotlib
cmap = matplotlib.cm.get_cmap('Spectral')
rgba = cmap(0.5)
print(rgba) # (0.99807766255210428, 0.99923106502084169, 0.74602077638401709, 1.0)
对于超出范围 [0.0, 1.0] 的值,它将分别返回下限和上限颜色。默认情况下,这是范围内的最小和最大颜色(因此为 0.0 和 1.0)。可以使用cmap.set_under()
和更改此默认值cmap.set_over()
。
对于诸如np.nan
和np.inf
之类的“特殊”数字,默认值为 0.0 值,可以使用cmap.set_bad()
类似于上述的 under 和 over 来更改它。
最后,您可能需要对数据进行规范化,使其符合范围[0.0, 1.0]
。这可以通过matplotlib.colors.Normalize
简单的操作来完成,如下面的小示例中所示,其中参数vmin
和vmax
描述了应分别将哪些数字映射到 0.0 和 1.0。
import matplotlib
norm = matplotlib.colors.Normalize(vmin=10.0, vmax=20.0)
print(norm(15.0)) # 0.5
对于具有大量值范围的数据范围,还可以使用对数标准化器(matplotlib.colors.LogNorm )。
(感谢Joe Kington和tcaswell对如何改进答案提出的建议。)
解决方案 2:
为了获取 rgba 整数值而不是浮点值,我们可以这样做
rgba = cmap(0.5,bytes=True)
因此,为了根据 Ffisegydd 的回答简化代码,代码将如下所示:
#import colormap
from matplotlib import cm
#normalize item number values to colormap
norm = matplotlib.colors.Normalize(vmin=0, vmax=1000)
#colormap possible values = viridis, jet, spectral
rgba_color = cm.jet(norm(400),bytes=True)
#400 is one of value between 0 and 1000
解决方案 3:
我曾经遇到过类似的情况,我需要从颜色图中选取“n”个颜色,以便将每种颜色分配给我的数据。我在名为“ mycolorpy ”的包中编译了相关代码。您可以使用 pip 安装它:
pip install mycolorpy
然后你可以执行以下操作:
from mycolorpy import colorlist as mcp
import numpy as np
示例:从 cmap“winter”创建 5 个十六进制字符串列表
color1=mcp.gen_color(cmap="winter",n=5)
print(color1)
输出:
['#0000ff', '#0040df', '#0080bf', '#00c09f', '#00ff80']
另一个示例是从 cmap bwr 生成 16 种颜色列表:
color2=mcp.gen_color(cmap="bwr",n=16)
print(color2)
输出:
['#0000ff', '#2222ff', '#4444ff', '#6666ff', '#8888ff', '#aaaaff', '#ccccff', '#eeeeff', '#ffeeee', '#ffcccc', '#ffaaaa', '#ff8888', '#ff6666', '#ff4444', '#ff2222', '#ff0000']
有一个包含使用示例的Python 笔记本,可以更好地形象化地展示这一点。
假设您想要从 cmap 生成一个颜色列表,该列表已标准化为给定数据。您可以使用以下方法执行此操作:
a=random.randint(1000, size=(200))
a=np.array(a)
color1=mcp.gen_color_normalized(cmap="seismic",data_arr=a)
plt.scatter(a,a,c=color1)
输出:
您还可以使用以下方法反转颜色:
color1=mcp.gen_color_normalized(cmap="seismic",data_arr=a,reverse=True)
plt.scatter(a,a,c=color1)
输出:
解决方案 4:
我发现使用 matplotlib 返回十六进制颜色列表的很短的方法N
:
import matplotlib
# Choose colormap
cmap = plt.cm.get_cmap('terrain', N)
colors = [matplotlib.colors.to_hex(cmap(i)) for i in range(N)]
更新
由于 get_cmap 函数在 Matplotlib 3.7 中已弃用并将很快被删除,因此选项可能是
import matplotlib
# Choose colormap
cmap = matplotlib.colormaps.get_cmap('terrain')
# Pick N numbers from 0 to 1
gradient = np.linspace(0, 1, N)
colors = [matplotlib.colors.to_hex(cmap(i)) for i in gradient]
解决方案 5:
我正好遇到了这个问题,但我需要连续的图具有高度对比的颜色。我还用包含参考数据的公共子图来绘制图,所以我希望颜色序列能够始终重复。
我最初尝试简单地随机生成颜色,在每次绘图之前重新播种 RNG。这种方法效果不错(在下面的代码中注释掉),但可能会生成几乎无法区分的颜色。我想要高对比度的颜色,最好从包含所有颜色的颜色图中采样。
我可以在单个图中拥有多达 31 个数据系列,因此我将颜色图分成了那么多步骤。然后我按照确保不会很快返回给定颜色邻域的顺序执行这些步骤。
我的数据处于高度不规则的时间序列中,所以我想看到点和线,其中点具有与线“相反”的颜色。
考虑到以上所有内容,最简单的方法是生成一个包含用于绘制各个系列的相关参数的字典,然后将其作为调用的一部分进行扩展。
这是我的代码。可能不漂亮,但很实用。
from matplotlib import cm
cmap = cm.get_cmap('gist_rainbow') #('hsv') #('nipy_spectral')
max_colors = 31 # Constant, max mumber of series in any plot. Ideally prime.
color_number = 0 # Variable, incremented for each series.
def restart_colors():
global color_number
color_number = 0
#np.random.seed(1)
def next_color():
global color_number
color_number += 1
#color = tuple(np.random.uniform(0.0, 0.5, 3))
color = cmap( ((5 * color_number) % max_colors) / max_colors )
return color
def plot_args(): # Invoked for each plot in a series as: '**(plot_args())'
mkr = next_color()
clr = (1 - mkr[0], 1 - mkr[1], 1 - mkr[2], mkr[3]) # Give line inverse of marker color
return {
"marker": "o",
"color": clr,
"mfc": mkr,
"mec": mkr,
"markersize": 0.5,
"linewidth": 1,
}
我的背景是 JupyterLab 和 Pandas,因此这里是示例绘图代码:
restart_colors() # Repeatable color sequence for every plot
fig, axs = plt.subplots(figsize=(15, 8))
plt.title("%s + T-meter"%name)
# Plot reference temperatures:
axs.set_ylabel("°C", rotation=0)
for s in ["T1", "T2", "T3", "T4"]:
df_tmeter.plot(ax=axs, x="Timestamp", y=s, label="T-meter:%s" % s, **(plot_args()))
# Other series gets their own axis labels
ax2 = axs.twinx()
ax2.set_ylabel(units)
for c in df_uptime_sensors:
df_uptime[df_uptime["UUID"] == c].plot(
ax=ax2, x="Timestamp", y=units, label="%s - %s" % (units, c), **(plot_args())
)
fig.tight_layout()
plt.show()
得到的图可能不是最好的例子,但是当以交互方式放大时它会变得更具相关性。
解决方案 6:
为了基于Ffisegydd和amaliammr的解决方案,下面是一个示例,我们在其中为自定义颜色图制作了 CSV 表示:
#! /usr/bin/env python3
import matplotlib
import numpy as np
vmin = 0.1
vmax = 1000
norm = matplotlib.colors.Normalize(np.log10(vmin), np.log10(vmax))
lognum = norm(np.log10([.5, 2., 10, 40, 150,1000]))
cdict = {
'red':
(
(0., 0, 0),
(lognum[0], 0, 0),
(lognum[1], 0, 0),
(lognum[2], 1, 1),
(lognum[3], 0.8, 0.8),
(lognum[4], .7, .7),
(lognum[5], .7, .7)
),
'green':
(
(0., .6, .6),
(lognum[0], 0.8, 0.8),
(lognum[1], 1, 1),
(lognum[2], 1, 1),
(lognum[3], 0, 0),
(lognum[4], 0, 0),
(lognum[5], 0, 0)
),
'blue':
(
(0., 0, 0),
(lognum[0], 0, 0),
(lognum[1], 0, 0),
(lognum[2], 0, 0),
(lognum[3], 0, 0),
(lognum[4], 0, 0),
(lognum[5], 1, 1)
)
}
mycmap = matplotlib.colors.LinearSegmentedColormap('my_colormap', cdict, 256)
norm = matplotlib.colors.LogNorm(vmin, vmax)
colors = {}
count = 0
step_size = 0.001
for value in np.arange(vmin, vmax+step_size, step_size):
count += 1
print("%d/%d %f%%" % (count, vmax*(1./step_size), 100.*count/(vmax*(1./step_size))))
rgba = mycmap(norm(value), bytes=True)
color = (rgba[0], rgba[1], rgba[2])
if color not in colors.values():
colors[value] = color
print ("value, red, green, blue")
for value in sorted(colors.keys()):
rgb = colors[value]
print("%s, %s, %s, %s" % (value, rgb[0], rgb[1], rgb[2]))
解决方案 7:
颜色图有其自己的标准化方法,因此如果您已经制作了图表,则可以访问某个值的颜色。
import matplotlib.pyplot as plt
import numpy as np
cmap = plt.cm.viridis
cm = plt.pcolormesh(np.random.randn(10, 10), cmap=cmap)
print(cmap(cm.norm(2.2)))
解决方案 8:
我通常使用的是
import matplotlib.pyplot as plt
n=10 # number of colors you want to get
cmap = plt.cm.get_cmap('rainbow', n) # get 10 colors from rainbow palette
# Use the color
cmap(0)
cmap(1)
...
cmap(9)
解决方案 9:
这是一个给出离散颜色值的解决方案。可以通过将离散颜色图一分为二来确定中点。
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
# Choose a colormap from Matplotlib
colormap = plt.cm.viridis
# Set number of colors
num_colors = 5
# Create a ListedColormap with discrete colors
discrete_cmap = ListedColormap(colormap(np.linspace(0, 1, num_colors)))
# Output RGB values
for i, rgb in enumerate(discrete_cmap.colors):
print(f"Color {i + 1}: RGB = {rgb}")
# Plot a colorbar to visualize
plt.imshow([[i] for i in range(num_colors)], cmap=discrete_cmap, aspect='auto')
plt.colorbar(ticks=range(num_colors))
plt.show()
扫码咨询,免费领取项目管理大礼包!