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

Skip to content

Commit 8dc3175

Browse files
committed
Make STIX fonts work.
svn path=/trunk/matplotlib/; revision=4110
1 parent 16cc4f1 commit 8dc3175

File tree

7 files changed

+107
-27
lines changed

7 files changed

+107
-27
lines changed

examples/mathtext_examples.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@
4848
r'$\mathcal{H} = \int d \tau \left(\epsilon E^2 + \mu H^2\right)$',
4949
r'$\widehat{abc}\widetilde{def}$',
5050
r'$\Gamma \Delta \Theta \Lambda \Xi \Pi \Sigma \Upsilon \Phi \Psi \Omega$',
51-
r'$\alpha \beta \gamma \delta \epsilon \zeta \eta \theta \iota \lambda \mu \nu \xi \pi \kappa \rho \sigma \tau \upsilon \phi \chi \psi$'
51+
r'$\alpha \beta \gamma \delta \epsilon \zeta \eta \theta \iota \lambda \mu \nu \xi \pi \kappa \rho \sigma \tau \upsilon \phi \chi \psi$',
52+
ur'Generic symbol: $\u23ce \mathrm{\ue0f2}$'
5253
]
5354

5455
from pylab import *

lib/matplotlib/_mathtext_data.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1755,7 +1755,10 @@
17551755

17561756
uni2type1 = dict([(v,k) for k,v in type12uni.items()])
17571757

