Revision: 3654
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3654&view=rev
Author: mdboom
Date: 2007-08-01 06:51:48 -0700 (Wed, 01 Aug 2007)
Log Message:
-----------
Use Python lists rather than linked lists to improve speed
Modified Paths:
--------------
trunk/matplotlib/lib/matplotlib/mathtext.py
Modified: trunk/matplotlib/lib/matplotlib/mathtext.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-01 13:06:07 UTC (rev
3653)
+++ trunk/matplotlib/lib/matplotlib/mathtext.py 2007-08-01 13:51:48 UTC (rev
3654)
@@ -850,30 +850,26 @@
# 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
+SUBDROP = 0.3
# Percentage of x-height that superscripts drop below the baseline
SUP1 = 0.7
# Percentage of x-height that subscripts drop below the baseline
SUB1 = 0.0
# Percentage of x-height that superscripts are offset relative to the subscript
-DELTA = 0.1
+DELTA = 0.25
class MathTextWarning(Warning):
pass
class Node(object):
- """A node in a linked list.
+ """A node in the TeX box model
@133
"""
def __init__(self):
- self.link = None
self.size = 0
def __repr__(self):
- s = self.__internal_repr__()
- if self.link:
- s += ' ' + self.link.__repr__()
- return s
+ return self.__internal_repr__()
def __internal_repr__(self):
return self.__class__.__name__
@@ -881,21 +877,14 @@
def get_kerning(self, next):
return 0.0
- def set_link(self, other):
- self.link = other
-
def shrink(self):
"""Shrinks one level smaller. There are only three levels of sizes,
after which things will no longer get smaller."""
- if self.link:
- self.link.shrink()
self.size += 1
def grow(self):
"""Grows one level larger. There is no limit to how big something
can get."""
- if self.link:
- self.link.grow()
self.size -= 1
def render(self, x, y):
@@ -1027,29 +1016,17 @@
def __init__(self, elements):
Box.__init__(self, 0., 0., 0.)
self.shift_amount = 0. # An arbitrary offset
- self.list_head = None # The head of a linked list of Nodes in this
box
+ self.children = elements # The child nodes of this list
# The following parameters are set in the vpack and hpack functions
self.glue_set = 0. # The glue setting of this list
self.glue_sign = 0 # 0: normal, -1: shrinking, 1: stretching
self.glue_order = 0 # The order of infinity (0 - 3) for the glue
-
- # Convert the Python list to a linked list
- if len(elements):
- elem = self.list_head = elements[0]
- for next in elements[1:]:
- elem.set_link(next)
- elem = next
def __repr__(self):
- 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 += ']'
- if self.link:
- s += ' ' + self.link.__repr__()
- return s
+ return '[%s <%d %d %d %d> %s]' % (self.__internal_repr__(),
+ self.width, self.height,
+ self.depth, self.shift_amount,
+ ' '.join(self.children))
def _determine_order(self, totals):
"""A helper function to determine the highest order of glue
@@ -1071,21 +1048,21 @@
self.glue_sign = 0
self.glue_ratio = 0.
if o == 0:
- if self.list_head is not None:
+ if len(self.children):
warn("%s %s: %r" % (error_type, self.__class__.__name__, self),
MathTextWarning)
def shrink(self):
- if self.list_head:
- self.list_head.shrink()
+ for child in self.children:
+ child.shrink()
Box.shrink(self)
if self.size < NUM_SIZE_LEVELS:
self.shift_amount *= SHRINK_FACTOR
self.glue_set *= SHRINK_FACTOR
def grow(self):
- if self.list_head:
- self.list_head.grow()
+ for child in self.children:
+ child.grow()
Box.grow(self)
self.shift_amount *= INV_SHRINK_FACTOR
self.glue_set *= INV_SHRINK_FACTOR
@@ -1103,15 +1080,21 @@
Chars themselves determine the amount of kerning they need
(in get_kerning), and this function just creates the linked
list in the correct way."""
- elem = self.list_head
- while elem is not None:
- next = elem.link
+ new_children = []
+ num_children = len(self.children)
+ for i in range(num_children):
+ elem = self.children[i]
+ if i < num_children - 1:
+ next = self.children[i + 1]
+ else:
+ next = None
+
+ new_children.append(elem)
kerning_distance = elem.get_kerning(next)
if kerning_distance != 0.:
kern = Kern(kerning_distance)
- elem.link = kern
- kern.link = next
- elem = next
+ new_children.append(kern)
+ self.children = new_children
def hpack(self, w=0., m='additional'):
"""The main duty of hpack is to compute the dimensions of the
@@ -1136,18 +1119,12 @@
x = 0.
total_stretch = [0.] * 4
total_shrink = [0.] * 4
- p = self.list_head
- while p is not None:
- # Layout characters in a tight inner loop (common case)
- while isinstance(p, Char):
+ for p in self.children:
+ if isinstance(p, Char):
x += p.width
h = max(h, p.height)
d = max(d, p.depth)
- p = p.link # Go to next node in list
- if p is None:
- break
-
- if isinstance(p, Box):
+ elif isinstance(p, Box):
x += p.width
if p.height is not None and p.depth is not None:
s = getattr(p, 'shift_amount', 0.)
@@ -1160,7 +1137,6 @@
total_shrink[glue_spec.shrink_order] += glue_spec.shrink
elif isinstance(p, Kern):
x += p.width
- p = p.link # Go to next node in list
self.height = h
self.depth = d
@@ -1207,11 +1183,8 @@
x = 0.
total_stretch = [0.] * 4
total_shrink = [0.] * 4
- p = self.list_head
- while p is not None:
- if isinstance(p, Char):
- raise RuntimeError("Internal mathtext error: Char node found
in Vlist.")
- elif isinstance(p, Box):
+ for p in self.children:
+ if isinstance(p, Box):
x += d + p.height
d = p.depth
if p.width is not None:
@@ -1227,8 +1200,9 @@
elif isinstance(p, Kern):
x += d + p.width
d = 0.
- p = p.link
-
+ elif isinstance(p, Char):
+ raise RuntimeError("Internal mathtext error: Char node found
in Vlist.")
+
self.width = w
if d > l:
x += d - l
@@ -1482,23 +1456,18 @@
cur_glue = 0.
glue_order = box.glue_order
glue_sign = box.glue_sign
- p = box.list_head
base_line = self.cur_v
left_edge = self.cur_h
self.cur_s += 1
self.max_push = max(self.cur_s, self.max_push)
- while p:
- while isinstance(p, Char):
+ for p in box.children:
+ if isinstance(p, Char):
p.render(self.cur_h + self.off_h, self.cur_v + self.off_v)
self.cur_h += p.width
- p = p.link
- if p is None:
- break
-
- if isinstance(p, List):
+ elif isinstance(p, List):
# @623
- if p.list_head is None:
+ if len(p.children) == 0:
self.cur_h += p.width
else:
edge = self.cur_h
@@ -1542,7 +1511,6 @@
self.cur_h += rule_width
elif isinstance(p, Kern):
self.cur_h += p.width
- p = p.link
self.cur_s -= 1
def vlist_out(self, box):
@@ -1550,18 +1518,15 @@
cur_glue = 0.
glue_order = box.glue_order
glue_sign = box.glue_sign
- p = box.list_head
self.cur_s += 1
self.max_push = max(self.max_push, self.cur_s)
left_edge = self.cur_h
self.cur_v -= box.height
top_edge = self.cur_v
- while p:
- if isinstance(p, Char):
- raise RuntimeError("Internal mathtext error: Char node found
in vlist")
- elif isinstance(p, List):
- if p.list_head is None:
+ for p in box.children:
+ if isinstance(p, List):
+ if len(p.children) == 0:
self.cur_v += p.height + p.depth
else:
self.cur_v += p.height
@@ -1601,8 +1566,8 @@
self.cur_v += rule_height
elif isinstance(p, Kern):
self.cur_v += p.width
-
- p = p.link
+ elif isinstance(p, Char):
+ raise RuntimeError("Internal mathtext error: Char node found
in vlist")
self.cur_s -= 1
ship = Ship()
@@ -1657,7 +1622,7 @@
_punctuation_symbols = Set(r', ; . ! \ldotp \cdotp'.split())
_overunder_symbols = Set(r'''
- \sum \prod \int \coprod \oint \bigcap \bigcup \bigsqcup \bigvee
+ \sum \prod \coprod \bigcap \bigcup \bigsqcup \bigvee
\bigwedge \bigodot \bigotimes \bigoplus \biguplus
'''.split()
)
@@ -1665,6 +1630,8 @@
_overunder_functions = Set(
r"lim liminf limsup sup max min".split()
)
+
+ _dropsub_symbols = Set(r'''\int \oint'''.split())
def __init__(self):
# All forward declarations are here
@@ -1843,6 +1810,7 @@
def clear(self):
self._expr = None
self._state_stack = None
+ self._em_width_cache = {}
def parse(self, s, fonts_object, fontsize, dpi):
self._state_stack = [self.State(fonts_object, 'default', fontsize,
dpi)]
@@ -1898,10 +1866,14 @@
def _make_space(self, percentage):
# All spaces are relative to em width
state = self.get_state()
- metrics = state.font_output.get_metrics(
- state.font, 'm', state.fontsize, state.dpi)
- em = metrics.advance
- return Kern(em * percentage)
+ key = (state.font, state.fontsize, state.dpi)
+ width = self._em_width_cache.get(key)
+ if width is None:
+ metrics = state.font_output.get_metrics(
+ state.font, 'm', state.fontsize, state.dpi)
+ width = metrics.advance
+ self._em_width_cache[key] = width
+ return Kern(width * percentage)
_space_widths = { r'\ ' : 0.3,
r'\,' : 0.4,
@@ -1919,17 +1891,19 @@
def symbol(self, s, loc, toks):
# print "symbol", toks
c = toks[0]
+ try:
+ char = Char(c, self.get_state())
+ except ValueError:
+ raise ParseFatalException("Unknown symbol: %s" % c)
+
if c in self._spaced_symbols:
return [Hlist( [self._make_space(0.2),
- Char(c, self.get_state()),
+ char,
self._make_space(0.2)] )]
elif c in self._punctuation_symbols:
- return [Hlist( [Char(c, self.get_state()),
+ return [Hlist( [char,
self._make_space(0.2)] )]
- try:
- return [Char(toks[0], self.get_state())]
- except ValueError:
- raise ParseFatalException("Unknown symbol: %s" % c)
+ return [char]
_accent_map = {
r'\hat' : r'\circumflexaccent',
@@ -2004,6 +1978,11 @@
elif isinstance(nucleus, Hlist) and hasattr(nucleus, 'function_name'):
return nucleus.function_name in self._overunder_functions
return False
+
+ def is_dropsub(self, nucleus):
+ if isinstance(nucleus, Char):
+ return nucleus.c in self._dropsub_symbols
+ return False
def subsuperscript(self, s, loc, toks):
assert(len(toks)==1)
@@ -2079,7 +2058,10 @@
return [result]
shift_up = nucleus.height - SUBDROP * xHeight
- shift_down = SUBDROP * xHeight
+ if self.is_dropsub(nucleus):
+ shift_down = nucleus.depth + SUBDROP * xHeight
+ else:
+ shift_down = SUBDROP * xHeight
if super is None:
# @757
sub.shrink()
@@ -2091,8 +2073,8 @@
x.shift_amount = shift_down
else:
super.shrink()
- x = Hlist([super])
- x.width += SCRIPT_SPACE * xHeight
+ x = Hlist([super, Kern(SCRIPT_SPACE * xHeight)])
+ # x.width += SCRIPT_SPACE * xHeight
clr = SUP1 * xHeight
shift_up = max(shift_up, clr)
clr = x.depth + (abs(xHeight) / 4.0)
@@ -2104,11 +2086,11 @@
y = Hlist([sub])
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))
+ clr = 2.0 * rule_thickness - ((shift_up - x.depth) - (y.height
- shift_down))
if clr > 0.:
shift_up += clr
shift_down += clr
- x.shift_amount = DELTA * xHeight
+ x.shift_amount = DELTA * (shift_up + shift_down)
x = Vlist([x,
Kern((shift_up - x.depth) - (y.height -
shift_down)),
y])
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems? Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins