Ich habe das getan.
Ein Beispiel ist ein Streudiagramm von MNIST, dessen Dimension durch t-SNE reduziert wurde. Wenn Sie den Mauszeiger über ein Diagramm bewegen, wird die diesem Diagramm entsprechende Abbildung angezeigt.
Dieser Artikel befasst sich mit der Verwendung von matplotlib. Die Erklärung von MNIST und t-SNE entfällt.
Welche Art von Variablennamen und wie er erstellt wurde, hängt jedoch vom Programm ab. Daher werde ich den Code dort veröffentlichen.
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
ist die Breite des Bildes. nskip
ist (die Umkehrung von) der Lotteriewahrscheinlichkeit der Probe. Die Stichprobengröße beträgt derzeit 70.000, was für das Plotten zu viel ist. Stellen Sie sie daher auf 1/35 ein und verwenden Sie 2000 Stichproben.
Details anderer Sequenzen sind wie folgt.
mnist_img
: (2000, 784) Dimensionales Gleitkomma-Array mit doppelter Genauigkeit. Rohbilddaten, gespeichert mit Pixelwerten von 0 bis 255.mnist_label
: Ein Array von (2000,) Dimensionen. Nummernbezeichnungen werden als Zeichenfolgen gespeichert.mnist_int
: (2000,) Ein Array von Dimensionen. Ein ganzzahliger Typ von mnist_label
.Wahrscheinlich die zweitkomplizierteste Handlung.
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()
Die Idee, Zahlen zu zeichnen https://qiita.com/stfate/items/8988d01aad9596f9d586 Beruhte auf.
Der Bereich der x- und y-Achsen, der mithilfe von "Streuung" automatisch angepasst werden kann, passt "xlim" und "ylim" aufgrund der Methode zum Platzieren von "Text" an jedem Punkt an. Muss sein. Sie sehen jedoch auf einen Blick, dass für jede Zahl Gruppen gebildet werden und manchmal andere Zahlen wie Rauschen gemischt werden.
Schau dir das an
Ich dachte. Lassen Sie uns also zuerst die Beschriftung mit der Maus anzeigen.
Dies fand die Antwort in Stackoverflow.
https://stackoverflow.com/questions/7908636/possible-to-make-labels-appear-when-hovering-over-a-point-in-matplotlib
Ändern Sie diesen Code für diesen 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()
Nun, es wird ein allgemeines Ereignis in der GUI verwendet. Erstellen Sie zuerst ein leeres "Annotation" -Objekt "Annot" und erstellen Sie dann eine Funktion "update_annot", die seine Position, ihren Inhalt usw. aktualisiert. Registrieren Sie die Funktion "Schweben" als "fig.canvas.mpl_connect (" motion_notify_event ", hover)" und rufen Sie "update_annot" auf, während Sie "annot" anzeigen, wenn der Cursor auf einen Punkt im "Schwebeflug" zeigt. Verstecke "Annot", wenn es nicht auf einen Punkt zeigt.
Um die Farbe auf "c = mnist_int / 10.0" in "Scatter" zu setzen, habe ich ein "mnist_int" -Array mit einer Ganzzahlbezeichnung vorbereitet.
Jetzt können Sie ein interaktives Streudiagramm wie im obigen Video zeichnen.
Ich habe diesmal übersprungen, aber ich denke, es wäre freundlicher, irgendwo eine Legende von Farben und Zahlen anzuzeigen.
Dadurch wurde ich unzufriedener.
"Wie speziell sieht ein verrauschter Punkt aus, zum Beispiel 7 in einem Cluster von 1s? Vielleicht macht der Algorithmus einen normalen Punkt verrauscht, also nur die Beschriftung Ich möchte auch die Rohdaten überprüfen. "
Um dies zu realisieren, scheint es gut, das Originalbild mit der Maus darüber anzuzeigen.
Es gab offiziell eine Demo, um Bilder mit Anmerkungen anzuzeigen.
https://matplotlib.org/3.1.0/gallery/text_labels_and_annotations/demo_annotation_box.html
Kombinieren Sie dies mit der zuvor erwähnten Event-Registrierung.
Erstens, da die Anmerkung nur Text früher war, war "Anmerkung" in Ordnung, aber wenn es um Bilder geht, ist es ein bisschen mühsam,
Eine zweistufige Operation ist erforderlich. Importieren Sie zunächst die gewünschte Klasse.
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
Vorbereitung der notwendigen Grafikobjekte.
fig, ax = plt.subplots()
cmap = plt.cm.RdYlGn
Bereiten Sie danach "OffsetImage" vor, aber verwenden Sie zu diesem Zeitpunkt das 0. Bild als Dummy-Bild.
img = mnist_img[0, :].reshape((width, width))
imagebox = OffsetImage(img, zoom=1.0)
imagebox.image.axes = ax
Erstellen Sie darauf basierend eine "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)
Beachten Sie, dass "xybox" nicht die Größe von "annot" angibt, sondern die Position relativ zum Annotationspunkt "xy".
Als nächstes werden die Diagramme und Bilder aktualisiert.
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)
Ich aktualisiere die neuen Bilddaten für "imagebox", aber es scheint, dass der Aktualisierungsprozess für "annot" nicht erforderlich ist.
Da ich separat experimentiert habe, reagiert es auch dynamisch, selbst wenn sich die Größe von "img" ändert. Ich denke, es gibt einen Prozess, um es separat hinzuzufügen, selbst wenn es verschiedene Größen gibt.
Der Rest der Eventregistrierung ist der gleiche.
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()
Es tut mir leid, dass es nur für einen Moment angezeigt wird, aber ich habe festgestellt, dass die Form des Rauschens sicherlich nahe an einer anderen Zahl liegt und wahrscheinlich falsch verstanden wird.
Nun, es ist eine bedeutungslose Technik, die mit der Bildausgabe zu tun hat, aber ich denke, sie kann während des Versuchs und Irrtums recht gut verwendet werden.
In diesem Vortrag erfuhr ich von der Existenz der abstrakten Stammklasse "Artist", die Objekte in matplotlib beschreibt.
Ändern Sie den Teil des Diagramms, den Sie anzeigen möchten, von "if False:" in "if True:". Wir haben den Vorgang nicht bestätigt, wenn mehrere auf "True" gesetzt sind.
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