MEP26: Stile dell'artista #

Stato n.

Respinto

Filiali e Pull request #

Estratto n.

Questo MEP propone una nuova implementazione del foglio di stile per consentire uno stile più completo e dinamico degli artisti.

L'attuale versione di matplotlib (1.4.0) consente di applicare fogli di stile basati sulla sintassi rcParams prima della creazione di un grafico. La metodologia di seguito propone una nuova sintassi, basata su CSS, che consentirebbe lo styling di singoli artisti e proprietà, che possono essere applicati dinamicamente agli oggetti esistenti.

Ciò è correlato (e fa passi verso) l'obiettivo generale di passare a un'architettura DOM/simile ad un albero.

Descrizione dettagliata #

Attualmente, l'aspetto e l'aspetto degli oggetti dell'artista esistenti (figura, assi, Line2D, ecc.) possono essere aggiornati solo tramite set_e get_metodi sull'oggetto dell'artista, il che è piuttosto laborioso, soprattutto se non è stato memorizzato alcun riferimento all'artista o agli artisti . I nuovi fogli di stile introdotti nella versione 1.4 consentono lo styling prima della creazione di una trama, ma non offrono alcun mezzo per aggiornare dinamicamente le trame o distinguere tra artisti dello stesso tipo (ovvero specificare e separatamente per oggetti diversi).line colorline styleLine2D

Lo sviluppo iniziale dovrebbe concentrarsi sul consentire lo styling delle primitive dell'artista (quelle Artists che non contengono altri Artists), e un ulteriore sviluppo potrebbe espandere le regole di sintassi CSS e il parser per consentire uno styling più complesso. Vedere l'appendice per un elenco di primitive.

La nuova metodologia richiederebbe lo sviluppo di una serie di fasi:

  • Una nuova sintassi del foglio di stile (probabilmente basata su CSS) per consentire la selezione di artisti per tipo, classe, id, ecc.

  • Un meccanismo mediante il quale analizzare un foglio di stile in un albero

  • Un meccanismo con cui tradurre l'albero di analisi in qualcosa che può essere utilizzato per aggiornare le proprietà di artisti rilevanti. Idealmente questo implementerebbe un metodo con cui attraversare gli artisti in una struttura ad albero.

  • Un meccanismo mediante il quale generare un foglio di stile dalle proprietà dell'artista esistenti. Ciò sarebbe utile per consentire a un utente di esportare un foglio di stile da una figura esistente (dove l'aspetto potrebbe essere stato impostato utilizzando l'API matplotlib)...

Implementazione n.

Sarà più semplice consentire a una "terza parte" di modificare/impostare lo stile di un artista se lo "stile" viene creato come classe separata e memorizzato sull'artista come proprietà. La GraphicsContextBaseclasse fornisce già una base di una Styleclasse e il metodo di un artista drawpuò essere rifattorizzato per utilizzare la Styleclasse piuttosto che impostarne una propria GraphicsContextBasee trasferirvi le sue proprietà relative allo stile. Un esempio minimo di come questo potrebbe essere implementato è mostrato qui: https://github.com/JamesRamm/mpl_experiment

IMO, questo renderà anche l'API e la base di codice molto più ordinate poiché i singoli metodi get/set per le proprietà dello stile dell'artista sono ora ridondanti ... Indirettamente correlato sarebbe un'unità generale per sostituire i metodi get/set con le proprietà. L'implementazione della classe di stile con le proprietà sarebbe un grande passo avanti verso questo ...

Per lo sviluppo iniziale, suggerisco di sviluppare una sintassi basata su una versione molto (molto) semplificata di CSS. Sono favorevole al doppiaggio di questo foglio di stile dell'artista :+1: :

BNF Grammatica #

Propongo una sintassi molto semplice da implementare inizialmente (come una prova di concetto), che può essere ampliata in futuro. La forma BNF della sintassi è data di seguito e poi spiegata

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

