config with traits

I am trying to work out some way to make rcdefaults() work with the traited
config. Along the way, I discovered this in mplconfig:

    class mathtext(TConfig):
        cal = T.Trait("['cursive']", mplT.FontPropertiesHandler())
        rm = T.Trait("['serif']", mplT.FontPropertiesHandler())
        tt = T.Trait("['monospace']", mplT.FontPropertiesHandler())
        it = T.Trait("['serif'], style='oblique'",
mplT.FontPropertiesHandler())
        bf = T.Trait("['serif'], weight='bold'", mplT.FontPropertiesHandler())
        sf = T.Trait("['sans-serif']", mplT.FontPropertiesHandler())
        use_cm = T.true
        fallback_to_cm = T.true

I dont think that will work. One of the highlights of the new config files is
that when a file says:

[mathtext]
rm = ['serif', 'sans-serif']

you actually get a list, not a string, to pass to
mplT.FontPropertiesHandler(). I discovered the code by trying to do this:

rcParams.update(rcParamsDefault)

Another thing about T.Trait to keep in mind:

T.Trait("['cursive']", mplT.FontPropertiesHandler())
"['cursive']" is the default value and is *not validated*. Nor is it
necessarily an allowed value. For example:

T.Trait('small', 'medium', 'large')
'small' is the default value, but any future attempt to set that trait
to 'small' will fail. Only items following the default are allowed.

T.Trait('small', 'small', 'medium', 'large')
Now 'small' is a valid setting.

Darren

This was an attempt to do a direct translation from what I had in the "classic" rcsetup.py. (The previous version in mplconfig.py was semantically incorrect.) I had tested this with settings in my matplotlib.conf, but didn't realise that the default wasn't validated (and thus not interpreted into a FontPropertiesProxy object).

Darren Dale wrote:

I am trying to work out some way to make rcdefaults() work with the traited config. Along the way, I discovered this in mplconfig:

    class mathtext(TConfig):
        cal = T.Trait("['cursive']", mplT.FontPropertiesHandler())
        rm = T.Trait("['serif']", mplT.FontPropertiesHandler())
        tt = T.Trait("['monospace']", mplT.FontPropertiesHandler())
        it = T.Trait("['serif'], style='oblique'", mplT.FontPropertiesHandler())
        bf = T.Trait("['serif'], weight='bold'", mplT.FontPropertiesHandler())
        sf = T.Trait("['sans-serif']", mplT.FontPropertiesHandler())
        use_cm = T.true
        fallback_to_cm = T.true

I dont think that will work. One of the highlights of the new config files is that when a file says:

[mathtext]
rm = ['serif', 'sans-serif']

you actually get a list, not a string, to pass to mplT.FontPropertiesHandler().

Right. But it works like:

rm = "['serif', 'sans-serif']"

I realize it's hacky. The most obvious alternative is to expect a dictionary here, e.g.:

   rm = { 'family': ['serif'], 'style': 'oblique' }

But that's less like the FontProperties constructor. My goal was to make specifying fonts as similar as possible to the FontProperties object so the user doesn't have to learn a new syntax. Is there a better way to do this with Traits? Can the user specify the arguments (with keyword arguments) to a constructor?

Cheers,
Mike

I've committed a fix so this at least works. (We can change how the trait is specified later if necessary.) The validation is not as tight as it should be, yet.

I think I've passed through this bug onto another one, though:

Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
   File "/home/mdroe/usr/lib/python2.5/site-packages/matplotlib/config/mplconfig.py", line 469, in update
     self[key] = arg[key]
   File "/home/mdroe/usr/lib/python2.5/site-packages/matplotlib/config/mplconfig.py", line 454, in __setitem__
     See rcParams.keys() for a list of valid parameters.'%key)
KeyError: 'text.fontangle is not a valid rc parameter.See rcParams.keys() for a list of valid parameters.'

It seems that unlike the regular string choice traits, the custom Trait handlers *are* called with the default value when initialized. Is that something to be relied on? (Other parts of mplconfig, such as the colors, depend on this).

Cheers,
Mike

Michael Droettboom wrote:

···

This was an attempt to do a direct translation from what I had in the "classic" rcsetup.py. (The previous version in mplconfig.py was semantically incorrect.) I had tested this with settings in my matplotlib.conf, but didn't realise that the default wasn't validated (and thus not interpreted into a FontPropertiesProxy object).

Darren Dale wrote:

I am trying to work out some way to make rcdefaults() work with the traited config. Along the way, I discovered this in mplconfig:

    class mathtext(TConfig):
        cal = T.Trait("['cursive']", mplT.FontPropertiesHandler())
        rm = T.Trait("['serif']", mplT.FontPropertiesHandler())
        tt = T.Trait("['monospace']", mplT.FontPropertiesHandler())
        it = T.Trait("['serif'], style='oblique'", mplT.FontPropertiesHandler())
        bf = T.Trait("['serif'], weight='bold'", mplT.FontPropertiesHandler())
        sf = T.Trait("['sans-serif']", mplT.FontPropertiesHandler())
        use_cm = T.true
        fallback_to_cm = T.true

I dont think that will work. One of the highlights of the new config files is that when a file says:

[mathtext]
rm = ['serif', 'sans-serif']

you actually get a list, not a string, to pass to mplT.FontPropertiesHandler().

Right. But it works like:

rm = "['serif', 'sans-serif']"

I realize it's hacky. The most obvious alternative is to expect a dictionary here, e.g.:

   rm = { 'family': ['serif'], 'style': 'oblique' }

But that's less like the FontProperties constructor. My goal was to make specifying fonts as similar as possible to the FontProperties object so the user doesn't have to learn a new syntax. Is there a better way to do this with Traits? Can the user specify the arguments (with keyword arguments) to a constructor?

Cheers,
Mike

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems? Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
matplotlib-devel List Signup and Options

This was an attempt to do a direct translation from what I had in the
"classic" rcsetup.py. (The previous version in mplconfig.py was
semantically incorrect.) I had tested this with settings in my
matplotlib.conf, but didn't realise that the default wasn't validated
(and thus not interpreted into a FontPropertiesProxy object).

Darren Dale wrote:
> I am trying to work out some way to make rcdefaults() work with the
> traited config. Along the way, I discovered this in mplconfig:
>
> class mathtext(TConfig):
> cal = T.Trait("['cursive']", mplT.FontPropertiesHandler())
> rm = T.Trait("['serif']", mplT.FontPropertiesHandler())
> tt = T.Trait("['monospace']", mplT.FontPropertiesHandler())
> it = T.Trait("['serif'], style='oblique'",
> mplT.FontPropertiesHandler())
> bf = T.Trait("['serif'], weight='bold'",
> mplT.FontPropertiesHandler()) sf = T.Trait("['sans-serif']",
> mplT.FontPropertiesHandler()) use_cm = T.true
> fallback_to_cm = T.true
>
> I dont think that will work. One of the highlights of the new config
> files is that when a file says:
>
> [mathtext]
> rm = ['serif', 'sans-serif']
>
> you actually get a list, not a string, to pass to
> mplT.FontPropertiesHandler().

Right. But it works like:

rm = "['serif', 'sans-serif']"

I realize it's hacky. The most obvious alternative is to expect a
dictionary here, e.g.:

   rm = { 'family': ['serif'], 'style': 'oblique' }

But that's less like the FontProperties constructor.

Why do you say that? Here is the constructor:

    def __init__(self,
                 family = None,
                 style = None,
                 variant= None,
                 weight = None,
                 stretch= None,
                 size = None,
                 fname = None,
                 ):

wouldnt FontProperties(**rm) work?

My goal was to
make specifying fonts as similar as possible to the FontProperties
object so the user doesn't have to learn a new syntax. Is there a
better way to do this with Traits? Can the user specify the arguments
(with keyword arguments) to a constructor?

I think this is getting a little out of hand, isnt it?:

#mathtext.cal : ['cursive']
#mathtext.rm : ['serif']
#mathtext.tt : ['monospace']
#mathtext.it : ['serif'], style='oblique'
#mathtext.bf : ['serif'], weight='bold'
#mathtext.sf : ['sans-serif']

That means we have comma-separated strings for lists of fonts, but
bracket-enclosed comma-separated quoted strings for mathtext properties.

If you want all that flexibility, why not do it in the usual way:

#mathtext.it.family : 'serif'
#mathtext.it.style : 'oblique'

But is that much flexibility needed?

Darren

···

On Wednesday 22 August 2007 03:09:30 pm Michael Droettboom wrote:

Darren Dale wrote:

I realize it's hacky. The most obvious alternative is to expect a
dictionary here, e.g.:

   rm = { 'family': ['serif'], 'style': 'oblique' }

But that's less like the FontProperties constructor.

Why do you say that? Here is the constructor:

    def __init__(self,
                 family = None,
                 style = None,
                 variant= None,
                 weight = None,
                 stretch= None,
                 size = None,
                 fname = None,
                 ):

