MEP27: Pyplot von Backends entkoppeln #

Status #

Fortschritt

Branches und Pull-Requests #

Haupt-PR (einschließlich GTK3):

Backend-spezifische Branch-Diffs:

Zusammenfassung #

Dieser MEP überarbeitet die Backends, um eine strukturiertere und konsistentere API zu erhalten, entfernt generischen Code und konsolidiert bestehenden Code. Dazu schlagen wir eine Aufteilung vor:

  1. FigureManagerBaseund ihre abgeleiteten Klassen in die Kernfunktionalitätsklasse FigureManagerund eine Backend-spezifische Klasse WindowBaseund

  2. ShowBaseund seine abgeleiteten Klassen in Gcf.show_allund MainLoopBase.

Detaillierte Beschreibung #

Dieses MEP zielt darauf ab, die Backend-API in einer einzigen einheitlichen API zu konsolidieren, generischen Code aus dem Backend (einschließlich _pylab_helpersund Gcf) zu entfernen und Code auf eine angemessenere Ebene in matplotlib zu verschieben. Damit entfernen wir automatisch Inkonsistenzen, die in den Backends auftreten, wie z. B. die manchmal den Canvas setzen und manchmal das gesamte Fenster auf die angegebenen Abmessungen setzen, je nach Backend.FigureManagerBase.resize(w, h)

Two main places for generic code appear in the classes derived from FigureManagerBase and ShowBase.

  1. FigureManagerBase has three jobs at the moment:

    1. The documentation describes it as a Helper class for pyplot mode, wraps everything up into a neat bundle

    2. But it doesn't just wrap the canvas and toolbar, it also does all of the windowing tasks itself. The conflation of these two tasks gets seen the best in the following line: self.set_window_title("Figure %d" % num) This combines backend specific code self.set_window_title(title) with matplotlib generic code title = "Figure %d" % num.

    3. Currently the backend specific subclass of FigureManager decides when to end the mainloop. This also seems very wrong as the figure should have no control over the other figures.

  2. ShowBase has two jobs:

    1. Es hat die Aufgabe, alle registrierten Figurenmanager durchzugehen _pylab_helpers.Gcfund ihnen zu sagen, dass sie sich zeigen sollen.

    2. Und zweitens hat es die Aufgabe, das Backend spezifisch auszuführen mainloop, um das Hauptprogramm zu blockieren und so das Zahlensterben zu verhindern.

Implementierung #

Die Beschreibung dieses Abgeordneten gibt uns den größten Teil der Lösung:

  1. Um den Windowing-Aspekt aus dem Zulassen zu entfernen, FigureManagerBasepacken Sie einfach diese neue Klasse zusammen mit den anderen Backend-Klassen ein. Erstellen Sie eine neue WindowBaseKlasse, die diese Funktionalität handhaben kann, mit Pass-Through-Methoden (:arrow_right:) bis WindowBase. Von Klassen, die eine Unterklasse bilden, WindowBasesollte auch die GUI-spezifische Fensterklasse abgeleitet werden, um die Abwärtskompatibilität zu gewährleisten ( ).manager.window == manager.window

  2. Refaktorieren Sie die Hauptschleife von ShowBasein MainLoopBase, die auch das Ende der Schleife kapselt. Wir geben eine Instanz von MainLoopto FigureManagerals Schlüssel, um die Exit-Methode zu entsperren (wobei alle Schlüssel zurückgegeben werden müssen, bevor die Schleife sterben kann). Beachten Sie, dass dies die Möglichkeit eröffnet, dass mehrere Backends gleichzeitig ausgeführt werden.

  3. Nun, FigureManagerBasedas enthält keine Backend-Besonderheiten, um es in umzubenennen FigureManagerund in eine neue Datei zu verschieben, wobei Folgendes zu backend_managers.pybeachten ist:

    1. Dadurch können wir die Konvertierung von Backends in separate PRs aufteilen, da wir die vorhandene FigureManagerBase Klasse und ihre Abhängigkeiten intakt halten können.

    2. Und dies nimmt auch MEP22 vorweg, wo sich das neue NavigationBasein ein unabhängiges Backend verwandelt hat ToolManager.

