6

我只是从scipy堆栈开始。我正在使用 CSV 版本的 iris 数据集。我可以使用以下方法加载它:

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)))
4

2 回答 2

5

一种方式是否优雅有点主观。我个人发现您的方法比“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。这就是掩蔽会派上用场的地方。

于 2012-03-16T16:55:04.877 回答
5

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

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()

在此处输入图像描述

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

依靠轴颜色循环并多次调用 plot 更容易(您还可以获得单独的艺术家而不是集合,这对于诸如此类的离散数据是一件好事)。

默认情况下,坐标区的颜色循环为:蓝色、绿色、红色、青色、洋红色、黄色、黑色。

在 7 次调用之后plot,它将循环返回这些颜色,因此如果您有更多项目,则需要手动设置它(或者只需在每次调用中指定颜色,以plot使用类似于上面@Yann 建议的插值颜色条) .

于 2012-03-17T14:51:44.407 回答