Estou tentando fazer um gráfico de dispersão simples em pyplot usando um objeto Pandas DataFrame, mas quero uma maneira eficiente de plotar duas variáveis, mas tem os símbolos ditados por uma terceira coluna (chave). Eu tentei várias maneiras usando df.groupby, mas não com sucesso. Um exemplo de script df está abaixo. Isso colore os marcadores de acordo com 'chave1', mas gostaria de ver uma legenda com as categorias 'chave1'. Eu estou perto? Obrigado.
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()
fonte
ax.legend(numpoints=1)
para mostrar apenas um marcador. Existem dois, comoLine2D
acontece com um , geralmente há uma linha conectando os dois marcadores.plt.hold(True)
após oax.plot()
comando. Alguma ideia do porquê?set_color_cycle()
foi descontinuado no matplotlib 1.5. Existeset_prop_cycle()
, agora.Isso é simples de fazer com Seaborn (
pip install seaborn
) como um onelinersns.scatterplot(x_vars="one", y_vars="two", data=df, hue="key1")
: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.scatterplot(x="one", y="two", data=df, hue="key1")
Aqui está o dataframe para referência:
Como você tem três colunas de variáveis em seus dados, pode desejar plotar todas as dimensões de pares com:
sns.pairplot(vars=["one","two","three"], data=df, hue="key1")
https://rasbt.github.io/mlxtend/user_guide/plotting/category_scatter/ é outra opção.
fonte
Com
plt.scatter
, só consigo pensar em um: para usar um 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)
E o resultado é:
fonte
Você pode usar df.plot.scatter e passar uma matriz para o argumento c = que define a cor de cada ponto:
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()
fonte
Você também pode tentar o Altair ou o ggpot, que se concentram em visualizações 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))
Código Altair
from altair import Chart c = Chart(df) c.mark_circle().encode(x='x', y='y', color='label')
código ggplot
from ggplot import * ggplot(aes(x='x', y='y', color='label'), data=df) +\ geom_point(size=50) +\ theme_bw()
fonte
A partir do matplotlib 3.1 em diante, você pode usar
.legend_elements()
. Um exemplo é mostrado na criação de legenda automatizada . A vantagem é que uma única chamada de dispersão pode ser usada.Nesse caso:
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) fig, ax = plt.subplots() sc = ax.scatter(df['one'], df['two'], marker = 'o', c = df['key1'], alpha = 0.8) ax.legend(*sc.legend_elements()) plt.show()
Caso as chaves não tenham sido fornecidas diretamente como números, seria
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'] = list("AAABBBCCCC") labels, index = np.unique(df["key1"], return_inverse=True) fig, ax = plt.subplots() sc = ax.scatter(df['one'], df['two'], marker = 'o', c = index, alpha = 0.8) ax.legend(sc.legend_elements()[0], labels) plt.show()
fonte
fig, ax = plt.subplots(1, 1, figsize = (4,4)) scat = ax.scatter(rand_jitter(important_dataframe["workout_type_int"], jitter = 0.04), important_dataframe["distance"], c = color_list, marker = 'o', alpha = 0.9) print(scat.legends_elements()) #ax.legend(*scat.legend_elements())
legends_elements
elegend_elements
.É bastante hacky, mas você pode usar
one1
como um recursoFloat64Index
para fazer tudo de uma vez:df.set_index('one').sort_index().groupby('key1')['two'].plot(style='--o', legend=True)
Observe que a partir de 0,20.3, a classificação do índice é necessária e a legenda é um pouco instável .
fonte
seaborn tem uma função de invólucro
scatterplot
que o faz de forma mais eficiente.sns.scatterplot(data = df, x = 'one', y = 'two', data = 'key1'])
fonte