MEP26:艺术家造型#

状态#

被拒绝

分支和拉取请求#

摘要#

该 MEP 提出了一种新的样式表实现,以允许对艺术家进行更全面和动态的样式设置。

当前版本的 matplotlib (1.4.0) 允许在创建绘图之前应用基于 rcParams 语法的样式表。下面的方法提出了一种基于 CSS 的新语法,它允许对单个艺术家和属性进行样式设置,可以动态地应用于现有对象。

这与迁移到类似 DOM/树的架构的总体目标相关(并朝着这些目标迈进了一步)。

详细说明#

目前,现有艺术家对象(图形、轴、Line2D 等)的外观只能通过艺术家对象上的set_get_方法进行更新,这非常费力,尤其是在没有存储对艺术家的引用的情况下. 1.4 中引入的新样式表允许在创建绘图之前进行样式设置,但不提供任何方法来动态更新绘图或区分相同类型的艺术家(即为不同的对象分别指定和)。line colorline styleLine2D

最初的开发应该集中于允许艺术家原语的样式(那些Artist不包含其他 Artists 的 s),进一步的开发可以扩展 CSS 语法规则和解析器以允许更复杂的样式。有关原语列表,请参见附录。

新方法将需要制定一些步骤:

  • 一种新的样式表语法(可能基于 CSS),允许按类型、类、id 等选择艺术家。

  • 一种将样式表解析为树的机制

  • 一种将解析树转换为可用于更新相关艺术家属性的机制。理想情况下,这将实现一种在树状结构中遍历艺术家的方法。

  • 一种从现有艺术家属性生成样式表的机制。这对于允许用户从现有图形(可能已使用 matplotlib API 设置外观)导出样式表很有用...

实施#

如果将“样式”创建为单独的类并将艺术家作为属性存储,则允许“第 3 方”修改/设置艺术家的风格将是最容易的。该类GraphicsContextBase已经提供了类的基础, 并且可以重构Style艺术家的方法以使用该类,而不是设置自己的类并将其与样式相关的属性传递给它。此处显示了如何实现此功能的最小示例:https ://github.com/JamesRamm/mpl_experimentdrawStyleGraphicsContextBase

IMO,这也将使 API 和代码库更加整洁,因为艺术家风格属性的单个 get/set 方法现在是多余的……间接相关的是用属性替换 get/set 方法的一般驱动。使用属性实现样式类将是朝着这个方向迈出的一大步……

对于初始开发,我建议开发一种基于非常(非常)简化的 CSS 版本的语法。我赞成为这个艺术家样式表配音 :+1: :

BNF 语法#

我提出了一个非常简单的语法来最初实现(如概念证明),将来可以扩展。下面给出语法的 BNF 形式,然后解释

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

SelectorSequence :: = Selector {"," Selector}

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

Selector ::= ArtistIdent{"#"Ident}

propName ::= Ident

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

ArtistIdentIdent和是由正则表达式定义的标记(表达式的基本构建块)NumberColour

语法#

CSS 样式表由一系列按层次顺序排列的规则集组成(规则从上到下应用)。每个规则都遵循语法

selector {attribute: value;}

每个规则可以有任意数量的对,样式表可以有任意数量的规则。attribute: value

初始语法仅为Artist原语设计。它没有解决如何在Container类型上设置属性的问题(其属性本身可能Artist是具有可设置属性的 s),但是,未来的解决方案可以简单地嵌套 RuleSets

选择器#

选择器定义属​​性更新应该应用到的对象。作为起点,我建议在初始开发中只使用 2 个选择器:

艺术家类型选择器

按类型选择一个Artist。例如Line2DText

Line2D {attribute: value}

匹配艺术家类型选择器(ArtistIdent在 BNF 语法中)的正则表达式将是:

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

GID 选择器#

Artist按其选择一个gid

Line2D#myGID {attribute: value}

Agid可以是任何字符串,所以正则表达式可以如下:

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

上述选择器大致对应于它们的 CSS 对应物(http://www.w3.org/TR/CSS21/selector.html

属性和值#

  • Attributes是相关问题的任何有效(可设置)属性Artist

  • Values是属性的任何有效值(通常是字符串或数字)。

解析#

解析将包括将样式表分解为标记(python 食谱在第 66 页提供了一个很好的标记化配方),应用语法规则并构造一个Tree. 这需要定义样式表的语法(同样,我们可以借鉴 CSS)并编写解析器。令人高兴的是,python 食谱中也有这个食谱。

matplotlib 图的访问者模式#

为了将样式表规则应用于相关艺术家,我们需要“访问”图中的每个艺术家并应用相关规则。这是一个访问者类(再次感谢 python 食谱),其中每个 node人都是图中的艺术家。visit_需要为每个 mpl 艺术家实现一个方法,以处理每个 mpl 艺术家的不同属性

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)

然后一个evaluator类将采用样式表规则并在每个规则上实现访问者。

向后兼容性#

实现一个单独的Style类会破坏向后兼容性,因为艺术家上的许多 get/set 方法将变得多余。虽然可以更改这些方法以挂接到Style类中(存储为针对艺术家的属性),但我赞成简单地删除它们以整理/简化代码库并提供简单、整洁的 API。 .

替代方案#

没有其他选择,但这里涵盖的一些领域与 MEP25 重叠,这可能有助于这一发展

附录#

Matplotlib 原语#

这将形成样式表可以使用的初始选择器。

  • 线2D

  • 文本

  • 轴图像

  • 图图像

  • 修补