Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 13ed1fd

Browse files
committed
Expose Unicode font functionality for mathtext through rcParams
svn path=/trunk/matplotlib/; revision=3677
1 parent 27b60a0 commit 13ed1fd

5 files changed

Lines changed: 135 additions & 38 deletions

File tree

lib/matplotlib/_mathtext_data.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2211,7 +2211,7 @@
22112211
'$': 36,
22122212
'{': 123,
22132213
'}': 125,
2214-
'imath': 0xfd,
2214+
'imath': 0x131,
22152215
'circumflexaccent' : 770,
22162216
'combiningbreve' : 774,
22172217
'combiningoverline' : 772,

lib/matplotlib/mathtext.py

Lines changed: 87 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@
133133
from cStringIO import StringIO
134134
from math import floor, ceil
135135
from sets import Set
136-
from unicodedata import category
136+
import unicodedata
137137
from warnings import warn
138138

139139
from numpy import inf, isinf
@@ -462,7 +462,7 @@ def _get_font(self, font):
462462

463463
cached_font = self.fonts.get(basename)
464464
if cached_font is None:
465-
font = FT2Font(os.path.join(self.basepath, basename + ".ttf"))
465+
font = FT2Font(basename)
466466
cached_font = self.CachedFont(font)
467467
self.fonts[basename] = cached_font
468468
self.fonts[font.postscript_name] = cached_font
@@ -545,15 +545,24 @@ class BakomaFonts(TruetypeFonts):
545545
"""
546546
Use the Bakoma true type fonts for rendering
547547
"""
548-
fontmap = { 'cal' : 'cmsy10',
549-
'rm' : 'cmr10',
550-
'tt' : 'cmtt10',
551-
'it' : 'cmmi10',
552-
'bf' : 'cmb10',
553-
'sf' : 'cmss10',
554-
'ex' : 'cmex10'
555-
}
556-
548+
_fontmap = { 'cal' : 'cmsy10',
549+
'rm' : 'cmr10',
550+
'tt' : 'cmtt10',
551+
'it' : 'cmmi10',
552+
'bf' : 'cmb10',
553+
'sf' : 'cmss10',
554+
'ex' : 'cmex10'
555+
}
556+
fontmap = {}
557+
558+
def __init__(self, *args, **kwargs):
559+
TruetypeFonts.__init__(self, *args, **kwargs)
560+
if not len(self.fontmap):
561+
for key, val in self._fontmap.items():
562+
fullpath = os.path.join(self.basepath, val + ".ttf")
563+
self.fontmap[key] = fullpath
564+
self.fontmap[val] = fullpath
565+
557566
def _get_offset(self, cached_font, glyph, fontsize, dpi):
558567
if cached_font.font.postscript_name == 'Cmex10':
559568
return glyph.height/64.0/2.0 + 256.0/64.0 * dpi/72.0
@@ -564,7 +573,7 @@ def _get_offset(self, cached_font, glyph, fontsize, dpi):
564573
def _get_glyph(self, fontname, sym, fontsize):
565574
if fontname in self.fontmap and latex_to_bakoma.has_key(sym):
566575
basename, num = latex_to_bakoma[sym]
567-
slanted = basename == "cmmi10" or sym in self._slanted_symbols
576+
slanted = (basename == "cmmi10") or sym in self._slanted_symbols
568577
cached_font = self._get_font(basename)
569578
symbol_name = cached_font.font.get_glyph_name(num)
570579
num = cached_font.glyphmap[num]
@@ -638,15 +647,24 @@ def get_sized_alternatives_for_symbol(self, fontname, sym):
638647
class UnicodeFonts(TruetypeFonts):
639648
"""An abstract base class for handling Unicode fonts.
640649
"""
641-
fontmap = { 'cal' : 'cmsy10',
642-
'rm' : 'DejaVuSerif',
643-
'tt' : 'DejaVuSansMono',
644-
'it' : 'DejaVuSerif-Italic',
645-
'bf' : 'DejaVuSerif-Bold',
646-
'sf' : 'DejaVuSans',
647-
None : 'DejaVuSerif-Italic'
648-
}
649650

651+
fontmap = {}
652+
653+
def __init__(self, *args, **kwargs):
654+
# This must come first so the backend's owner is set correctly
655+
if rcParams['mathtext.fallback_to_cm']:
656+
self.cm_fallback = BakomaFonts(*args, **kwargs)
657+
else:
658+
self.cm_fallback = None
659+
TruetypeFonts.__init__(self, *args, **kwargs)
660+
if not len(self.fontmap):
661+
for texfont in "cal rm tt it bf sf".split():
662+
setting = rcParams['mathtext.' + texfont]
663+
family, weight, style = setting
664+
prop = FontProperties(family=family, weight=weight, style=style)
665+
font = fontManager.findfont(prop)
666+
self.fontmap[texfont] = font
667+
650668
def _get_offset(self, cached_font, glyph, fontsize, dpi):
651669
return 0.
652670

