MEP26: Estilo do artista #
Estado #
rejeitado
Filiais e solicitações pull #
Resumo #
Este MEP propõe uma nova implementação de folha de estilo para permitir um estilo mais abrangente e dinâmico dos artistas.
A versão atual do matplotlib (1.4.0) permite que folhas de estilo baseadas na sintaxe rcParams sejam aplicadas antes da criação de um gráfico. A metodologia abaixo propõe uma nova sintaxe, baseada em CSS, que permitiria estilizar artistas e propriedades individuais, que podem ser aplicadas dinamicamente a objetos existentes.
Isso está relacionado (e dá passos em direção a) ao objetivo geral de mudar para uma arquitetura DOM/tipo árvore.
Descrição detalhada #
Atualmente, a aparência dos objetos de artista existentes (figura, eixos, Line2D, etc.) só podem ser atualizados por meio set_
de métodos e get_
no objeto de artista, o que é bastante trabalhoso, especialmente se nenhuma referência ao(s) artista(s) foi armazenada . As novas folhas de estilo introduzidas em 1.4 permitem estilizar antes que um gráfico seja criado, mas não oferece nenhum meio de atualizar gráficos dinamicamente ou distinguir entre artistas do mesmo tipo (ou seja, especificar o e separadamente para objetos diferentes).line color
line
style
Line2D
O desenvolvimento inicial deve se concentrar em permitir o estilo dos primitivos do artista (aqueles Artist
s que não contêm outros
Artist
s), e o desenvolvimento posterior pode expandir as regras de sintaxe CSS e o analisador para permitir um estilo mais complexo. Consulte o apêndice para obter uma lista de primitivos.
A nova metodologia exigiria o desenvolvimento de uma série de etapas:
Uma nova sintaxe de folha de estilo (provavelmente baseada em CSS) para permitir a seleção de artistas por tipo, classe, id, etc.
Um mecanismo para analisar uma folha de estilo em uma árvore
Um mecanismo para traduzir a árvore de análise em algo que pode ser usado para atualizar as propriedades de artistas relevantes. Idealmente, isso implementaria um método para atravessar os artistas em uma estrutura semelhante a uma árvore.
Um mecanismo para gerar uma folha de estilo a partir das propriedades existentes do artista. Isso seria útil para permitir que um usuário exporte uma folha de estilo de uma figura existente (onde a aparência pode ter sido definida usando a API matplotlib)...
Implementação #
Será mais fácil permitir que um 'terceiro' modifique/defina o estilo de um artista se o 'estilo' for criado como uma classe separada e armazenado no artista como uma propriedade. A GraphicsContextBase
classe já fornece a base de uma
Style
classe e o método de um artista draw
pode ser refatorado para usar a Style
classe em vez de configurar sua própria GraphicsContextBase
e transferir suas propriedades relacionadas ao estilo para ela. Um exemplo mínimo de como isso pode ser implementado é mostrado aqui: https://github.com/JamesRamm/mpl_experiment
IMO, isso também tornará a API e a base de código muito mais organizadas, já que métodos get/set individuais para propriedades de estilo de artista agora são redundantes... Indiretamente relacionado seria uma unidade geral para substituir métodos get/set por propriedades. Implementar a classe de estilo com propriedades seria um grande passo em direção a isso...
Para o desenvolvimento inicial, sugiro desenvolver uma sintaxe baseada em uma versão muito (muito) simplificada do CSS. Sou a favor de dublar as Folhas de Estilo do Artista :+1: :
Gramática BNF #
Proponho uma sintaxe muito simples de implementar inicialmente (como uma prova de conceito), que pode ser expandida no futuro. A forma BNF da sintaxe é fornecida abaixo e depois explicada
RuleSet ::= SelectorSequence "{"Declaration"}"
SelectorSequence :: = Selector {"," Selector}
Declaration ::= propName":" propValue";"
Selector ::= ArtistIdent{"#"Ident}
propName ::= Ident
propValue ::= Ident | Number | Colour | "None"
ArtistIdent
, Ident
, Number
e Colour
são tokens (os blocos de construção básicos da expressão) que são definidos por expressões regulares.
Sintaxe #
Uma folha de estilo CSS consiste em uma série de conjuntos de regras em ordem hierárquica (as regras são aplicadas de cima para baixo). Cada regra segue a sintaxe
selector {attribute: value;}
Cada regra pode ter qualquer número de pares e uma folha de estilo pode ter qualquer número de regras.attribute: value
A sintaxe inicial é projetada apenas para Artist
primitivos. Ele não aborda a questão de como definir propriedades em Container
tipos (cujas propriedades podem ser Artist
s com propriedades configuráveis), no entanto, uma solução futura para isso poderia ser simplesmente
RuleSet
s aninhados
Seletores #
Os seletores definem o objeto ao qual as atualizações de atributo devem ser aplicadas. Como ponto de partida, proponho apenas 2 seletores para usar no desenvolvimento inicial:
Seletor de tipo de artista
Selecione um Artist
por seu tipo. Ex.: Line2D
ou Text
:
Line2D {attribute: value}
O regex para corresponder ao seletor de tipo de artista ( ArtistIdent
na gramática BNF) seria:
ArtistIdent = r'(?P<ArtistIdent>\bLine2D\b|\bText\b|\bAxesImage\b|\bFigureImage\b|\bPatch\b)'
Seletor GID #
Selecione um Artist
por seu gid
:
Line2D#myGID {attribute: value}
A gid
pode ser qualquer string, então o regex pode ser o seguinte:
Ident = r'(?P<Ident>[a-zA-Z_][a-zA-Z_0-9]*)'
Os seletores acima correspondem aproximadamente às suas contrapartes CSS ( http://www.w3.org/TR/CSS21/selector.html )
Atributos e valores #
Attributes
são quaisquer propriedades válidas (configuráveis) para oArtist
em questão.Values
são qualquer valor válido para a propriedade (geralmente uma string ou número).
Analisando #
A análise consistiria em dividir a folha de estilo em tokens (o livro de receitas do python fornece uma boa receita de tokenização na página 66), aplicar as regras de sintaxe e construir um arquivo Tree
. Isso requer definir a gramática da folha de estilo (novamente, podemos pegar emprestado do CSS) e escrever um analisador. Felizmente, também existe uma receita para isso no livro de receitas do python.
Padrão de visitante para figura matplotlib #
Para aplicar as regras da folha de estilo aos artistas relevantes, precisamos 'visitar' cada artista em uma figura e aplicar a regra relevante. Aqui está uma aula de visitante (novamente, graças ao livro de receitas do python), onde cada um
node
seria um artista na figura. Um visit_
método precisaria ser implementado para cada artista mpl, para lidar com as diferentes propriedades de cada
class Visitor:
def visit(self, node):
name = 'visit_' + type(node).__name__
meth = getattr(self, name, None)
if meth is None:
raise NotImplementedError
return meth(node)
Uma evaluator
classe então pegaria as regras da folha de estilo e implementaria o visitante em cada uma delas.
Compatibilidade com versões anteriores #
A implementação de uma Style
classe separada quebraria a compatibilidade com versões anteriores, pois muitos métodos get/set em um artista se tornariam redundantes. Embora seja possível alterar esses métodos para se conectar à Style
classe (armazenados como uma propriedade contra o artista), eu seria a favor de simplesmente removê-los para limpar/simplificar a base de código e fornecer uma API simples e organizada. .
Alternativas #
Não há alternativas, mas parte do terreno coberto aqui se sobrepõe ao MEP25, o que pode ajudar nesse desenvolvimento
Apêndice #
Primitivas Matplotlib #
Isso formará os seletores iniciais que as folhas de estilo podem usar.
Linha2D
Texto
AxesImage
FiguraImagem
Correção