J'utilise matplotlib pour créer des diagrammes de dispersion. Chaque point du nuage de points est associé à un objet nommé. J'aimerais pouvoir voir le nom d'un objet lorsque je survole le point situé sur le diagramme de dispersion associé à cet objet. En particulier, il serait bien de pouvoir voir rapidement les noms des points aberrants. La chose la plus proche que j'ai pu trouver lors de la recherche ici est la commande annoter, mais cela semble créer une étiquette fixe sur le tracé. Malheureusement, avec le nombre de points que j'ai, le diagramme de dispersion serait illisible si je marquais chaque point. Est-ce que quelqu'un connaît un moyen de créer des étiquettes qui n'apparaissent que lorsque le curseur se place au voisinage de ce point?
Il semble qu'aucune des autres réponses ne réponde réellement à la question. Voici donc un code qui utilise une dispersion et affiche une annotation sur survolant les points de dispersion.
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)
x = np.random.Rand(15)
y = np.random.Rand(15)
names = np.array(list("ABCDEFGHIJKLMNO"))
c = np.random.randint(1,5,size=15)
norm = plt.Normalize(1,4)
cmap = plt.cm.RdYlGn
fig,ax = plt.subplots()
sc = plt.scatter(x,y,c=c, s=100, cmap=cmap, norm=norm)
annot = ax.annotate("", xy=(0,0), xytext=(20,20),textcoords="offset points",
bbox=dict(boxstyle="round", fc="w"),
arrowprops=dict(arrowstyle="->"))
annot.set_visible(False)
def update_annot(ind):
pos = sc.get_offsets()[ind["ind"][0]]
annot.xy = pos
text = "{}, {}".format(" ".join(list(map(str,ind["ind"]))),
" ".join([names[n] for n in ind["ind"]]))
annot.set_text(text)
annot.get_bbox_patch().set_facecolor(cmap(norm(c[ind["ind"][0]])))
annot.get_bbox_patch().set_alpha(0.4)
def hover(event):
vis = annot.get_visible()
if event.inaxes == ax:
cont, ind = sc.contains(event)
if cont:
update_annot(ind)
annot.set_visible(True)
fig.canvas.draw_idle()
else:
if vis:
annot.set_visible(False)
fig.canvas.draw_idle()
fig.canvas.mpl_connect("motion_notify_event", hover)
plt.show()
Parce que les gens veulent aussi utiliser cette solution pour une ligne plot
au lieu d'une dispersion, la solution suivante serait la même solution pour plot
(qui fonctionne légèrement différemment).
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)
x = np.sort(np.random.Rand(15))
y = np.sort(np.random.Rand(15))
names = np.array(list("ABCDEFGHIJKLMNO"))
norm = plt.Normalize(1,4)
cmap = plt.cm.RdYlGn
fig,ax = plt.subplots()
line, = plt.plot(x,y, marker="o")
annot = ax.annotate("", xy=(0,0), xytext=(-20,20),textcoords="offset points",
bbox=dict(boxstyle="round", fc="w"),
arrowprops=dict(arrowstyle="->"))
annot.set_visible(False)
def update_annot(ind):
x,y = line.get_data()
annot.xy = (x[ind["ind"][0]], y[ind["ind"][0]])
text = "{}, {}".format(" ".join(list(map(str,ind["ind"]))),
" ".join([names[n] for n in ind["ind"]]))
annot.set_text(text)
annot.get_bbox_patch().set_alpha(0.4)
def hover(event):
vis = annot.get_visible()
if event.inaxes == ax:
cont, ind = line.contains(event)
if cont:
update_annot(ind)
annot.set_visible(True)
fig.canvas.draw_idle()
else:
if vis:
annot.set_visible(False)
fig.canvas.draw_idle()
fig.canvas.mpl_connect("motion_notify_event", hover)
plt.show()
Si quelqu'un recherche une solution pour les lignes sur deux axes, reportez-vous à Comment faire apparaître des étiquettes lorsque vous survolez un point sur plusieurs axes?
Si quelqu'un recherche une solution pour les parcelles à barres, veuillez vous reporter à la page cette réponse .
Cette solution fonctionne lorsque vous survolez une ligne sans avoir à cliquer dessus:
import matplotlib.pyplot as plt
fig = plt.figure()
plot = fig.add_subplot(111)
# create some curves
for i in range(4):
plot.plot(
[i*1,i*2,i*3,i*4],
gid=i)
def on_plot_hover(event):
for curve in plot.get_lines():
if curve.contains(event)[0]:
print "over %s" % curve.get_gid()
fig.canvas.mpl_connect('motion_notify_event', on_plot_hover)
plt.show()
De http://matplotlib.sourceforge.net/examples/event_handling/pick_event_demo.html :
from matplotlib.pyplot import figure, show
import numpy as npy
from numpy.random import Rand
if 1: # picking on a scatter plot (matplotlib.collections.RegularPolyCollection)
x, y, c, s = Rand(4, 100)
def onpick3(event):
ind = event.ind
print 'onpick3 scatter:', ind, npy.take(x, ind), npy.take(y, ind)
fig = figure()
ax1 = fig.add_subplot(111)
col = ax1.scatter(x, y, 100*s, c, picker=True)
#fig.savefig('pscoll.eps')
fig.canvas.mpl_connect('pick_event', onpick3)
show()
Une légère modification sur un exemple fourni dans http://matplotlib.org/users/Shell.html :
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_title('click on points')
line, = ax.plot(np.random.Rand(100), '-', picker=5) # 5 points tolerance
def onpick(event):
thisline = event.artist
xdata = thisline.get_xdata()
ydata = thisline.get_ydata()
ind = event.ind
print 'onpick points:', Zip(xdata[ind], ydata[ind])
fig.canvas.mpl_connect('pick_event', onpick)
plt.show()
Ceci trace un tracé en ligne droite, comme le demandait Sohaib
mpld3 le résoudre pour moi. MODIFIER (CODE AJOUTÉ):
import matplotlib.pyplot as plt
import numpy as np
import mpld3
fig, ax = plt.subplots(subplot_kw=dict(axisbg='#EEEEEE'))
N = 100
scatter = ax.scatter(np.random.normal(size=N),
np.random.normal(size=N),
c=np.random.random(size=N),
s=1000 * np.random.random(size=N),
alpha=0.3,
cmap=plt.cm.jet)
ax.grid(color='white', linestyle='solid')
ax.set_title("Scatter Plot (with tooltips!)", size=20)
labels = ['point {0}'.format(i + 1) for i in range(N)]
tooltip = mpld3.plugins.PointLabelTooltip(scatter, labels=labels)
mpld3.plugins.connect(fig, tooltip)
mpld3.show()
Vous pouvez vérifier this exemple
mplcursors a travaillé pour moi. mplcursors fournit des annotations cliquables pour matplotlib. Il est fortement inspiré de mpldatacursor ( https://github.com/joferkington/mpldatacursor ), avec une API très simplifiée.
import matplotlib.pyplot as plt
import numpy as np
import mplcursors
data = np.outer(range(10), range(1, 5))
fig, ax = plt.subplots()
lines = ax.plot(data)
ax.set_title("Click somewhere on a line.\nRight-click to deselect.\n"
"Annotations can be dragged.")
mplcursors.cursor(lines) # or just mplcursors.cursor()
plt.show()
Les autres réponses ne répondaient pas à mon besoin d'afficher correctement les info-bulles dans une version récente de la figure matplotlib inline de Jupyter. Celui-ci fonctionne bien:
import matplotlib.pyplot as plt
import numpy as np
import mplcursors
np.random.seed(42)
fig, ax = plt.subplots()
ax.scatter(*np.random.random((2, 26)))
ax.set_title("Mouse over a point")
crs = mplcursors.cursor(ax,hover=True)
crs.connect("add", lambda sel: sel.annotation.set_text(
'Point {},{}'.format(sel.target[0], sel.target[1])))
plt.show()
Cela conduit à quelque chose comme l’image suivante lorsque vous passez sur un point avec la souris:
Vous cherchez quelque chose comme ça.
URL: https://matplotlib.org/2.0.1/examples/pylab_examples/cursor_demo.html
Essayez simplement de copier-coller et voyez si cela répond à vos besoins.
J'ai beaucoup cherché et la plupart des réponses n'imprimaient les points qu'après le survol ou les étiquettes n'étaient tirées qu'après un clic de souris. Cette (solution dans le lien ci-dessus) combine les avantages des deux solutions.
J'ai créé un système d'annotation multiligne à ajouter à: https://stackoverflow.com/a/47166787/1030202 . pour la version la plus récente: https://github.com/AidenBurgess/MultiAnnotationLineGraph
Modifiez simplement les données dans la section inférieure.
import matplotlib.pyplot as plt
def update_annot(ind, line, annot, ydata):
x, y = line.get_data()
annot.xy = (x[ind["ind"][0]], y[ind["ind"][0]])
# Get x and y values, then format them to be displayed
x_values = " ".join(list(map(str, ind["ind"])))
y_values = " ".join(str(ydata[n]) for n in ind["ind"])
text = "{}, {}".format(x_values, y_values)
annot.set_text(text)
annot.get_bbox_patch().set_alpha(0.4)
def hover(event, line_info):
line, annot, ydata = line_info
vis = annot.get_visible()
if event.inaxes == ax:
# Draw annotations if cursor in right position
cont, ind = line.contains(event)
if cont:
update_annot(ind, line, annot, ydata)
annot.set_visible(True)
fig.canvas.draw_idle()
else:
# Don't draw annotations
if vis:
annot.set_visible(False)
fig.canvas.draw_idle()
def plot_line(x, y):
line, = plt.plot(x, y, marker="o")
# Annotation style may be changed here
annot = ax.annotate("", xy=(0, 0), xytext=(-20, 20), textcoords="offset points",
bbox=dict(boxstyle="round", fc="w"),
arrowprops=dict(arrowstyle="->"))
annot.set_visible(False)
line_info = [line, annot, y]
fig.canvas.mpl_connect("motion_notify_event",
lambda event: hover(event, line_info))
# Your data values to plot
x1 = range(21)
y1 = range(0, 21)
x2 = range(21)
y2 = range(0, 42, 2)
# Plot line graphs
fig, ax = plt.subplots()
plot_line(x1, y1)
plot_line(x2, y2)
plt.show()