MEP26: Artist-level stylesheets

Hi James,

Thanks for sharing the MEP - it’s a really interesting idea, and the MEP itself looks like a good start.

I’d strongly encourage you to stick with standard CSS syntax/behaviour instead of extending it. For example, the selector of “Axes.ylabel” would be more consistent as “Axes .ylabel” (or perhaps “Axis.y .label”).

Do you have ideas on how one or more stylesheets would be “attached” to a particular figure, etc?

Regards,
Richard Hattersley

Hi James,

···

Thanks for sharing the MEP - it’s a really interesting idea, and the MEP itself looks like a good start.

It is indeed a very interesting idea, and a challenging one! Thanks for tackling this problem.

I’d strongly encourage you to stick with standard CSS syntax/behaviour instead of extending it. For example, the selector of “Axes.ylabel” would be more consistent as “Axes .ylabel” (or perhaps “Axis.y .label”).

I actually think we need to focus on something easy to parse and easy to use, not necessarily stick to the CSS syntax and behaviour. Back in the day where I was doing web development and design integration, everyone seemed to hate CSS, so I am a bit curious and dubious about this choice.

I think we need to be careful about the choice of the grammar and the API: we know there are tools that are “doing it right”, and tools that aren’t (matplotlib falls in the second category). Before trying our own recipe I suggest that we look elsewhere, on how other libraries are tackling this problem, to see if we can reuse some of the good ideas and avoid errors. I am thinking in particular about ggplot2 (which I have never used, but I hear is very nice).

Thanks,

Nelle

Do you have ideas on how one or more stylesheets would be “attached” to a particular figure, etc?

Regards,
Richard Hattersley


Want fast and easy access to all the code in your enterprise? Index and

search up to 200,000 lines of code with a free copy of Black Duck

Code Sight - the same software that powers the world’s largest code

search on Ohloh, the Black Duck Open Hub! Try it now.

http://p.sf.net/sfu/bds


Matplotlib-devel mailing list

Matplotlib-devel@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/matplotlib-devel

Nelle Varoquaux wrote

I'd strongly encourage you to stick with standard CSS syntax/behaviour
instead of extending it. For example, the selector of "Axes.ylabel" would
be more consistent as "Axes .ylabel" (or perhaps "Axis.y .label").

I actually think we need to focus on something easy to parse and easy to
use, not necessarily stick to the CSS syntax and behaviour. Back in the
day
where I was doing web development and design integration, everyone seemed
to hate CSS, so I am a bit curious and dubious about this choice.

We cannot stick with the 'standard' CSS syntax by necessity, simply because
the standard CSS selectors and properties are defined from HTML and do not
match with matplotlib.
I.E we want to select by artist type, which doesn't exist in HTML and use
properties such as linewidth.
So, we would need to define a new syntax based on these tokens.
I have updated MEP26 with a BNF form of a basic syntax to use - take a look!

Another option would be to use the syntax for the ConfigParser module; this
way we already have a parser :slight_smile:

Nelle Varoquaux wrote

I think we need to be careful about the choice of the grammar and the API:
we know there are tools that are "doing it right", and tools that aren't
(matplotlib falls in the second category). Before trying our own recipe I
suggest that we look elsewhere, on how other libraries are tackling this
problem, to see if we can reuse some of the good ideas and avoid errors. I
am thinking in particular about ggplot2 (which I have never used, but I
hear is very nice).

Thanks,
Nelle

I thought CSS would be a good language to base it on as it is a widely known
and by far the most popular (as far as I know) 'stylesheet' language.
Other libraries that use style sheets, based on some form of CSS are:

