2014-04-16 4 views
4

Avec maptplotlib, je trace quelques points avec la méthode scatter (voir le code ci-dessous). Je voudrais étiqueter chaque point individuellement.Matplotlib: comment étiqueter des points individuellement?

Ce code marquera chaque point avec le tableau labels, mais j'aimerais que mon premier point soit étiqueté avec labels[0], le second avec labels[1] et ainsi de suite.

import numpy as np; import matplotlib.pyplot as plt 
y = np.arange(10) # points to plot 
labels = np.arange(10) # labels of the points 
fig, ax = plt.subplots(nrows=1, ncols=1) 
ax.scatter(x=np.arange(10), y=y, label=labels, picker=3) 

Y at-il un moyen de faire cela? Et BTW, est-il possible de parcourir les points dans ax? La méthode ax.get_children() donne des données que je ne comprends pas.

Merci!

+1

utilisez 'annotate'. Il vous permet d'ajouter des étiquettes + flèches pointant vers des points arbitraires. – tacaswell

+0

https://stackoverflow.com/questions/14938541/how-to-improve-the-label-placement-for-matplotlib-scatter-chart-code-algorithm/15859652#15859652 – tacaswell

+0

Voulez-vous étiqueter chaque point (que est de mettre une étiquette de texte dans les axes pointant sur le point ou) voulez-vous une entrée de légende pour chaque point? – tacaswell

Répondre

4

En supposant que vous n'êtes pas complotez beaucoup de points de diffusion, vous pouvez simplement faire un scatter pour chaque point:

import numpy as np; import matplotlib.pyplot as plt 
y = np.arange(10) # points to plot 
x=np.arange(10) 
labels = np.arange(10) # labels of the points 
fig, ax = plt.subplots(nrows=1, ncols=1) 
for x_,y_,label in zip(x,y,labels): 
    ax.scatter([x_], [y_], label=label, picker=3) 

Cela commencera à retard si vous complotez de milliers ou des dizaines de milliers de points, mais si ce n'est que quelques-uns, alors ce n'est pas un problème.

Pour répondre à la deuxième partie de votre question, ax.get_children() renvoie une liste d'objets qui composent ces axes, par exemple:

[<matplotlib.axis.XAxis at 0x103acc410>, 
<matplotlib.axis.YAxis at 0x103acddd0>, 
<matplotlib.collections.PathCollection at 0x10308ba10>, #<--- this is a set of scatter points 
<matplotlib.text.Text at 0x103082d50>, 
<matplotlib.patches.Rectangle at 0x103082dd0>, 
<matplotlib.spines.Spine at 0x103acc2d0>, 
<matplotlib.spines.Spine at 0x103ac9f90>, 
<matplotlib.spines.Spine at 0x103acc150>, 
<matplotlib.spines.Spine at 0x103ac9dd0>] 

Si vous êtes à la recherche pour obtenir les ensembles de points de dispersion dans vos axes, le moyen le plus simple est par ax.collections. C'est un list qui contient toutes les instances collections tracées dans les axes (les points de dispersion appartiennent à PathCollection).

In [9]: ax.collections 
Out[9]: [<matplotlib.collections.PathCollection at 0x10308ba10>] 

Si vous avez tracé un scatter séparé pour chaque point, itérer sur les points est aussi facile que:

# iterate over points and turn them all red 
for point in ax.collections: 
    point.set_facecolor("red") 
+0

Merci pour cette réponse détaillée. Je suppose alors qu'il n'y a aucun moyen de parcourir les points si je n'utilise pas un 'scatter 'séparé pour chaque point? Si oui, savez-vous pourquoi?Cela me semble être une fonctionnalité plutôt utile/pas si bizarre, parce que j'ai des milliers de points à gagner. – Niourf

+0

@Niourf Je ne suis pas sûr, j'ai cherché des façons de le faire à plusieurs reprises, mais je n'ai pas eu beaucoup de chance. Cependant, je pense qu'une meilleure façon de le faire pourrait être d'utiliser 'plot' plutôt que' scatter', avec 'lw = 0'. La classe utilisée pour les lignes a plus de flexibilité que la classe 'PathCollections'. – ebarr

+0

Okay. J'utilise «scatter» plutôt que «plot» parce que je dois utiliser des couleurs fantaisistes. Je suis assez nouveau à matplotlib mais j'ai tendance à le trouver beaucoup plus compliqué que ça pourrait l'être ... – Niourf

2

Tout cela peut être enveloppé d'un caché dans une fonction ou d'une classe:

# import stuff 
import matplotlib.pyplot as plt 
import numpy as np 

# create dictionary we will close over (twice) 
label_dict = dict() 
# helper function to do the scatter plot + shove data into label_dict 
def lab_scatter(ax, x, y, label_list, *args, **kwargs): 
    if 'picker' not in kwargs: 
     kwargs['picker'] = 3 
    sc = ax.scatter(x, y, *args, **kwargs) 
    label_dict[sc] = label_list 
    return sc 
# call back function which also closes over label_dict, should add more sanity checks 
# (that artist is actually in the dict, deal with multiple hits in ind ect) 
def cb_fun(event): 
    # grab list of labels from the dict, print the right one 
    print label_dict[event.artist][event.ind[0]] 
# create the figure and axes to use 
fig, ax = plt.subplots(1, 1) 
# loop over 5 synthetic data sets 
for j in range(5): 
    # use our helper function to do the plotting 
    lab_scatter(ax, 
       np.ones(10) * j, 
       np.random.rand(10), 
       # give each point a unique label 
       label_list = ['label_{s}_{f}'.format(s=j, f=k) for k in range(10)]) 
# connect up the call back function 
cid = fig.canvas.mpl_connect('pick_event', cb_fun) 
Questions connexes