Skip to content

Commit f367003

Browse files
authored
Merge pull request #7007 from tacaswell/api_set_font_size_at_creation_time
API: convert string fontsize to points immediately
2 parents 23392f8 + 5f4eead commit f367003

File tree

3 files changed

+64
-50
lines changed

3 files changed

+64
-50
lines changed

lib/matplotlib/font_manager.py

+44-45
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,13 @@
122122
MSFolders = \
123123
r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders'
124124

125-
MSFontDirectories = [
125+
126+
MSFontDirectories = [
126127
r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts',
127128
r'SOFTWARE\Microsoft\Windows\CurrentVersion\Fonts']
128129

129-
X11FontDirectories = [
130+
131+
X11FontDirectories = [
130132
# an old standard installation point
131133
"/usr/X11R6/lib/X11/fonts/TTF/",
132134
"/usr/X11/lib/X11/fonts",
@@ -156,6 +158,7 @@
156158
path = os.path.join(home, '.fonts')
157159
X11FontDirectories.append(path)
158160

161+
159162
def get_fontext_synonyms(fontext):
160163
"""
161164
Return a list of file extensions extensions that are synonyms for
@@ -165,6 +168,7 @@ def get_fontext_synonyms(fontext):
165168
'otf': ('ttf', 'otf'),
166169
'afm': ('afm',)}[fontext]
167170

171+
168172
def list_fonts(directory, extensions):
169173
"""
170174
Return a list of all fonts matching any of the extensions,
@@ -174,6 +178,7 @@ def list_fonts(directory, extensions):
174178
for ext in extensions])
175179
return cbook.listFiles(directory, pattern)
176180

181+
177182
def win32FontDirectory():
178183
"""
179184
Return the user-specified font directory for Win32. This is
@@ -186,21 +191,22 @@ def win32FontDirectory():
186191
try:
187192
from six.moves import winreg
188193
except ImportError:
189-
pass # Fall through to default
194+
pass # Fall through to default
190195
else:
191196
try:
192197
user = winreg.OpenKey(winreg.HKEY_CURRENT_USER, MSFolders)
193198
try:
194199
try:
195200
return winreg.QueryValueEx(user, 'Fonts')[0]
196201
except OSError:
197-
pass # Fall through to default
202+
pass # Fall through to default
198203
finally:
199204
winreg.CloseKey(user)
200205
except OSError:
201-
pass # Fall through to default
206+
pass # Fall through to default
202207
return os.path.join(os.environ['WINDIR'], 'Fonts')
203208

209+
204210
def win32InstalledFonts(directory=None, fontext='ttf'):
205211
"""
206212
Search for fonts in the specified font directory, or use the
@@ -246,6 +252,7 @@ def win32InstalledFonts(directory=None, fontext='ttf'):
246252
winreg.CloseKey(local)
247253
return None
248254

255+
249256
def OSXInstalledFonts(directories=None, fontext='ttf'):
250257
"""
251258
Get list of font files on OS X - ignores font suffix by default.
@@ -297,6 +304,7 @@ def get_fontconfig_fonts(fontext='ttf'):
297304
if os.path.splitext(fname)[1][1:] in fontext]
298305

299306

307+
300308
def findSystemFonts(fontpaths=None, fontext='ttf'):
301309
"""
302310
Search for fonts in the specified font paths. If no paths are
@@ -338,6 +346,7 @@ def findSystemFonts(fontpaths=None, fontext='ttf'):
338346

339347
return [fname for fname in fontfiles if os.path.exists(fname)]
340348

349+
341350
def weight_as_number(weight):
342351
"""
343352
Return the weight property as a numeric value. String values
@@ -419,7 +428,6 @@ def ttfFontProperty(font):
419428
else:
420429
style = 'normal'
421430

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

425433
# !!!! Untested
@@ -451,8 +459,8 @@ def ttfFontProperty(font):
451459
# Relative stretches are: wider, narrower
452460
# Child value is: inherit
453461

454-
if sfnt4.find('narrow') >= 0 or sfnt4.find('condensed') >= 0 or \
455-
sfnt4.find('cond') >= 0:
462+
if (sfnt4.find('narrow') >= 0 or sfnt4.find('condensed') >= 0 or
463+
sfnt4.find('cond') >= 0):
456464
stretch = 'condensed'
457465
elif sfnt4.find('demi cond') >= 0:
458466
stretch = 'semi-condensed'
@@ -673,12 +681,12 @@ def __init__(self,
673681
fname = None, # if this is set, it's a hardcoded filename to use
674682
_init = None # used only by copy()
675683
):
676-
self._family = None
677-
self._slant = None
678-
self._variant = None
679-
self._weight = None
680-
self._stretch = None
681-
self._size = None
684+
self._family = _normalize_font_family(rcParams['font.family'])
685+
self._slant = rcParams['font.style']
686+
self._variant = rcParams['font.variant']
687+
self._weight = rcParams['font.weight']
688+
self._stretch = rcParams['font.stretch']
689+
self._size = rcParams['font.size']
682690
self._file = None
683691

684692
# This is used only by copy()
@@ -732,11 +740,6 @@ def get_family(self):
732740
"""
733741
Return a list of font names that comprise the font family.
734742
"""
735-
if self._family is None:
736-
family = rcParams['font.family']
737-
if is_string_like(family):
738-
return [family]
739-
return family
740743
return self._family
741744

742745
def get_name(self):
@@ -751,8 +754,6 @@ def get_style(self):
751754
Return the font style. Values are: 'normal', 'italic' or
752755
'oblique'.
753756
"""
754-
if self._slant is None:
755-
return rcParams['font.style']
756757
return self._slant
757758
get_slant = get_style
758759

@@ -761,8 +762,6 @@ def get_variant(self):
761762
Return the font variant. Values are: 'normal' or
762763
'small-caps'.
763764
"""
764-
if self._variant is None:
765-
return rcParams['font.variant']
766765
return self._variant
767766

768767
def get_weight(self):
@@ -772,8 +771,6 @@ def get_weight(self):
772771
'medium', 'roman', 'semibold', 'demibold', 'demi', 'bold',
773772
'heavy', 'extra bold', 'black'
774773
"""
775-
if self._weight is None:
776-
return rcParams['font.weight']
777774
return self._weight
778775

779776
def get_stretch(self):
@@ -782,26 +779,16 @@ def get_stretch(self):
782779
'extra-condensed', 'condensed', 'semi-condensed', 'normal',
783780
'semi-expanded', 'expanded', 'extra-expanded', 'ultra-expanded'.
784781
"""
785-
if self._stretch is None:
786-
return rcParams['font.stretch']
787782
return self._stretch
788783

789784
def get_size(self):
790785
"""
791786
Return the font size.
792787
"""
793-
if self._size is None:
794-
return rcParams['font.size']
795788
return self._size
796789

797790
def get_size_in_points(self):
798-
if self._size is not None:
799-
try:
800-
return float(self._size)
801-
except ValueError:
802-
pass
803-
default_size = FontManager.get_default_size()
804-
return default_size * font_scalings.get(self._size)
791+
return self._size
805792

806793
def get_file(self):
807794
"""
@@ -833,11 +820,7 @@ def set_family(self, family):
833820
"""
834821
if family is None:
835822
family = rcParams['font.family']
836-
if is_string_like(family):
837-
family = [six.text_type(family)]
838-
elif not is_string_like(family) and isinstance(family, Iterable):
839-
family = [six.text_type(f) for f in family]
840-
self._family = family
823+
self._family = _normalize_font_family(family)
841824
set_name = set_family
842825

843826
def set_style(self, style):
@@ -847,7 +830,7 @@ def set_style(self, style):
847830
"""
848831
if style is None:
849832
style = rcParams['font.style']
850-
if style not in ('normal', 'italic', 'oblique', None):
833+
if style not in ('normal', 'italic', 'oblique'):
851834
raise ValueError("style must be normal, italic or oblique")
852835
self._slant = style
853836
set_slant = set_style
@@ -858,7 +841,7 @@ def set_variant(self, variant):
858841
"""
859842
if variant is None:
860843
variant = rcParams['font.variant']
861-
if variant not in ('normal', 'small-caps', None):
844+
if variant not in ('normal', 'small-caps'):
862845
raise ValueError("variant must be normal or small-caps")
863846
self._variant = variant
864847

@@ -910,10 +893,15 @@ def set_size(self, size):
910893
try:
911894
size = float(size)
912895
except ValueError:
913-
if size is not None and size not in font_scalings:
896+
try:
897+
scale = font_scalings[size]
898+
except KeyError:
914899
raise ValueError(
915900
"Size is invalid. Valid font size are " + ", ".join(
916901
str(i) for i in font_scalings.keys()))
902+
else:
903+
size = scale * FontManager.get_default_size()
904+
917905
self._size = size
918906

919907
def set_file(self, file):
@@ -942,7 +930,8 @@ def set_fontconfig_pattern(self, pattern):
942930

943931
def copy(self):
944932
"""Return a deep copy of self"""
945-
return FontProperties(_init = self)
933+
return FontProperties(_init=self)
934+
946935

947936
def ttfdict_to_fnames(d):
948937
"""
@@ -958,6 +947,7 @@ def ttfdict_to_fnames(d):
958947
fnames.append(fname)
959948
return fnames
960949

950+
961951
def pickle_dump(data, filename):
962952
"""
963953
Equivalent to pickle.dump(data, open(filename, 'w'))
@@ -966,6 +956,7 @@ def pickle_dump(data, filename):
966956
with open(filename, 'wb') as fh:
967957
pickle.dump(data, fh)
968958

959+
969960
def pickle_load(filename):
970961
"""
971962
Equivalent to pickle.load(open(filename, 'r'))
@@ -976,6 +967,14 @@ def pickle_load(filename):
976967
return data
977968

978969

970+
def _normalize_font_family(family):
971+
if is_string_like(family):
972+
family = [six.text_type(family)]
973+
elif isinstance(family, Iterable):
974+
family = [six.text_type(f) for f in family]
975+
return family
976+
977+
979978
class TempCache(object):
980979
"""
981980
A class to store temporary caches that are (a) not saved to disk

lib/matplotlib/tests/test_text.py

+12
Original file line numberDiff line numberDiff line change
@@ -399,3 +399,15 @@ def test_agg_text_clip():
399399
ax1.text(x, y, "foo", clip_on=True)
400400
ax2.text(x, y, "foo")
401401
plt.show()
402+
403+
404+
@cleanup
405+
def test_text_size_binding():
406+
from matplotlib.font_manager import FontProperties
407+
408+
matplotlib.rcParams['font.size'] = 10
409+
fp = FontProperties(size='large')
410+
sz1 = fp.get_size_in_points()
411+
matplotlib.rcParams['font.size'] = 100
412+
413+
assert sz1 == fp.get_size_in_points()

lib/matplotlib/text.py

+8-5
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ def _get_layout(self, renderer):
355355

356356
baseline = 0
357357
for i, line in enumerate(lines):
358-
clean_line, ismath = self.is_math_text(line)
358+
clean_line, ismath = self.is_math_text(line, self.get_usetex())
359359
if clean_line:
360360
w, h, d = renderer.get_text_width_height_descent(clean_line,
361361
self._fontproperties,
@@ -782,7 +782,8 @@ def draw(self, renderer):
782782
y = y + posy
783783
if renderer.flipy():
784784
y = canvash - y
785-
clean_line, ismath = textobj.is_math_text(line)
785+
clean_line, ismath = textobj.is_math_text(line,
786+
self.get_usetex())
786787

787788
if textobj.get_path_effects():
788789
from matplotlib.patheffects import PathEffectRenderer
@@ -1212,7 +1213,7 @@ def set_text(self, s):
12121213
self.stale = True
12131214

12141215
@staticmethod
1215-
def is_math_text(s):
1216+
def is_math_text(s, usetex=None):
12161217
"""
12171218
Returns a cleaned string and a boolean flag.
12181219
The flag indicates if the given string *s* contains any mathtext,
@@ -1222,7 +1223,9 @@ def is_math_text(s):
12221223
"""
12231224
# Did we find an even number of non-escaped dollar signs?
12241225
# If so, treat is as math text.
1225-
if rcParams['text.usetex']:
1226+
if usetex is None:
1227+
usetex = rcParams['text.usetex']
1228+
if usetex:
12261229
if s == ' ':
12271230
s = r'\ '
12281231
return s, 'TeX'
@@ -1256,7 +1259,7 @@ def set_usetex(self, usetex):
12561259
`rcParams['text.usetex']`
12571260
"""
12581261
if usetex is None:
1259-
self._usetex = None
1262+
self._usetex = rcParams['text.usetex']
12601263
else:
12611264
self._usetex = bool(usetex)
12621265
self.stale = True

0 commit comments

Comments
 (0)