diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index 51920abd2781..dc41207b0a18 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -122,11 +122,13 @@ MSFolders = \ r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders' -MSFontDirectories = [ + +MSFontDirectories = [ r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts', r'SOFTWARE\Microsoft\Windows\CurrentVersion\Fonts'] -X11FontDirectories = [ + +X11FontDirectories = [ # an old standard installation point "/usr/X11R6/lib/X11/fonts/TTF/", "/usr/X11/lib/X11/fonts", @@ -156,6 +158,7 @@ path = os.path.join(home, '.fonts') X11FontDirectories.append(path) + def get_fontext_synonyms(fontext): """ Return a list of file extensions extensions that are synonyms for @@ -165,6 +168,7 @@ def get_fontext_synonyms(fontext): 'otf': ('ttf', 'otf'), 'afm': ('afm',)}[fontext] + def list_fonts(directory, extensions): """ Return a list of all fonts matching any of the extensions, @@ -174,6 +178,7 @@ def list_fonts(directory, extensions): for ext in extensions]) return cbook.listFiles(directory, pattern) + def win32FontDirectory(): """ Return the user-specified font directory for Win32. This is @@ -186,7 +191,7 @@ def win32FontDirectory(): try: from six.moves import winreg except ImportError: - pass # Fall through to default + pass # Fall through to default else: try: user = winreg.OpenKey(winreg.HKEY_CURRENT_USER, MSFolders) @@ -194,13 +199,14 @@ def win32FontDirectory(): try: return winreg.QueryValueEx(user, 'Fonts')[0] except OSError: - pass # Fall through to default + pass # Fall through to default finally: winreg.CloseKey(user) except OSError: - pass # Fall through to default + pass # Fall through to default return os.path.join(os.environ['WINDIR'], 'Fonts') + def win32InstalledFonts(directory=None, fontext='ttf'): """ Search for fonts in the specified font directory, or use the @@ -246,6 +252,7 @@ def win32InstalledFonts(directory=None, fontext='ttf'): winreg.CloseKey(local) return None + def OSXInstalledFonts(directories=None, fontext='ttf'): """ Get list of font files on OS X - ignores font suffix by default. @@ -297,6 +304,7 @@ def get_fontconfig_fonts(fontext='ttf'): if os.path.splitext(fname)[1][1:] in fontext] + def findSystemFonts(fontpaths=None, fontext='ttf'): """ Search for fonts in the specified font paths. If no paths are @@ -338,6 +346,7 @@ def findSystemFonts(fontpaths=None, fontext='ttf'): return [fname for fname in fontfiles if os.path.exists(fname)] + def weight_as_number(weight): """ Return the weight property as a numeric value. String values @@ -419,7 +428,6 @@ def ttfFontProperty(font): else: style = 'normal' - # Variants are: small-caps and normal (default) # !!!! Untested @@ -451,8 +459,8 @@ def ttfFontProperty(font): # Relative stretches are: wider, narrower # Child value is: inherit - if sfnt4.find('narrow') >= 0 or sfnt4.find('condensed') >= 0 or \ - sfnt4.find('cond') >= 0: + if (sfnt4.find('narrow') >= 0 or sfnt4.find('condensed') >= 0 or + sfnt4.find('cond') >= 0): stretch = 'condensed' elif sfnt4.find('demi cond') >= 0: stretch = 'semi-condensed' @@ -673,12 +681,12 @@ def __init__(self, fname = None, # if this is set, it's a hardcoded filename to use _init = None # used only by copy() ): - self._family = None - self._slant = None - self._variant = None - self._weight = None - self._stretch = None - self._size = None + self._family = _normalize_font_family(rcParams['font.family']) + self._slant = rcParams['font.style'] + self._variant = rcParams['font.variant'] + self._weight = rcParams['font.weight'] + self._stretch = rcParams['font.stretch'] + self._size = rcParams['font.size'] self._file = None # This is used only by copy() @@ -732,11 +740,6 @@ def get_family(self): """ Return a list of font names that comprise the font family. """ - if self._family is None: - family = rcParams['font.family'] - if is_string_like(family): - return [family] - return family return self._family def get_name(self): @@ -751,8 +754,6 @@ def get_style(self): Return the font style. Values are: 'normal', 'italic' or 'oblique'. """ - if self._slant is None: - return rcParams['font.style'] return self._slant get_slant = get_style @@ -761,8 +762,6 @@ def get_variant(self): Return the font variant. Values are: 'normal' or 'small-caps'. """ - if self._variant is None: - return rcParams['font.variant'] return self._variant def get_weight(self): @@ -772,8 +771,6 @@ def get_weight(self): 'medium', 'roman', 'semibold', 'demibold', 'demi', 'bold', 'heavy', 'extra bold', 'black' """ - if self._weight is None: - return rcParams['font.weight'] return self._weight def get_stretch(self): @@ -782,26 +779,16 @@ def get_stretch(self): 'extra-condensed', 'condensed', 'semi-condensed', 'normal', 'semi-expanded', 'expanded', 'extra-expanded', 'ultra-expanded'. """ - if self._stretch is None: - return rcParams['font.stretch'] return self._stretch def get_size(self): """ Return the font size. """ - if self._size is None: - return rcParams['font.size'] return self._size def get_size_in_points(self): - if self._size is not None: - try: - return float(self._size) - except ValueError: - pass - default_size = FontManager.get_default_size() - return default_size * font_scalings.get(self._size) + return self._size def get_file(self): """ @@ -833,11 +820,7 @@ def set_family(self, family): """ if family is None: family = rcParams['font.family'] - if is_string_like(family): - family = [six.text_type(family)] - elif not is_string_like(family) and isinstance(family, Iterable): - family = [six.text_type(f) for f in family] - self._family = family + self._family = _normalize_font_family(family) set_name = set_family def set_style(self, style): @@ -847,7 +830,7 @@ def set_style(self, style): """ if style is None: style = rcParams['font.style'] - if style not in ('normal', 'italic', 'oblique', None): + if style not in ('normal', 'italic', 'oblique'): raise ValueError("style must be normal, italic or oblique") self._slant = style set_slant = set_style @@ -858,7 +841,7 @@ def set_variant(self, variant): """ if variant is None: variant = rcParams['font.variant'] - if variant not in ('normal', 'small-caps', None): + if variant not in ('normal', 'small-caps'): raise ValueError("variant must be normal or small-caps") self._variant = variant @@ -910,10 +893,15 @@ def set_size(self, size): try: size = float(size) except ValueError: - if size is not None and size not in font_scalings: + try: + scale = font_scalings[size] + except KeyError: raise ValueError( "Size is invalid. Valid font size are " + ", ".join( str(i) for i in font_scalings.keys())) + else: + size = scale * FontManager.get_default_size() + self._size = size def set_file(self, file): @@ -942,7 +930,8 @@ def set_fontconfig_pattern(self, pattern): def copy(self): """Return a deep copy of self""" - return FontProperties(_init = self) + return FontProperties(_init=self) + def ttfdict_to_fnames(d): """ @@ -958,6 +947,7 @@ def ttfdict_to_fnames(d): fnames.append(fname) return fnames + def pickle_dump(data, filename): """ Equivalent to pickle.dump(data, open(filename, 'w')) @@ -966,6 +956,7 @@ def pickle_dump(data, filename): with open(filename, 'wb') as fh: pickle.dump(data, fh) + def pickle_load(filename): """ Equivalent to pickle.load(open(filename, 'r')) @@ -976,6 +967,14 @@ def pickle_load(filename): return data +def _normalize_font_family(family): + if is_string_like(family): + family = [six.text_type(family)] + elif isinstance(family, Iterable): + family = [six.text_type(f) for f in family] + return family + + class TempCache(object): """ A class to store temporary caches that are (a) not saved to disk diff --git a/lib/matplotlib/tests/test_text.py b/lib/matplotlib/tests/test_text.py index 88bbc4ad0349..44d2abb38aee 100644 --- a/lib/matplotlib/tests/test_text.py +++ b/lib/matplotlib/tests/test_text.py @@ -399,3 +399,15 @@ def test_agg_text_clip(): ax1.text(x, y, "foo", clip_on=True) ax2.text(x, y, "foo") plt.show() + + +@cleanup +def test_text_size_binding(): + from matplotlib.font_manager import FontProperties + + matplotlib.rcParams['font.size'] = 10 + fp = FontProperties(size='large') + sz1 = fp.get_size_in_points() + matplotlib.rcParams['font.size'] = 100 + + assert sz1 == fp.get_size_in_points() diff --git a/lib/matplotlib/text.py b/lib/matplotlib/text.py index 029cbb65f098..2fad1ee19caf 100644 --- a/lib/matplotlib/text.py +++ b/lib/matplotlib/text.py @@ -355,7 +355,7 @@ def _get_layout(self, renderer): baseline = 0 for i, line in enumerate(lines): - clean_line, ismath = self.is_math_text(line) + clean_line, ismath = self.is_math_text(line, self.get_usetex()) if clean_line: w, h, d = renderer.get_text_width_height_descent(clean_line, self._fontproperties, @@ -782,7 +782,8 @@ def draw(self, renderer): y = y + posy if renderer.flipy(): y = canvash - y - clean_line, ismath = textobj.is_math_text(line) + clean_line, ismath = textobj.is_math_text(line, + self.get_usetex()) if textobj.get_path_effects(): from matplotlib.patheffects import PathEffectRenderer @@ -1212,7 +1213,7 @@ def set_text(self, s): self.stale = True @staticmethod - def is_math_text(s): + def is_math_text(s, usetex=None): """ Returns a cleaned string and a boolean flag. The flag indicates if the given string *s* contains any mathtext, @@ -1222,7 +1223,9 @@ def is_math_text(s): """ # Did we find an even number of non-escaped dollar signs? # If so, treat is as math text. - if rcParams['text.usetex']: + if usetex is None: + usetex = rcParams['text.usetex'] + if usetex: if s == ' ': s = r'\ ' return s, 'TeX' @@ -1256,7 +1259,7 @@ def set_usetex(self, usetex): `rcParams['text.usetex']` """ if usetex is None: - self._usetex = None + self._usetex = rcParams['text.usetex'] else: self._usetex = bool(usetex) self.stale = True