MEP9: Administrador de interacción global #

Agregue un administrador global para toda la interactividad del usuario con los artistas; haga que cualquier artista se pueda cambiar de tamaño, mover, resaltar y seleccionar según lo desee el usuario.

Estado #

Discusión

Sucursales y solicitudes de extracción #

https://github.com/dhyams/matplotlib/tree/MEP9

Resumen #

El objetivo es poder interactuar con los artistas de matplotlib de una manera muy similar a como lo hacen los programas de dibujo. Cuando corresponda, el usuario debería poder mover, cambiar el tamaño o seleccionar un artista que ya se encuentra en el lienzo. Por supuesto, el guionista tiene el control en última instancia de si se puede interactuar con un artista o si es estático.

Este código para hacer esto ya se ha implementado y probado de forma privada, y debería migrarse de su implementación "mixin" actual a una parte de buena fe de matplotlib.

El resultado final sería tener cuatro nuevas palabras clave disponibles para matplotlib.artist.Artist: _moveable_, _resizeable_, _selectable_ y _highlightable_. Establecer cualquiera de estas palabras clave en True activaría la interactividad para ese artista.

En efecto, este MEP es una extensión lógica del manejo de eventos en matplotlib; matplotlib ya admite interacciones de "bajo nivel", como presionar el botón izquierdo del mouse, presionar una tecla o similar. El MEP extiende el soporte al nivel lógico, donde se realizan devoluciones de llamada a los artistas cuando se detectan ciertos gestos interactivos del usuario.

Descripción detallada #

Esta nueva funcionalidad se usaría para permitir que el usuario final interactúe mejor con el gráfico. Muchas veces, un gráfico es casi lo que el usuario quiere, pero es necesario un pequeño reposicionamiento y/o cambio de tamaño de los componentes. En lugar de obligar al usuario a volver a la secuencia de comandos para probar y fallar la ubicación, lo apropiado sería simplemente arrastrar y soltar.

Además, esto admitiría mejor las aplicaciones que usan matplotlib; aquí, el usuario final no tiene un acceso razonable o deseo de editar la fuente subyacente para afinar una trama. Aquí, si matplotlib ofreciera la capacidad, uno podría mover o cambiar el tamaño de los artistas en el lienzo para satisfacer sus necesidades. Además, el usuario debería poder resaltar (con el mouse sobre) un artista y seleccionarlo con un doble clic, si la aplicación admite ese tipo de cosas. En este MEP, también queremos admitir el resaltado y la selección de forma nativa; depende de la aplicación manejar lo que sucede cuando se selecciona el artista. Un manejo típico sería mostrar un cuadro de diálogo para editar las propiedades del artista.

En el futuro, también (esto no es parte de este MEP), matplotlib podría ofrecer diálogos de propiedades específicas del back-end para cada artista, que se generan en la selección del artista. Este eurodiputado sería un trampolín necesario para ese tipo de capacidad.

Actualmente hay algunas capacidades interactivas en matplotlib (por ejemplo, legend.draggable()), pero tienden a estar dispersas y no están disponibles para todos los artistas. Este eurodiputado busca unificar la interfaz interactiva y hacer que funcione para todos los artistas.

El MEP actual también incluye manijas de agarre para cambiar el tamaño de los artistas y cuadros apropiados dibujados cuando los artistas se mueven o cambian de tamaño.

Implementación #

  • Agregue métodos apropiados al "árbol" de artistas para que el administrador de interactividad tenga una interfaz consistente para que el administrador de interactividad se encargue. Los métodos propuestos para agregar a los artistas, si son para apoyar la interactividad, son:

    • get_pixel_position_ll(self): obtiene la posición de píxel de la esquina inferior izquierda del cuadro delimitador del artista

    • get_pixel_size(self): obtiene el tamaño del cuadro delimitador del artista, en píxeles

    • set_pixel_position_and_size(self,x,y,dx,dy): establece el nuevo tamaño del artista, de modo que se ajuste al cuadro delimitador especificado.

  • agregue capacidad a los backends para 1) proporcionar cursores, ya que estos son necesarios para la indicación visual de movimiento/cambio de tamaño, y 2) proporcionar una función que obtenga la posición actual del mouse

  • Implementar el administrador. Esto ya se ha hecho de forma privada (por dhyams) como una mezcla, y se ha probado bastante. El objetivo sería mover la funcionalidad del administrador a los artistas para que esté en matplotlib correctamente, y no como un "parche de mono" como lo tengo codificado actualmente.

Resumen actual del mixin #

(Tenga en cuenta que este mixin es por ahora solo un código privado, pero obviamente se puede agregar a una rama)

