побудуйте різні кольори для різних категоріальних рівнів за допомогою matplotlib


102

У мене є цей фрейм даних, diamondsякий складається з таких змінних, як (carat, price, color), і я хочу намалювати графік розсіювання priceдо caratдля кожного color, що означає, colorщо різний колір має різний колір в графі.

Це легко Rз ggplot:

ggplot(aes(x=carat, y=price, color=color),  #by setting color=color, ggplot automatically draw in different colors
       data=diamonds) + geom_point(stat='summary', fun.y=median)

введіть тут опис зображення

Цікаво, як це можна зробити в Python за допомогою matplotlib?

PS:

Я знаю про допоміжні графічні пакети, такі як seabornі ggplot for python, і я не віддаю їм перевагу, просто хочу з'ясувати, чи можна виконати роботу, використовуючи matplotlibсамостійно,; P


1
Було б дуже добре, щоб щось подібне було вбудовано в matplotlib, але, схоже, це буде непросто. Обговорення тут: github.com/matplotlib/matplotlib/issues/6214
naught101

Відповіді:


156

Ви можете передати plt.scatterв cаргумент , який дозволить вам вибрати кольору. У наведеному нижче коді визначено colorsсловник для відображення ваших діамантових кольорів до кольорів для побудови графіків.

import matplotlib.pyplot as plt
import pandas as pd

carat = [5, 10, 20, 30, 5, 10, 20, 30, 5, 10, 20, 30]
price = [100, 100, 200, 200, 300, 300, 400, 400, 500, 500, 600, 600]
color =['D', 'D', 'D', 'E', 'E', 'E', 'F', 'F', 'F', 'G', 'G', 'G',]

df = pd.DataFrame(dict(carat=carat, price=price, color=color))

fig, ax = plt.subplots()

colors = {'D':'red', 'E':'blue', 'F':'green', 'G':'black'}

ax.scatter(df['carat'], df['price'], c=df['color'].apply(lambda x: colors[x]))

plt.show()

df['color'].apply(lambda x: colors[x]) ефективно відображає кольори від "діамантового" до "графічного".

(Вибачте мене за те, що я не ставлю ще один приклад зображення, я думаю, досить 2: P)

С seaborn

Ви можете використовувати seabornобгортку, matplotlibяка за замовчуванням робить її красивішою (швидше заснована на думках, я знаю: P), але також додає деякі функції побудови графіків.

Для цього ви можете використовувати seaborn.lmplotз fit_reg=False(що НЕ заважає йому автоматично робити деякі регресії).

У наведеному нижче коді використовується приклад набору даних. Вибравши, hue='color'ви кажете Seaborn розділити ваш кадр даних на основі ваших кольорів, а потім побудувати кожен з них.

import matplotlib.pyplot as plt
import seaborn as sns

import pandas as pd

carat = [5, 10, 20, 30, 5, 10, 20, 30, 5, 10, 20, 30]
price = [100, 100, 200, 200, 300, 300, 400, 400, 500, 500, 600, 600]
color =['D', 'D', 'D', 'E', 'E', 'E', 'F', 'F', 'F', 'G', 'G', 'G',]

df = pd.DataFrame(dict(carat=carat, price=price, color=color))

sns.lmplot('carat', 'price', data=df, hue='color', fit_reg=False)

plt.show()

введіть тут опис зображення

Без seabornвикористанняpandas.groupby

Якщо ви не хочете використовувати seaborn, ви можете використовувати, pandas.groupbyщоб отримати кольори поодинці, а потім побудувати їх за допомогою просто matplotlib, але вам доведеться вручну призначати кольори, я додав приклад нижче:

fig, ax = plt.subplots()

colors = {'D':'red', 'E':'blue', 'F':'green', 'G':'black'}

grouped = df.groupby('color')
for key, group in grouped:
    group.plot(ax=ax, kind='scatter', x='carat', y='price', label=key, color=colors[key])

plt.show()

Цей код передбачає той самий DataFrame, що і вище, а потім групує його на основі color. Потім здійснюється ітерація щодо цих груп, складаючи графік для кожної з них. Для вибору кольору я створив colorsсловник, який може зіставити діамантовий колір (наприклад D) із справжнім кольором (наприклад red).

введіть тут опис зображення


Дякую, але я просто хочу дізнатись, як зробити роботу лише з matplotlib.
авокадо

Так, через це groupbyя міг би це зробити, тому є така функція, matplotlibяка може автоматично малювати для різних рівнів категоріальних, використовуючи різний колір, так?
авокадо

@loganecolss Добре, бачу :) Я відредагував його ще раз і додав дуже простий приклад, який використовує словник для відображення кольорів, подібно до groupbyприкладу.
Ffisegydd

1
@Ffisegydd Використовуючи перший метод, який є ax.scatter, як би ви додали до нього легенди? Я намагаюся використовувати, label=df['color']але потім plt.legend()безуспішно.
ahoosh

1
Краще було б перейти ax.scatter(df['carat'], df['price'], c=df['color'].apply(lambda x: colors[x]))наax.scatter(df['carat'], df['price'], c=df['color'].map(colors)
Давей

33

Ось коротке та загальне рішення для використання кольорової палітри, що народилася в морі.

Спочатку знайдіть палітру кольорів, яка вам подобається, і за бажанням візуалізуйте її:

sns.palplot(sns.color_palette("Set2", 8))

Тоді ви можете використовувати це, matplotlibроблячи це:

# Unique category labels: 'D', 'F', 'G', ...
color_labels = df['color'].unique()

# List of RGB triplets
rgb_values = sns.color_palette("Set2", 8)

# Map label to RGB
color_map = dict(zip(color_labels, rgb_values))

# Finally use the mapped values
plt.scatter(df['carat'], df['price'], c=df['color'].map(color_map))

2
Мені подобається ваш підхід. З огляду на приклад вище, ви, звичайно, можете також зіставити значення з простими назвами кольорів, як це: 1) визначте кольори кольори = {'D': 'червоний', 'E': 'синій', 'F': 'зелений ',' G ':' чорний '} 2) зіставити їх так само, як і раніше: ax.scatter (df [' carat '], df [' price '], c = df [' color ']. Map (colors))
Stefan

1
Однак як би ви додали ярлик за кольором?
Франсуа Леблан

2
Щоб додати ще трохи абстракції, ви можете замінити 8in sns.color_palette("Set2", 8)на len(color_labels).
Swier

Це чудово, але це має робити автоматично морський народжений. Необхідність використання карти для категоріальних змінних кожного разу, коли ви хочете щось швидко побудувати, неймовірно заважає. Не кажучи вже про ідіотську ідею зняти можливість показу статистики на сюжеті. Сіборн, на жаль, відмовляється від посилок через ці причини
погоня

8

У мене було одне і те ж питання, і я цілий день пробував різні пакети.

Я спочатку використовував matlibplot: і не був задоволений жодним зіставленням категорій за попередньо визначеними кольорами; або групування / агрегування, а потім ітерація по групах (і все одно доводиться відображати кольори). Я просто відчув, що це погана реалізація пакету.

Сіборн не працював би над моєю справою, а Альтаїр працює ТІЛЬКИ всередині блокнота Юпітера.

Найкращим рішенням для мене був PlotNine, який "є реалізацією граматики графіки в Python на основі ggplot2".

Нижче наведено код plotnine для відтворення вашого прикладу R у Python:

from plotnine import *
from plotnine.data import diamonds

g = ggplot(diamonds, aes(x='carat', y='price', color='color')) + geom_point(stat='summary')
print(g)

приклад плотнінових діамантів

Так чисто і просто :)


Задано питання для matplotlib
Чак

6

Використання Altair .

from altair import *
import pandas as pd

df = datasets.load_dataset('iris')
Chart(df).mark_point().encode(x='petalLength',y='sepalLength', color='species')

введіть тут опис зображення


Задано питання для matplotlib
Чак

5

Тут поєднання маркерів та кольорів з якісної карти кольорів у matplotlib:

import itertools
import numpy as np
from matplotlib import markers
import matplotlib.pyplot as plt

m_styles = markers.MarkerStyle.markers
N = 60
colormap = plt.cm.Dark2.colors  # Qualitative colormap
for i, (marker, color) in zip(range(N), itertools.product(m_styles, colormap)):
    plt.scatter(*np.random.random(2), color=color, marker=marker, label=i)
plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0., ncol=4);

введіть тут опис зображення


In mpl.cm.Dark2.colors- mplсхоже, не визначено у вашому коді і Dark2не має атрибута colors.
Шовальт

@Shovalt Дякуємо за огляд. Я повинен був імпортувати matplotlibяк mpl, я виправив свій код, використовуючи pltякий також містить cm. Принаймні, у matplotlibверсії, яку я використовую 2.0.0 Dark2, є атрибутcolors
Пабло Рейес

1
Пізно, але якщо у вас немає атрибута кольори: iter (plt.cm.Dark2 (np.linspace (0,1, N)))
Geoff Lentsch

3

За допомогою df.plot ()

Зазвичай, коли я швидко складаю графік DataFrame, я використовую pd.DataFrame.plot(). При цьому індекс приймається як значення x, значення - як значення y, і кожен стовпець окремо наноситься на інший колір. DataFrame у цій формі можна досягти, використовуючи set_indexта unstack.

import matplotlib.pyplot as plt
import pandas as pd

carat = [5, 10, 20, 30, 5, 10, 20, 30, 5, 10, 20, 30]
price = [100, 100, 200, 200, 300, 300, 400, 400, 500, 500, 600, 600]
color =['D', 'D', 'D', 'E', 'E', 'E', 'F', 'F', 'F', 'G', 'G', 'G',]

df = pd.DataFrame(dict(carat=carat, price=price, color=color))

df.set_index(['color', 'carat']).unstack('color')['price'].plot(style='o')
plt.ylabel('price')

сюжет

За допомогою цього методу не потрібно вручну вказувати кольори.

Ця процедура може мати більше сенсу для інших серій даних. У моєму випадку у мене є дані часових рядів, тому MultiIndex складається з дати та категорій. Також можна використовувати цей підхід для того, щоб забарвити більше одного стовпця, але легенда наводить безлад.


0

Я зазвичай роблю це, використовуючи Seaborn, який побудований поверх matplotlib

import seaborn as sns
iris = sns.load_dataset('iris')
sns.scatterplot(x='sepal_length', y='sepal_width',
              hue='species', data=iris); 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.