wykreśl różne kolory dla różnych poziomów kategorialnych za pomocą matplotlib

104

Muszę tej ramki danych diamonds, które składa się ze zmiennych jak (carat, price, color), i chce wyciągnąć wykres punktowy price, aby caratdla każdego color, który oznacza różne colorma inny kolor w powierzchni.

Jest to łatwe Rdzięki 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)

wprowadź opis obrazu tutaj

Zastanawiam się, jak można to zrobić w Pythonie za pomocą matplotlib?

PS:

Wiem o pomocniczych pakietach do kreślenia, takich jak seaborni ggplot for python, i nie lubię ich, chcę się tylko dowiedzieć, czy da się to zrobić matplotlibsamodzielnie,; P

awokado
źródło
1
Byłoby naprawdę fajnie mieć coś takiego wbudowanego w matplotlib, ale wygląda na to, że nie będzie to łatwe. Dyskusja tutaj: github.com/matplotlib/matplotlib/issues/6214
naught101

Odpowiedzi:

159

Możesz przejść plt.scatterdo cargumentu, który pozwoli Ci wybrać kolory. Poniższy kod definiuje colorssłownik do mapowania kolorów diamentów na kolory kreślenia.

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]) efektywnie odwzorowuje kolory od „diamentu” do „kreślenia”.

(Wybaczcie, że nie umieszczam kolejnego przykładowego obrazu, myślę, że 2 wystarczy: P)

Z seaborn

Możesz użyć, seabornktóra jest otoką, matplotlibktóra sprawia, że ​​domyślnie wygląda ładniej (raczej oparta na opiniach, wiem: P), ale także dodaje kilka funkcji kreślących.

Do tego możesz użyć seaborn.lmplotwith fit_reg=False(co zapobiega automatycznemu wykonywaniu regresji).

Poniższy kod wykorzystuje przykładowy zestaw danych. Wybierając hue='color', każesz seabornowi podzielić ramkę danych na podstawie twoich kolorów, a następnie wykreślić każdy z nich.

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

wprowadź opis obrazu tutaj

Bez seabornużyciapandas.groupby

Jeśli nie chcesz używać poroża morskiego, możesz użyć, pandas.groupbyaby uzyskać same kolory, a następnie wykreślić je za pomocą tylko matplotlib, ale będziesz musiał ręcznie przypisywać kolory w trakcie, dodałem przykład poniżej:

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

Ten kod zakłada tę samą ramkę DataFrame, co powyżej, a następnie grupuje ją na podstawie color. Następnie dokonuje iteracji po tych grupach, wykreślając dla każdej z nich. Aby wybrać kolor, stworzyłem colorssłownik, który może odwzorować kolor diamentu (na przykład D) na rzeczywisty kolor (na przykład red).

wprowadź opis obrazu tutaj

Ffisegydd
źródło
Dzięki, ale chcę się tylko dowiedzieć, jak wykonać tę pracę z samym matplotlib.
awokado
Tak, przez groupbyto mogłem to zrobić, więc jest taka funkcja, matplotlibktóra może automatycznie rysować dla różnych poziomów kategorii przy użyciu innego koloru, prawda?
awokado
@loganecolss Ok, widzę :) Ponownie wyedytowałem i dodałem bardzo prosty przykład, który używa słownika do mapowania kolorów, podobnie jak w groupbyprzykładzie.
Ffisegydd
1
@Ffisegydd Korzystając z pierwszej metody ax.scatter, jak dodać do niej legendy? Próbuję użyć, label=df['color']ale plt.legend()bezskutecznie.
ahoosh
1
Lepiej byłoby zmienić ax.scatter(df['carat'], df['price'], c=df['color'].apply(lambda x: colors[x]))naax.scatter(df['carat'], df['price'], c=df['color'].map(colors)
Dawei
37

Oto zwięzłe i ogólne rozwiązanie dotyczące korzystania z palety kolorów morskiej.

Najpierw znajdź paletę kolorów, którą lubisz i opcjonalnie zwizualizuj ją:

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

Następnie możesz go użyć, matplotlibrobiąc to:

# 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))
Rems
źródło
2
Podoba mi się twoje podejście. Biorąc pod uwagę powyższy przykład, możesz oczywiście przypisać wartości do prostych nazw kolorów, takich jak ta: 1) zdefiniuj kolory = {'D': 'czerwony', 'E': 'niebieski', 'F': 'zielony ',' G ':' black '} 2) odwzoruj je tak, jak zrobiłeś: ax.scatter (df [' karat '], df [' cena '], c = df [' kolor ']. Mapa (kolory))
Stefan,
1
Jak jednak dodasz w tym przypadku etykietę według koloru?
François Leblanc
3
Aby dodać trochę więcej abstrakcję, można wymienić 8in sns.color_palette("Set2", 8)przez len(color_labels).
Świer
To świetnie, ale powinno to być zrobione automatycznie przez morskie zwierzęta. Konieczność używania mapy dla zmiennych kategorialnych za każdym razem , gdy chcesz coś szybko wykreślić, jest niesamowicie utrudniająca. Nie wspominając o idiotycznym pomyśle, aby wyrzucić możliwość wyświetlania statystyk na działce. Seaborn niestety spada jako paczka z tych powodów
ścigaj
7

