Diagtwigs de dispersión en Pandas / Pyplot: Cómo trazar por categoría

Estoy tratando de hacer un gráfico de dispersión simple en una plot de puntos utilizando un objeto Pandas DataFrame, pero quiero una forma eficiente de trazar dos variables, pero los símbolos están dictados por una tercera columna (clave). He intentado varias maneras de usar df.groupby, pero no con éxito. A continuación se muestra un ejemplo de script df. Esto colorea los marcadores de acuerdo con ‘key1’, pero me gusta ver una leyenda con categorías ‘key1’. ¿Estoy cerca? Gracias.

import numpy as np import pandas as pd import matplotlib.pyplot as plt df = pd.DataFrame(np.random.normal(10,1,30).reshape(10,3), index = pd.date_range('2010-01-01', freq = 'M', periods = 10), columns = ('one', 'two', 'three')) df['key1'] = (4,4,4,6,6,6,8,8,8,8) fig1 = plt.figure(1) ax1 = fig1.add_subplot(111) ax1.scatter(df['one'], df['two'], marker = 'o', c = df['key1'], alpha = 0.8) plt.show() 

Puede usar scatter para esto, pero eso requiere tener valores numéricos para su key1 , y no tendrá una leyenda, como notó.

Es mejor usar solo la plot para categorías discretas como esta. Por ejemplo:

 import matplotlib.pyplot as plt import numpy as np import pandas as pd np.random.seed(1974) # Generate Data num = 20 x, y = np.random.random((2, num)) labels = np.random.choice(['a', 'b', 'c'], num) df = pd.DataFrame(dict(x=x, y=y, label=labels)) groups = df.groupby('label') # Plot fig, ax = plt.subplots() ax.margins(0.05) # Optional, just adds 5% padding to the autoscaling for name, group in groups: ax.plot(group.x, group.y, marker='o', linestyle='', ms=12, label=name) ax.legend() plt.show() 

introduzca la descripción de la imagen aquí

Si desea que las cosas se vean como el estilo predeterminado de los pandas , simplemente actualice los rcParams con la hoja de estilos de los pandas y use su generador de color. (También estoy retocando ligeramente la leyenda):

 import matplotlib.pyplot as plt import numpy as np import pandas as pd np.random.seed(1974) # Generate Data num = 20 x, y = np.random.random((2, num)) labels = np.random.choice(['a', 'b', 'c'], num) df = pd.DataFrame(dict(x=x, y=y, label=labels)) groups = df.groupby('label') # Plot plt.rcParams.update(pd.tools.plotting.mpl_stylesheet) colors = pd.tools.plotting._get_standard_colors(len(groups), color_type='random') fig, ax = plt.subplots() ax.set_color_cycle(colors) ax.margins(0.05) for name, group in groups: ax.plot(group.x, group.y, marker='o', linestyle='', ms=12, label=name) ax.legend(numpoints=1, loc='upper left') plt.show() 

introduzca la descripción de la imagen aquí

Esto es fácil de hacer con Seaborn ( pip install seaborn ) como oneliner

sns.pairplot(x_vars=["one"], y_vars=["two"], data=df, hue="key1", size=5) :

 import seaborn as sns import pandas as pd import numpy as np np.random.seed(1974) df = pd.DataFrame( np.random.normal(10, 1, 30).reshape(10, 3), index=pd.date_range('2010-01-01', freq='M', periods=10), columns=('one', 'two', 'three')) df['key1'] = (4, 4, 4, 6, 6, 6, 8, 8, 8, 8) sns.pairplot(x_vars=["one"], y_vars=["two"], data=df, hue="key1", size=5) 

introduzca la descripción de la imagen aquí

Aquí está el dataframe para referencia:

introduzca la descripción de la imagen aquí

Ya que tiene tres columnas variables en sus datos, es posible que desee trazar todas las dimensiones por pares con:

 sns.pairplot(vars=["one","two","three"], data=df, hue="key1", size=5) 

introduzca la descripción de la imagen aquí

https://rasbt.github.io/mlxtend/user_guide/plotting/category_scatter/ es otra opción.

Con plt.scatter , solo puedo pensar en uno: usar un artista proxy:

 df = pd.DataFrame(np.random.normal(10,1,30).reshape(10,3), index = pd.date_range('2010-01-01', freq = 'M', periods = 10), columns = ('one', 'two', 'three')) df['key1'] = (4,4,4,6,6,6,8,8,8,8) fig1 = plt.figure(1) ax1 = fig1.add_subplot(111) x=ax1.scatter(df['one'], df['two'], marker = 'o', c = df['key1'], alpha = 0.8) ccm=x.get_cmap() circles=[Line2D(range(1), range(1), color='w', marker='o', markersize=10, markerfacecolor=item) for item in ccm((array([4,6,8])-4.0)/4)] leg = plt.legend(circles, ['4','6','8'], loc = "center left", bbox_to_anchor = (1, 0.5), numpoints = 1) 

Y el resultado es:

introduzca la descripción de la imagen aquí

Puede usar df.plot.scatter y pasar una matriz a c = argumento que define el color de cada punto:

 import numpy as np import pandas as pd import matplotlib.pyplot as plt df = pd.DataFrame(np.random.normal(10,1,30).reshape(10,3), index = pd.date_range('2010-01-01', freq = 'M', periods = 10), columns = ('one', 'two', 'three')) df['key1'] = (4,4,4,6,6,6,8,8,8,8) colors = np.where(df["key1"]==4,'r','-') colors[df["key1"]==6] = 'g' colors[df["key1"]==8] = 'b' print(colors) df.plot.scatter(x="one",y="two",c=colors) plt.show() 

introduzca la descripción de la imagen aquí

También puede probar Altair o ggpot que se centran en visualizaciones declarativas.

 import numpy as np import pandas as pd np.random.seed(1974) # Generate Data num = 20 x, y = np.random.random((2, num)) labels = np.random.choice(['a', 'b', 'c'], num) df = pd.DataFrame(dict(x=x, y=y, label=labels)) 

Codigo altair

 from altair import Chart c = Chart(df) c.mark_circle().encode(x='x', y='y', color='label') 

introduzca la descripción de la imagen aquí

código ggplot

 from ggplot import * ggplot(aes(x='x', y='y', color='label'), data=df) +\ geom_point(size=50) +\ theme_bw() 

introduzca la descripción de la imagen aquí

Es bastante intrépido, pero puedes usar one1 como un Float64Index para hacer todo de una vez:

 df.set_index('one').sort_index().groupby('key1')['two'].plot(style='--o', legend=True) 

introduzca la descripción de la imagen aquí

Tenga en cuenta que a partir de 0.20.3, es necesario clasificar el índice , y la leyenda es un poco torpe .