@@ -662,33 +680,65 @@ def _get_glyph(self, fontname, sym, fontsize):
662680
uniindex = get_unicode_index(sym[4:])
663681
fontsize *= GROW_FACTOR
664682
else:
665-
warn("No TeX to unicode mapping for '%s'" % sym,
683+
uniindex = ord('?')
684+
warn("No TeX to unicode mapping for '%s'" % sym.encode('ascii', 'replace'),
666685
MathTextWarning)
667686

668687
# Only characters in the "Letter" class should be italicized in 'it'
669-
# mode. This class includes greek letters, of course.
670-
if (fontname == 'it'
671-
and not category(unichr(uniindex)).startswith("L")):
672-
fontname = 'rm'
673-
674-
slanted = (fontname == 'it')
675-
676-
cached_font = self._get_font(fontname)
688+
# mode. Greek capital letters should be Roman.
677689
if found_symbol:
690+
new_fontname = fontname
691+
692+
if fontname == 'it':
693+
unistring = unichr(uniindex)
694+
if (not unicodedata.category(unistring).startswith("L")
695+
or unicodedata.name(unistring).startswith("GREEK CAPITAL")):
696+
new_fontname = 'rm'
697+
698+
slanted = (new_fontname == 'it')
699+
cached_font = self._get_font(new_fontname)
678700
try:
679701
glyphindex = cached_font.charmap[uniindex]
680702
except KeyError:
681703
warn("Font '%s' does not have a glyph for '%s'" %
682-
(cached_font.font.postscript_name, sym),
704+
(cached_font.font.postscript_name, sym.encode('ascii', 'replace')),
683705
MathTextWarning)
684706
found_symbol = False
685707

686708
if not found_symbol:
687-
uniindex = 0xA4 # currency character, for lack of anything better
688-
glyphindex = cached_font.charmap[uniindex]
709+
if self.cm_fallback:
710+
warn("Substituting with a symbol from the Computer Modern family.",
711+
MathTextWarning)
712+
return self.cm_fallback._get_glyph(fontname, sym, fontsize)
713+
else:
714+
new_fontname = fontname
715+
cached_font = self._get_font(fontname)
716+
uniindex = 0xA4 # currency character, for lack of anything better
717+
glyphindex = cached_font.charmap[uniindex]
718+
slanted = False
689719

690720
symbol_name = cached_font.font.get_glyph_name(glyphindex)
691721
return cached_font, uniindex, symbol_name, fontsize, slanted
722+
723+
def set_canvas_size(self, w, h):
724+
'Dimension the drawing canvas; may be a noop'
725+
TruetypeFonts.set_canvas_size(self, w, h)
726+
if self.cm_fallback:
727+
self.cm_fallback.set_canvas_size(w, h)
728+
729+
def get_used_characters(self):
730+
used_characters = dict(self.used_characters)
731+
if self.cm_fallback:
732+
fallback_characters = self.cm_fallback.get_used_characters()
733+
for key, val in fallback_characters:
734+
used_characters.setdefault(key, Set()).update(val)
735+
return used_characters
736+
737+
def get_fonts(self):
738+
fonts = [x.font for x in self.fonts.values()]
739+
if self.cm_fallback:
740+
fonts.extend(self.cm_fallback.get_fonts())
741+
return list(set(fonts))
692742

693743
class StandardPsFonts(Fonts):
694744
"""
@@ -750,7 +800,7 @@ def _get_info (self, fontname, sym, fontsize, dpi):
750800
# This class includes greek letters, so we're ok
751801
if (fontname == 'it' and
752802
(len(sym) > 1 or
753-
not category(unicode(sym)).startswith("L"))):
803+
not unicodedata.category(unicode(sym)).startswith("L"))):
754804
fontname = 'rm'
755805

756806
found_symbol = False
@@ -2302,10 +2352,10 @@ def __call__(self, s, dpi, prop, angle=0):
23022352
font_output = StandardPsFonts(prop)
23032353
else:
23042354
backend = self._backend_mapping[self.output]()
2305-
font_output = BakomaFonts(prop, backend)
2306-
# When we have a decent Unicode font, we should test and
2307-
# then make this available as an option
2308-
#~ font_output = UnicodeFonts(prop, backend)
2355+
if rcParams['mathtext.use_cm']:
2356+
font_output = BakomaFonts(prop, backend)
2357+
else:
2358+
font_output = UnicodeFonts(prop, backend)
23092359

23102360
fontsize = prop.get_size_in_points()
23112361
if self._parser is None:

lib/matplotlib/mpl-data/matplotlibrc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,22 @@ numerix : numpy # numpy, Numeric or numarray
159159
# In that case, all text will be sent to TeX for
160160
# processing.
161161

162+
# The following settings allow you to select the fonts in math mode.
163+
# They map from a TeX font name to a 3-tuple of the form:
164+
# (family, weight, style)
165+
# These settings are only used if mathtext.use_cm is False, otherwise, the
166+
# Bakoma TeX Computer Modern fonts are used.
167+
#mathtext.cal : (['cursive'], 'normal', 'normal')
168+
#mathtext.rm : (['serif'], 'normal', 'normal')
169+
#mathtext.tt : (['monospace'], 'normal', 'normal')
170+
#mathtext.it : (['serif'], 'normal', 'oblique')
171+
#mathtext.bf : (['serif'], 'bold', 'normal')
172+
#mathtext.sf : (['sans-serif'], 'normal', 'normal')
173+
#mathtext.use_cm : True
174+
#mathtext.fallback_to_cm : True # When True, use symbols from the Computer Modern
175+
# fonts when a symbol can not be found in one of
176+
# the user-specified math fonts.
177+
162178
### AXES
163179
# default face and edge color, default tick sizes,
164180
# default fontsizes for ticklabels, and so on. See

lib/matplotlib/rcsetup.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,12 @@ def validate_fontsize(s):
198198
except ValueError:
199199
raise ValueError('not a valid font size')
200200

201+
def validate_mathtext_font(s):
202+
s = eval(s)
203+
if type(s) in (list, tuple) and len(s) == 3:
204+
return s
205+
raise ValueError('Mathtext font specifier must be a 3-tuple of (family, weight, style)')
206+
201207
validate_markup = ValidateInStrings(
202208
'markup',
203209
['plain', 'tex'],
@@ -357,6 +363,15 @@ def __call__(self, s):
357363
'text.fontsize' : ['medium', validate_fontsize],
358364
'text.markup' : ['plain', validate_markup],
359365

366+
'mathtext.cal' : [(['cursive'], 'normal', 'normal'), validate_mathtext_font],
367+
'mathtext.rm' : [(['serif'], 'normal', 'normal'), validate_mathtext_font],
368+
'mathtext.tt' : [(['monospace'], 'normal', 'normal'), validate_mathtext_font],
369+
'mathtext.it' : [(['serif'], 'normal', 'oblique'), validate_mathtext_font],
370+
'mathtext.bf' : [(['serif'], 'bold', 'normal'), validate_mathtext_font],
371+
'mathtext.sf' : [(['sans-serif'], 'normal', 'normal'), validate_mathtext_font],
372+
'mathtext.use_cm' : [True, validate_bool],
373+
'mathtext.fallback_to_cm' : [True, validate_bool],
374+
360375
'image.aspect' : ['equal', validate_aspect], # equal, auto, a number
361376
'image.interpolation' : ['bilinear', str],
362377
'image.cmap' : ['jet', str], # one of gray, jet, etc

matplotlibrc.template

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,22 @@ numerix : %(numerix)s # numpy, Numeric or numarray
159159
# In that case, all text will be sent to TeX for
160160
# processing.
161161

162+
# The following settings allow you to select the fonts in math mode.
163+
# They map from a TeX font name to a 3-tuple of the form:
164+
# (family, weight, style)
165+
# These settings are only used if mathtext.use_cm is False, otherwise, the
166+
# Bakoma TeX Computer Modern fonts are used.
167+
#mathtext.cal : (['cursive'], 'normal', 'normal')
168+
#mathtext.rm : (['serif'], 'normal', 'normal')
169+
#mathtext.tt : (['monospace'], 'normal', 'normal')
170+
#mathtext.it : (['serif'], 'normal', 'oblique')
171+
#mathtext.bf : (['serif'], 'bold', 'normal')
172+
#mathtext.sf : (['sans-serif'], 'normal', 'normal')
173+
#mathtext.use_cm : True
174+
#mathtext.fallback_to_cm : True # When True, use symbols from the Computer Modern
175+
# fonts when a symbol can not be found in one of
176+
# the user-specified math fonts.
177+
162178
### AXES
163179
# default face and edge color, default tick sizes,
164180
# default fontsizes for ticklabels, and so on. See

0 commit comments

Comments
 (0)