MEP9: Gerente de interação global #

Adicione um gerenciador global para toda a interatividade do usuário com os artistas; torne qualquer artista redimensionável, móvel, destacável e selecionável conforme desejado pelo usuário.

Estado #

Discussão

Filiais e solicitações pull #

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

Resumo #

O objetivo é ser capaz de interagir com os artistas do matplotlib de uma maneira muito semelhante à dos programas de desenho. Quando apropriado, o usuário deve ser capaz de mover, redimensionar ou selecionar um artista que já esteja na tela. Claro, o roteirista está em última instância no controle se um artista pode ser interagido ou se é estático.

Este código para fazer isso já foi implementado e testado de forma privada e precisaria ser migrado de sua implementação "mixin" atual para uma parte genuína do matplotlib.

O resultado final seria ter quatro novas palavras-chave disponíveis para matplotlib.artist.Artist: _moveable_, _resizeable_, _selectable_ e _highlightable_. Definir qualquer uma dessas palavras-chave como True ativaria a interatividade para esse artista.

Na verdade, esse MEP é uma extensão lógica da manipulação de eventos em matplotlib; matplotlib já oferece suporte a interações de "baixo nível", como pressionar o botão esquerdo do mouse, pressionar uma tecla ou similar. O MEP estende o suporte ao nível lógico, onde callbacks são executados nos artistas quando determinados gestos interativos do usuário são detectados.

Descrição detalhada #

Essa nova funcionalidade seria usada para permitir que o usuário final interaja melhor com o gráfico. Muitas vezes, um gráfico é quase o que o usuário deseja, mas é necessário um pequeno reposicionamento e/ou redimensionamento dos componentes. Em vez de forçar o usuário a voltar ao script para tentar e errar o local, um simples arrastar e soltar seria apropriado.

Além disso, isso daria melhor suporte a aplicativos que usam matplotlib; aqui, o usuário final não tem acesso ou desejo razoável de editar a fonte subjacente para ajustar um gráfico. Aqui, se o matplotlib oferecesse a capacidade, era possível mover ou redimensionar os artistas na tela para atender às suas necessidades. Além disso, o usuário deve ser capaz de destacar (com o mouse sobre) um artista e selecioná-lo com um clique duplo, se o aplicativo suportar esse tipo de coisa. Neste MEP, também queremos oferecer suporte nativo ao realce e seleção; cabe ao aplicativo lidar com o que acontece quando o artista é selecionado. Um tratamento típico seria exibir uma caixa de diálogo para editar as propriedades do artista.

No futuro, também (isso não faz parte deste MEP), matplotlib poderia oferecer diálogos de propriedade específicos de back-end para cada artista, que são gerados na seleção do artista. Este MPE seria um trampolim necessário para esse tipo de capacidade.

Atualmente, existem alguns recursos interativos no matplotlib (por exemplo, legend.draggable()), mas eles tendem a ser dispersos e não estão disponíveis para todos os artistas. Este MEP busca unificar a interface interativa e fazê-la funcionar para todos os artistas.

O MEP atual também inclui alças para redimensionar artistas e caixas apropriadas desenhadas quando os artistas são movidos ou redimensionados.

Implementação #

  • Adicione métodos apropriados à "árvore" de artistas para que o gerenciador de interatividade tenha uma interface consistente para o gerenciador de interatividade lidar. Os métodos propostos para agregar aos artistas, caso sejam de suporte à interatividade, são:

    • get_pixel_position_ll(self): obtém a posição do pixel do canto inferior esquerdo da caixa delimitadora do artista

    • get_pixel_size(self): obtém o tamanho da caixa delimitadora do artista, em pixels

    • set_pixel_position_and_size(self,x,y,dx,dy): define o novo tamanho do artista, de forma que caiba dentro da caixa delimitadora especificada.

  • adicionar capacidade aos back-ends para 1) fornecer cursores, uma vez que são necessários para indicação visual de movimento/redimensionamento e 2) fornecer uma função que obtém a posição atual do mouse

  • Implemente o gerenciador. Isso já foi feito em particular (por dhyams) como um mixin e foi bastante testado. O objetivo seria mover a funcionalidade do gerenciador para os artistas de modo que esteja no matplotlib corretamente, e não como um "patch de macaco" como eu o codifiquei atualmente.

