一种方式是否优雅有点主观。我个人发现您的方法比“matplotlib”方式更好。来自 matplotlib 的 color 模块:
颜色映射通常涉及两个步骤:首先是一个数据数组
使用 Normalize 或 a 的实例映射到范围 0-1
子类;然后使用 0-1 范围内的这个数字映射到颜色
Colormap 子类的一个实例。
关于您的问题,我从中得到的是,您需要一个 Normalize 的子类,它接受字符串并将它们映射到 0-1。
这里有一个例子,它继承自Normalize,创建一个子类TextNorm,用于将字符串转换为0到1之间的值。这种规范化用于获取对应的颜色。
import matplotlib.pyplot as plt
from matplotlib.colors import Normalize
import numpy as np
from numpy import ma
class TextNorm(Normalize):
'''Map a list of text values to the float range 0-1'''
def __init__(self, textvals, clip=False):
self.clip = clip
# if you want, clean text here, for duplicate, sorting, etc
ltextvals = set(textvals)
self.N = len(ltextvals)
self.textmap = dict(
[(text, float(i)/(self.N-1)) for i, text in enumerate(ltextvals)])
self.vmin = 0
self.vmax = 1
def __call__(self, x, clip=None):
#Normally this would have a lot more to do with masking
ret = ma.asarray([self.textmap.get(xkey, -1) for xkey in x])
return ret
def inverse(self, value):
return ValueError("TextNorm is not invertible")
iris = np.recfromcsv("iris.csv")
norm = TextNorm(iris.field(4))
plt.scatter(iris.field(0), iris.field(1), c=norm(iris.field(4)), cmap='RdYlGn')
plt.savefig('textvals.png')
plt.show()
这会产生:
我选择了“RdYlGn”颜色图,以便于区分三种类型的点。我没有将clip 功能作为__call__ 的一部分包含在内,尽管可以进行一些修改。
传统上,您可以使用norm 关键字测试scatter 方法的规范化,但scatter 测试c 关键字以查看它是否存储字符串,如果是,则假定您正在通过颜色作为它们的字符串值,例如“红色”、“蓝色”等。因此调用 plt.scatter(iris.field(0), iris.field(1), c=iris.field(4), cmap='RdYlGn', norm=norm) 失败。相反,我只使用TextNorm 和iris.field(4) 上的“操作”来返回一个从0 到1 的值数组。
请注意,对于不在列表 textvals 中的字符串,返回值 -1。这就是掩蔽会派上用场的地方。