wouldnt FontProperties(**rm) work?

Sure. I just meant that

   rm = { 'family': ['serif'], 'style': 'oblique' }

is syntactically different from

   rm = FontProperties(['serif'], style='oblique')

My goal was to make specifying fonts as similar as possible to the FontProperties
object so the user doesn't have to learn a new syntax. Is there a
better way to do this with Traits? Can the user specify the arguments
(with keyword arguments) to a constructor?

I think this is getting a little out of hand, isnt it?:

#mathtext.cal : ['cursive']
#mathtext.rm : ['serif']
#mathtext.tt : ['monospace']
#mathtext.it : ['serif'], style='oblique'
#mathtext.bf : ['serif'], weight='bold'
#mathtext.sf : ['sans-serif']

That means we have comma-separated strings for lists of fonts, but bracket-enclosed comma-separated quoted strings for mathtext properties.

Well, they are different beasts. The former only specifies a choice of families. The latter specifies a specific font. I didn't intend to invent something new for mathtext -- there were no other instances where a full set of font properties was required to specify a font. (Sure font.* is a sort of example of that, but it includes other things as well...)

If you want all that flexibility, why not do it in the usual way:

#mathtext.it.family : 'serif'
#mathtext.it.style : 'oblique'

That seems reasonable. I think I had a mental block around this because of the verbosity (and seeing a font specification as a single unit), but it does seem to fit in much better with the existing options (i.e. a subset of font.*).

*IF* fontconfig is ever adopted, we could use fontconfig patterns as an alternative, which are at least some kind of standard.

But is that much flexibility needed?

The flexibility is certainly needed, and came directly out of a request on matplotlib-user. There are cases where you want the variable names (the 'it' font in TeX parlance) to be in an upright serif font. So you can't hardcode either the family or the style. And there is no way (AFAIK) to go from a given serif font to its companion sans-serif font, so when changing to a new font "collection", each one will have to be specified individually.

Cheers,
Mike

···

On Wednesday 22 August 2007 03:09:30 pm Michael Droettboom wrote:

Right:

mathtext.it : serif-12:italic # use the default serif, 12 pt italic
or
mathtext.it : times:italic # use the times italic font, default size

Could this syntax be adopted, even without fontconfig? Then if we decided to
use fontconfig in the future, the disruption would not be too great.

Darren

···

On Wednesday 22 August 2007 4:20:08 pm Michael Droettboom wrote:

Darren Dale wrote:
> On Wednesday 22 August 2007 03:09:30 pm Michael Droettboom wrote:
>> I realize it's hacky. The most obvious alternative is to expect a
>> dictionary here, e.g.:
>>
>> rm = { 'family': ['serif'], 'style': 'oblique' }
>>
>> But that's less like the FontProperties constructor.
>
> Why do you say that? Here is the constructor:
>
> def __init__(self,
> family = None,
> style = None,
> variant= None,
> weight = None,
> stretch= None,
> size = None,
> fname = None,
> ):
>
> wouldnt FontProperties(**rm) work?

Sure. I just meant that

   rm = { 'family': ['serif'], 'style': 'oblique' }

is syntactically different from

   rm = FontProperties(['serif'], style='oblique')

>> My goal was to
>> make specifying fonts as similar as possible to the FontProperties
>> object so the user doesn't have to learn a new syntax. Is there a
>> better way to do this with Traits? Can the user specify the arguments
>> (with keyword arguments) to a constructor?
>
> I think this is getting a little out of hand, isnt it?:
>
> #mathtext.cal : ['cursive']
> #mathtext.rm : ['serif']
> #mathtext.tt : ['monospace']
> #mathtext.it : ['serif'], style='oblique'
> #mathtext.bf : ['serif'], weight='bold'
> #mathtext.sf : ['sans-serif']
>
> That means we have comma-separated strings for lists of fonts, but
> bracket-enclosed comma-separated quoted strings for mathtext properties.

Well, they are different beasts. The former only specifies a choice of
families. The latter specifies a specific font. I didn't intend to
invent something new for mathtext -- there were no other instances where
a full set of font properties was required to specify a font. (Sure
font.* is a sort of example of that, but it includes other things as
well...)

> If you want all that flexibility, why not do it in the usual way:
>
> #mathtext.it.family : 'serif'
> #mathtext.it.style : 'oblique'