InteractiveArtistMixin:

Mixin class para hacer que cualquier objeto genérico que se dibuje en un lienzo de matplotlib se pueda mover y posiblemente cambiar de tamaño. El modelo de Powerpoint se sigue lo más fielmente posible; no porque esté enamorado de Powerpoint, sino porque eso es lo que la mayoría de la gente entiende. También se puede seleccionar un artista, lo que significa que el artista recibirá la devolución de llamada on_activated() cuando se haga doble clic. Finalmente, un artista puede ser resaltable, lo que significa que se dibuja un resaltado en el artista cada vez que se pasa el mouse. Por lo general, los artistas destacables también se podrán seleccionar, pero eso se deja en manos del usuario. Entonces, básicamente hay cuatro atributos que el usuario puede configurar por artista:

  • destacable

  • seleccionable

  • movible

  • redimensionable

Para ser móvil (arrastrable) o redimensionable, el objeto que es el objetivo del mixin debe admitir los siguientes protocolos:

  • get_pixel_position_ll(uno mismo)

  • get_pixel_size(uno mismo)

  • set_pixel_position_and_size(self,x,y,sx,sy)

Tenga en cuenta que los objetos que no se pueden cambiar de tamaño pueden ignorar los parámetros sx y sy. Para ser resaltable, el objeto que es el objetivo del mixin también debe admitir el siguiente protocolo:

  • get_highlight(uno mismo)

Lo que devuelve una lista de artistas que se utilizarán para dibujar lo más destacado.

Si el objeto que es el objetivo del mixin no es un artista de matplotlib, también se deben implementar los siguientes protocolos. Hacerlo suele ser bastante trivial, ya que tiene que haber un artista en algún lugar que esté siendo dibujado. Por lo general, su objeto solo enrutaría estas llamadas a ese artista.

  • get_figure(uno mismo)

  • get_axes(uno mismo)

  • contiene(auto,evento)

  • set_animated(yo,bandera)

  • dibujar (uno mismo, renderizador)

  • get_visible(uno mismo)

Las siguientes notificaciones se solicitan al artista, y el artista puede implementarlas opcionalmente.

  • on_select_begin(uno mismo)

  • on_select_end(uno mismo)

  • on_drag_begin(uno mismo)

  • on_drag_end(uno mismo)

  • on_activated(auto)

  • on_highlight(uno mismo)

  • on_right_click(auto,evento)

  • on_left_click(auto,evento)

  • on_middle_click(auto,evento)

  • on_context_click(auto,evento)

  • on_key_up(auto,evento)

  • on_key_down(auto,evento)

Las siguientes notificaciones se llaman en el lienzo, si ningún artista interactivo maneja el evento:

  • on_press(auto,evento)

  • on_left_click(auto,evento)

  • on_middle_click(auto,evento)

  • on_right_click(auto,evento)

  • on_context_click(auto,evento)

  • on_key_up(auto,evento)

  • on_key_down(auto,evento)

Las siguientes funciones, si están presentes, se pueden utilizar para modificar el comportamiento del objeto interactivo:

  • press_filter(self,event) # determina si el objeto quiere que se le enrute el evento de prensa

  • handle_unpicked_cursor() # puede ser utilizado por el objeto para establecer un cursor cuando el cursor pasa sobre el objeto cuando se deselecciona.

Admite múltiples lienzos, manteniendo un bloqueo de arrastre, un notificador de movimiento y una bandera global "habilitada" por lienzo. Admite cambios de tamaño de relación de aspecto fija manteniendo presionada la tecla Mayús durante el cambio de tamaño.

Problemas conocidos:

  • Zorder no se obedece durante las operaciones de selección/arrastre. Debido a la técnica de blit utilizada, no creo que esto se pueda arreglar. La única forma que se me ocurre es buscar a todos los artistas que tengan un zorder mayor que yo, ponerlos todos en animación y luego volver a dibujarlos en la parte superior durante cada actualización de arrastre. Esto podría ser muy lento; necesitas intentar.

  • el mixin solo funciona para backends de wx debido a dos cosas: 1) los cursores están codificados y 2) hay una llamada a wx.GetMousePosition() Ambas deficiencias se solucionan razonablemente al hacer que cada backend suministre estas cosas.

Compatibilidad con versiones anteriores #

No hay problemas con la compatibilidad con versiones anteriores, aunque una vez que esto esté en su lugar, sería apropiado dejar obsoletas algunas de las funciones interactivas existentes (como legend.draggable())

Alternativas #

Ninguno que yo sepa.