Pylab:将标签映射到颜色

时间:2012-03-16 16:16:40

标签: python scipy matplotlib scatter-plot

我刚开始使用scipy堆栈。我正在使用CSV版本的虹膜数据集。我可以使用以下方法加载它:

iris=numpy.recfromcsv("iris.csv")

并绘制它:

pylab.scatter(iris.field(0), iris.field(1))
pylab.show()

现在我还要绘制存储在iris.field(4)

中的类
chararray(['setosa', ...], dtype='|S10')

将这些字符串映射到用于绘图的颜色的优雅方法是什么? scatter(iris.field(0), iris.field(1), c=iris.field(4))不起作用(来自它预期浮点值或色彩映射的文档)。我没有找到一种自动生成彩色地图的优雅方式。

cols = {"versicolor": "blue", "virginica": "green", "setosa": "red"}
scatter(iris.field(0), iris.field(1), c=map(lambda x:cols[x], iris.field(4)))

大概是我想要的,但我不太喜欢手动颜色规格。

修改 :最后一行稍微优雅的版本:

scatter(iris.field(0), iris.field(1), c=map(cols.get, iris.field(4)))

2 个答案:

答案 0 :(得分:5)

一种方式是否优雅有点主观。我个人认为你的方法比'matplotlib'更好。来自matplotlib的color模块:

  

Colormapping通常涉及两个步骤:首先是数据数组   使用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()

这会产生:

enter image description here

我选择了'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之间的值数组。

请注意,对于不在列表textvals中的sting,将返回值-1。这就是屏​​蔽会派上用场的地方。

答案 1 :(得分:4)

无论它值多少,在这种情况下你通常会做更多这样的事情:

import numpy as np
import matplotlib.pyplot as plt

iris = np.recfromcsv('iris.csv')
names = set(iris['class'])

x,y = iris['sepal_length'],  iris['sepal_width']

for name in names:
    cond = iris['class'] == name
    plt.plot(x[cond], y[cond], linestyle='none', marker='o', label=name)

plt.legend(numpoints=1)
plt.show()

enter image description here

@Yann建议的内容没有错,但scatter更适合连续数据。

依靠轴颜色循环更容易,只需多次调用绘图(你也可以获得单独的艺术家而不是集合,这对于像这样的离散数据来说是一件好事。)

默认情况下,轴的颜色周期为:蓝色,绿色,红色,青色,品红色,黄色,黑色。

在对plot进行7次调用后,它会循环显示这些颜色,因此如果您有更多项目,则需要set it manually(或者只需指定每次调用{{3}的颜色1}}使用类似于@Yann建议的内插颜色条。)