如果你有一个Colormap cmap,例如:
cmap = matplotlib.cm.get_cmap('Spectral')
在0和1之间,0是地图上的第一种颜色,1是地图上的最后一种颜色,你如何从0和1之间得到特定的颜色?
理想情况下,我可以通过这样做来获得地图中的中间颜色:
>>> do_some_magic(cmap, 0.5) # Return an RGBA tuple
(0.1, 0.2, 0.3, 1.0)
如果你有一个Colormap cmap,例如:
cmap = matplotlib.cm.get_cmap('Spectral')
在0和1之间,0是地图上的第一种颜色,1是地图上的最后一种颜色,你如何从0和1之间得到特定的颜色?
理想情况下,我可以通过这样做来获得地图中的中间颜色:
>>> do_some_magic(cmap, 0.5) # Return an RGBA tuple
(0.1, 0.2, 0.3, 1.0)
当前回答
在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]))
其他回答
我正好遇到了这个问题,但我需要连续的图具有强烈的对比色。我还制作了包含参考数据的公共子图,所以我希望颜色序列是一致可重复的。
我最初尝试简单地随机生成颜色,在每个情节之前重新播种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,所以这里是示例plot代码:
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()
由此产生的图形可能不是最好的例子,但当以交互方式放大时,它变得更加相关。
颜色地图有自己的标准化方法,所以如果你已经有了一个图,你可以在某个值访问颜色。
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)))
在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]))
您可以使用下面的代码来实现这一点,您问题中的代码实际上非常接近您所需要的,您所要做的就是调用您所拥有的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)也可用于具有较大值范围的数据范围。
(感谢乔·金顿和tcaswell对如何改进答案的建议。)
为了得到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