Skip to content

Commit

Permalink
Change behavior of font.* rcParams so they take effect only on to-b…
Browse files Browse the repository at this point in the history
…e-created text objects
  • Loading branch information
mdboom committed May 14, 2013
1 parent edb1526 commit cc61700
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 30 deletions.
7 changes: 6 additions & 1 deletion doc/api/api_changes.rst
Expand Up @@ -15,7 +15,12 @@ For new features that were added to matplotlib, please see
Changes in 1.3.x
================

* Fixed a bug in setting the position for the right/top spine with data
* The `font.*` rcParams now affect only text objects created after the
rcParam has been set, and will not retroactively affect already
existing text objects. This brings their behavior in line with most
other rcParams.

* Fixed a bug in setting the position for the right/top spine with data
position type. Previously, it would draw the right or top spine at
+1 data offset.

Expand Down
7 changes: 7 additions & 0 deletions doc/users/whats_new.rst
Expand Up @@ -33,6 +33,13 @@ simply call `pyplot.xkcd` before creating your plot.
.. plot:: mpl_examples/showcase/xkcd.py


Changes to font rcParams
------------------------
The `font.*` rcParams now affect only text objects created after the
rcParam has been set, and will not retroactively affect already
existing text objects. This brings their behavior in line with most
other rcParams.

``axes.xmargin`` and ``axes.ymargin`` added to rcParams
-------------------------------------------------------
``rcParam`` values (``axes.xmargin`` and ``axes.ymargin``) were added
Expand Down
60 changes: 33 additions & 27 deletions lib/matplotlib/font_manager.py
Expand Up @@ -808,18 +808,19 @@ def set_family(self, family):
'fantasy', or 'monospace', or a real font name.
"""
if family is None:
self._family = None
else:
if is_string_like(family):
family = [family]
self._family = family
family = rcParams['font.family']
if is_string_like(family):
family = [family]
self._family = family
set_name = set_family

def set_style(self, style):
"""
Set the font style. Values are: 'normal', 'italic' or
'oblique'.
"""
if style is None:
style = rcParams['font.style']
if style not in ('normal', 'italic', 'oblique', None):
raise ValueError("style must be normal, italic or oblique")
self._slant = style
Expand All @@ -829,6 +830,8 @@ def set_variant(self, variant):
"""
Set the font variant. Values are: 'normal' or 'small-caps'.
"""
if variant is None:
variant = rcParams['font.variant']
if variant not in ('normal', 'small-caps', None):
raise ValueError("variant must be normal or small-caps")
self._variant = variant
Expand All @@ -840,14 +843,15 @@ def set_weight(self, weight):
'regular', 'book', 'medium', 'roman', 'semibold', 'demibold',
'demi', 'bold', 'heavy', 'extra bold', 'black'
"""
if weight is not None:
try:
weight = int(weight)
if weight < 0 or weight > 1000:
raise ValueError()
except ValueError:
if weight not in weight_dict:
raise ValueError("weight is invalid")
if weight is None:
weight = rcParams['font.weight']
try:
weight = int(weight)
if weight < 0 or weight > 1000:
raise ValueError()
except ValueError:
if weight not in weight_dict:
raise ValueError("weight is invalid")
self._weight = weight

def set_stretch(self, stretch):
Expand All @@ -857,14 +861,15 @@ def set_stretch(self, stretch):
'semi-expanded', 'expanded', 'extra-expanded' or
'ultra-expanded', or a numeric value in the range 0-1000.
"""
if stretch is not None:
try:
stretch = int(stretch)
if stretch < 0 or stretch > 1000:
raise ValueError()
except ValueError:
if stretch not in stretch_dict:
raise ValueError("stretch is invalid")
if stretch is None:
stretch = rcParams['font.weight']

This comment has been minimized.

Copy link
@pelson

pelson May 15, 2013

Member

Was this supposed to be 'font.stretch'? Relates to #2006

This comment has been minimized.

Copy link
@mdboom

mdboom May 15, 2013

Author Member

Indeed. Sorry about that -- didn't take long to find, though. Fix in de956ef

try:
stretch = int(stretch)
if stretch < 0 or stretch > 1000:
raise ValueError()
except ValueError:
if stretch not in stretch_dict:
raise ValueError("stretch is invalid")
self._stretch = stretch

def set_size(self, size):
Expand All @@ -873,12 +878,13 @@ def set_size(self, size):
'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'
or an absolute font size, e.g., 12.
"""
if size is not None:
try:
size = float(size)
except ValueError:
if size is not None and size not in font_scalings:
raise ValueError("size is invalid")
if size is None:
size = rcParams['font.size']
try:
size = float(size)
except ValueError:
if size is not None and size not in font_scalings:
raise ValueError("size is invalid")
self._size = size

def set_file(self, file):
Expand Down
4 changes: 2 additions & 2 deletions lib/matplotlib/rcsetup.py
Expand Up @@ -262,7 +262,7 @@ def validate_colorlist(s):

def validate_stringlist(s):
'return a list'
if type(s) is str:
if type(s) in (str, unicode):
return [v.strip() for v in s.split(',')]
else:
assert type(s) in [list, tuple]
Expand Down Expand Up @@ -513,7 +513,7 @@ def __call__(self, s):


## font props
'font.family': ['sans-serif', str], # used by text object
'font.family': ['sans-serif', validate_stringlist], # used by text object

This comment has been minimized.

Copy link
@leejjoon

leejjoon May 15, 2013

Contributor

@mdboom : is this change necessary? This causes an error with texmanager.py, which expects rcParams["font.family"] to be a string. And I guess there are user codes that will fail with this change.

This comment has been minimized.

Copy link
@mdboom

mdboom May 15, 2013

Author Member

Ah -- I missed that about texmanager. The other text handling handled this just fine without further changes. I think maybe we should try to fix texmanager to support a list (see #2012).

Here the use case that brought this about:

The xkcd function needs to change the font of all text that is created while it is in effect, and then go back to the previous settings afterward. If you set font.family to fantasy and change font.fantasy to Humor Sans, this doesn't work, because the lookup from a category name ('fantasy') to a concrete name is dynamic so when font.family is reverted, so is all of the text that was created in the xkcd context. I think this is the correct behavior for category names, as they are supposed to be dynamically updatable. So the only way to make the font setting on a text object permanent is to not use the category names but to use an actual concrete font name. And ideally that should be provided as a list so that we can account for users who don't have a particular font installed.

I'm not sure what user code would fail because of this change -- if it does, I think it's probably a real corner case. I know there is a lot of code that sets font.family as a single name, but that will continue to work. But I think it's much less common that user code will read this value.

'font.style': ['normal', str],
'font.variant': ['normal', str],
'font.stretch': ['normal', str],
Expand Down

0 comments on commit cc61700

Please sign in to comment.