MEP27: Disaccoppia pyplot dai backend #
Stato n.
Progresso
Filiali e Pull request #
PR principale (incluso GTK3):
Differenze di ramo specifiche del backend:
Estratto n.
Questo MEP esegue il refactoring dei backend per fornire un'API più strutturata e coerente, rimuovendo il codice generico e consolidando il codice esistente. Per fare questo proponiamo la suddivisione:
FigureManagerBase
e le sue classi derivate nella classe della funzionalità principaleFigureManager
e in una classe specifica del backendWindowBase
eShowBase
e le sue classi derivate inGcf.show_all
eMainLoopBase
.
Descrizione dettagliata #
Questo MEP mira a consolidare l'API back-end in un'unica API uniforme, rimuovendo il codice generico dal back-end (che include
_pylab_helpers
e Gcf
) e spingendo il codice a un livello più appropriato in matplotlib. Con questo rimuoviamo automaticamente le incoerenze che appaiono nei backend, come ad esempio
che a volte imposta la tela, e altre volte imposta l'intera finestra alle dimensioni date, a seconda del backend.FigureManagerBase.resize(w, h)
Due posti principali per il codice generico appaiono nelle classi derivate da
FigureManagerBase
e ShowBase
.
FigureManagerBase
ha tre lavori al momento:La documentazione lo descrive come una classe Helper per la modalità pyplot, racchiude tutto in un pacchetto ordinato
Ma non avvolge solo la tela e la barra degli strumenti, ma esegue anche tutte le attività di windowing. La fusione di queste due attività viene vista al meglio nella riga seguente: Questo combina il codice specifico del back-end con il codice generico matplotlib .
self.set_window_title("Figure %d" % num)
self.set_window_title(title)
title = "Figure %d" % num
Attualmente la sottoclasse specifica del backend
FigureManager
decide quando terminare il mainloop. Anche questo sembra molto sbagliato in quanto la figura non dovrebbe avere alcun controllo sulle altre figure.
ShowBase
ha due lavori:Ha il compito di esaminare tutte le figure manager registrate
_pylab_helpers.Gcf
e dire loro di mostrarsi.E in secondo luogo ha il compito di eseguire il backend specifico
mainloop
per bloccare il programma principale e quindi evitare che le figure muoiano.
Implementazione n.
La descrizione di questo eurodeputato ci dà la maggior parte della soluzione:
Per rimuovere l'aspetto delle finestre dal
FigureManagerBase
lasciarlo avvolgere semplicemente questa nuova classe insieme alle altre classi di back-end. Crea una nuovaWindowBase
classe in grado di gestire questa funzionalità, con metodi pass-through (:arrow_right:) aWindowBase
. Le classi che sottoclasseWindowBase
dovrebbero anche sottoclassare la classe della finestra specifica della GUI per garantire la compatibilità con le versioni precedenti ( ).manager.window == manager.window
Rifattorizza il mainloop di
ShowBase
intoMainLoopBase
, che incapsula anche la fine del ciclo. Diamo un'istanza diMainLoop
toFigureManager
as a key unlock the exit method (richiedendo che tutte le chiavi vengano restituite prima che il ciclo possa morire). Nota che questo apre la possibilità di eseguire contemporaneamente più back-end.Ora che
FigureManagerBase
non contiene specifiche di back-end, rinominarlo inFigureManager
e passare a un nuovo filebackend_managers.py
notando che:Questo ci consente di suddividere la conversione dei backend in PR separati in quanto possiamo mantenere intatte la
FigureManagerBase
classe esistente e le sue dipendenze.E questo anticipa anche MEP22 dove il nuovo
NavigationBase
si è trasformato in un backend indipendenteToolManager
.
FigureManagerBase(canvas, num) |
FigureManager(figura, num) |
|
Appunti |
---|---|---|---|
mostrare |
mostrare |
||
distruggere |
chiama destroy su tutti i componenti |
distruggere |
|
full_screen_toggle |
gestisce la logica |
set_schermo intero |
|
ridimensiona |
ridimensiona |
||
key_press |
key_press |
||
get_window_title |
get_window_title |
||
set_finestra_titolo |
set_finestra_titolo |
||
_get_toolbar |
Un metodo comune a tutte le sottoclassi di FigureManagerBase |
||
set_default_size |
|||
add_element_to_window |
MostraBase |
MainLoopBase |
Appunti |
---|---|---|
mainloop |
inizio |
|
fine |
Viene chiamato automaticamente quando non esistono più istanze della sottoclasse |
|
__chiamata__ |
Metodo spostato in Gcf.show_all |
Compatibilità futura #
Come accennato in precedenza durante la discussione su MEP 22, questo refactor semplifica l'aggiunta di nuove funzionalità generiche. Al momento, MEP 22 deve fare brutti hack a ogni classe che si estende da FigureManagerBase
. Con questo codice, questo deve essere fatto solo nella singola FigureManager
classe. Questo rende anche la successiva deprecazione di
NavigationToolbar2
molto semplice, avendo solo bisogno di toccare la singola FigureManager
classe
MEP 23 rappresenta un altro caso d'uso in cui questo codice refactored sarà molto utile.
Compatibilità con le versioni precedenti #
Poiché lasciamo intatto tutto il codice di backend, aggiungendo solo i metodi mancanti alle classi esistenti, questo dovrebbe funzionare senza problemi per tutti i casi d'uso. L'unica differenza starà per i backend che prima
FigureManager.resize
ridimensionavano il canvas e non la finestra, a causa della standardizzazione dell'API.
Immagino che le classi rese obsolete da questo refactor vengano deprecate e rimosse con lo stesso calendario di
NavigationToolbar2
, si noti inoltre che la modifica della firma della chiamata al FigureCanvasWx
costruttore, sebbene compatibile con le versioni precedenti, penso che la vecchia firma (imho brutto stile) dovrebbe essere deprecata e rimosso allo stesso modo di tutto il resto.
back-end |
manager.resize(w,h) |
Extra |
---|---|---|
gtk3 |
finestra |
|
Tk |
tela |
|
Qt |
finestra |
|
Wx |
tela |
FigureManagerWx aveva
|
Alternative #
Se esistessero soluzioni alternative per risolvere lo stesso problema, dovrebbero essere discusse qui, insieme a una giustificazione per l'approccio scelto.
Domande #
Mdehoon: Puoi approfondire come eseguire più backend contemporaneamente?
OceanWolf: @mdehoon, come ho detto, non per questo eurodeputato, ma vedo che questo eurodeputato lo apre come una possibilità futura. Fondamentalmente la MainLoopBase
classe agisce un Gcf per backend, in questo MEP tiene traccia del numero di figure aperte per backend e gestisce i mainloop per quei backend. Chiude il mainloop specifico del backend quando rileva che nessuna cifra rimane aperta per quel backend. Per questo motivo, immagino che con solo una piccola quantità di modifiche possiamo eseguire matplotlib full-multi-backend. Non ho ancora idea del motivo per cui uno vorrebbe, ma lascio la possibilità lì in MainLoopBase. Con tutte le specifiche del codice di back-end rifattorizzate FigureManager
anche in questo, un manager per governarli (i back-end) tutti.
Mdehoon: @OceanWolf, OK, grazie per la spiegazione. Avere un'API uniforme per i backend è molto importante per la manutenibilità di matplotlib. Penso che questo eurodeputato sia un passo nella giusta direzione.