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:

  1. FigureManagerBasey sus clases derivadas en la clase de funcionalidad central FigureManagery una clase específica de back-end WindowBasey

  2. ShowBasey sus clases derivadas en Gcf.show_ally MainLoopBase.

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_helpersy 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 FigureManagerBasey ShowBase.

  1. FigureManagerBasetiene tres trabajos en este momento:

    1. La documentación lo describe como una clase auxiliar para el modo pyplot, envuelve todo en un paquete ordenado

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

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

  2. ShowBasetiene dos trabajos:

    1. Tiene el trabajo de revisar todos los administradores de figuras registrados _pylab_helpers.Gcfy decirles que se muestren.

    2. Y en segundo lugar tiene la función de realizar el backend específico mainlooppara 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:

  1. Para eliminar el aspecto de la ventana de FigureManagerBasepermitir que simplemente envuelva esta nueva clase junto con las otras clases de back-end. Cree una nueva WindowBaseclase que pueda manejar esta funcionalidad, con métodos de transferencia (:arrow_right:) a WindowBase. Las clases de esa subclase WindowBasetambién deben subclasificar la clase de ventana específica de la GUI para garantizar la compatibilidad con versiones anteriores ( ).manager.window == manager.window

  2. Refactorice el bucle principal de ShowBaseinto MainLoopBase, que también encapsula el final del bucle. Damos una instancia de MainLoopcomo FigureManagerclave 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.

  3. Ahora que FigureManagerBaseno tiene detalles de back-end, cambie el nombre a FigureManagery muévase a un nuevo archivo y tenga en backend_managers.pycuenta que:

    1. Esto nos permite dividir la conversión de backends en PR separados, ya que podemos mantener FigureManagerBase intactas la clase existente y sus dependencias.

    2. Y esto también anticipa MEP22 donde lo nuevo NavigationBasese ha transformado en un backend independiente ToolManager.

FigureManagerBase(lienzo, número)

FigureManager(figura, número)

WindowBase(title)

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 NavigationToolbar2muy sencilla, solo necesita tocar la FigureManagerclase ú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.resizecambiar 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 FigureCanvasWxconstructor, 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 framecomo alias a la ventana, por lo que esto también rompe BC.

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 FigureManagertambié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.