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 colorline styleLine2D

Le développement initial devrait se concentrer sur l'autorisation du style des primitives d'artiste (ceux Artistqui ne contiennent pas d'autres Artists), 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 GraphicsContextBaseclasse fournit déjà la base d'une Styleclasse et la méthode d'un artiste drawpeut être refactorisée pour utiliser la Styleclasse plutôt que de créer la sienne GraphicsContextBaseet 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, Identet sont Numberdes Colourjetons (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 Artistles primitives. Il n'aborde pas la question de savoir comment définir des propriétés sur des Containertypes (dont les propriétés peuvent elles-mêmes être Artists avec des propriétés définissables), cependant, une future solution à cela pourrait simplement être imbriquée RuleSets

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 Artistpar son type. Ex Line2Dou Text:

Line2D {attribute: value}

L'expression régulière pour faire correspondre le sélecteur de type d'artiste ( ArtistIdentdans la grammaire BNF) serait :

ArtistIdent = r'(?P<ArtistIdent>\bLine2D\b|\bText\b|\bAxesImage\b|\bFigureImage\b|\bPatch\b)'

Sélecteur GID #

Sélectionnez un Artistpar son gid:

Line2D#myGID {attribute: value}

A gidpeut ê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 #

  • Attributessont des propriétés valides (réglables) pour le Artisten question.

  • Valuessont 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 nodeserait 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 evaluatorclasse 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 Styleromprait 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 Styleclasse (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