Resumo atual do mixin #

(Observe que este mixin é por enquanto apenas código privado, mas pode ser adicionado a um branch obviamente)

InteractiveArtistMixin:

Mixin para tornar qualquer objeto genérico desenhado em uma tela matplotlib móvel e possivelmente redimensionável. O modelo Powerpoint é seguido o mais próximo possível; não porque sou apaixonado por Powerpoint, mas porque é isso que a maioria das pessoas entende. Um artista também pode ser selecionável, o que significa que o artista receberá o callback on_activated() quando clicar duas vezes. Por fim, um artista pode ser destacado, o que significa que um destaque é desenhado no artista sempre que o mouse passa sobre ele. Normalmente, os artistas destacáveis ​​também podem ser selecionados, mas isso é deixado para o usuário. Então, basicamente, existem quatro atributos que podem ser definidos pelo usuário por artista:

  • destacável

  • selecionável

  • móvel

  • redimensionável

Para ser móvel (arrastável) ou redimensionável, o objeto alvo do mixin deve suportar os seguintes protocolos:

  • get_pixel_position_ll(self)

  • get_pixel_size(auto)

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

Observe que objetos não redimensionáveis ​​podem ignorar os parâmetros sx e sy. Para ser destacável, o objeto alvo do mixin também deve suportar o seguinte protocolo:

  • get_highlight(self)

Que retorna uma lista de artistas que serão usados ​​para desenhar o destaque.

Se o objeto alvo do mixin não for um artista matplotlib, os seguintes protocolos também devem ser implementados. Fazer isso geralmente é bastante trivial, pois deve haver um artista em algum lugar que está sendo desenhado. Normalmente, seu objeto apenas encaminharia essas chamadas para esse artista.

  • get_figure(self)

  • get_axes(self)

  • contém(auto,evento)

  • set_animated(self,flag)

  • draw(auto, renderizador)

  • get_visible(self)

As seguintes notificações são chamadas no artista, e o artista pode opcionalmente implementá-las.

  • on_select_begin(self)

  • on_select_end(self)

  • on_drag_begin(self)

  • on_drag_end(self)

  • on_activated(self)

  • on_highlight(self)

  • on_right_click(self,evento)

  • on_left_click(self,evento)

  • on_middle_click(self,evento)

  • on_context_click(self,evento)

  • on_key_up(self,evento)

  • on_key_down(self,evento)

As seguintes notificações são chamadas na tela, se nenhum artista interativo manipular o evento:

  • on_press(self,evento)

  • on_left_click(self,evento)

  • on_middle_click(self,evento)

  • on_right_click(self,evento)

  • on_context_click(self,evento)

  • on_key_up(self,evento)

  • on_key_down(self,evento)

As seguintes funções, se presentes, podem ser usadas para modificar o comportamento do objeto interativo:

  • press_filter(self,event) # determina se o objeto deseja que o evento press seja roteado para ele

  • handle_unpicked_cursor() # pode ser usado pelo objeto para definir um cursor conforme o cursor passa sobre o objeto quando ele é desmarcado.

Oferece suporte a várias telas, mantendo um bloqueio de arrastar, notificador de movimento e um sinalizador global "ativado" por tela. Suporta redimensionamentos de proporção fixa mantendo pressionada a tecla shift durante o redimensionamento.

Problemas conhecidos:

  • Zorder não é obedecido durante as operações de seleção/arrastar. Por causa da técnica blit usada, não acredito que isso possa ser consertado. A única maneira que consigo pensar é pesquisar todos os artistas que têm uma zorder maior do que eu, defini-los como animados e, em seguida, redesenhá-los todos no topo durante cada atualização de arrastar. Isso pode ser muito lento; precisa tentar.

  • o mixin funciona apenas para backends wx por causa de duas coisas: 1) os cursores são codificados e 2) há uma chamada para wx.GetMousePosition() Ambas as deficiências são razoavelmente corrigidas fazendo com que cada backend forneça essas coisas.

Compatibilidade com versões anteriores #

Sem problemas com compatibilidade com versões anteriores, embora uma vez que isso esteja em vigor, seria apropriado tornar obsoletas algumas das funções interativas existentes (como legend.draggable())

Alternativas #

Nenhum que eu saiba.