|
From: <md...@us...> - 2007-07-26 19:44:15
|
Revision: 3620
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3620&view=rev
Author: mdboom
Date: 2007-07-26 12:44:09 -0700 (Thu, 26 Jul 2007)
Log Message:
-----------
Lots of sizing and layout tweaks. Support $\sqrt[3]{foo}. The line
meets up with the check mark rather clumsily on the Agg backends due
to rounding errors and lack of subpixel placement... will look into that.
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/_mathtext_data.py
trunk/matplotlib/lib/matplotlib/mathtext.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2007-07-26 18:40:36 UTC (rev 3619)
+++ trunk/matplotlib/CHANGELOG 2007-07-26 19:44:09 UTC (rev 3620)
@@ -23,8 +23,11 @@
- Double sub/superscripts (eg. $x_i_j$) are considered
ambiguous and raise an exception. Use braces to disambiguate.
- - $\frac{x}{y}$ can be used for displaying fractions
+ - $\frac{x}{y}$ can be used for displaying fractions.
+ - $\sqrt[3]{x}$ can be used to display the radical symbol
+ with a root number and body.
+
- $\left(\frac{x}{y}\right)$ may be used to create
parentheses and other delimiters that automatically
resize to the height of their contents.
Modified: trunk/matplotlib/lib/matplotlib/_mathtext_data.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/_mathtext_data.py 2007-07-26 18:40:36 UTC (rev 3619)
+++ trunk/matplotlib/lib/matplotlib/_mathtext_data.py 2007-07-26 19:44:09 UTC (rev 3620)
@@ -170,6 +170,7 @@
r'\swarrow' : ('cmsy10', 116),
r'\propto' : ('cmsy10', 15),
r'\prime' : ('cmsy10', 73),
+ r"'" : ('cmsy10', 73),
r'\infty' : ('cmsy10', 32),
r'\in' : ('cmsy10', 59),
r'\ni' : ('cmsy10', 122),
@@ -253,6 +254,7 @@
r'\prec' : ('cmsy10', 93),
r'\succ' : ('cmsy10', 49),
r'\rightarrow' : ('cmsy10', 12),
+ r'\to' : ('cmsy10', 12),
r'\spadesuit' : ('cmsy10', 7),
}
Modified: trunk/matplotlib/lib/matplotlib/mathtext.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/mathtext.py 2007-07-26 18:40:36 UTC (rev 3619)
+++ trunk/matplotlib/lib/matplotlib/mathtext.py 2007-07-26 19:44:09 UTC (rev 3620)
@@ -138,7 +138,8 @@
from matplotlib.pyparsing import Literal, Word, OneOrMore, ZeroOrMore, \
Combine, Group, Optional, Forward, NotAny, alphas, nums, alphanums, \
StringStart, StringEnd, ParseFatalException, FollowedBy, Regex, \
- operatorPrecedence, opAssoc, ParseResults, Or, Suppress, oneOf
+ operatorPrecedence, opAssoc, ParseResults, Or, Suppress, oneOf, \
+ ParseException, MatchFirst
from matplotlib.afm import AFM
from matplotlib.cbook import enumerate, iterable, Bunch, get_realpath_and_stat, \
@@ -151,13 +152,7 @@
####################
-# symbols that have the sub and superscripts over/under
-overunder_symbols = {
- r'\sum' : 1,
- r'\int' : 1,
- r'\prod' : 1,
- r'\coprod' : 1,
- }
+
# a character over another character
charOverChars = {
# The first 2 entires in the tuple are (font, char, sizescale) for
@@ -692,7 +687,11 @@
def render_rect_filled(self, x1, y1, x2, y2):
assert len(self.fonts)
font = self.fonts.values()[0]
- font.font.draw_rect_filled(x1, y1, max(x2 - 1, x1), max(y2 - 1, y1))
+ font.font.draw_rect_filled(
+ max(0, x1 - 1),
+ y1,
+ max(x2 - 1, x1),
+ max(y2 - 1, y1))
def get_used_characters(self):
return self.used_characters
@@ -956,14 +955,16 @@
# The number of different sizes of chars to use, beyond which they will not
# get any smaller
NUM_SIZE_LEVELS = 3
-# Percentage of x-height that subscripts drop below the baseline
-SUBDROP = 0.05
+# Percentage of x-height of additional horiz. space after sub/superscripts
+SCRIPT_SPACE = 0.3
+# Percentage of x-height that sub/superscripts drop below the baseline
+SUBDROP = 0.4
# Percentage of x-height that superscripts drop below the baseline
-SUP1 = 0.2
+SUP1 = 0.7
# Percentage of x-height that subscripts drop below the baseline
-SUB1 = 0.3
+SUB1 = 0.0
# Percentage of x-height that superscripts are offset relative to the subscript
-DELTA = 0.05
+DELTA = 0.1
class MathTextWarning(Warning):
pass
@@ -991,10 +992,6 @@
def set_link(self, other):
self.link = other
- def pack(self):
- if self.link:
- self.link.pack()
-
def shrink(self):
"""Shrinks one level smaller. There are only three levels of sizes,
after which things will no longer get smaller."""
@@ -1062,7 +1059,10 @@
def _update_metrics(self):
metrics = self._metrics = self.font_output.get_metrics(
self.font, self.c, self.fontsize, self.dpi)
- self.width = metrics.width
+ if self.c == ' ':
+ self.width = metrics.advance
+ else:
+ self.width = metrics.width
self.height = metrics.iceberg
self.depth = -(metrics.iceberg - metrics.height)
@@ -1124,7 +1124,9 @@
elem = next
def __repr__(self):
- s = '[' + self.__internal_repr__() + " <%d %d %d %d> " % (self.width, self.height, self.depth, self.shift_amount)
+ s = '[%s <%d %d %d %d> ' % (self.__internal_repr__(),
+ self.width, self.height,
+ self.depth, self.shift_amount)
if self.list_head:
s += ' ' + self.list_head.__repr__()
s += ']'
@@ -1162,6 +1164,7 @@
Box.shrink(self)
if self.size < NUM_SIZE_LEVELS:
self.shift_amount *= SHRINK_FACTOR
+ self.glue_set *= SHRINK_FACTOR
class Hlist(List):
"""A horizontal list of boxes.
@@ -1186,12 +1189,6 @@
kern.link = next
elem = next
- def pack(self):
- if self.list_head:
- self.list_head.pack()
- self.hpack()
- Node.pack(self)
-
def hpack(self, w=0., m='additional'):
"""The main duty of hpack is to compute the dimensions of the
resulting boxes, and to adjust the glue if one of those dimensions is
@@ -1265,12 +1262,6 @@
List.__init__(self, elements)
self.vpack()
- def pack(self):
- if self.list_head:
- self.list_head.pack()
- self.vpack()
- Node.pack(self)
-
def vpack(self, h=0., m='additional', l=float('inf')):
"""The main duty of vpack is to compute the dimensions of the
resulting boxes, and to adjust the glue if one of those dimensions is
@@ -1386,6 +1377,13 @@
glue_spec = glue_spec.copy()
self.glue_spec = glue_spec
+ def shrink(self):
+ Node.shrink(self)
+ if self.size < NUM_SIZE_LEVELS:
+ if self.glue_spec.width != 0.:
+ self.glue_spec = self.glue_spec.copy()
+ self.glue_spec.width *= SHRINK_FACTOR
+
class GlueSpec(object):
"""@150, @151"""
def __init__(self, width=0., stretch=0., stretch_order=0, shrink=0., shrink_order=0):
@@ -1406,7 +1404,7 @@
def factory(cls, glue_type):
return cls._types[glue_type]
factory = classmethod(factory)
-
+
GlueSpec._types = {
'fil': GlueSpec(0., 1., 1, 0., 0),
'fill': GlueSpec(0., 1., 2, 0., 0),
@@ -1444,11 +1442,6 @@
def __init__(self):
Glue.__init__(self, 'neg_filll')
-class FixedGlue(Glue):
- def __init__(self, width):
- Glue.__init__(self, 'empty', copy=True)
- self.glue_spec.width = width
-
class SsGlue(Glue):
def __init__(self):
Glue.__init__(self, 'ss')
@@ -1463,7 +1456,7 @@
"""A convenience class to create an Vlist whose contents are centered
within its enclosing box."""
def __init__(self, elements):
- Vlist.__init__(self, [Fill()] + elements + [Fill()])
+ Vlist.__init__(self, [SsGlue()] + elements + [SsGlue()])
class Kern(Node):
"""A Kern node has a width field to specify a (normally negative)
@@ -1668,7 +1661,7 @@
class Parser(object):
_binary_operators = Set(r'''
- + - *
+ + *
\pm \sqcap \rhd
\mp \sqcup \unlhd
\times \vee \unrhd
@@ -1711,6 +1704,16 @@
_spaced_symbols = _binary_operators | _relation_symbols | _arrow_symbols
_punctuation_symbols = Set(r', ; . ! \ldotp \cdotp'.split())
+
+ _overunder_symbols = Set(r'''
+ \sum \int \prod \coprod \oint \bigcap \bigcup \bigsqcup \bigvee
+ \bigwedge \bigodot \bigotimes \bigoplus \biguplus
+ '''.split()
+ )
+
+ _overunder_functions = Set(
+ r"lim liminf limsup sup max min".split()
+ )
def __init__(self):
# All forward declarations are here
@@ -1761,14 +1764,14 @@
r"[a-zA-Z0-9 ]",
r"[+\-*/]",
r"[<>=]",
- r"[:,.;!]",
- r"[!@%&]",
- r"[[\]()]",
+ r"[:,.;!'@[()]",
r"\\[$%{}]",
])
+ ")"
).setParseAction(self.symbol).leaveWhitespace()
+ rightBracket = Literal("[").setParseAction(self.symbol).leaveWhitespace()
+
accent = Group(
Combine(bslash + accent)
+ placeable
@@ -1800,11 +1803,30 @@
+ group
).setParseAction(self.frac).setName("frac")
+ sqrt = Group(
+ Suppress(
+ bslash
+ + Literal("sqrt")
+ )
+ + Optional(
+ Suppress(Literal("["))
+ + OneOrMore(
+ symbol
+ ^ font
+ )
+ + Suppress(Literal("]")),
+ default = None
+ )
+ + group
+ ).setParseAction(self.sqrt).setName("sqrt")
+
placeable <<(accent
^ function
^ symbol
+ ^ rightBracket
^ group
^ frac
+ ^ sqrt
)
simple <<(space
@@ -1939,7 +1961,10 @@
elif c in self._punctuation_symbols:
return [Hlist([Char(c, self.get_state()),
self._make_space(0.3)])]
- return [Char(toks[0], self.get_state())]
+ try:
+ return [Char(toks[0], self.get_state())]
+ except:
+ raise ParseException()
_accent_map = {
r'\hat' : r'\circumflexaccent',
@@ -1971,7 +1996,7 @@
centered.shift_amount = accent._metrics.xmin
return Vlist([
centered,
- FixedGlue(thickness * 2.0),
+ Vbox(0., thickness * 2.0),
Hlist([sym])
])
@@ -1982,6 +2007,7 @@
state.font = 'rm'
hlist = Hlist([Char(c, state) for c in toks[0]])
self.pop_state()
+ hlist.function_name = toks[0]
return hlist
def start_group(self, s, loc, toks):
@@ -2007,7 +2033,9 @@
def is_overunder(self, nucleus):
if isinstance(nucleus, Char):
- return overunder_symbols.has_key(nucleus.c)
+ return nucleus.c in self._overunder_symbols
+ elif isinstance(nucleus, Hlist) and hasattr(nucleus, 'function_name'):
+ return nucleus.function_name in self._overunder_functions
return False
def subsuperscript(self, s, loc, toks):
@@ -2061,24 +2089,22 @@
width = nucleus.width
if super is not None:
super.shrink()
- super.pack()
width = max(width, super.width)
if sub is not None:
sub.shrink()
- sub.pack()
width = max(width, sub.width)
if super is not None:
hlist = HCentered([super])
hlist.hpack(width, 'exactly')
- vlist.extend([hlist, FixedGlue(rule_thickness * 2.0)])
+ vlist.extend([hlist, Vbox(0., rule_thickness * 2.0)])
hlist = HCentered([nucleus])
hlist.hpack(width, 'exactly')
vlist.append(hlist)
if sub is not None:
hlist = HCentered([sub])
hlist.hpack(width, 'exactly')
- vlist.extend([FixedGlue(rule_thickness), hlist])
+ vlist.extend([Vbox(0., rule_thickness), hlist])
shift = hlist.height + hlist.depth + rule_thickness * 2.0
vlist = Vlist(vlist)
vlist.shift_amount = shift
@@ -2086,12 +2112,12 @@
return [result]
shift_up = nucleus.height - SUBDROP * xHeight
- shift_down = nucleus.depth + SUBDROP * xHeight
+ shift_down = SUBDROP * xHeight
if super is None:
# @757
sub.shrink()
x = Hlist([sub])
- #x.width += SCRIPT_SPACE
+ x.width += SCRIPT_SPACE * xHeight
shift_down = max(shift_down, SUB1)
clr = x.height - (abs(xHeight * 4.0) / 5.0)
shift_down = max(shift_down, clr)
@@ -2099,7 +2125,7 @@
else:
super.shrink()
x = Hlist([super])
- #x.width += SCRIPT_SPACE
+ x.width += SCRIPT_SPACE * xHeight
clr = SUP1 * xHeight
shift_up = max(shift_up, clr)
clr = x.depth + (abs(xHeight) / 4.0)
@@ -2109,13 +2135,13 @@
else: # Both sub and superscript
sub.shrink()
y = Hlist([sub])
- #y.width += SCRIPT_SPACE
+ y.width += SCRIPT_SPACE * xHeight
shift_down = max(shift_down, SUB1 * xHeight)
clr = 4.0 * rule_thickness - ((shift_up - x.depth) - (y.height - shift_down))
if clr > 0.:
shift_up += clr
shift_down += clr
- x.shift_amount = DELTA
+ x.shift_amount = DELTA * xHeight
x = Vlist([x,
Kern((shift_up - x.depth) - (y.height - shift_down)),
y])
@@ -2127,33 +2153,78 @@
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]
num.shrink()
den.shrink()
cnum = HCentered([num])
cden = HCentered([den])
- width = max(num.width, den.height)
+ width = max(num.width, den.width) + thickness * 10.
cnum.hpack(width, 'exactly')
cden.hpack(width, 'exactly')
- state = self.get_state()
- thickness = state.font_output.get_underline_thickness(
- state.font, state.fontsize, state.dpi)
- space = thickness * 3.0
vlist = Vlist([cnum,
- FixedGlue(thickness * 2.0),
- Hrule(self.get_state()),
- FixedGlue(thickness * 3.0),
+ Vbox(0, thickness * 2.0),
+ Hrule(state),
+ Vbox(0, thickness * 4.0),
cden
])
+ # Shift so the fraction line sits in the middle of the
+ # equals sign
metrics = state.font_output.get_metrics(
state.font, '=', state.fontsize, state.dpi)
- shift = cden.height - (metrics.ymax + metrics.ymin) / 2 + thickness * 2.5
+ shift = (cden.height -
+ (metrics.ymax + metrics.ymin) / 2 +
+ thickness * 2.5)
vlist.shift_amount = shift
- hlist = Hlist([vlist, FixedGlue(thickness * 2.)])
+ hlist = Hlist([vlist, Hbox(thickness * 2.)])
return [hlist]
+ def sqrt(self, s, loc, toks):
+ #~ print "sqrt", toks
+ root, body = toks[0]
+ state = self.get_state()
+ thickness = state.font_output.get_underline_thickness(
+ state.font, state.fontsize, state.dpi)
+
+ if root is None:
+ root = Box()
+ else:
+ root.shrink()
+ root.shrink()
+
+ # Add a little extra to the height so the body
+ # doesn't seem cramped
+ height = body.height - body.shift_amount + thickness * 5.0
+ depth = body.depth + body.shift_amount
+ check = AutoSizedDelim(r'\sqrt', height, depth, state)
+
+ height = check.height - check.shift_amount
+ depth = check.depth + check.shift_amount
+ rightside = Vlist([Hrule(state),
+ Fill(),
+ # Pack a little extra to the left and right
+ # of the body
+ Hlist([Hbox(thickness * 2.0),
+ body,
+ Hbox(thickness * 2.0)])])
+ # Stretch the glue between the hrule and the body
+ rightside.vpack(height + 1.0, depth, 'exactly')
+
+ root_vlist = Vlist([Hlist([root])])
+ root_vlist.shift_amount = -height * 0.5
+
+ hlist = Hlist([root_vlist,
+ Kern(-check.width * 0.5),
+ check,
+ Kern(-thickness * 0.5),
+ rightside])
+ return [hlist]
+
def auto_sized_delimiter(self, s, loc, toks):
#~ print "auto_sized_delimiter", toks
front, middle, back = toks
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|