1758-
tex2uni = {'doteq': 8784,
1758+
tex2uni = {
1759+
'widehat': 0x0302,
1760+
'widetilde': 0x0303,
1761+
'doteq': 8784,
17591762
'partial': 8706,
17601763
'gg': 8811,
17611764
'asymp': 8781,

lib/matplotlib/config/mplconfig.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ class mathtext(TConfig):
166166
it = T.Trait('serif:oblique' , mplT.FontconfigPatternHandler())
167167
bf = T.Trait('serif:bold' , mplT.FontconfigPatternHandler())
168168
sf = T.Trait('sans' , mplT.FontconfigPatternHandler())
169-
use_cm = T.true
169+
fontset = T.Trait('cm', 'cm', 'stix', 'custom')
170170
fallback_to_cm = T.true
171171

172172
class axes(TConfig):
@@ -344,7 +344,7 @@ def __init__(self, tconfig):
344344
'mathtext.it' : (self.tconfig.mathtext, 'it'),
345345
'mathtext.bf' : (self.tconfig.mathtext, 'bf'),
346346
'mathtext.sf' : (self.tconfig.mathtext, 'sf'),
347-
'mathtext.use_cm' : (self.tconfig.mathtext, 'use_cm'),
347+
'mathtext.fontset' : (self.tconfig.mathtext, 'fontset'),
348348
'mathtext.fallback_to_cm' : (self.tconfig.mathtext, 'fallback_to_cm'),
349349

350350
'image.aspect' : (self.tconfig.image, 'aspect'),

lib/matplotlib/config/rcsetup.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ def validate_font_properties(s):
203203
parse_fontconfig_pattern(s)
204204
return s
205205

206+
validate_fontset = ValidateInStrings('fontset', ['cm', 'stix', 'custom'])
207+
206208
validate_verbose = ValidateInStrings('verbose',[
207209
'silent', 'helpful', 'debug', 'debug-annoying',
208210
])
@@ -365,7 +367,7 @@ def __call__(self, s):
365367
'mathtext.it' : ['serif:italic', validate_font_properties],
366368
'mathtext.bf' : ['serif:bold', validate_font_properties],
367369
'mathtext.sf' : ['sans\-serif', validate_font_properties],
368-
'mathtext.use_cm' : [True, validate_bool],
370+
'mathtext.fontset' : ['cm', validate_fontset],
369371
'mathtext.fallback_to_cm' : [True, validate_bool],
370372

371373
'image.aspect' : ['equal', validate_aspect], # equal, auto, a number

lib/matplotlib/mathtext.py

Lines changed: 88 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ class TruetypeFonts(Fonts):
528528
A generic base class for all font setups that use Truetype fonts
529529
(through ft2font)
530530
"""
531-
basepath = os.path.join( get_data_path(), 'fonts', 'ttf' )
531+
basepath = os.path.join( get_data_path(), 'fonts' )
532532

533533
class CachedFont:
534534
def __init__(self, font):
@@ -665,7 +665,7 @@ def __init__(self, *args, **kwargs):
665665
TruetypeFonts.__init__(self, *args, **kwargs)
666666
if not len(self.fontmap):
667667
for key, val in self._fontmap.iteritems():
668-
fullpath = os.path.join(self.basepath, val + ".ttf")
668+
fullpath = os.path.join(self.basepath, 'ttf', val + ".ttf")
669669
self.fontmap[key] = fullpath
670670
self.fontmap[val] = fullpath
671671

@@ -750,7 +750,8 @@ class UnicodeFonts(TruetypeFonts):
750750
"""
751751

752752
fontmap = {}
753-
753+
use_cmex = True
754+
754755
def __init__(self, *args, **kwargs):
755756
# This must come first so the backend's owner is set correctly
756757
if rcParams['mathtext.fallback_to_cm']:
@@ -772,18 +773,20 @@ def __init__(self, *args, **kwargs):
772773
def _get_glyph(self, fontname, sym, fontsize):
773774
found_symbol = False
774775

775-
uniindex = latex_to_cmex.get(sym)
776-
if uniindex is not None:
777-
fontname = 'ex'
778-
found_symbol = True
779-
else:
776+
if self.use_cmex:
777+
uniindex = latex_to_cmex.get(sym)
778+
if uniindex is not None:
779+
fontname = 'ex'
780+
found_symbol = True
781+
782+
if not found_symbol:
780783
try:
781784
uniindex = get_unicode_index(sym)
782785
found_symbol = True
783786
except ValueError:
784787
uniindex = ord('?')
785788
warn("No TeX to unicode mapping for '%s'" %
786-
sym.encode('ascii', 'replace'),
789+
sym.encode('ascii', 'backslashreplace'),
787790
MathTextWarning)
788791

789792
# Only characters in the "Letter" class should be italicized in 'it'
@@ -804,7 +807,7 @@ def _get_glyph(self, fontname, sym, fontsize):
804807
except KeyError:
805808
warn("Font '%s' does not have a glyph for '%s'" %
806809
(cached_font.font.postscript_name,
807-
sym.encode('ascii', 'replace')),
810+
sym.encode('ascii', 'backslashreplace')),
808811
MathTextWarning)
809812
found_symbol = False
810813

@@ -815,6 +818,7 @@ def _get_glyph(self, fontname, sym, fontsize):
815818
return self.cm_fallback._get_glyph(fontname, sym, fontsize)
816819
else:
817820
warn("Substituting with a dummy symbol.", MathTextWarning)
821+
fontname = 'rm'
818822
new_fontname = fontname
819823
cached_font = self._get_font(fontname)
820824
uniindex = 0xA4 # currency character, for lack of anything better
@@ -829,6 +833,71 @@ def get_sized_alternatives_for_symbol(self, fontname, sym):
829833
return self.cm_fallback.get_sized_alternatives_for_symbol(
830834
fontname, sym)
831835
return [(fontname, sym)]
836+
837+
class StixFonts(UnicodeFonts):
838+
_fontmap = { 'rm' : ('STIXGeneral', 'otf'),
839+
'tt' : ('VeraMono', 'ttf'),
840+
'it' : ('STIXGeneralItalic', 'otf'),
841+
'bf' : ('STIXGeneralBol', 'otf'),
842+
'sf' : ('Vera', 'ttf'),
843+
'nonunirm' : ('STIXNonUni', 'otf'),
844+
'nonuniit' : ('STIXNonUniIta', 'otf'),
845+
'nonunibf' : ('STIXNonUniBol', 'otf'),
846+
847+
0 : ('STIXGeneral', 'otf'),
848+
1 : ('STIXSiz1Sym', 'otf'),
849+
2 : ('STIXSiz2Sym', 'otf'),
850+
3 : ('STIXSiz3Sym', 'otf'),
851+
4 : ('STIXSiz4Sym', 'otf'),
852+
5 : ('STIXSiz5Sym', 'otf')
853+
}
854+
fontmap = {}
855+
use_cmex = False
856+
cm_fallback = False
857+
858+
def __init__(self, *args, **kwargs):
859+
TruetypeFonts.__init__(self, *args, **kwargs)
860+
if not len(self.fontmap):
861+
for key, (name, ext) in self._fontmap.iteritems():
862+
fullpath = os.path.join(self.basepath, ext, name + "." + ext)
863+
self.fontmap[key] = fullpath
864+
self.fontmap[name] = fullpath
865+
866+
def _get_glyph(self, fontname, sym, fontsize):
867+
# Handle calligraphic letters
868+
if fontname == 'cal':
869+
if len(sym) != 1 or ord(sym) < ord('A') or ord(sym) > ord('Z'):
870+
raise ValueError(r"Sym '%s' is not available in \mathcal font" % sym)
871+
fontname = 'nonuniit'
872+
sym = unichr(ord(sym) + 0xe22d - ord('A'))
873+
874+
# Handle private use area glyphs
875+
if (fontname in ('it', 'rm', 'bf') and
876+
len(sym) == 1 and ord(sym) >= 0xe000 and ord(sym) <= 0xf8ff):
877+
fontname = 'nonuni' + fontname
878+
879+
return UnicodeFonts._get_glyph(self, fontname, sym, fontsize)
880+
881+
_size_alternatives = {}
882+
def get_sized_alternatives_for_symbol(self, fontname, sym):
883+
alternatives = self._size_alternatives.get(sym)
884+
if alternatives:
885+
return alternatives
886+
887+
alternatives = []
888+
try:
889+
uniindex = get_unicode_index(sym)
890+
except ValueError:
891+
return [(fontname, sym)]
892+
893+
for i in range(6):
894+
cached_font = self._get_font(i)
895+
glyphindex = cached_font.charmap.get(uniindex)
896+
if glyphindex is not None:
897+
alternatives.append((i, unichr(uniindex)))
898+
899+
self._size_alternatives[sym] = alternatives
900+
return alternatives
832901

833902
class StandardPsFonts(Fonts):
834903
"""
@@ -1091,7 +1160,7 @@ def __init__(self, c, state):
10911160
Node.__init__(self)
10921161
self.c = c
10931162
self.font_output = state.font_output
1094-
assert isinstance(state.font, str)
1163+
assert isinstance(state.font, (str, unicode, int))
10951164
self.font = state.font
10961165
self.fontsize = state.fontsize
10971166
self.dpi = state.dpi
@@ -1876,7 +1945,7 @@ def __init__(self):
18761945
) | Error(r"Expected \hspace{n}"))
18771946
).setParseAction(self.customspace).setName('customspace')
18781947

1879-
symbol =(Regex(r"([a-zA-Z0-9 +\-*/<>=:,.;!'@()])|(\\[%${}\[\]])")
1948+
symbol =(Regex(ur"([a-zA-Z0-9 +\-*/<>=:,.;!'@()\u0080-\uffff])|(\\[%${}\[\]])")
18801949
| Combine(
18811950
bslash
18821951
+ oneOf(tex2uni.keys())
@@ -2508,10 +2577,15 @@ def parse(self, s, dpi = 72, prop = None):
25082577
font_output = StandardPsFonts(prop)
25092578
else:
25102579
backend = self._backend_mapping[self._output]()
2511-
if rcParams['mathtext.use_cm']:
2580+
fontset = rcParams['mathtext.fontset']
2581+
if fontset == 'cm':
25122582
font_output = BakomaFonts(prop, backend)
2513-
else:
2583+
elif fontset == 'stix':
2584+
font_output = StixFonts(prop, backend)
2585+
elif fontset == 'custom':
25142586
font_output = UnicodeFonts(prop, backend)
2587+
else:
2588+
raise ValueError("mathtext.fontset must be either 'cm', 'stix', or 'custom'")
25152589

25162590
fontsize = prop.get_size_in_points()
25172591

lib/matplotlib/rcsetup.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,9 @@ def validate_fontsize(s):
202202
def validate_font_properties(s):
203203
parse_fontconfig_pattern(s)
204204
return s
205-
205+
206+
validate_fontset = ValidateInStrings('fontset', ['cm', 'stix', 'custom'])
207+
206208
validate_verbose = ValidateInStrings('verbose',[
207209
'silent', 'helpful', 'debug', 'debug-annoying',
208210
])
@@ -365,7 +367,7 @@ def __call__(self, s):
365367
'mathtext.it' : ['serif:italic', validate_font_properties],
366368
'mathtext.bf' : ['serif:bold', validate_font_properties],
367369
'mathtext.sf' : ['sans\-serif', validate_font_properties],
368-
'mathtext.use_cm' : [True, validate_bool],
370+
'mathtext.fontset' : [True, validate_fontset],
369371
'mathtext.fallback_to_cm' : [True, validate_bool],
370372

371373
'image.aspect' : ['equal', validate_aspect], # equal, auto, a number

matplotlibrc.template

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -160,20 +160,18 @@ numerix : %(numerix)s # numpy, Numeric or numarray
160160
# processing.
161161

162162
# The following settings allow you to select the fonts in math mode.
163-
# They map from a TeX font name to a set of arguments for the FontProperties constructor.
164-
# (See FontProperties for more details).
165-
# These settings are only used if mathtext.use_cm is False, otherwise, the
166-
# Bakoma TeX Computer Modern fonts are used.
163+
# They map from a TeX font name to a fontconfig font pattern.
164+
# These settings are only used if mathtext.fontset is 'custom'.
167165
#mathtext.cal : cursive
168166
#mathtext.rm : serif
169167
#mathtext.tt : monospace
170168
#mathtext.it : serif:italic
171169
#mathtext.bf : serif:bold
172170
#mathtext.sf : sans
173-
#mathtext.use_cm : True
171+
#mathtext.fontset : cm # Should be 'cm' (Computer Modern), 'stix' or 'custom'
174172
#mathtext.fallback_to_cm : True # When True, use symbols from the Computer Modern
175173
# fonts when a symbol can not be found in one of
176-
# the user-specified math fonts.
174+
# the custom math fonts.
177175

178176
### AXES
179177
# default face and edge color, default tick sizes,

0 commit comments

Comments
 (0)