一种方式是否优雅有点主观。我个人发现您的方法比“matplotlib”方式更好。来自 matplotlib 的颜色模块:
颜色映射通常涉及两个步骤:首先使用 Normalize 或子类的实例将数据数组映射到 0-1 范围内;然后使用 Colormap 的子类的实例将 0-1 范围内的这个数字映射到颜色。
关于您的问题,我从中得到的是,您需要一个Normalize
接受字符串并将它们映射到 0-1 的子类。
下面是一个继承 from 的例子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__
,尽管可以进行一些修改。
scatter
传统上,您可以使用关键字测试方法的规范化norm
,但scatter
测试c
关键字以查看它是否存储字符串,如果是,则假定您将颜色作为字符串值传递,例如“红色”、“蓝色”等。所以调用plt.scatter(iris.field(0), iris.field(1), c=iris.field(4), cmap='RdYlGn', norm=norm)
失败。相反,我只是在 上使用TextNorm
和“操作”iris.field(4)
来返回一个范围从 0 到 1 的值数组。
请注意,对于不在列表中的字符串,将返回 -1 值textvals
。这就是掩蔽会派上用场的地方。