FigureManagerBase(canvas, num)

FigureManager(Zahl, Zahl)

WindowBase(title)

Anmerkungen

Show

Show

zerstören

ruft auf allen Komponenten destrue auf

zerstören

full_screen_toggle

behandelt Logik

set_fullscreen

Größe ändern

Größe ändern

Tastendruck

Tastendruck

get_window_title

get_window_title

set_window_title

set_window_title

_get_toolbar

Eine gemeinsame Methode für alle Unterklassen von FigureManagerBase

set_default_size

add_element_to_window

ShowBase

MainLoopBase

Anmerkungen

Hauptschleife

Start

Ende

Wird automatisch aufgerufen, wenn keine Instanzen der Unterklasse mehr existieren

__Anruf__

Methode nach Gcf.show_all verschoben

Zukunftskompatibilität #

Wie oben bei der Erörterung von MEP 22 umgangen, erleichtert dieser Refactor das Hinzufügen neuer generischer Funktionen. Im Moment muss MEP 22 hässliche Hacks für jede Klasse machen, die von FigureManagerBase. Mit diesem Code muss dies nur in der Einzelklasse gemacht FigureManager werden. Dies macht auch die spätere Abwertung sehr einfach, da nur die einzelne Klasse NavigationToolbar2berührt werden mussFigureManager

MEP 23 ist ein weiterer Anwendungsfall, bei dem sich dieser umgestaltete Code als sehr nützlich erweisen wird.

Abwärtskompatibilität #

Da wir den gesamten Backend-Code intakt lassen und nur fehlende Methoden zu vorhandenen Klassen hinzufügen, sollte dies für alle Anwendungsfälle nahtlos funktionieren. FigureManager.resizeDer einzige Unterschied besteht aufgrund der Standardisierung der API für Backends, die früher die Größe der Leinwand und nicht des Fensters geändert haben.

Ich würde mir vorstellen, dass die Klassen, die durch diesen Refactor obsolet gemacht wurden, veraltet sind und im selben Zeitplan wie entfernt NavigationToolbar2werden. Beachten Sie auch, dass die Änderung der Aufrufsignatur für den FigureCanvasWxKonstruktor zwar abwärtskompatibel ist, aber ich denke, dass die alte Signatur (imho hässlicher Stil) veraltet sein sollte und auf die gleiche Weise wie alles andere entfernt.

Backend

manager.resize(w,h)

Extra

gtk3

Fenster

Tk

Leinwand

Qt

Fenster

Wx

Leinwand

FigureManagerWx hatte frameals Alias ​​für window, also unterbricht dies auch BC.

Alternativen #

Wenn es alternative Lösungen zur Lösung des gleichen Problems gibt, sollten diese hier diskutiert werden, zusammen mit einer Begründung für den gewählten Ansatz.

Fragen #

Mdehoon: Können Sie erläutern, wie Sie mehrere Backends gleichzeitig ausführen können?

OceanWolf: @mdehoon, wie ich schon sagte, nicht für diesen Abgeordneten, aber ich sehe, dass dieser Abgeordnete es als zukünftige Möglichkeit eröffnet. Grundsätzlich fungiert die MainLoopBase Klasse als Gcf pro Backend, in diesem MEP verfolgt sie die Anzahl der pro Backend geöffneten Figuren und verwaltet die Hauptschleifen für diese Backends. Es schließt die Backend-spezifische Hauptschleife, wenn es feststellt, dass für dieses Backend keine Zahlen offen bleiben. Aus diesem Grund stelle ich mir vor, dass wir mit nur wenigen Anpassungen eine vollständige Multi-Backend-Matplotlib erstellen können. Noch keine Ahnung, warum man das wollen sollte, aber ich lasse die Möglichkeit in MainLoopBase da. Mit all den Back-End-Code-Besonderheiten, die FigureManagerauch umgestaltet wurden, hilft dabei ein Manager, der sie (die Back-Ends) alle regiert.

Mdehoon: @OceanWolf, OK, danke für die Erklärung. Eine einheitliche API für die Backends zu haben, ist sehr wichtig für die Wartbarkeit von matplotlib. Ich denke, dieser Abgeordnete ist ein Schritt in die richtige Richtung.