Diagramme de dispersion Matplotlib avec un texte différent à chaque point de données

252

J'essaie de faire un nuage de points et d'annoter des points de données avec différents nombres à partir d'une liste. Ainsi, par exemple, je veux tracer yvs xet annoter avec les nombres correspondants 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')

Des idées?

Labibah
la source
Vous pouvez également obtenir un nuage de points avec des étiquettes d'infobulle au survol à l'aide de la bibliothèque mpld3. mpld3.github.io/examples/scatter_tooltip.html
Claude COULOMBE

Réponses:

466

Je ne connais aucune méthode de traçage qui prend des tableaux ou des listes, mais vous pouvez utiliser annotate()tout en itérant les valeurs dans 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]))

Il existe de nombreuses options de formatage pour annotate(), voir le site Web de matplotlib:

entrez la description de l'image ici

Rutger Kassies
la source
1
Fonctionne bien au-dessus de Seaborn regplotsans trop de perturbations.
ijoseph
@Rutger J'utilise un datframe pandas et j'obtiens en quelque sorte un KeyError- donc je suppose qu'un dict()objet est attendu? Est - il une autre façon d'étiqueter les données à l' aide enumerate, annotateet une trame de données pandas?
Rachel
@Rachel, vous pouvez utiliser for row in df.iterrows():, puis accéder aux valeurs avec row['text'], row['x-coord']etc. Si vous postez une question distincte, je vais y jeter un œil.
Rutger Kassies
@RutgerKassies Merci, Rutger! J'ai posté une question ici stackoverflow.com/questions/41481153/… Je crains que cela ne ressemble à cette question. Mais je ne peux pas le résoudre d'une manière ou d'une autre. Merci de votre aide!
Rachel
1
@aviator, pas intégré malheureusement. Mais voyez par exemple cela en utilisant le moteur de mise en page de networkx: stackoverflow.com/a/34697108/1755432
Rutger Kassies
32

Dans les versions antérieures à matplotlib 2.0, il ax.scattern'est pas nécessaire de tracer du texte sans marqueurs. Dans la version 2.0, vous devrez ax.scatterdéfinir la plage et les marqueurs appropriés pour le texte.

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

Et dans ce lien, vous pouvez trouver un exemple en 3D.

rafaelvalle
la source
C'est génial! Merci d'avoir partagé cette solution. Pouvez-vous également partager le code approprié pour définir la taille de la figure? Les implémentations telles que plt.figure(figsize=(20,10))ne fonctionnent pas comme prévu, en ce sens que l'invocation de ce code ne change pas réellement la taille de l'image. Dans l'attente de votre aide. Merci!
Levine
fig, ax = plt.subplots (figsize = (20,10))
rafaelvalle
21

Dans le cas où quelqu'un essaie d'appliquer les solutions ci-dessus à un .scatter () au lieu d'un .subplot (),

J'ai essayé d'exécuter le code suivant

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

Mais il a rencontré des erreurs indiquant "impossible de décompresser l'objet PathCollection non itérable", l'erreur pointant spécifiquement sur la ligne de code fig, ax = plt.scatter (z, y)

J'ai finalement résolu l'erreur en utilisant le code suivant

plt.scatter(z, y)

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

Je ne m'attendais pas à ce qu'il y ait une différence entre .scatter () et .subplot () que j'aurais dû mieux connaître.

Heather Claxton
la source
11

Vous pouvez également utiliser pyplot.text(voir ici ).

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)

entrez la description de l'image ici

irudyak
la source
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
la source
2

En une ligne avec compréhension de liste et numpy:

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

l'installation est idem à la réponse de Rutger.

andor kesselman
la source
1

J'adorerais ajouter que vous pouvez même utiliser des flèches / zones de texte pour annoter les étiquettes. Voici ce que je veux dire:

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

Ce qui va générer le graphique suivant: entrez la description de l'image ici

Anwarvic
la source