J'ai fait ça.
Un exemple est un diagramme de dispersion de MNIST réduit en dimension par t-SNE. Lorsque vous déplacez le curseur de la souris sur un tracé, la figure correspondant à ce tracé s'affiche.
Cet article se concentre sur l'utilisation de matplotlib. L'explication de MNIST et t-SNE est omise.
Cependant, le type de nom de variable et la façon dont il a été créé dépendent du programme, donc je posterai le code là-bas.
import numpy as np
from sklearn.datasets import fetch_openml
from sklearn.manifold import TSNE
width = 28
nskip = 35
mnist = fetch_openml("mnist_784", version=1)
mnist_img = mnist["data"][::nskip, :]
mnist_label = mnist["target"][::nskip]
mnist_int = np.asarray(mnist_label, dtype=int)
x_embedded = TSNE(n_components=2).fit_transform(mnist_img)
width
est la largeur de l'image. «nskip» est (l'inverse de) la probabilité de loterie de l'échantillon. Dans l'état actuel des choses, la taille de l'échantillon est de 70 000, ce qui est trop pour le traçage, alors réglez-la sur 1/35 et utilisez 2000 échantillons.
Les détails des autres séquences sont les suivants.
mnist_img
: (2000, 784) Tableau à virgule flottante double précision dimensionnelle. Données d'image brutes, stockées avec des valeurs de pixel comprises entre 0 et 255.mnist_label
: Un tableau de (2000,) dimensions. Les étiquettes numériques sont stockées sous forme de chaînes de caractères.mnist_int
: (2000,) Un tableau de dimensions. Un type entier de mnist_label
.Probablement le deuxième complot le plus simple.
plt.xlim(x_embedded[:, 0].min(), x_embedded[:, 0].max())
plt.ylim(x_embedded[:, 1].min(), x_embedded[:, 1].max())
for x, label in zip(x_embedded, mnist_label):
plt.text(x[0], x[1], label)
plt.xlabel("component 0")
plt.ylabel("component 1")
plt.show()
L'idée de tracer des nombres https://qiita.com/stfate/items/8988d01aad9596f9d586 S'appuyait sur.
Si vous utilisez «scatter» docilement, la plage des axes x et y sera ajustée automatiquement. En raison de la méthode de placement du «texte» à chaque point, vous pouvez ajuster «xlim» et «ylim» vous-même. Doit être. Cependant, vous pouvez voir en un coup d'œil que des groupes sont formés pour chaque nombre, et parfois d'autres nombres sont mélangés comme du bruit.
Regarde ça
J'ai pensé. Alors, commençons par afficher l'étiquette en survolant la souris.
Cela a trouvé la réponse dans Stackoverflow.
https://stackoverflow.com/questions/7908636/possible-to-make-labels-appear-when-hovering-over-a-point-in-matplotlib
Modifiez ce code pour ce MNIST.
fig, ax = plt.subplots()
cmap = plt.cm.RdYlGn
sc = plt.scatter(x_embedded[:, 0], x_embedded[:, 1], c=mnist_int/10.0, cmap=cmap, s=3)
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):
i = ind["ind"][0]
pos = sc.get_offsets()[i]
annot.xy = pos
text = mnist_label[i]
annot.set_text(text)
annot.get_bbox_patch().set_facecolor(cmap(int(text)/10))
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()
Eh bien, il utilise un événement commun dans l'interface graphique.
Tout d'abord, créez un objet ʻAnnotation vide ʻannot
, puis créez une fonction ʻupdate_annotqui met à jour sa position, son contenu, etc. Enregistrez la fonction
hover comme
fig.canvas.mpl_connect (" motion_notify_event ", hover), et si le curseur pointe vers un point quelconque de ce
hover, appelez ʻupdate_annot
tout en affichant ʻannot. Cacher ʻannot
s'il ne pointe pas vers un point.
Afin de définir la couleur sur «c = mnist_int / 10.0» dans «scatter», j'ai préparé un tableau «mnist_int» avec une étiquette entière.
Vous pouvez maintenant dessiner un diagramme de dispersion interactif comme celui de la vidéo ci-dessus.
J'ai sauté cette fois, mais je pense qu'il serait plus gentil d'afficher une légende des couleurs et des nombres quelque part.
En faisant jusqu'à présent, j'ai eu plus d'insatisfaction.
"À quel point un point bruyant, par exemple 7 dans un groupe de 1, est-il spécial? Peut-être que l'algorithme rend un point normal bruyant, donc juste l'étiquette Je veux également vérifier les données brutes. "
Pour réaliser cela, il semble bon d'afficher l'image d'origine en survolant la souris.
Il y avait officiellement une démo pour afficher des images avec des annotations.
https://matplotlib.org/3.1.0/gallery/text_labels_and_annotations/demo_annotation_box.html
Combinez cela avec l'enregistrement d'événement mentionné précédemment.
Tout d'abord, puisque l'annotation n'était que du texte auparavant, «Annotation» était bien, mais quand il s'agit d'images, c'est un peu gênant,
Une opération en deux étapes est requise. Tout d'abord, importez la classe requise.
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
Préparation des objets graphiques nécessaires.
fig, ax = plt.subplots()
cmap = plt.cm.RdYlGn
Après cela, préparez ʻOffsetImage`, mais à ce moment-là, utilisez la 0ème image comme image factice.
img = mnist_img[0, :].reshape((width, width))
imagebox = OffsetImage(img, zoom=1.0)
imagebox.image.axes = ax
Sur cette base, créez ʻAnnotation Bbox`.
annot = AnnotationBbox(imagebox, xy=(0,0), xybox=(width,width),
xycoords="data", boxcoords="offset points", pad=0.5,
arrowprops=dict( arrowstyle="->", connectionstyle="arc3,rad=-0.3"))
annot.set_visible(False)
ax.add_artist(annot)
Notez que xybox
n'indique pas la taille de ʻannot, mais la position par rapport au point d'annotation
xy`.
Vient ensuite la mise à jour des graphiques et des images.
sc = plt.scatter(x_embedded[:, 0], x_embedded[:, 1], c=mnist_int/10.0, cmap=cmap, s=3)
def update_annot(ind):
i = ind["ind"][0]
pos = sc.get_offsets()[i]
annot.xy = (pos[0], pos[1])
img = mnist_img[i, :].reshape((width, width))
imagebox.set_data(img)
Je mets à jour les nouvelles données d'image pour ʻimagebox, mais il semble que le processus de mise à jour ne soit pas nécessaire pour ʻannot
.
De plus, comme j'ai expérimenté séparément, il répond dynamiquement même si la taille de ʻimg` change, donc je pense qu'il y a un processus pour l'ajouter séparément même s'il y a différentes tailles.
Le reste de l'inscription à l'événement est le même.
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()
Je suis désolé qu'il ne s'affiche que pendant un moment, mais j'ai trouvé que la forme du bruit est certainement proche d'un autre nombre et qu'il est susceptible d'être mal lu.
Eh bien, c'est une technique sans signification à voir avec la sortie d'image, mais je pense qu'elle peut être utilisée un peu pendant les essais et erreurs.
Dans cet exposé, j'ai appris l'existence de la classe abstraite racine ʻArtist` qui décrit les objets dans matplotlib.
Changez la partie du tracé que vous voulez afficher de ʻif False: à ʻif True:
.
Nous n'avons pas confirmé l'opération lorsque plusieurs sont définis sur «True».
import numpy as np
from sklearn.datasets import fetch_openml
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
width = 28
nskip = 35
mnist = fetch_openml("mnist_784", version=1)
mnist_img = mnist["data"][::nskip, :]
mnist_label = mnist["target"][::nskip]
mnist_int = np.asarray(mnist_label, dtype=int)
print(type(mnist_img))
print(mnist_img.max())
print(mnist_img.dtype)
exit()
x_embedded = TSNE(n_components=2).fit_transform(mnist_img)
if True:
plt.xlim(x_embedded[:, 0].min(), x_embedded[:, 0].max())
plt.ylim(x_embedded[:, 1].min(), x_embedded[:, 1].max())
for x, label in zip(x_embedded, mnist_label):
plt.text(x[0], x[1], label)
plt.xlabel("component 0")
plt.ylabel("component 1")
plt.show()
exit()
fig, ax = plt.subplots()
cmap = plt.cm.RdYlGn
if False:
sc = plt.scatter(x_embedded[:, 0], x_embedded[:, 1], c=mnist_int/10.0, cmap=cmap, s=3)
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):
i = ind["ind"][0]
pos = sc.get_offsets()[i]
annot.xy = pos
text = mnist_label[i]
annot.set_text(text)
annot.get_bbox_patch().set_facecolor(cmap(int(text)/10))
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()
if False:
img = mnist_img[0, :].reshape((width, width))
imagebox = OffsetImage(img, zoom=1.0)
imagebox.image.axes = ax
sc = plt.scatter(x_embedded[:, 0], x_embedded[:, 1], c=mnist_int/10.0, cmap=cmap, s=3)
annot = AnnotationBbox(imagebox, xy=(0,0), xybox=(width,width),
xycoords="data", boxcoords="offset points", pad=0.5,
arrowprops=dict( arrowstyle="->", connectionstyle="arc3,rad=-0.3"))
annot.set_visible(False)
ax.add_artist(annot)
def update_annot(ind):
i = ind["ind"][0]
pos = sc.get_offsets()[i]
annot.xy = (pos[0], pos[1])
img = mnist_img[i, :].reshape((width, width))
imagebox.set_data(img)
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()
Recommended Posts