Pylab: наложение меток на цвета

Я только начинаю со scipy стека. Я использую набор диафрагмы iris в версии 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)) не работает (из документов, которые он ожидает значения float или colormap). Я не нашел элегантный способ автоматического создания цветовой карты.

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

Что бы это ни стоило, в этом случае вы обычно делаете нечто подобное:

 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 лучше подходит для непрерывных данных.

Легче полагаться на цветной цикл осей и просто называть график несколько раз (вы также получаете отдельных художников вместо коллекции, что хорошо для дискретных данных, таких как это).

По умолчанию цикл цвета для осей: синий, зеленый, красный, голубой, пурпурный, желтый, черный.

После 7 звонков на plot он будет циклически возвращаться к этим цветам, поэтому, если у вас есть больше предметов, вам нужно будет установить его вручную (или просто указать цвет в каждом вызове на plot используя интерполированный цветной байт, аналогичный тому, что предложил @Yann выше).

Является ли способ элегантным или нет, является несколько субъективным. Я лично нахожу ваши подходы лучше, чем «matplotlib». Из цветового модуля matplotlib:

Коллаппирование обычно включает в себя два этапа: массив данных сначала отображается на диапазон 0-1, используя экземпляр Normalize или подкласса; то это число в диапазоне 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__ , хотя это возможно с несколькими изменениями.

Традиционно вы можете протестировать нормализацию метода scatter с использованием ключевого слова norm , но scatter тестирует ключевое слово c чтобы увидеть, хранит ли он строки, и если это так, то предполагается, что вы передаете цвета в качестве их строковых значений, например, «Красный», , «Синий» и т. Д. Поэтому вызов plt.scatter(iris.field(0), iris.field(1), c=iris.field(4), cmap='RdYlGn', norm=norm) терпит неудачу. Вместо этого я просто использую TextNorm и « TextNorm » на iris.field(4) чтобы вернуть массив значений от 0 до 1.

Обратите внимание, что значение -1 возвращается для укуса не в textvals списка. Здесь маскировка пригодится.