Qt - Pyside/PyQt ('QSS')
Mapnik ('CartoCSS')
PyGal supports stylesheets (don't know much about this library)

As I say, an alternative could be simply using the ConfigParser

Richard Hattersley wrote

Do you have ideas on how one or more stylesheets would be "attached" to a
particular figure, etc?

Regards,
Richard Hattersley

This is the big question. We need a standard way in which to traverse all
the artists in a figure, filter them by the selectors and applying the
property updates.
The last part is easiest - the update() method on artists will accept a
dictionary. We can simply ensure that our stylesheet rules are parsed into a
dict structure (which is quite a common method to use).

The hard part is
a) Getting a complete figure description/traversing the artists.
This is currently tricky, but I think the ideas proposed in MEP25 will make
it much easier.

b) Filtering artists
Another problem is that we would generally want to treat artists which are
solely for the construction of the Axes differently to those artists that
define a plot. I.E we might want to define Line2D as having the colour red,
but we want lines which compose the Axes to be black or grey.
My initial proposal is to develop stylesheets for artist primitives only.
But eventually we will want to style artist containers aswell.
The problem matplotlib has is that the properties for artist containers are
not uniform/intuitive.
It generally has a API where artists which are 'contained' by other artists
are set by calling properties...e.g. axes.set_ylabel(text = , etc...)

I would prefer to be able to simply pass a class instance...e.g create an
instance of Text() and pass that to set_ylabel()
I believe this is similar to the Plotly API that is quite nice:
https://plot.ly/python/line-and-scatter/

An ideal solution would be trying to seperate out the style of artists from
the actual drawing/data
PyGal accepts a `Style` instance as an arguement to it's plotting functions,
which would be a good way to go.

I would imagine setting stylesheets through the axes or figure methods
(axes.setStyleSheet() or figure.setStyleSheet()). Via figure would require
being able to differentiate between different axes - i.e. introducing the
'container' level syntax I mentioned above.

I would imagine that this would eventually replace rcparams to define the
default style. I would also like to see the default look of graphs moving
away from the very dated, 90's style MATLAB appearance!

Anyway, there are a lot of ideas above, some of which are feasible, some of
which perhaps not, all of which need more thinking about!

···

--
View this message in context: http://matplotlib.1069221.n5.nabble.com/MEP26-Artist-level-stylesheets-tp43664p43671.html
Sent from the matplotlib - devel mailing list archive at Nabble.com.

We cannot stick with the 'standard' CSS syntax by necessity, simply because
the standard CSS selectors and properties are defined from HTML and do not
match with matplotlib.
I.E we want to select by artist type, which doesn't exist in HTML and use
properties such as linewidth.

I'm not sure what it is about CSS syntax that isn't up to the job. For
example, SVG works with standard CSS syntax (see
Styling — SVG 2). Perhaps we just have
a different view of what constitutes CSS vs. HTML/SVG/whatever.

The example in the SVG spec is:

rect {
  fill: red;
  stroke: blue;
  stroke-width: 3
}

But if we define the element name for a Line2D instance as "line2d" then
CSS snippet could just become:

line2d {
  stroke: blue;
  stroke-width: 3
}

Sure, matplotlib doesn't define a genuine DOM, but I understand there is
interest in moving to a model more like that. In which case, perhaps a good
way to proceed in the meantime would be to have artists expose a DOM facade
suitable for styling. (Perhaps even using SVG element conventions?)

NB. matplotlib already uses pyparsing, so it would be pretty
straightforward to knock together a parser for CSS (or whatever subset is
needed). Or there are existing Python CSS parser libraries.

Qt - Pyside/PyQt ('QSS')
Mapnik ('CartoCSS')
PyGal supports stylesheets (don't know much about this library)

If we don't use CSS then +1 for using some other standard.

As I say, an alternative could be simply using the ConfigParser

Richard Hattersley wrote
>>
>> Do you have ideas on how one or more stylesheets would be "attached" to
a
>> particular figure, etc?
>>
>> Regards,
>> Richard Hattersley
>>

b) Filtering artists
Another problem is that we would generally want to treat artists which are
solely for the construction of the Axes differently to those artists that
define a plot. I.E we might want to define Line2D as having the colour red,
but we want lines which compose the Axes to be black or grey.
My initial proposal is to develop stylesheets for artist primitives only.
But eventually we will want to style artist containers aswell.
The problem matplotlib has is that the properties for artist containers are
not uniform/intuitive.
It generally has a API where artists which are 'contained' by other artists
are set by calling properties...e.g. axes.set_ylabel(text = , etc...)