That seems reasonable. I think I had a mental block around this because
of the verbosity (and seeing a font specification as a single unit), but
it does seem to fit in much better with the existing options (i.e. a
subset of font.*).

*IF* fontconfig is ever adopted, we could use fontconfig patterns as an
alternative, which are at least some kind of standard.

Darren Dale wrote:

Darren Dale wrote:

If you want all that flexibility, why not do it in the usual way:

#mathtext.it.family : 'serif'
#mathtext.it.style : 'oblique'

That seems reasonable. I think I had a mental block around this because
of the verbosity (and seeing a font specification as a single unit), but
it does seem to fit in much better with the existing options (i.e. a
subset of font.*).

*IF* fontconfig is ever adopted, we could use fontconfig patterns as an
alternative, which are at least some kind of standard.

Right:

mathtext.it : serif-12:italic # use the default serif, 12 pt italic
or
mathtext.it : times:italic # use the times italic font, default size

Could this syntax be adopted, even without fontconfig? Then if we decided to use fontconfig in the future, the disruption would not be too great.

Sure, it's certainly an easy enough format to support.

Of course, the matching algorithm used by font_manager.py is different from fontconfig. font_manager.py essentially looks for an exact match or falls back to a single default. fontconfig does a nearest neighbor search, so often finds a better alternative. So even if they use the same syntax, the results will be different (in some side cases) if we ever move over to fontconfig. (There are pros and cons to using fontconfig already discussed on this list. I'm not really advocating for or against it myself.)

Still, IMHO, it's worth supporting this syntax now even though users may need to change their font specifiers later -- those changes should be more minor than if we go with

#mathtext.it.family : 'serif'
#mathtext.it.style : 'oblique'

now.

If we go this way, it would also be worthwhile to support this syntax internally (anywhere a FontProperties object is currently accepted it could alternatively be a fontconfig string.)

Cheers,
Mike

···

On Wednesday 22 August 2007 4:20:08 pm Michael Droettboom wrote:

Michael Droettboom wrote:

Darren Dale wrote:

Darren Dale wrote:

If you want all that flexibility, why not do it in the usual way:

#mathtext.it.family : 'serif'
#mathtext.it.style : 'oblique'

That seems reasonable. I think I had a mental block around this because
of the verbosity (and seeing a font specification as a single unit), but
it does seem to fit in much better with the existing options (i.e. a
subset of font.*).

*IF* fontconfig is ever adopted, we could use fontconfig patterns as an
alternative, which are at least some kind of standard.

Right:
mathtext.it : serif-12:italic # use the default serif, 12 pt italic
or
mathtext.it : times:italic # use the times italic font, default size

Could this syntax be adopted, even without fontconfig? Then if we decided to use fontconfig in the future, the disruption would not be too great.

Sure, it's certainly an easy enough format to support.

Of course, the matching algorithm used by font_manager.py is different from fontconfig. font_manager.py essentially looks for an exact match or falls back to a single default. fontconfig does a nearest neighbor search, so often finds a better alternative. So even if they use the same syntax, the results will be different (in some side cases) if we ever move over to fontconfig. (There are pros and cons to using fontconfig already discussed on this list. I'm not really advocating for or against it myself.)

Still, IMHO, it's worth supporting this syntax now even though users may need to change their font specifiers later -- those changes should be more minor than if we go with

#mathtext.it.family : 'serif'
#mathtext.it.style : 'oblique'

now.

I just committed code to support fontconfig patterns on all of the mathtext.* fonts. You can also use fontconfig patterns in the pylab and OO interfaces -- e.g.:

    title("This is my title", fontproperties="Helvetica:italic")

(Note this doesn't actually use fontconfig -- I've just borrowed its font-specification syntax.)

I was thinking we probably want to collapse the following options down to one as well --->

#font.family : sans-serif
#font.style : normal
#font.variant : normal
#font.weight : medium
#font.stretch : normal
# note that font.size controls default text sizes. To configure
# special text sizes tick labels, axes, labels, title, etc, see the rc
# settings for axes and ticks. Special text sizes can be defined
# relative to font.size, using the following values: xx-small, x-small,
# small, medium, large, x-large, xx-large, larger, or smaller
#font.size : 12.0

probably to "font.default" ? For backward compatibility, we probably want to continue to support these, but "font.default" would override them if provided. Any ideas on how to best do that? I only have a rough sense of where the new traited config stuff is going wrt backward compatibility etc.

Cheers,
Mike

···

On Wednesday 22 August 2007 4:20:08 pm Michael Droettboom wrote: