Skip to content

API: convert string fontsize to points immediately #7007

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Dec 12, 2016
89 changes: 44 additions & 45 deletions lib/matplotlib/font_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -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
Expand All @@ -186,21 +191,22 @@ 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)
try:
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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -419,7 +428,6 @@ def ttfFontProperty(font):
else:
style = 'normal'


# Variants are: small-caps and normal (default)

# !!!! Untested
Expand Down Expand Up @@ -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'
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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):
Expand All @@ -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

Expand All @@ -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):
Expand All @@ -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):
Expand All @@ -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):
"""
Expand Down Expand Up @@ -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):
Expand All @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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):
"""
Expand All @@ -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'))
Expand All @@ -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'))
Expand All @@ -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
Expand Down
12 changes: 12 additions & 0 deletions lib/matplotlib/tests/test_text.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
13 changes: 8 additions & 5 deletions lib/matplotlib/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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'
Expand Down Expand Up @@ -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
Expand Down