[PYTHON] Lorsque vous passez la souris sur Matplotlib, l'image correspondante s'affiche.

Résumé

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.

Figure-1-2020-01-24-21-54-54_Trim.gif

environnement

Tout d'abord, le traitement t-SNE

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.

Tracé ordinaire

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

コメント 2020-01-24 224601.png

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.

Affichage des annotations avec survol de 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()

Figure-1-2020-01-24-22-33-54_Trim.gif

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 fonctionhover 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.

Affichage de l'image avec survol de 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()

Figure-1-2020-01-24-21-54-54_Trim.gif

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.

la fin

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.

Code bonus dans son ensemble

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».

Cliquez ici pour agrandir / replier
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

Lorsque vous passez la souris sur Matplotlib, l'image correspondante s'affiche.
Appliquons la couleur de l'image de marque à la carte des couleurs de matplotlib!
Python Open CV a essayé d'afficher l'image sous forme de texte.
Point selon l'image
La route pour télécharger Matplotlib
Affichez l'image de la caméra connectée à l'ordinateur personnel sur l'interface graphique.
Deux façons d'afficher plusieurs graphiques dans une seule image avec matplotlib
Comment afficher la barre de progression (tqdm)
Comment supprimer l'erreur d'affichage dans matplotlib
[Python] Comment spécifier la position d'affichage de la fenêtre et la taille de matplotlib
Affichage de l'image prise avec l'ISIGHT intégré
Préparez une URL pour afficher vous-même l'image téléchargée par Active Storage
Je veux afficher la barre de progression
Afficher les marqueurs au-dessus de la bordure avec matplotlib
Alignez la barre de couleurs sur la figure avec matplotlib
Comment désactiver l'affichage de la valeur d'échelle en quittant la grille avec matplotlib
Comment afficher dans toute la fenêtre lors de la définition de l'image d'arrière-plan avec tkinter
Comment attribuer plusieurs valeurs à la barre de couleurs Matplotlib
Essayez d'ajouter la distorsion de l'objectif fisheye à l'image
Coupez l'image aux coins arrondis avec pythonista
[Python] Comment changer le format de la date (format d'affichage)
Je souhaite afficher plusieurs images avec matplotlib.
J'ai essayé de corriger la forme trapézoïdale de l'image
Comment afficher des images en continu avec matplotlib Memo
Je veux afficher la progression en Python!
Afficher l'image après l'augmentation des données avec Pytorch
Afficher le 邊
Téléchargez l'image téléchargée par requêtes directement vers S3
J'ai essayé de détecter l'iris à partir de l'image de la caméra
Ajoutez des informations au bas de la figure avec Matplotlib
[Python] Spécifiez la plage de l'image en faisant glisser la souris
Enregistrer le graphique dessiné par pyqtgraph dans une image
Convertissez l'image au format .zip en PDF avec Python
Comment éliminer les caractères déformés dans l'image de sortie matplotlib
Reliez la souris au gyroscope du Nintendo Switch Procon
Afficher le graphique lors de la modification des paramètres avec PySimpleGUI + Matplotlib
[Introduction à Python] Utilisation basique de la bibliothèque matplotlib
Redimensionner l'image à la taille spécifiée et noircir les marges
J'ai essayé de compresser l'image en utilisant l'apprentissage automatique
Que faire si l'image n'est pas affichée à l'aide de matplotlib etc. dans le conteneur Docker