MEP26 : Stylisme d'artiste #
Statut #
Rejeté
Branches et demandes d'extraction #
Résumé #
Ce MEP propose une nouvelle implémentation de feuille de style pour permettre un style plus complet et dynamique des artistes.
La version actuelle de matplotlib (1.4.0) permet d'appliquer des feuilles de style basées sur la syntaxe rcParams avant la création d'un tracé. La méthodologie ci-dessous propose une nouvelle syntaxe, basée sur CSS, qui permettrait de styliser des artistes et des propriétés individuels, qui peuvent être appliqués dynamiquement à des objets existants.
Ceci est lié à (et fait des pas vers) l'objectif global de passer à une architecture DOM/arborescente.
Descriptif détaillé #
Actuellement, l'aspect et l'apparence des objets d'artiste existants (figure, axes, Line2D, etc.) ne peuvent être mis à jour que via set_
et get_
des méthodes sur l'objet d'artiste, ce qui est assez laborieux, surtout si aucune référence à l'artiste (s) n'a été stockée . Les nouvelles feuilles de style introduites dans la version 1.4 permettent le style avant la création d'un tracé, mais n'offrent aucun moyen de mettre à jour dynamiquement les tracés ou de distinguer les artistes du même type (c'est-à-dire de spécifier le et séparément pour des objets différents).line color
line
style
Line2D
Le développement initial devrait se concentrer sur l'autorisation du style des primitives d'artiste (ceux Artist
qui ne contiennent pas d'autres
Artist
s), et un développement ultérieur pourrait étendre les règles de syntaxe CSS et l'analyseur pour permettre un style plus complexe. Voir l'annexe pour une liste des primitives.
La nouvelle méthodologie nécessiterait le développement d'un certain nombre d'étapes :
Une nouvelle syntaxe de feuille de style (probablement basée sur CSS) pour permettre la sélection d'artistes par type, classe, identifiant, etc.
Un mécanisme par lequel analyser une feuille de style dans un arbre
Un mécanisme permettant de traduire l'arbre d'analyse en quelque chose qui peut être utilisé pour mettre à jour les propriétés des artistes concernés. Idéalement, cela mettrait en œuvre une méthode permettant de parcourir les artistes dans une structure arborescente.
Un mécanisme permettant de générer une feuille de style à partir de propriétés d'artiste existantes. Cela serait utile pour permettre à un utilisateur d'exporter une feuille de style à partir d'une figure existante (dont l'apparence peut avoir été définie à l'aide de l'API matplotlib)...
Mise en œuvre #
Il sera plus facile d'autoriser un "tiers" à modifier/définir le style d'un artiste si le "style" est créé en tant que classe distincte et stocké contre l'artiste en tant que propriété. La GraphicsContextBase
classe fournit déjà la base d'une
Style
classe et la méthode d'un artiste draw
peut être refactorisée pour utiliser la Style
classe plutôt que de créer la sienne GraphicsContextBase
et de lui transférer ses propriétés liées au style. Un exemple minimal de la façon dont cela pourrait être mis en œuvre est montré ici : https://github.com/JamesRamm/mpl_experiment
IMO, cela rendra également l'API et la base de code beaucoup plus claires car les méthodes get/set individuelles pour les propriétés de style d'artiste sont désormais redondantes... Indirectement lié serait un lecteur général pour remplacer les méthodes get/set par des propriétés. Implémenter la classe de style avec des propriétés serait un grand pas vers cela...
Pour le développement initial, je propose de développer une syntaxe basée sur une version beaucoup (beaucoup) simplifiée de CSS. Je suis favorable au doublage de ces feuilles de style d'artiste :+1: :
BNF Grammaire #
Je propose une syntaxe très simple à implémenter dans un premier temps (comme une preuve de concept), qui pourra être développée dans le futur. La forme BNF de la syntaxe est donnée ci-dessous puis expliquée
RuleSet ::= SelectorSequence "{"Declaration"}"
SelectorSequence :: = Selector {"," Selector}
Declaration ::= propName":" propValue";"
Selector ::= ArtistIdent{"#"Ident}
propName ::= Ident
propValue ::= Ident | Number | Colour | "None"
ArtistIdent
, Ident
et sont Number
des Colour
jetons (les blocs de construction de base de l'expression) qui sont définis par des expressions régulières.
Syntaxe #
Une feuille de style CSS se compose d'une série d' ensembles de règles dans l'ordre hiérarchique (les règles sont appliquées de haut en bas). Chaque règle suit la syntaxe
selector {attribute: value;}
Chaque règle peut avoir n'importe quel nombre de paires et une feuille de style peut avoir n'importe quel nombre de règles.attribute: value
La syntaxe initiale est conçue uniquement pour Artist
les primitives. Il n'aborde pas la question de savoir comment définir des propriétés sur des Container
types (dont les propriétés peuvent elles-mêmes être Artist
s avec des propriétés définissables), cependant, une future solution à cela pourrait simplement être imbriquée
RuleSet
s
Sélecteurs #
Les sélecteurs définissent l'objet auquel les mises à jour d'attribut doivent être appliquées. Comme point de départ, je propose juste 2 sélecteurs à utiliser dans le développement initial :
Sélecteur de type d'artiste
Sélectionnez un Artist
par son type. Ex Line2D
ou Text
:
Line2D {attribute: value}
L'expression régulière pour faire correspondre le sélecteur de type d'artiste ( ArtistIdent
dans la grammaire BNF) serait :
ArtistIdent = r'(?P<ArtistIdent>\bLine2D\b|\bText\b|\bAxesImage\b|\bFigureImage\b|\bPatch\b)'
Sélecteur GID #
Sélectionnez un Artist
par son gid
:
Line2D#myGID {attribute: value}
A gid
peut être n'importe quelle chaîne, donc l'expression régulière peut être la suivante :
Ident = r'(?P<Ident>[a-zA-Z_][a-zA-Z_0-9]*)'
Les sélecteurs ci-dessus correspondent à peu près à leurs homologues CSS ( http://www.w3.org/TR/CSS21/selector.html )
Attributs et valeurs #
Attributes
sont des propriétés valides (réglables) pour leArtist
en question.Values
sont n'importe quelle valeur valide pour la propriété (généralement une chaîne ou un nombre).
Analyse #
L'analyse consisterait à décomposer la feuille de style en jetons (le livre de cuisine python donne une belle recette de tokenisation à la page 66), à appliquer les règles de syntaxe et à construire un fichier Tree
. Cela nécessite de définir la grammaire de la feuille de style (encore une fois, nous pouvons emprunter à CSS) et d'écrire un parseur. Heureusement, il existe également une recette pour cela dans le livre de cuisine Python.
Modèle de visiteur pour la figure matplotlib #
Afin d'appliquer les règles de la feuille de style aux artistes concernés, nous devons "visiter" chaque artiste dans une figure et appliquer la règle correspondante. Voici une classe de visiteurs (encore une fois, grâce au livre de cuisine python), où chacun
node
serait un artiste de la figure. Une visit_
méthode devrait être implémentée pour chaque artiste mpl, pour gérer les différentes propriétés de chaque
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)
Une evaluator
classe prendrait alors les règles de la feuille de style et implémenterait le visiteur sur chacune d'elles.
Rétrocompatibilité #
L'implémentation d'une classe distincte Style
romprait la compatibilité ascendante car de nombreuses méthodes get/set sur un artiste deviendraient redondantes. Bien qu'il soit possible de modifier ces méthodes pour s'accrocher à la Style
classe (stockée en tant que propriété contre l'artiste), je serais en faveur de les supprimer simplement pour à la fois nettoyer/simplifier la base de code et fournir une API simple et épurée. .
Alternatives #
Pas d'alternative, mais une partie du terrain couvert ici chevauche MEP25, ce qui peut aider à ce développement
Annexe #
Primitives Matplotlib #
Cela formera les sélecteurs initiaux que les feuilles de style peuvent utiliser.
Ligne2D
Texte
AxesImage
FigureImage
Correctif