Matplotlib Kreuzhaarschirmcursor

MatplotlibMatplotlibBeginner
Jetzt üben

This tutorial is from open-source community. Access the source code

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

Einführung

Matplotlib ist eine beliebte Datenvisualisierungsbibliothek, die eine Vielzahl von Tools zum Erstellen von Visualisierungen in Python bietet. Eine der interessanten Funktionen von Matplotlib ist die Möglichkeit, einen Kreuzhaarschirmcursor zu einem Diagramm hinzuzufügen. In diesem Lab werden Sie lernen, wie man einen Kreuzhaarschirmcursor zu einem Matplotlib-Diagramm hinzufügt.

VM-Tipps

Nachdem der VM-Start abgeschlossen ist, klicken Sie in der oberen linken Ecke, um zur Registerkarte Notebook zu wechseln und Jupyter Notebook für die Übung zu nutzen.

Manchmal müssen Sie einige Sekunden warten, bis Jupyter Notebook vollständig geladen ist. Die Validierung von Vorgängen kann aufgrund von Einschränkungen in Jupyter Notebook nicht automatisiert werden.

Wenn Sie bei der Lernphase Probleme haben, können Sie Labby gerne fragen. Geben Sie nach der Sitzung Feedback, und wir werden das Problem für Sie prompt beheben.

Einfacher Cursor

Der erste Schritt besteht darin, einen einfachen Cursor zu einem Matplotlib-Diagramm hinzuzufügen. Dieser Cursor wird die x- und y-Werte der aktuellen Mausposition anzeigen.

import matplotlib.pyplot as plt
import numpy as np

from matplotlib.backend_bases import MouseEvent

class Cursor:
    """
    Ein Kreuzhaarschirmcursor.
    """
    def __init__(self, ax):
        self.ax = ax
        self.horizontal_line = ax.axhline(color='k', lw=0.8, ls='--')
        self.vertical_line = ax.axvline(color='k', lw=0.8, ls='--')
        ## Textposition in Koordinaten des Achsenbereichs
        self.text = ax.text(0.72, 0.9, '', transform=ax.transAxes)

    def set_cross_hair_visible(self, visible):
        need_redraw = self.horizontal_line.get_visible()!= visible
        self.horizontal_line.set_visible(visible)
        self.vertical_line.set_visible(visible)
        self.text.set_visible(visible)
        return need_redraw

    def on_mouse_move(self, event):
        if not event.inaxes:
            need_redraw = self.set_cross_hair_visible(False)
            if need_redraw:
                self.ax.figure.canvas.draw()
        else:
            self.set_cross_hair_visible(True)
            x, y = event.xdata, event.ydata
            ## Aktualisierung der Linienpositionen
            self.horizontal_line.set_ydata([y])
            self.vertical_line.set_xdata([x])
            self.text.set_text(f'x={x:1.2f}, y={y:1.2f}')
            self.ax.figure.canvas.draw()

x = np.arange(0, 1, 0.01)
y = np.sin(2 * 2 * np.pi * x)

fig, ax = plt.subplots()
ax.set_title('Einfacher Cursor')
ax.plot(x, y, 'o')
cursor = Cursor(ax)
fig.canvas.mpl_connect('motion_notify_event', cursor.on_mouse_move)

plt.show()

Schneller Cursor mit Blitting

Der im vorherigen Schritt erstellte Cursor ist etwas langsam, da das Diagramm bei jeder Mausbewegung neu gezeichnet wird. In diesem Schritt werden wir einen Cursor erstellen, der Blitting für eine schnellere Darstellung verwendet.

