MEP27: Desacoplar pyplot de backends #
Estado #
Progreso
Sucursales y solicitudes de extracción #
PR principal (incluyendo GTK3):
Diferencias de rama específicas de backend:
Resumen #
Este MEP refactoriza los backends para brindar una API más estructurada y consistente, eliminando el código genérico y consolidando el código existente. Para ello proponemos dividir:
FigureManagerBase
y sus clases derivadas en la clase de funcionalidad centralFigureManager
y una clase específica de back-endWindowBase
yShowBase
y sus clases derivadas enGcf.show_all
yMainLoopBase
.
Descripción detallada #
Este MEP tiene como objetivo consolidar la API de backends en una sola API uniforme, eliminando el código genérico del backend (que incluye
_pylab_helpers
y Gcf
) y empujando el código a un nivel más apropiado en matplotlib. Con esto eliminamos automáticamente las inconsistencias que aparecen en los backends, como
que a veces configura el lienzo, y otras veces configura toda la ventana a las dimensiones dadas, dependiendo del backend.FigureManagerBase.resize(w, h)
Dos lugares principales para el código genérico aparecen en las clases derivadas de
FigureManagerBase
y ShowBase
.
FigureManagerBase
tiene tres trabajos en este momento:La documentación lo describe como una clase auxiliar para el modo pyplot, envuelve todo en un paquete ordenado
Pero no solo envuelve el lienzo y la barra de herramientas, sino que también realiza todas las tareas de creación de ventanas. La combinación de estas dos tareas se ve mejor en la siguiente línea: Esto combina el código específico del backend con el código genérico de matplotlib .
self.set_window_title("Figure %d" % num)
self.set_window_title(title)
title = "Figure %d" % num
Actualmente, la subclase específica de back -end
FigureManager
decide cuándo finalizar el bucle principal. Esto también parece muy incorrecto ya que la figura no debería tener control sobre las otras figuras.
ShowBase
tiene dos trabajos:Tiene el trabajo de revisar todos los administradores de figuras registrados
_pylab_helpers.Gcf
y decirles que se muestren.Y en segundo lugar tiene la función de realizar el backend específico
mainloop
para bloquear el programa principal y así evitar que mueran las figuras.
Implementación #
La descripción de este eurodiputado nos da la mayor parte de la solución:
Para eliminar el aspecto de la ventana de
FigureManagerBase
permitir que simplemente envuelva esta nueva clase junto con las otras clases de back-end. Cree una nuevaWindowBase
clase que pueda manejar esta funcionalidad, con métodos de transferencia (:arrow_right:) aWindowBase
. Las clases de esa subclaseWindowBase
también deben subclasificar la clase de ventana específica de la GUI para garantizar la compatibilidad con versiones anteriores ( ).manager.window == manager.window
Refactorice el bucle principal de
ShowBase
intoMainLoopBase
, que también encapsula el final del bucle. Damos una instancia deMainLoop
comoFigureManager
clave para desbloquear el método de salida (que requiere que se devuelvan todas las claves antes de que el ciclo pueda morir). Tenga en cuenta que esto abre la posibilidad de que varios backends se ejecuten simultáneamente.Ahora que
FigureManagerBase
no tiene detalles de back-end, cambie el nombre aFigureManager
y muévase a un nuevo archivo y tenga enbackend_managers.py
cuenta que:Esto nos permite dividir la conversión de backends en PR separados, ya que podemos mantener
FigureManagerBase
intactas la clase existente y sus dependencias.Y esto también anticipa MEP22 donde lo nuevo
NavigationBase
se ha transformado en un backend independienteToolManager
.
FigureManagerBase(lienzo, número) |
FigureManager(figura, número) |
|
notas |
---|---|---|---|
mostrar |
mostrar |
||
destruir |
llama a destruir en todos los componentes |
destruir |
|
alternar_pantalla_completa |
maneja la lógica |
establecer_pantalla completa |
|
cambiar el tamaño |
cambiar el tamaño |
||
pulsar_tecla |
pulsar_tecla |
||
get_window_title |
get_window_title |
||
establecer_ventana_título |
establecer_ventana_título |
||
_get_barra de herramientas |
Un método común para todas las subclases de FigureManagerBase |
||
establecer_tamaño_predeterminado |
|||
agregar_elemento_a_la_ventana |
ShowBase |
MainLoopBase |
notas |
---|---|---|
bucle principal |
empezar |
|
final |
Se llama automáticamente cuando no existen más instancias de la subclase |
|
__llamar__ |
Método movido a Gcf.show_all |
Compatibilidad futura #
Como se eludió anteriormente cuando se discutió el MEP 22, este refactor facilita la adición de nuevas características genéricas. Por el momento, MEP 22 tiene que hacer feos trucos para cada clase que se extiende desde FigureManagerBase
. Con este código, esto solo necesita hacerse en la FigureManager
clase única. Esto también hace que la desaprobación posterior de sea
NavigationToolbar2
muy sencilla, solo necesita tocar la FigureManager
clase única
MEP 23 es otro caso de uso en el que este código refactorizado será muy útil.
Compatibilidad con versiones anteriores #
Como dejamos intacto todo el código de back-end, solo agregamos los métodos faltantes a las clases existentes, esto debería funcionar sin problemas para todos los casos de uso. La única diferencia radicará en los backends que solían
FigureManager.resize
cambiar el tamaño del lienzo y no de la ventana, debido a la estandarización de la API.
Me imagino que las clases obsoletas por este refactor quedan en desuso y se eliminan en el mismo horario que
NavigationToolbar2
, también tenga en cuenta que el cambio en la firma de llamada al FigureCanvasWx
constructor, aunque es compatible con versiones anteriores, creo que la firma anterior (en mi humilde opinión, estilo feo) debería quedar en desuso y eliminado de la misma manera que todo lo demás.
back-end |
manager.resize(w,h) |
Extra |
---|---|---|
gtk3 |
ventana |
|
Tk |
lienzo |
|
Qt |
ventana |
|
Ancho x |
lienzo |
FigureManagerWx tenía
|
Alternativas #
Si existieran soluciones alternativas para resolver el mismo problema, deben discutirse aquí, junto con una justificación del enfoque elegido.
Preguntas #
Mdehoon: ¿Puede dar más detalles sobre cómo ejecutar varios backends al mismo tiempo?
OceanWolf: @mdehoon, como digo, no para este eurodiputado, pero veo que este eurodiputado lo abre como una posibilidad futura. Básicamente, la MainLoopBase
clase actúa como un Gcf por backend, en este MEP rastrea la cantidad de figuras abiertas por backend y administra los bucles principales para esos backends. Cierra el mainloop específico del backend cuando detecta que no quedan cifras abiertas para ese backend. Debido a esto, me imagino que con solo una pequeña cantidad de ajustes podemos hacer matplotlib de backend múltiple completo. Aún no tengo idea de por qué uno querría hacerlo, pero dejo la posibilidad allí en MainLoopBase. Con todas las especificaciones del código de backend refactorizadas FigureManager
también ayuda en esto, un administrador para gobernarlos (los backends) a todos.
Mdehoon: @OceanWolf, OK, gracias por la explicación. Tener una API uniforme para los backends es muy importante para la mantenibilidad de matplotlib. Creo que este eurodiputado es un paso en la dirección correcta.