Miałem to samo pytanie i spędziłem cały dzień na wypróbowywaniu różnych pakietów.

Pierwotnie użyłem matlibplot: i nie byłem zadowolony z przypisania kategorii do predefiniowanych kolorów; lub grupowanie / agregowanie, a następnie iterowanie po grupach (i wciąż konieczność mapowania kolorów). Po prostu czułem, że to słaba implementacja pakietu.

Seaborn nie działałby na mojej walizce, a Altair działa TYLKO w notatniku Jupyter.

Najlepszym dla mnie rozwiązaniem był PlotNine, który „jest implementacją gramatyki grafiki w Pythonie i opartą na ggplot2”.

Poniżej znajduje się kod plotnine do replikacji przykładu R w Pythonie:

from plotnine import *
from plotnine.data import diamonds

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

przykład plotnine diamentów

Tak czysto i prosto :)

deprekate
źródło
Pytanie zadane matplotlib
Chuck
6

Korzystanie z Altair .

from altair import *
import pandas as pd

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

wprowadź opis obrazu tutaj

Nipun Batra
źródło
Pytanie zadane matplotlib
Chuck
5

Tutaj kombinacja markerów i kolorów z jakościowej mapy kolorów w 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);

wprowadź opis obrazu tutaj

Pablo Reyes
źródło
W mpl.cm.Dark2.colors- mplnie wydaje się być zdefiniowane w kodzie i Dark2nie ma atrybutu colors.
Shovalt
@Shovalt Dzięki za recenzję. Powinienem był zaimportować matplotlibjako mpl, poprawiłem swój kod za pomocą, pltktóry również zawiera cm. Przynajmniej w matplotlibwersji, której używam 2.0.0 Dark2, ma atrybutcolors
Pablo Reyes
1
Późno, ale jeśli nie masz atrybutu kolorów: iter (plt.cm.Dark2 (np.linspace (0,1, N)))
Geoff Lentsch
3

Z df.plot ()

Zwykle podczas szybkiego kreślenia ramki DataFrame używam pd.DataFrame.plot(). To przyjmuje indeks jako wartość x, wartość jako wartość y i wykreśla każdą kolumnę osobno innym kolorem. Ramkę DataFrame w tym formularzu można uzyskać za pomocą set_indexi 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')

wątek

Dzięki tej metodzie nie musisz ręcznie określać kolorów.

Ta procedura może mieć większy sens w przypadku innych serii danych. W moim przypadku mam dane timeeries, więc MultiIndex składa się z datetime i kategorii. Możliwe jest również użycie tego podejścia do kolorowania więcej niż jednej kolumny, ale legenda robi się bałagan.

Szymon
źródło
0

Zwykle robię to za pomocą Seaborn, który jest zbudowany na bazie matplotlib

import seaborn as sns
iris = sns.load_dataset('iris')
sns.scatterplot(x='sepal_length', y='sepal_width',
              hue='species', data=iris); 
VICTOR RODEÑO SANCHEZ
źródło
0

Możesz przekonwertować kolumnę kategorialną na liczbową, używając poleceń:

#we converting it into categorical data
cat_col = df['column_name'].astype('categorical') 

#we are getting codes for it 
cat_col = cat_col.cat.codes 

# we are using c parameter to change the color.
plt.scatter(df['column1'],df['column2'], c=cat_col) 
chaitanya ashish
źródło