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:

  1. FigureManagerBasee le sue classi derivate nella classe della funzionalità principale FigureManagere in una classe specifica del backend WindowBasee

  2. ShowBasee le sue classi derivate in Gcf.show_alle MainLoopBase.

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_helperse 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 FigureManagerBasee ShowBase.

  1. FigureManagerBaseha tre lavori al momento:

    1. La documentazione lo descrive come una classe Helper per la modalità pyplot, racchiude tutto in un pacchetto ordinato

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

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

  2. ShowBaseha due lavori:

    1. Ha il compito di esaminare tutte le figure manager registrate _pylab_helpers.Gcfe dire loro di mostrarsi.

    2. E in secondo luogo ha il compito di eseguire il backend specifico mainloopper 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:

  1. Per rimuovere l'aspetto delle finestre dal FigureManagerBaselasciarlo avvolgere semplicemente questa nuova classe insieme alle altre classi di back-end. Crea una nuova WindowBaseclasse in grado di gestire questa funzionalità, con metodi pass-through (:arrow_right:) a WindowBase. Le classi che sottoclasse WindowBasedovrebbero anche sottoclassare la classe della finestra specifica della GUI per garantire la compatibilità con le versioni precedenti ( ).manager.window == manager.window

  2. Rifattorizza il mainloop di ShowBaseinto MainLoopBase, che incapsula anche la fine del ciclo. Diamo un'istanza di MainLoopto FigureManageras 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.

  3. Ora che FigureManagerBasenon contiene specifiche di back-end, rinominarlo in FigureManagere passare a un nuovo file backend_managers.pynotando che:

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

    2. E questo anticipa anche MEP22 dove il nuovo NavigationBasesi è trasformato in un backend indipendente ToolManager.

FigureManagerBase(canvas, num)

FigureManager(figura, num)

WindowBase(title)

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 NavigationToolbar2molto semplice, avendo solo bisogno di toccare la singola FigureManagerclasse

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.resizeridimensionavano 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 FigureCanvasWxcostruttore, 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 framecome alias di window, quindi anche questo interrompe BC.

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