matrices - trazar diferentes colores para diferentes niveles categóricos usando matplotlib
matplotlib title position (7)
Aquí hay una solución sucinta y genérica para usar una paleta de colores nacidos.
Primero encuentre una paleta de colores que le guste y, opcionalmente, visualícela:
sns.palplot(sns.color_palette("Set2", 8))
Entonces puede usarlo con
matplotlib
haciendo esto:
# 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))
Tengo este
diamonds
marco de datos que se compone de variables como
(carat, price, color)
, y quiero dibujar un diagrama de dispersión de
price
a
carat
para cada
color
, lo que significa que un
color
diferente tiene un color diferente en el diagrama.
Esto es fácil en
R
con
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)
Me pregunto cómo podría hacerse esto en Python usando
matplotlib
.
PD:
Sé acerca de los paquetes de trazado auxiliar, como
seaborn
y
ggplot for python
, y no los prefiero, solo quiero saber si es posible hacer el trabajo usando solo
matplotlib
; P
Aquí una combinación de marcadores y colores de un mapa de colores cualitativo en
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);
Por lo general, lo hago usando Seaborn, que está construido sobre matplotlib
import seaborn as sns
iris = sns.load_dataset(''iris'')
sns.scatterplot(x=''sepal_length'', y=''sepal_width'',
hue=''species'', data=iris);
Puede pasar
plt.scatter
un argumento
c
que le permitirá seleccionar los colores.
El siguiente código define un diccionario de
colors
para asignar sus colores de diamante a los colores de trazado.
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])
mapea efectivamente los colores de "diamante" a "trazado".
(Perdóname por no poner otra imagen de ejemplo, creo que 2 es suficiente: P)
Con
seaborn
Puede usar
seaborn
que es un contenedor alrededor de
matplotlib
que lo hace parecer más bonito por defecto (más bien basado en opiniones, lo sé: P) pero también agrega algunas funciones de trazado.
Para esto, puede usar
seaborn.lmplot
con
fit_reg=False
(lo que evita que realice alguna regresión automáticamente).
El siguiente código utiliza un conjunto de datos de ejemplo.
Al seleccionar
hue=''color''
le dice a seaborn que divida su marco de datos en función de sus colores y luego trace cada uno.
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()
Sin
seaborn
usando
pandas.groupby
Si no desea usar seaborn, puede usar
pandas.groupby
para obtener los colores solos y luego trazarlos usando solo matplotlib, pero tendrá que asignar manualmente los colores a medida que avanza, agregué un ejemplo a continuación:
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()
Este código asume el mismo DataFrame que el anterior y luego lo agrupa según el
color
.
Luego itera sobre estos grupos, trazando para cada uno.
Para seleccionar un color, he creado un diccionario de
colors
que puede asignar el color del diamante (por ejemplo,
D
) a un color real (por ejemplo,
red
).
Tenía la misma pregunta y he pasado todo el día probando diferentes paquetes.
Originalmente había usado matlibplot: y no estaba contento con ninguna de las categorías de mapeo a colores predefinidos; o agrupar / agregar y luego iterar a través de los grupos (y aún así tener que asignar colores). Simplemente sentí que era una implementación deficiente del paquete.
Seaborn no funcionaría en mi caso, y Altair SOLO funciona dentro de un cuaderno Jupyter.
La mejor solución para mí fue PlotNine, que "es una implementación de una gramática de gráficos en Python y basada en ggplot2".
A continuación se muestra el código de la trama para replicar su ejemplo R en 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)
Tan limpio y simple :)
Usando Altair .
from altair import *
import pandas as pd
df = datasets.load_dataset(''iris'')
Chart(df).mark_point().encode(x=''petalLength'',y=''sepalLength'', color=''species'')
Con df.plot ()
Normalmente, cuando trazo rápidamente un DataFrame, uso
pd.DataFrame.plot()
.
Esto toma el índice como el valor x, el valor como el valor y y traza cada columna por separado con un color diferente.
Se puede lograr un DataFrame de esta forma utilizando
set_index
y
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'')
Con este método no tiene que especificar manualmente los colores.
Este procedimiento puede tener más sentido para otras series de datos. En mi caso, tengo datos de series de tiempo, por lo que MultiIndex consta de fecha y hora y categorías. También es posible utilizar este enfoque para colorear más de una columna, pero la leyenda se está volviendo un desastre.