From: <md...@us...> - 2009-12-03 20:21:32
|
Revision: 8005 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=8005&view=rev Author: mdboom Date: 2009-12-03 20:21:21 +0000 (Thu, 03 Dec 2009) Log Message: ----------- Backport a number of mathtext fixes from mathtex project. Add unit tests. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/__init__.py trunk/matplotlib/lib/matplotlib/mathtext.py trunk/matplotlib/lib/matplotlib/testing/decorators.py Added Paths: ----------- trunk/matplotlib/lib/matplotlib/tests/baseline_images/test_mathtext/ trunk/matplotlib/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext.pdf trunk/matplotlib/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext.png trunk/matplotlib/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext.svg trunk/matplotlib/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix.pdf trunk/matplotlib/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix.png trunk/matplotlib/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix.svg trunk/matplotlib/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans.pdf trunk/matplotlib/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans.png trunk/matplotlib/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans.svg Modified: trunk/matplotlib/lib/matplotlib/__init__.py =================================================================== --- trunk/matplotlib/lib/matplotlib/__init__.py 2009-12-03 19:24:30 UTC (rev 8004) +++ trunk/matplotlib/lib/matplotlib/__init__.py 2009-12-03 20:21:21 UTC (rev 8005) @@ -912,6 +912,7 @@ 'matplotlib.tests.test_spines', 'matplotlib.tests.test_image', 'matplotlib.tests.test_simplification', + 'matplotlib.tests.test_mathtext' ] def test(verbosity=0): Modified: trunk/matplotlib/lib/matplotlib/mathtext.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mathtext.py 2009-12-03 19:24:30 UTC (rev 8004) +++ trunk/matplotlib/lib/matplotlib/mathtext.py 2009-12-03 20:21:21 UTC (rev 8005) @@ -999,6 +999,11 @@ if glyphindex is not None: alternatives.append((i, unichr(uniindex))) + # The largest size of the radical symbol in STIX has incorrect + # metrics that cause it to be disconnected from the stem. + if sym == r'\__sqrt__': + alternatives = alternatives[:-1] + self._size_alternatives[sym] = alternatives return alternatives @@ -1186,7 +1191,7 @@ GROW_FACTOR = 1.0 / SHRINK_FACTOR # The number of different sizes of chars to use, beyond which they will not # get any smaller -NUM_SIZE_LEVELS = 4 +NUM_SIZE_LEVELS = 6 # Percentage of x-height of additional horiz. space after sub/superscripts SCRIPT_SPACE = 0.2 # Percentage of x-height that sub/superscripts drop below the baseline @@ -1648,9 +1653,10 @@ """ Convenience class to create a horizontal rule. """ - def __init__(self, state): - thickness = state.font_output.get_underline_thickness( - state.font, state.fontsize, state.dpi) + def __init__(self, state, thickness=None): + if thickness is None: + thickness = state.font_output.get_underline_thickness( + state.font, state.fontsize, state.dpi) height = depth = thickness * 0.5 Rule.__init__(self, inf, height, depth, state) @@ -2202,6 +2208,41 @@ | Error(r"Expected \frac{num}{den}")) ).setParseAction(self.frac).setName("frac") + stackrel = Group( + Suppress(Literal(r"\stackrel")) + + ((group + group) + | Error(r"Expected \stackrel{num}{den}")) + ).setParseAction(self.stackrel).setName("stackrel") + + + binom = Group( + Suppress(Literal(r"\binom")) + + ((group + group) + | Error(r"Expected \binom{num}{den}")) + ).setParseAction(self.binom).setName("binom") + + ambiDelim = oneOf(list(self._ambiDelim)) + leftDelim = oneOf(list(self._leftDelim)) + rightDelim = oneOf(list(self._rightDelim)) + rightDelimSafe = oneOf(list(self._rightDelim - set(['}']))) + genfrac = Group( + Suppress(Literal(r"\genfrac")) + + ((Suppress(Literal('{')) + + oneOf(list(self._ambiDelim | self._leftDelim | set(['']))) + + Suppress(Literal('}')) + + Suppress(Literal('{')) + + oneOf(list(self._ambiDelim | + (self._rightDelim - set(['}'])) | + set(['', r'\}']))) + + Suppress(Literal('}')) + + Suppress(Literal('{')) + + Regex("[0-9]*(\.?[0-9]*)?") + + Suppress(Literal('}')) + + group + group + group) + | Error(r"Expected \genfrac{ldelim}{rdelim}{rulesize}{style}{num}{den}")) + ).setParseAction(self.genfrac).setName("genfrac") + + sqrt = Group( Suppress(Literal(r"\sqrt")) + Optional( @@ -2218,6 +2259,9 @@ ^ accent ^ group ^ frac + ^ stackrel + ^ binom + ^ genfrac ^ sqrt ) @@ -2239,9 +2283,6 @@ | placeable ) - ambiDelim = oneOf(list(self._ambiDelim)) - leftDelim = oneOf(list(self._leftDelim)) - rightDelim = oneOf(list(self._rightDelim)) autoDelim <<(Suppress(Literal(r"\left")) + ((leftDelim | ambiDelim) | Error("Expected a delimiter")) + Group( @@ -2626,9 +2667,9 @@ hlist = HCentered([sub]) hlist.hpack(width, 'exactly') vlist.extend([Kern(rule_thickness * 3.0), hlist]) - shift = hlist.height + hlist.depth + rule_thickness * 2.0 + shift = hlist.height vlist = Vlist(vlist) - vlist.shift_amount = shift + nucleus.depth * 0.5 + vlist.shift_amount = shift + nucleus.depth result = Hlist([vlist]) return [result] @@ -2677,40 +2718,78 @@ result = Hlist([nucleus, x]) return [result] - def frac(self, s, loc, toks): - assert(len(toks)==1) - assert(len(toks[0])==2) + def _genfrac(self, ldelim, rdelim, rule, style, num, den): state = self.get_state() thickness = state.font_output.get_underline_thickness( state.font, state.fontsize, state.dpi) - num, den = toks[0] + rule = float(rule) num.shrink() den.shrink() cnum = HCentered([num]) cden = HCentered([den]) - width = max(num.width, den.width) + thickness * 10. + width = max(num.width, den.width) cnum.hpack(width, 'exactly') cden.hpack(width, 'exactly') vlist = Vlist([cnum, # numerator Vbox(0, thickness * 2.0), # space - Hrule(state), # rule - Vbox(0, thickness * 4.0), # space + Hrule(state, rule), # rule + Vbox(0, thickness * 2.0), # space cden # denominator ]) # Shift so the fraction line sits in the middle of the # equals sign metrics = state.font_output.get_metrics( - state.font, rcParams['mathtext.default'], '=', state.fontsize, state.dpi) + state.font, rcParams['mathtext.default'], + '=', state.fontsize, state.dpi) shift = (cden.height - ((metrics.ymax + metrics.ymin) / 2 - thickness * 3.0)) vlist.shift_amount = shift - hlist = Hlist([vlist, Hbox(thickness * 2.)]) - return [hlist] + result = [Hlist([vlist, Hbox(thickness * 2.)])] + if ldelim or rdelim: + if ldelim == '': + ldelim = '.' + if rdelim == '': + rdelim = '.' + elif rdelim == r'\}': + rdelim = '}' + return self._auto_sized_delimiter(ldelim, result, rdelim) + return result + def genfrac(self, s, loc, toks): + assert(len(toks)==1) + assert(len(toks[0])==6) + + return self._genfrac(*tuple(toks[0])) + + def frac(self, s, loc, toks): + assert(len(toks)==1) + assert(len(toks[0])==2) + state = self.get_state() + + thickness = state.font_output.get_underline_thickness( + state.font, state.fontsize, state.dpi) + num, den = toks[0] + + return self._genfrac('', '', thickness, '', num, den) + + def stackrel(self, s, loc, toks): + assert(len(toks)==1) + assert(len(toks[0])==2) + num, den = toks[0] + + return self._genfrac('', '', 0.0, '', num, den) + + def binom(self, s, loc, toks): + assert(len(toks)==1) + assert(len(toks[0])==2) + num, den = toks[0] + + return self._genfrac('(', ')', 0.0, '', num, den) + def sqrt(self, s, loc, toks): #~ print "sqrt", toks root, body = toks[0] @@ -2756,9 +2835,7 @@ rightside]) # Body return [hlist] - def auto_sized_delimiter(self, s, loc, toks): - #~ print "auto_sized_delimiter", toks - front, middle, back = toks + def _auto_sized_delimiter(self, front, middle, back): state = self.get_state() height = max([x.height for x in middle]) depth = max([x.depth for x in middle]) @@ -2766,12 +2843,19 @@ # \left. and \right. aren't supposed to produce any symbols if front != '.': parts.append(AutoHeightChar(front, height, depth, state)) - parts.extend(middle.asList()) + parts.extend(middle) if back != '.': parts.append(AutoHeightChar(back, height, depth, state)) hlist = Hlist(parts) return hlist + + def auto_sized_delimiter(self, s, loc, toks): + #~ print "auto_sized_delimiter", toks + front, middle, back = toks + + return self._auto_sized_delimiter(front, middle.asList(), back) + ### ############################################################################## Modified: trunk/matplotlib/lib/matplotlib/testing/decorators.py =================================================================== --- trunk/matplotlib/lib/matplotlib/testing/decorators.py 2009-12-03 19:24:30 UTC (rev 8004) +++ trunk/matplotlib/lib/matplotlib/testing/decorators.py 2009-12-03 20:21:21 UTC (rev 8005) @@ -88,7 +88,7 @@ orig_expected_fnames = [os.path.join(baseline_dir,fname) + '.' + extension for fname in baseline_images] expected_fnames = [os.path.join(result_dir,'expected-'+fname) + '.' + extension for fname in baseline_images] for src,dst in zip( orig_expected_fnames, expected_fnames ): - if not os.path.exists(dst): + if os.path.exists(src) and not os.path.exists(dst): shutil.copyfile(src,dst) actual_fnames = [os.path.join(result_dir, fname) + '.' + extension for fname in baseline_images] have_baseline_images = [os.path.exists(expected) for expected in expected_fnames] Added: trunk/matplotlib/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext.pdf =================================================================== --- trunk/matplotlib/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext.pdf (rev 0) +++ trunk/matplotlib/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext.pdf 2009-12-03 20:21:21 UTC (rev 8005) @@ -0,0 +1,2076 @@ +%PDF-1.4 +%\xAC\xDC \xAB\xBA +1 0 obj +<< /Type /Catalog /Pages 2 0 R >> +endobj +8 0 obj +<< /XObject 7 0 R /Pattern 5 0 R +/ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /ExtGState 4 0 R +/Shading 6 0 R /Font 3 0 R >> +endobj +10 0 obj +<< /Contents 9 0 R /Type /Page /Resources 8 0 R /Parent 2 0 R +/MediaBox [ 0 0 360 2268 ] >> +endobj +9 0 obj +<< /Filter /FlateDecode /Length 11 0 R >> +stream +x\x9C\xED\{\xAF\xB7q\xFF\xFF~\x8A\xD34E\xAFa\x9C5\xDF\xB7\x8A \xB1\x93\xFC\xA4UZ\xB9(Ȗ\xE4J\x96d=\xC0N\x81|\xBB\xE9#\x9AčS\xA4\xAD\xEC\xB4M?Xg\x96C\xEE\x90K\xEE\xD9s\xAF\x8A&\x818\x92\xF6p\x87\xDC\xE1<~\xF3 \xE5\xE1\xFE\x85:|\xF3 \xEF\xC0o\\x88\x838<<h\x87>\x98\xFFT\xCA\xF8+\xFB\xFCr\xF1\xF9M\xF8\xDB;\xF0\xDFO.$\xFCy9\x8F\xD3\xEA\xF0\xF6Ë\xAF܀1rr^o7n_\xBC\xF2\xBA<Hu\xB8q\xF7\xE2\xF2\xD6K\x87\xF7/\xC2d\x8C\xD2:e\xE1\xBDy\x84\xCA#^\x9EGH1 o}\x90ˈB\xE3\xADy\x84\x9F\x94\xF5F\xCDs\xF4i(;yu\xFE=S\x96\x93py\xEE)\xFD\x8E\xBF~w\xFE\xF5(\xA6>;\xB2\xD9\xE4\xCFhr\xAF\x84\x96\xC3\xE5\xED\xC6\xC5\xA4\x91m\xE9o\xDAO\xD1\xFA\xF4Za\xF0\xEB\x95?\xBB\xF1\x8D\x9Bo\xDCyt\xE7\xE9\xAD\xC7;\xDC{\xFC\xEC\xC3W\xF8v\x87\x88\x8F\x93\xB6\xD68|w'\x91o7\xDB$\xA3+ۤ\xFB\xDB\xF4AbU\x98\xA4r\xD2/<\xBE\xFCp\xFCy\xBE\xCE9#\x90\xB1z\xB4\xB2\xEF=\xBA\xA7\x94\x83\x85\x81\xD4兩\xA9\xAC\xCA\xE4U}\x99x\xEF\xB4\xF1n\x9EK9x.\xCE|>\xCD\xCF\xF5\xA41v\xD9ݳ\xE9\xFAt\x92\xDFt1V"l\xF3\x88\xEFfF\xAF\x98\xA4̢db\xF2Y\xFE@\xA7\x93̤*\xE6,\xFF\xDB\xFF\xC6EfR\xAF&5\x9At\xD4\xCE\x96\x87\xF4\xA9Aɖ\x97\x8E \xF7j\xD6\xE4\x86>\xA6賊\xB3X+?\xD9e\xC6 \xFE\xEF\xE9\x9D\xC3\xDD\xC3Z^DL\x90I\xB3z\x82\xEC\xA6`\xA2\xE3\xB6\xE0\xC3{\x85U\x8C\xA6\x92\xE4\xD2~\xBE K\xD3\xC7I\xAD-[\xD6iگ\xBDhڗL㍶\xCC"_c\x89\xAF\x92\xF8\xFBҿMz\xBDYD\xAD\xFBW\xB8"\xC3V\xF8'\xF4\xA6V\xE0۸j\x96ؓɌgC6\xA9\x9A\xABT\xA1\xFF\xAF?\xA0\xC4f\x85W\x97\xDF\xFC!}\xBDU!\x8A\xF1\xA7\xED\xE7\xFEk\xD5\xCA\xD3\xDBv +A-ҷ\x83\xE5_\xE6Tv0Z\xC6 \xF6y\xA9-f\xFC:i\x8B\x9A|e\xA1\xAF\xCE +F;\xD0甼\xCA&n\xD1\xFE\xE8\xCA*\xA3a\xFEa\xF2ɤ\xEE2\x8A\xAF\xBC\xEE\xEBv\xAA\xF47\xB4\xEF\xAFVW\xD6\x93v&#\x95V>\xAE^\xEC4\xE9h+\x99\x9F#\xBC\xAB\xDCU\xFE\xC1N\xCA{\xAFM\xBB +\xE7\xB1a\xBDAF\x80ũ\xF66\xBF\xBF\xFA\xB2<\x85\x9Ad-\xB5\x9F<C\xCAf"\xC3;g\xCC\xDF\xF9#\xE2r\xB1\xE8U\xB3I\xAD\xD9\xF9V_/\x9F\x92wv\xB1\xC0[\x95J\xBFM\x9B\xAD\xACwg\xF0\xFCQ\xF5*\xD0\xC2ۅ\x95o\xF8\xF1\x90z1\xA3 +\xF8\xAC |