class BlittedCursor:
    """
    Ein Kreuzhaarschirmcursor, der Blitting für eine schnellere Neuziehung verwendet.
    """
    def __init__(self, ax):
        self.ax = ax
        self.background = None
        self.horizontal_line = ax.axhline(color='k', lw=0.8, ls='--')
        self.vertical_line = ax.axvline(color='k', lw=0.8, ls='--')
        ## Textposition in Koordinaten des Achsenbereichs
        self.text = ax.text(0.72, 0.9, '', transform=ax.transAxes)
        self._creating_background = False
        ax.figure.canvas.mpl_connect('draw_event', self.on_draw)

    def on_draw(self, event):
        self.create_new_background()

    def set_cross_hair_visible(self, visible):
        need_redraw = self.horizontal_line.get_visible()!= visible
        self.horizontal_line.set_visible(visible)
        self.vertical_line.set_visible(visible)
        self.text.set_visible(visible)
        return need_redraw

    def create_new_background(self):
        if self._creating_background:
            ## Ignoriere Aufrufe, die von dieser Funktion selbst ausgelöst werden
            return
        self._creating_background = True
        self.set_cross_hair_visible(False)
        self.ax.figure.canvas.draw()
        self.background = self.ax.figure.canvas.copy_from_bbox(self.ax.bbox)
        self.set_cross_hair_visible(True)
        self._creating_background = False

    def on_mouse_move(self, event):
        if self.background is None:
            self.create_new_background()
        if not event.inaxes:
            need_redraw = self.set_cross_hair_visible(False)
            if need_redraw:
                self.ax.figure.canvas.restore_region(self.background)
                self.ax.figure.canvas.blit(self.ax.bbox)
        else:
            self.set_cross_hair_visible(True)
            ## Aktualisierung der Linienpositionen
            x, y = event.xdata, event.ydata
            self.horizontal_line.set_ydata([y])
            self.vertical_line.set_xdata([x])
            self.text.set_text(f'x={x:1.2f}, y={y:1.2f}')

            self.ax.figure.canvas.restore_region(self.background)
            self.ax.draw_artist(self.horizontal_line)
            self.ax.draw_artist(self.vertical_line)
            self.ax.draw_artist(self.text)
            self.ax.figure.canvas.blit(self.ax.bbox)

x = np.arange(0, 1, 0.01)
y = np.sin(2 * 2 * np.pi * x)

fig, ax = plt.subplots()
ax.set_title('Blitted cursor')
ax.plot(x, y, 'o')
blitted_cursor = BlittedCursor(ax)
fig.canvas.mpl_connect('motion_notify_event', blitted_cursor.on_mouse_move)

plt.show()

An die Datenpunkte anhaften

Der im vorherigen Schritt erstellte Cursor ist immer noch etwas langsam, da die Cursorposition bei jeder Mausbewegung aktualisiert wird. In diesem Schritt werden wir einen Cursor erstellen, der an die Datenpunkte eines Line2D-Objekts anhaftet.

class SnappingCursor:
    """
    Ein Kreuzhaarschirmcursor, der an den Datenpunkt einer Linie anhaftet, der
    am nächsten an die *x*-Position des Cursors liegt.

    Aus Gründen der Einfachheit wird hier vorausgesetzt, dass die *x*-Werte der Daten sortiert sind.
    """
    def __init__(self, ax, line):
        self.ax = ax
        self.horizontal_line = ax.axhline(color='k', lw=0.8, ls='--')
        self.vertical_line = ax.axvline(color='k', lw=0.8, ls='--')
        self.x, self.y = line.get_data()
        self._last_index = None
        ## Textposition in Achsenkoordinaten
        self.text = ax.text(0.72, 0.9, '', transform=ax.transAxes)

    def set_cross_hair_visible(self, visible):
        need_redraw = self.horizontal_line.get_visible()!= visible
        self.horizontal_line.set_visible(visible)
        self.vertical_line.set_visible(visible)
        self.text.set_visible(visible)
        return need_redraw

    def on_mouse_move(self, event):
        if not event.inaxes:
            self._last_index = None
            need_redraw = self.set_cross_hair_visible(False)
            if need_redraw:
                self.ax.figure.canvas.draw()
        else:
            self.set_cross_hair_visible(True)
            x, y = event.xdata, event.ydata
            index = min(np.searchsorted(self.x, x), len(self.x) - 1)
            if index == self._last_index:
                return  ## noch am selben Datenpunkt. Keine Aktion erforderlich.
            self._last_index = index
            x = self.x[index]
            y = self.y[index]
            ## Aktualisierung der Linienpositionen
            self.horizontal_line.set_ydata([y])
            self.vertical_line.set_xdata([x])
            self.text.set_text(f'x={x:1.2f}, y={y:1.2f}')
            self.ax.figure.canvas.draw()

x = np.arange(0, 1, 0.01)
y = np.sin(2 * 2 * np.pi * x)

fig, ax = plt.subplots()
ax.set_title('Anhaftender Cursor')
line, = ax.plot(x, y, 'o')
snap_cursor = SnappingCursor(ax, line)
fig.canvas.mpl_connect('motion_notify_event', snap_cursor.on_mouse_move)

plt.show()

Zusammenfassung

In diesem Lab haben Sie gelernt, wie man einen Kreuzhaarschirmcursor zu einem Matplotlib-Diagramm hinzufügt. Sie haben einen einfachen Cursor, einen Cursor, der Blitting für eine schnellere Darstellung verwendet, und einen Cursor erstellt, der an die Datenpunkte eines Line2D-Objekts anhaftet. Diese Cursor können hilfreich sein, um Daten zu untersuchen und Erkenntnisse aus Visualisierungen zu gewinnen.