The DOM facade could help bridge the gap. For example, a "DOM" instance
returned by an Axes object could pretend to have "text" element children.
Styling those would route the style information back to the underlying Axes
object. For example:

text {
  font-size: 12pt;
}

axes text.ylabel {
  font-size: 10pt;
}

I would imagine setting stylesheets through the axes or figure methods

(axes.setStyleSheet() or figure.setStyleSheet()). Via figure would require
being able to differentiate between different axes - i.e. introducing the
'container' level syntax I mentioned above.

I would imagine that this would eventually replace rcparams to define the
default style. I would also like to see the default look of graphs moving
away from the very dated, 90's style MATLAB appearance!

That would be an excellent start. More complicated mechanisms can always be
added later if necessary.

Richard

···

On 20 July 2014 14:23, jamesramm <jamessramm@...149...> wrote:

R Hattersley wrote

I’m not sure what it is about CSS syntax that isn’t up to the job. For
example, SVG works with standard CSS syntax (see
Styling — SVG 2). Perhaps we just have
a different view of what constitutes CSS vs. HTML/SVG/whatever.
The example in the SVG spec is:

  rect {
fill: red;
stroke: blue;
stroke-width: 3
}

But if we define the element name for a Line2D instance as “line2d” then
CSS snippet could just become:

  line2d {
stroke: blue;
stroke-width: 3
}

You’ve just noted it: Line2D isn’t a CSS selector…likewise, the properties we want to call upon (like linewidth) are not CSS attributes. There are many matplotlib properties that don’t have an analogous CSS property/attribute (that I know of); we might aswell define the mpl properties in our ‘CSS’ subset.
So we could base our language on CSS rules, but we need to define new tokens. This means writing, or more likely, extending a parser. Not huge, but not trivial.

R Hattersley wrote

The DOM facade could help bridge the gap. For example, a “DOM” instance
returned by an Axes object could pretend to have “text” element children.
Styling those would route the style information back to the underlying Axes
object. For example:

  text {
font-size: 12pt;
}
axes text.ylabel {
font-size: 10pt;
}

This could be one way. Another way that would fit and I quite like is similar to what is employed by mapnik/the tilemill, in that we simply have nested declaration blocks, e.g:

        Axes {
gid: 'axes1';
autoscalex_on: True;
::ylabel {
text: 'Y-Axis';
font-size: 10;
}
}

I think this would be easier to parse and slightly clearer to read as it can be ‘attached’ to the artist container it refers to (imagine if there were 2 axes in a figure…). It is also easy to write in BNF, by just adding another option to the Declaration block:


Rule := Selector '{' [Declaration] '}'
Declaration := Attribute':' Value';' | Rule
...

But…small steps. I would start by introducing something for artist primitives and for selectively applying to primitives using the gid

···

View this message in context: Re: MEP26: Artist-level stylesheets

Sent from the matplotlib - devel mailing list archive at Nabble.com.

As a side note, SVG already has specs which extend css to apply to 2D graphics:

www.w3.org/TR/SVGTiny12/styling.html

so we don't need to entirely re-inventing the wheel.

···

On Mon, Jul 21, 2014 at 9:48 AM, jamesramm <jamessramm@...149...> wrote:

R Hattersley wrote
I'm not sure what it is about CSS syntax that isn't up to the job. For
example, SVG works with standard CSS syntax (see
Styling — SVG 2). Perhaps we just have
a different view of what constitutes CSS vs. HTML/SVG/whatever. The example
in the SVG spec is:

rect {
  fill: red;
  stroke: blue;
  stroke-width: 3
}

But if we define the element name for a Line2D instance as "line2d" then CSS
snippet could just become:

line2d {
  stroke: blue;
  stroke-width: 3
}

You've just noted it: Line2D isn't a CSS selector..likewise, the properties
we want to call upon (like linewidth) are not CSS attributes. There are many
matplotlib properties that don't have an analogous CSS property/attribute
(that I know of); we might aswell define the mpl properties in our 'CSS'
subset. So we could base our language on CSS rules, but we need to define
new tokens. This means writing, or more likely, extending a parser. Not
huge, but not trivial.

R Hattersley wrote
The DOM facade could help bridge the gap. For example, a "DOM" instance
returned by an Axes object could pretend to have "text" element children.
Styling those would route the style information back to the underlying Axes
object. For example:

text {
  font-size: 12pt;
}

axes text.ylabel {
  font-size: 10pt;
}

This could be one way. Another way that would fit and I quite like is
similar to what is employed by mapnik/the tilemill, in that we simply have
nested declaration blocks, e.g:

    Axes {
        gid: 'axes1';
        autoscalex_on: True;
        ::ylabel {
                text: 'Y-Axis';
                font-size: 10;
                  }
        }

I think this would be easier to parse and slightly clearer to read as it can
be 'attached' to the artist container it refers to (imagine if there were 2
axes in a figure...). It is also easy to write in BNF, by just adding
another option to the Declaration block:

Rule := Selector '{' [Declaration] '}'

Declaration := Attribute':' Value';' | Rule

...

But...small steps. I would start by introducing something for artist
primitives and for selectively applying to primitives using the gid
________________________________
View this message in context: Re: MEP26: Artist-level stylesheets

Sent from the matplotlib - devel mailing list archive at Nabble.com.

------------------------------------------------------------------------------
Want fast and easy access to all the code in your enterprise? Index and
search up to 200,000 lines of code with a free copy of Black Duck
Code Sight - the same software that powers the world's largest code
search on Ohloh, the Black Duck Open Hub! Try it now.
http://p.sf.net/sfu/bds
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
matplotlib-devel List Signup and Options

--
Thomas Caswell
tcaswell@...149...

You've just noted it: Line2D isn't a CSS selector

CSS doesn't define any particular element names - it just operates on
element names in a document tree. So a standard CSS parser will work just
as well with "line2d { ... }" as it would with "h1 { ... }".

..likewise, the properties we want to call upon (like linewidth) are not
CSS attributes.

Agreed - not all properties are standard CSS properties, so I was
suggesting borrowing SVG properties to augment the list. NB. That would
make the property controlling line width be called "stroke-width". But
whatever names we choose, a CSS parser doesn't care what the names are.

But really the issue is not so much about CSS and SVG-styling-properties -
it is whether to use existing standards or not. Clearly I'm in favour of
adopting standards. But perhaps there is another standard set of CSS
styling properties which would be a closer match to matplotlib? Perhaps CSS
is not the answer at all, and something like SLD/SE would be better? (I
suspect not! But there could easily be other technologies I'm not aware of!)

    Axes {

        gid: 'axes1';
        autoscalex_on: True;
        ::ylabel {
                text: 'Y-Axis';
                font-size: 10;
                  }
        }

I think this would be easier to parse and slightly clearer to read as it
can be 'attached' to the artist container it refers to (imagine if there
were 2 axes in a figure...)

In the case of two Axes, the CSS version would be:

Axes#axes1 {
  border: 1px solid black;
}

Axes#axes2 {
  border: 2px dashed green;
}

···

On 21 July 2014 14:48, jamesramm <jamessramm@...149...> wrote:
On 21 July 2014 14:48, jamesramm <jamessramm@...149...> wrote:

Or if you want to borrow from more advanced selector syntax, you could do
fun stuff like:

Axes:nth-child(odd) {
  border: 1px solid black;
}

Axes:nth-child(even) {
  border: 2px dashed green;
}

···

On 21 July 2014 17:40, R Hattersley <rhattersley@...149...> wrote:

In the case of two Axes, the CSS version would be:

Axes#axes1 {
  border: 1px solid black;
}

Axes#axes2 {
  border: 2px dashed green;
}

I have updated MEP26 to include discussion on 'decoupling' the style from
artists and having a generic Style class.

(copied over from the github issue):

I have been thinking that a good way to get stylesheets in, would be if the
'style' of an artist was entirely independent.
I.E a single property which points to some kind of 'style' object. This way,
style objects could be created on their own (programatically, or by some
other means (Stylesheets!)) and then applied to artists at will
(programatically, or by some other means (a stylesheet parser....)).

Then I thought...when it comes to drawing, the style **is** entirely
independent - it has been transferred to the `GraphicsContext` object. So
all that is needed is to expose this object at the artist level and we can
create styles!

I created a very minimal example to explain here:
https://github.com/JamesRamm/mpl_experiment

Basically, it just provides a `Style` class (which is just
`GraphicsContextBase` propertified and with a new function to generate one
from a dict) and a minimal reimplementation of Line2D and Text to show how
it would be used for both.

Just run run.py (and have a look at it) to see how the user would use style
objects.
(Note it is a bit convoluted as I have not added any axes plotting routines,
so a Line2D needs to be manually created and added).

Basically, this involves reimplementing the `draw` method to use the `style`
property rather than creating a new `GraphicsContext` instance.

It also has the benefits that you could create 1 style object and apply it
to multiple artists, or tweak a couple of properties on each...which is
nicer than using individual get/set methods on artists (IMO).

So the API could potentially become something like:

    arts = axes.plot(xdata, ydata) #Note not providing any 'style' info
    myStyle = Style.from_dict({'color': '#484D7A', 'linewidth': 1.9,
'linestyle': 'dashed'})

    arts.style = myStyle
    arts.style.color = '#FFFFFF'

or:

    myStyle = Style()
    axes.plot([0,1],[0,1], style = myStyle)

···

--
View this message in context: http://matplotlib.1069221.n5.nabble.com/MEP26-Artist-level-stylesheets-tp43664p43770.html
Sent from the matplotlib - devel mailing list archive at Nabble.com.

We’ve written a style system that lives on top of the MPL code that has a similar syntax to what you’re proposing. A simple example:

style = smgr.create( “Big Title” )

style.axes.title.font.family = “sans-serif”

style.axes.title.font.size = 24

style.apply( figure )

  • Styles get created using an x.y.z notation (or via dictionaries) and then apply themselves to Artist elements. So you can apply a style to a Figure, an Axes, a Line, etc.

  • Styles can be saved and reloaded automatically into human readable Python files.

  • Styles remember what artists they’re applied to so you can change a style and say “style.reapply()” and the plots automatically update. This makes it very easy to try out different settings without having to recreate the whole plot.

  • Artists can be tagged with names and then styles can be applied using the tag names. This is a crucial capability that’s often overlooked. This allows us to deliver a library of scripts to users that create a lot of common plots without worrying about how
    they should look. Our users call those scripts and then apply styles to the elements of a plot by setting the correct tags.

def createPlot():

l = ax.plot( x, y )

smgr.tag( l, “Elevation” )

return fig

fig = creatPlot()

smgr.set( fig, { ‘line.color’ : ‘blue’ }, tag=“Elevation” )
I’ve attached a stripped down HTML page of our user’s guide for styles. It has a lot of examples on how to use it.

If people think this something worthwhile that could be incorporated back into MPL, we can work on making the code for the style system available.

Ted

styles.html (45.5 KB)

···

From: jamesramm [jamessramm@…149…]

Sent: Sunday, August 10, 2014 12:40 AM

To: matplotlib-devel@lists.sourceforge.net

Subject: Re: [matplotlib-devel] MEP26: Artist-level stylesheets

I have updated MEP26 to include discussion on ‘decoupling’ the style from

artists and having a generic Style class.

(copied over from the github issue):

I have been thinking that a good way to get stylesheets in, would be if the

