MEP27 : Découpler pyplot des backends #
Statut #
Progrès
Branches et demandes d'extraction #
PR principal (y compris GTK3):
Différences de branche spécifiques au backend :
Résumé #
Ce MEP refactorise les backends pour donner une API plus structurée et cohérente, en supprimant le code générique et en consolidant le code existant. Pour ce faire, nous vous proposons de diviser :
FigureManagerBase
et ses classes dérivées dans la classe de fonctionnalité de baseFigureManager
et une classe spécifique au backendWindowBase
etShowBase
et ses classes dérivées dansGcf.show_all
etMainLoopBase
.
Descriptif détaillé #
Ce MEP vise à consolider l'API backends en une seule API uniforme, en supprimant le code générique du backend (qui inclut
_pylab_helpers
et Gcf
), et à pousser le code à un niveau plus approprié dans matplotlib. Avec cela, nous supprimons automatiquement les incohérences qui apparaissent dans les backends, telles que
parfois définir le canevas, et d'autres fois définir la fenêtre entière aux dimensions données, en fonction du backend.FigureManagerBase.resize(w, h)
Deux endroits principaux pour le code générique apparaissent dans les classes dérivées de
FigureManagerBase
et ShowBase
.
FigureManagerBase
a trois emplois en ce moment :La documentation le décrit comme une classe Helper pour le mode pyplot, encapsule tout dans un ensemble soigné
Mais il ne se contente pas d'envelopper le canevas et la barre d'outils, il effectue également toutes les tâches de fenêtrage lui-même. La fusion de ces deux tâches est mieux vue dans la ligne suivante : Cela combine le code spécifique au backend avec le code générique matplotlib .
self.set_window_title("Figure %d" % num)
self.set_window_title(title)
title = "Figure %d" % num
Actuellement, la sous-classe spécifique au backend
FigureManager
décide quand mettre fin à la boucle principale. Cela semble également très faux car la figure ne devrait avoir aucun contrôle sur les autres figures.
ShowBase
a deux métiers :Il a pour tâche de passer en revue tous les managers de personnages enregistrés
_pylab_helpers.Gcf
et de leur dire de se montrer.Et deuxièmement, il a pour tâche d'effectuer le backend spécifique
mainloop
pour bloquer le programme principal et ainsi empêcher les chiffres de mourir.
Mise en œuvre #
La description de ce MEP nous donne l'essentiel de la solution :
Pour supprimer l'aspect fenêtrage de le
FigureManagerBase
laisser simplement envelopper cette nouvelle classe avec les autres classes principales. Créez une nouvelleWindowBase
classe qui peut gérer cette fonctionnalité, avec des méthodes pass-through (:arrow_right:) àWindowBase
. Les classes de cette sous-classeWindowBase
doivent également sous-classer la classe de fenêtre spécifique à l'interface graphique pour assurer la compatibilité ascendante ( ).manager.window == manager.window
Refactorisez la boucle principale de
ShowBase
dansMainLoopBase
, qui encapsule également la fin de la boucle. Nous donnons une instance deMainLoop
toFigureManager
en tant que clé pour déverrouiller la méthode de sortie (nécessitant que toutes les clés soient renvoyées avant que la boucle puisse mourir). Notez que cela ouvre la possibilité à plusieurs backends de s'exécuter simultanément.Maintenant, cela
FigureManagerBase
n'a pas de détails sur le backend, pour le renommer enFigureManager
, et passer à un nouveau fichier enbackend_managers.py
notant que :Cela nous permet de diviser la conversion des backends en PR séparés car nous pouvons garder la
FigureManagerBase
classe existante et ses dépendances intactes.Et cela anticipe également MEP22 où le nouveau
NavigationBase
s'est transformé en un backend indépendantToolManager
.
FigureManagerBase(toile, nombre) |
FigureManager(chiffre, num) |
|
Remarques |
---|---|---|---|
Afficher |
Afficher |
||
détruire |
appelle destroy sur tous les composants |
détruire |
|
full_screen_toggle |
gère la logique |
set_fullscreen |
|
redimensionner |
redimensionner |
||
appuyez sur la touche |
appuyez sur la touche |
||
get_window_title |
get_window_title |
||
set_window_title |
set_window_title |
||
_get_toolbar |
Une méthode commune à toutes les sous-classes de FigureManagerBase |
||
set_default_size |
|||
add_element_to_window |
AfficherBase |
MainLoopBase |
Remarques |
---|---|---|
boucle principale |
commencer |
|
fin |
Est appelé automatiquement lorsqu'il n'existe plus d'instances de la sous-classe |
|
__appel__ |
Méthode déplacée vers Gcf.show_all |
Compatibilité future #
Comme évoqué ci-dessus lors de la discussion de MEP 22, ce refactor facilite l'ajout de nouvelles fonctionnalités génériques. Pour le moment, MEP 22 doit faire de vilains hacks à chaque classe allant de FigureManagerBase
. Avec ce code, cela ne doit être fait que dans la seule FigureManager
classe. Cela rend également la dépréciation ultérieure de
NavigationToolbar2
très simple, n'ayant besoin que de toucher la seule FigureManager
classe
MEP 23 constitue un autre cas d'utilisation où ce code refactorisé sera très pratique.
Rétrocompatibilité #
Comme nous laissons tout le code backend intact, en ajoutant uniquement les méthodes manquantes aux classes existantes, cela devrait fonctionner de manière transparente pour tous les cas d'utilisation. La seule différence résidera pour les backends qui
FigureManager.resize
redimensionnaient le canevas et non la fenêtre, en raison de la standardisation de l'API.
J'envisagerais que les classes rendues obsolètes par ce refactor soient obsolètes et supprimées selon le même calendrier que
NavigationToolbar2
, notez également que le changement de signature d'appel au FigureCanvasWx
constructeur, bien que rétrocompatible, je pense que l'ancienne signature (à mon humble avis) devrait être obsolète et supprimé de la même manière que tout le reste.
backend |
manager.resize(w,h) |
En plus |
---|---|---|
gtk3 |
la fenêtre |
|
TK |
Toile |
|
Qt |
la fenêtre |
|
Wx |
Toile |
FigureManagerWx avait
|
Alternatives #
S'il existait des solutions alternatives pour résoudre le même problème, elles devraient être discutées ici, accompagnées d'une justification de l'approche choisie.
Questions #
Mdehoon : Pouvez-vous nous expliquer comment exécuter plusieurs backends simultanément ?
OceanWolf : @mdehoon, comme je l'ai dit, pas pour ce député européen, mais je vois que ce député européen l'ouvre comme une possibilité future. Fondamentalement, la MainLoopBase
classe agit comme un Gcf par backend, dans ce MEP, elle suit le nombre de chiffres ouverts par backend et gère les boucles principales pour ces backends. Il ferme la boucle principale spécifique au backend lorsqu'il détecte qu'aucune figure ne reste ouverte pour ce backend. Pour cette raison, j'imagine qu'avec seulement quelques ajustements, nous pouvons créer un matplotlib multi-backend complet. Aucune idée encore pourquoi on voudrait, mais je laisse la possibilité là-bas dans MainLoopBase. Avec toutes les spécificités du code backend refactorisées, FigureManager
cela aide également à cela, un gestionnaire pour les gouverner tous (les backends).
Mdehoon : @OceanWolf, d'accord, merci pour l'explication. Avoir une API uniforme pour les backends est très important pour la maintenabilité de matplotlib. Je pense que ce député européen est un pas dans la bonne direction.