SelectorSequence :: = Selector {"," Selector}

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

Selector ::= ArtistIdent{"#"Ident}

propName ::= Ident

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

ArtistIdent, Ident, Numbere Coloursono token (gli elementi costitutivi di base dell'espressione) definiti da espressioni regolari.

Sintassi #

Un foglio di stile CSS è costituito da una serie di set di regole in ordine gerarchico (le regole vengono applicate dall'alto verso il basso). Ogni regola segue la sintassi

selector {attribute: value;}

Ogni regola può avere un numero qualsiasi di coppie e un foglio di stile può avere un numero qualsiasi di regole.attribute: value

La sintassi iniziale è progettata solo per Artistle primitive. Non affronta la questione di come impostare le proprietà sui Containertipi (le cui proprietà possono esse stesse essere Artists con proprietà impostabili), tuttavia, una soluzione futura a questo potrebbe essere semplicemente nidificata RuleSets

Selettori #

I selettori definiscono l'oggetto a cui devono essere applicati gli aggiornamenti degli attributi. Come punto di partenza, propongo solo 2 selettori da utilizzare nello sviluppo iniziale:

Selettore del tipo di artista

Seleziona un Artistin base al suo tipo. Es . Line2Doppure Text:

Line2D {attribute: value}

La regex per la corrispondenza del selettore del tipo di artista ( ArtistIdentnella grammatica BNF) sarebbe:

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

Selettore GID #

Seleziona un Artistper il suo gid:

Line2D#myGID {attribute: value}

A gidpuò essere qualsiasi stringa, quindi la regex potrebbe essere la seguente:

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

I selettori di cui sopra corrispondono approssimativamente alle loro controparti CSS ( http://www.w3.org/TR/CSS21/selector.html )

Attributi e valori #

  • Attributessono qualsiasi proprietà valida (impostabile) per l' Artistoggetto in questione.

  • Valuessono qualsiasi valore valido per la proprietà (solitamente una stringa o un numero).

#analisi _

L'analisi consisterebbe nel suddividere il foglio di stile in token (il ricettario di Python fornisce una bella ricetta per la tokenizzazione a pagina 66), applicando le regole di sintassi e costruendo un file Tree. Ciò richiede la definizione della grammatica del foglio di stile (di nuovo, possiamo prendere in prestito dai CSS) e la scrittura di un parser. Fortunatamente, c'è anche una ricetta per questo nel ricettario di Python.

Schema dei visitatori per la figura matplotlib n.

Per applicare le regole del foglio di stile agli artisti pertinenti, dobbiamo "visitare" ogni artista in una figura e applicare la regola pertinente. Ecco una classe di visitatori (di nuovo, grazie al libro di cucina di Python), in cui ognuno nodesarebbe un artista nella figura. visit_Sarebbe necessario implementare un metodo per ogni artista mpl, per gestire le diverse proprietà per ciascuno

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)

Una evaluatorclasse prenderebbe quindi le regole del foglio di stile e implementerebbe il visitatore su ciascuna di esse.

Compatibilità con le versioni precedenti #

L'implementazione di una Styleclasse separata interromperebbe la compatibilità con le versioni precedenti poiché molti metodi get/set su un artista diventerebbero ridondanti. Mentre sarebbe possibile modificare questi metodi per agganciarsi alla Styleclasse (memorizzata come proprietà contro l'artista), sarei favorevole a rimuoverli semplicemente sia per migliorare/semplificare la base di codice sia per fornire un'API semplice e ordinata. .

Alternative #

Nessuna alternativa, ma parte del terreno coperto qui si sovrappone a MEP25, il che potrebbe aiutare in questo sviluppo

Appendice #

Primitive Matplotlib #

Questo formerà i selettori iniziali che i fogli di stile possono usare.

  • Linea2D

  • Testo

  • AxesImage

  • FiguraImmagine

  • Toppa