Gráfico de dispersão Matplotlib com texto diferente em cada ponto de dados

252

Estou tentando fazer um gráfico de dispersão e anotar pontos de dados com números diferentes de uma lista. Então, por exemplo, eu quero plotar yvs xe anotar com os números correspondentes de n.

y = [2.56422, 3.77284, 3.52623, 3.51468, 3.02199]
z = [0.15, 0.3, 0.45, 0.6, 0.75]
n = [58, 651, 393, 203, 123]
ax = fig.add_subplot(111)
ax1.scatter(z, y, fmt='o')

Alguma ideia?

Labibah
fonte
Você também pode obter um gráfico de dispersão com rótulos de dica de ferramenta ao passar o mouse usando a biblioteca mpld3. mpld3.github.io/examples/scatter_tooltip.html
Claude COULOMBE

Respostas:

466

Não conheço nenhum método de plotagem que utilize matrizes ou listas, mas você pode usar annotate()enquanto itera os valores em n.

y = [2.56422, 3.77284, 3.52623, 3.51468, 3.02199]
z = [0.15, 0.3, 0.45, 0.6, 0.75]
n = [58, 651, 393, 203, 123]

fig, ax = plt.subplots()
ax.scatter(z, y)

for i, txt in enumerate(n):
    ax.annotate(txt, (z[i], y[i]))

Existem muitas opções de formatação para annotate(), consulte o site matplotlib:

insira a descrição da imagem aqui

Rutger Kassies
fonte
1
Funciona bem no Seaborn regplots sem muita interrupção também.
ijoseph
@ Rutger Eu uso um datframe de pandas e de alguma forma recebo um KeyError- então acho que um dict()objeto é esperado? Existe alguma outra maneira de rotular os dados usando enumerate, annotatee um quadro de dados pandas?
Rachel
@ Rachel, você pode usar for row in df.iterrows():e acessar os valores com row['text'], row['x-coord']etc. Se você postar uma pergunta separada, eu darei uma olhada nela.
Rutger Kassies
@RutgerKassies Obrigado, Rutger! Eu postei uma pergunta aqui stackoverflow.com/questions/41481153/… Receio que seja semelhante a essa mesma pergunta. Mas não consigo resolver de alguma forma. Obrigado pela ajuda!
Rachel
1
@aviator, infelizmente não embutido. Mas veja por exemplo isso usando o mecanismo de layout da networkx: stackoverflow.com/a/34697108/1755432
Rutger Kassies
32

Nas versões anteriores ao matplotlib 2.0, ax.scatternão é necessário plotar texto sem marcadores. Na versão 2.0, você precisará ax.scatterdefinir o intervalo e os marcadores adequados para o texto.

y = [2.56422, 3.77284, 3.52623, 3.51468, 3.02199]
z = [0.15, 0.3, 0.45, 0.6, 0.75]
n = [58, 651, 393, 203, 123]

fig, ax = plt.subplots()

for i, txt in enumerate(n):
    ax.annotate(txt, (z[i], y[i]))

E neste link você pode encontrar um exemplo em 3d.

rafaelvalle
fonte
Isso é incrível! Obrigado por compartilhar esta solução. Você também pode compartilhar qual é o código adequado para definir o tamanho da figura? Implementações como a que plt.figure(figsize=(20,10))não estão funcionando conforme o esperado, na medida em que invocar esse código não altera o tamanho da imagem. Aguardamos a sua ajuda. Obrigado!
Levine
fig, Ax = plt.subplots (figsize = (20,10))
rafaelvalle
21

Caso alguém esteja tentando aplicar as soluções acima em um .scatter () em vez de em um .subplot (),

Eu tentei executar o seguinte código

y = [2.56422, 3.77284, 3.52623, 3.51468, 3.02199]
z = [0.15, 0.3, 0.45, 0.6, 0.75]
n = [58, 651, 393, 203, 123]

fig, ax = plt.scatter(z, y)

for i, txt in enumerate(n):
    ax.annotate(txt, (z[i], y[i]))

Porém, ocorreram erros indicando que "não é possível descompactar o objeto PathCollection não iterável", com o erro apontando especificamente para a linha de código fig, ax = plt.scatter (z, y)

Acabei por resolver o erro usando o seguinte código

plt.scatter(z, y)

for i, txt in enumerate(n):
    plt.annotate(txt, (z[i], y[i]))

Eu não esperava que houvesse uma diferença entre .scatter () e .subplot () que eu deveria saber.

Heather Claxton
fonte
11

Você também pode usar pyplot.text(veja aqui ).

def plot_embeddings(M_reduced, word2Ind, words):
""" Plot in a scatterplot the embeddings of the words specified in the list "words".
    Include a label next to each point.
"""
for word in words:
    x, y = M_reduced[word2Ind[word]]
    plt.scatter(x, y, marker='x', color='red')
    plt.text(x+.03, y+.03, word, fontsize=9)
plt.show()

M_reduced_plot_test = np.array([[1, 1], [-1, -1], [1, -1], [-1, 1], [0, 0]])
word2Ind_plot_test = {'test1': 0, 'test2': 1, 'test3': 2, 'test4': 3, 'test5': 4}
words = ['test1', 'test2', 'test3', 'test4', 'test5']
plot_embeddings(M_reduced_plot_test, word2Ind_plot_test, words)

insira a descrição da imagem aqui

irudyak
fonte
7

Python 3.6+:

coordinates = [('a',1,2), ('b',3,4), ('c',5,6)]
for x in coordinates: plt.annotate(x[0], (x[1], x[2]))
palash
fonte
2

Como um liner usando compreensão de lista e numpy:

[ax.annotate(x[0], (x[1], x[2])) for x in np.array([n,z,y]).T]

A configuração deve-se à resposta de Rutger.

andor kesselman
fonte
1

Gostaria de acrescentar que você pode até usar setas / caixas de texto para anotar os rótulos. Aqui está o que eu quero dizer:

import random
import matplotlib.pyplot as plt


y = [2.56422, 3.77284, 3.52623, 3.51468, 3.02199]
z = [0.15, 0.3, 0.45, 0.6, 0.75]
n = [58, 651, 393, 203, 123]

fig, ax = plt.subplots()
ax.scatter(z, y)

ax.annotate(n[0], (z[0], y[0]), xytext=(z[0]+0.05, y[0]+0.3), 
    arrowprops=dict(facecolor='red', shrink=0.05))

ax.annotate(n[1], (z[1], y[1]), xytext=(z[1]-0.05, y[1]-0.3), 
    arrowprops = dict(  arrowstyle="->",
                        connectionstyle="angle3,angleA=0,angleB=-90"))

ax.annotate(n[2], (z[2], y[2]), xytext=(z[2]-0.05, y[2]-0.3), 
    arrowprops = dict(arrowstyle="wedge,tail_width=0.5", alpha=0.1))

ax.annotate(n[3], (z[3], y[3]), xytext=(z[3]+0.05, y[3]-0.2), 
    arrowprops = dict(arrowstyle="fancy"))

ax.annotate(n[4], (z[4], y[4]), xytext=(z[4]-0.1, y[4]-0.2),
    bbox=dict(boxstyle="round", alpha=0.1), 
    arrowprops = dict(arrowstyle="simple"))

plt.show()

O que gerará o seguinte gráfico: insira a descrição da imagem aqui

Anwarvic
fonte