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 :

  1. FigureManagerBaseet ses classes dérivées dans la classe de fonctionnalité de base FigureManageret une classe spécifique au backend WindowBaseet

  2. ShowBaseet ses classes dérivées dans Gcf.show_allet MainLoopBase.

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_helperset 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 FigureManagerBaseet ShowBase.

  1. FigureManagerBasea trois emplois en ce moment :

    1. La documentation le décrit comme une classe Helper pour le mode pyplot, encapsule tout dans un ensemble soigné

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

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

  2. ShowBasea deux métiers :

    1. Il a pour tâche de passer en revue tous les managers de personnages enregistrés _pylab_helpers.Gcfet de leur dire de se montrer.

    2. Et deuxièmement, il a pour tâche d'effectuer le backend spécifique mainlooppour 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 :

  1. Pour supprimer l'aspect fenêtrage de le FigureManagerBaselaisser simplement envelopper cette nouvelle classe avec les autres classes principales. Créez une nouvelle WindowBaseclasse qui peut gérer cette fonctionnalité, avec des méthodes pass-through (:arrow_right:) à WindowBase. Les classes de cette sous-classe WindowBasedoivent également sous-classer la classe de fenêtre spécifique à l'interface graphique pour assurer la compatibilité ascendante ( ).manager.window == manager.window

  2. Refactorisez la boucle principale de ShowBasedans MainLoopBase, qui encapsule également la fin de la boucle. Nous donnons une instance de MainLoopto FigureManageren 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.

  3. Maintenant, cela FigureManagerBasen'a pas de détails sur le backend, pour le renommer en FigureManager, et passer à un nouveau fichier en backend_managers.pynotant que :

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

    2. Et cela anticipe également MEP22 où le nouveau NavigationBases'est transformé en un backend indépendant ToolManager.

FigureManagerBase(toile, nombre)

FigureManager(chiffre, num)

WindowBase(title)

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 NavigationToolbar2très simple, n'ayant besoin que de toucher la seule FigureManagerclasse

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.resizeredimensionnaient 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 FigureCanvasWxconstructeur, 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 framecomme alias pour window, donc cela casse également BC.

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, FigureManagercela 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.