‘style’ of an artist was entirely independent.

I.E a single property which points to some kind of ‘style’ object. This way,

style objects could be created on their own (programatically, or by some

other means (Stylesheets!)) and then applied to artists at will

(programatically, or by some other means (a stylesheet parser…)).

Then I thought…when it comes to drawing, the style is entirely

independent - it has been transferred to the GraphicsContext object. So

all that is needed is to expose this object at the artist level and we can

create styles!

I created a very minimal example to explain here:

Basically, it just provides a Style class (which is just

GraphicsContextBase propertified and with a new function to generate one

from a dict) and a minimal reimplementation of Line2D and Text to show how

it would be used for both.

Just run run.py (and have a look at it) to see how the user would use style

objects.

(Note it is a bit convoluted as I have not added any axes plotting routines,

so a Line2D needs to be manually created and added).

Basically, this involves reimplementing the draw method to use the style

property rather than creating a new GraphicsContext instance.

It also has the benefits that you could create 1 style object and apply it

to multiple artists, or tweak a couple of properties on each…which is

nicer than using individual get/set methods on artists (IMO).

So the API could potentially become something like:

arts = axes.plot(xdata, ydata) #Note not providing any ‘style’ info

myStyle = Style.from_dict({‘color’: ‘#484D7A’, ‘linewidth’: 1.9,

‘linestyle’: ‘dashed’})

arts.style = myStyle

arts.style.color = ‘#FFFFFF

or:

myStyle = Style()

axes.plot([0,1],[0,1], style = myStyle)

View this message in context: http://matplotlib.1069221.n5.nabble.com/MEP26-Artist-level-stylesheets-tp43664p43770.html

Sent from the matplotlib - devel mailing list archive at Nabble.com.



Matplotlib-devel mailing list

Matplotlib-devel@lists.sourceforge.net

It would be great if we can see the code for the style system.

However, for integration into MPL, rather than something which 'sits on top'
of the existing API (I presume you are therefore working with getter/setter
functions), the MEP I'm proposing is also trying to achieve the seperation
of the 'style' of artists from their data/logic. The idea being that it
heads towards a more streamlined and extensible API.

Some of the techniques you are describing seem to cover some of the ideas
put forth in the MEP, so if you can make the code available, it would be a
great resource.

···

--
View this message in context: http://matplotlib.1069221.n5.nabble.com/MEP26-Artist-level-stylesheets-tp43664p43893.html
Sent from the matplotlib - devel mailing list archive at Nabble.com.

OK. I'm working on getting permission from management to make this available but nothing is going to happen (end if fiscal year) until early October. I'll let you know more as soon as I can.

It might be nice to start a list of functional requirements that a style system should meet. In implementing our style system for users, we found the style tagging system (see my previous emails) ended up being incredibly useful and wasn't an obvious need when we started. Maybe that's covered by the current MEP but it's not obvious to me.

Ted

···

________________________________________
From: jamesramm [jamessramm@...149...]
Sent: Friday, September 05, 2014 7:00 AM
To: matplotlib-devel@lists.sourceforge.net
Subject: Re: [matplotlib-devel] MEP26: Artist-level stylesheets

It would be great if we can see the code for the style system.

However, for integration into MPL, rather than something which 'sits on top'
of the existing API (I presume you are therefore working with getter/setter
functions), the MEP I'm proposing is also trying to achieve the seperation
of the 'style' of artists from their data/logic. The idea being that it
heads towards a more streamlined and extensible API.

Some of the techniques you are describing seem to cover some of the ideas
put forth in the MEP, so if you can make the code available, it would be a
great resource.

--
View this message in context: http://matplotlib.1069221.n5.nabble.com/MEP26-Artist-level-stylesheets-tp43664p43893.html
Sent from the matplotlib - devel mailing list archive at Nabble.com.

------------------------------------------------------------------------------
Slashdot TV.
Video for Nerds. Stuff that matters.
http://tv.slashdot.org/
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel