MEP26: Künstler-Styling #

Status #

Abgelehnt

Branches und Pull-Requests #

Zusammenfassung #

Dieses MdEP schlägt eine neue Stylesheet-Implementierung vor, um ein umfassenderes und dynamischeres Styling von Künstlern zu ermöglichen.

Die aktuelle Version von matplotlib (1.4.0) ermöglicht die Anwendung von Stylesheets basierend auf der rcParams-Syntax vor der Erstellung eines Plots. Die nachstehende Methodik schlägt eine neue, auf CSS basierende Syntax vor, die eine Gestaltung individueller Künstler und Eigenschaften ermöglichen würde, die dynamisch auf vorhandene Objekte angewendet werden können.

Dies hängt mit dem übergeordneten Ziel zusammen, zu einer DOM-/baumartigen Architektur überzugehen (und macht Schritte darauf zu).

Detaillierte Beschreibung #

Derzeit kann das Aussehen und Aussehen von bestehenden Künstlerobjekten (Figur, Achsen, Line2D usw.) nur über set_und get_Methoden am Künstlerobjekt aktualisiert werden, was ziemlich mühsam ist, insbesondere wenn kein Verweis auf den/die Künstler gespeichert wurde . Die neuen Stylesheets, die in 1.4 eingeführt wurden, ermöglichen das Stylen, bevor ein Plot erstellt wird, bieten jedoch keine Möglichkeit, Plots dynamisch zu aktualisieren oder zwischen Künstlern des gleichen Typs zu unterscheiden (dh und getrennt für unterschiedliche Objekte anzugeben).line colorline styleLine2D

Die anfängliche Entwicklung sollte sich darauf konzentrieren, das Stylen von Künstlerprimitiven zu ermöglichen (die Artists, die keine anderen Artists enthalten), und die weitere Entwicklung könnte die CSS-Syntaxregeln und den Parser erweitern, um ein komplexeres Styling zu ermöglichen. Im Anhang finden Sie eine Liste der Grundelemente.

Die neue Methodik würde die Entwicklung einer Reihe von Schritten erfordern:

  • Eine neue Stylesheet-Syntax (wahrscheinlich basierend auf CSS), um die Auswahl von Künstlern nach Typ, Klasse, ID usw. zu ermöglichen.

  • Ein Mechanismus, mit dem ein Stylesheet in einen Baum zerlegt wird

  • Ein Mechanismus zum Übersetzen des Analysebaums in etwas, das zum Aktualisieren der Eigenschaften relevanter Künstler verwendet werden kann. Idealerweise würde dies ein Verfahren implementieren, mit dem die Künstler in einer baumartigen Struktur durchlaufen werden.

  • Ein Mechanismus zum Generieren eines Stylesheets aus vorhandenen Künstlereigenschaften. Dies wäre nützlich, um einem Benutzer zu ermöglichen, ein Stylesheet aus einer vorhandenen Figur zu exportieren (wobei das Erscheinungsbild möglicherweise mit der Matplotlib-API festgelegt wurde) ...

Implementierung #

Es ist am einfachsten, einem „Drittanbieter“ zu erlauben, den Stil eines Künstlers zu modifizieren/einzustellen, wenn der „Stil“ als separate Klasse erstellt und als Eigenschaft für den Künstler gespeichert wird. Die GraphicsContextBaseKlasse stellt bereits die Grundlage einer StyleKlasse bereit, und die Methode eines Künstlers drawkann so umgestaltet werden, dass sie die StyleKlasse verwendet, anstatt eine eigene einzurichten GraphicsContextBaseund ihre stilbezogenen Eigenschaften darauf zu übertragen. Ein minimales Beispiel, wie dies implementiert werden könnte, wird hier gezeigt: https://github.com/JamesRamm/mpl_experiment

Meiner Meinung nach wird dies auch die API und die Codebasis viel übersichtlicher machen, da einzelne Get/Set-Methoden für Künstlerstileigenschaften jetzt überflüssig sind ... Indirekt damit verbunden wäre ein allgemeines Bestreben, Get/Set-Methoden durch Eigenschaften zu ersetzen. Die Implementierung der Stilklasse mit Eigenschaften wäre ein großer Schritt in diese Richtung ...

Für die anfängliche Entwicklung schlage ich vor, eine Syntax zu entwickeln, die auf einer sehr (viel) vereinfachten Version von CSS basiert. Ich bin dafür, diese Artist Style Sheets zu synchronisieren :+1: :

BNF-Grammatik #

Ich schlage eine sehr einfache Syntax vor, die zunächst implementiert werden kann (wie ein Machbarkeitsnachweis), die in Zukunft erweitert werden kann. Die BNF-Form der Syntax wird unten angegeben und dann erklärt

RuleSet ::= SelectorSequence "{"Declaration"}"

SelectorSequence :: = Selector {"," Selector}

Declaration ::= propName":" propValue";"

Selector ::= ArtistIdent{"#"Ident}

propName ::= Ident

propValue ::= Ident | Number | Colour | "None"

ArtistIdent, Ident, Numberund Coloursind Token (die Grundbausteine ​​des Ausdrucks), die durch reguläre Ausdrücke definiert werden.

Syntax #

Ein CSS-Stylesheet besteht aus einer Reihe von Regelsätzen in hierarchischer Reihenfolge (Regeln werden von oben nach unten angewendet). Jede Regel folgt der Syntax

selector {attribute: value;}

Jede Regel kann eine beliebige Anzahl von Paaren haben, und ein Stylesheet kann eine beliebige Anzahl von Regeln haben.attribute: value

Die anfängliche Syntax ist nur für ArtistPrimitive ausgelegt. Es befasst sich nicht mit der Frage, wie Eigenschaften für ContainerTypen festgelegt werden (deren Eigenschaften selbst Artists mit einstellbaren Eigenschaften sein können), jedoch könnte eine zukünftige Lösung dafür einfach verschachtelte RuleSets sein

Selektoren #

Selektoren definieren das Objekt, auf das die Attributaktualisierungen angewendet werden sollen. Als Ausgangspunkt schlage ich nur 2 Selektoren zur Verwendung in der anfänglichen Entwicklung vor:

Auswahl des Künstlertyps

Wählen Sie eine Artistnach ihrem Typ aus. zB Line2Doder Text:

Line2D {attribute: value}

Die Regex für den Abgleich der Künstlertypauswahl ( ArtistIdentin der BNF-Grammatik) wäre:

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

GID-Selektor #

Wählen Sie eine Artistanhand ihrer aus gid:

Line2D#myGID {attribute: value}

A gidkann ein beliebiger String sein, also könnte die Regex wie folgt aussehen:

Ident = r'(?P<Ident>[a-zA-Z_][a-zA-Z_0-9]*)'

Die obigen Selektoren entsprechen in etwa ihren CSS-Pendants ( http://www.w3.org/TR/CSS21/selector.html )

Attribute und Werte #

  • Attributessind alle gültigen (einstellbaren) Eigenschaften für die Artistfraglichen.

  • Valuessind alle gültigen Werte für die Eigenschaft (normalerweise eine Zeichenfolge oder Zahl).

Parsing #

Das Parsen würde darin bestehen, das Stylesheet in Tokens zu zerlegen (das Python-Kochbuch gibt auf Seite 66 ein nettes Tokenisierungsrezept), die Syntaxregeln anzuwenden und eine Tree. Dies erfordert die Definition der Grammatik des Stylesheets (wiederum können wir von CSS leihen) und das Schreiben eines Parsers. Glücklicherweise gibt es dafür auch ein Rezept im Python-Kochbuch.

Besuchermuster für Matplotlib-Figur #

Um die Stylesheet-Regeln auf die relevanten Künstler anzuwenden, müssen wir jeden Künstler in einer Figur „besuchen“ und die relevante Regel anwenden. Hier ist eine Besucherklasse (wieder dank python cookbook), wo jeder nodeein Künstler in der Figur wäre. visit_Für jeden mpl-Künstler müsste eine Methode implementiert werden, um die unterschiedlichen Eigenschaften für jeden zu handhaben

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)

Eine evaluatorKlasse würde dann die Stylesheet-Regeln nehmen und den Besucher auf jeder von ihnen implementieren.

Abwärtskompatibilität #

Die Implementierung einer separaten StyleKlasse würde die Abwärtskompatibilität beeinträchtigen, da viele get/set-Methoden für einen Künstler überflüssig würden. Obwohl es möglich wäre, diese Methoden so zu ändern, dass sie sich in die StyleKlasse einklinken (als Eigenschaft für den Künstler gespeichert), wäre ich dafür, sie einfach zu entfernen, um die Codebasis zu verschönern/vereinfachen und eine einfache, übersichtliche API bereitzustellen. .

Alternativen #

Keine Alternativen, aber einige der hier behandelten Themen überschneiden sich mit MEP25, was zu dieser Entwicklung beitragen kann

Anhang #

Matplotlib-Primitive #

Dies bildet die anfänglichen Selektoren, die Stylesheets verwenden können.

  • Linie2D

  • Text

  • AxesImage

  • AbbildungBild

  • Patch