From: <md...@us...> - 2007-11-21 16:25:39
|
Revision: 4406 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4406&view=rev Author: mdboom Date: 2007-11-21 08:25:31 -0800 (Wed, 21 Nov 2007) Log Message: ----------- Merged revisions 4401-4405 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r4402 | mdboom | 2007-11-21 10:24:22 -0500 (Wed, 21 Nov 2007) | 2 lines Fix to work on Python 2.3 ........ r4404 | mdboom | 2007-11-21 11:05:18 -0500 (Wed, 21 Nov 2007) | 5 lines Fix memory leak when using colorbar as discovered by Darren Dale. The (unit change) callbacks in the Axis objects were not cleared by cla(), so they would continue to grow long lists of callbacks that reference entire Axes objects. ........ r4405 | mdboom | 2007-11-21 11:18:52 -0500 (Wed, 21 Nov 2007) | 2 lines Fix mathtext bug. ........ Modified Paths: -------------- branches/transforms/lib/matplotlib/axis.py branches/transforms/lib/matplotlib/mathtext.py branches/transforms/lib/matplotlib/pyparsing.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-4400 + /trunk/matplotlib:1-4405 Modified: branches/transforms/lib/matplotlib/axis.py =================================================================== --- branches/transforms/lib/matplotlib/axis.py 2007-11-21 16:18:52 UTC (rev 4405) +++ branches/transforms/lib/matplotlib/axis.py 2007-11-21 16:25:31 UTC (rev 4406) @@ -526,6 +526,9 @@ self.set_minor_locator(NullLocator()) self.set_minor_formatter(NullFormatter()) + # Clear the callback registry for this axis, or it may "leak" + self.callbacks = CallbackRegistry(('units', 'units finalize')) + # whether the grids are on self._gridOnMajor = rcParams['axes.grid'] self._gridOnMinor = False Modified: branches/transforms/lib/matplotlib/mathtext.py =================================================================== --- branches/transforms/lib/matplotlib/mathtext.py 2007-11-21 16:18:52 UTC (rev 4405) +++ branches/transforms/lib/matplotlib/mathtext.py 2007-11-21 16:25:31 UTC (rev 4406) @@ -2077,9 +2077,9 @@ | placeable ) - ambiDelim = oneOf(self._ambiDelim) - leftDelim = oneOf(self._leftDelim) - rightDelim = oneOf(self._rightDelim) + 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( Modified: branches/transforms/lib/matplotlib/pyparsing.py =================================================================== --- branches/transforms/lib/matplotlib/pyparsing.py 2007-11-21 16:18:52 UTC (rev 4405) +++ branches/transforms/lib/matplotlib/pyparsing.py 2007-11-21 16:25:31 UTC (rev 4406) @@ -2846,7 +2846,11 @@ warnings.warn("Invalid argument to oneOf, expected string or list", SyntaxWarning, stacklevel=2) - symbols.sort(reverse=True) + try: + symbols.sort(reverse=True) + except TypeError: + symbols.sort() + symbols.reverse() i = 0 while i < len(symbols)-1: cur = symbols[i] This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-11-26 14:10:14
|
Revision: 4437 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4437&view=rev Author: mdboom Date: 2007-11-26 06:10:11 -0800 (Mon, 26 Nov 2007) Log Message: ----------- Merged revisions 4406-4436 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r4407 | mdboom | 2007-11-21 11:35:38 -0500 (Wed, 21 Nov 2007) | 2 lines Mathtext speed improvement. ........ r4434 | jdh2358 | 2007-11-25 23:06:01 -0500 (Sun, 25 Nov 2007) | 1 line added x11 to default darwin list ........ r4435 | mdboom | 2007-11-26 09:06:57 -0500 (Mon, 26 Nov 2007) | 2 lines Fix stixsans mode: Upper case Greek should be non-slanted. ........ r4436 | mdboom | 2007-11-26 09:08:30 -0500 (Mon, 26 Nov 2007) | 2 lines Fix stixsans mode: Circled numerals should never be slanted. ........ Modified Paths: -------------- branches/transforms/lib/matplotlib/_mathtext_data.py branches/transforms/lib/matplotlib/mathtext.py branches/transforms/setupext.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-4405 + /trunk/matplotlib:1-4436 Modified: branches/transforms/lib/matplotlib/_mathtext_data.py =================================================================== --- branches/transforms/lib/matplotlib/_mathtext_data.py 2007-11-26 14:08:30 UTC (rev 4436) +++ branches/transforms/lib/matplotlib/_mathtext_data.py 2007-11-26 14:10:11 UTC (rev 4437) @@ -2296,7 +2296,7 @@ [ (0x0041, 0x0041, 'it', 0xe154), # A-B (0x0043, 0x0043, 'it', 0x2102), # C (missing in beta STIX fonts) - (0x0044, 0x0044, 'it', 0x2145), # D + (0x0044, 0x0044, 'it', 0x2145), # D (0x0045, 0x0047, 'it', 0xe156), # E-G (0x0048, 0x0048, 'it', 0x210d), # H (missing in beta STIX fonts) (0x0049, 0x004d, 'it', 0xe159), # I-M @@ -2344,8 +2344,8 @@ ], 'it': [ - (0x0030, 0x0030, 'it', 0x24ea), # 0 - (0x0031, 0x0039, 'it', 0x2460), # 1-9 + (0x0030, 0x0030, 'rm', 0x24ea), # 0 + (0x0031, 0x0039, 'rm', 0x2460), # 1-9 (0x0041, 0x005a, 'it', 0x24b6), # A-Z (0x0061, 0x007a, 'it', 0x24d0) # a-z ], @@ -2434,10 +2434,10 @@ [ # These numerals are actually upright. We don't actually # want italic numerals ever. - (0x0030, 0x0039, 'rm', 0x1d7e2), # 0-9 + (0x0030, 0x0039, 'rm', 0x1d7e2), # 0-9 (0x0041, 0x005a, 'it', 0x1d608), # A-Z (0x0061, 0x007a, 'it', 0x1d622), # a-z - (0x0391, 0x03a9, 'it', 0xe1bf), # \Alpha-\Omega + (0x0391, 0x03a9, 'rm', 0xe17d), # \Alpha-\Omega (0x03b1, 0x03c9, 'it', 0xe1d8), # \alpha-\omega (0x03d1, 0x03d1, 'it', 0xe1f2), # theta variant (0x03d5, 0x03d5, 'it', 0xe1f3), # phi variant Modified: branches/transforms/lib/matplotlib/mathtext.py =================================================================== --- branches/transforms/lib/matplotlib/mathtext.py 2007-11-26 14:08:30 UTC (rev 4436) +++ branches/transforms/lib/matplotlib/mathtext.py 2007-11-26 14:10:11 UTC (rev 4437) @@ -503,6 +503,7 @@ (through ft2font) """ basepath = os.path.join( get_data_path(), 'fonts' ) + _fonts = {} class CachedFont: def __init__(self, font): @@ -517,21 +518,17 @@ def __init__(self, default_font_prop, mathtext_backend): Fonts.__init__(self, default_font_prop, mathtext_backend) self.glyphd = {} - self.fonts = {} - filename = findfont(default_font_prop) - default_font = self.CachedFont(FT2Font(str(filename))) + if self._fonts == {}: + filename = findfont(default_font_prop) + default_font = self.CachedFont(FT2Font(str(filename))) - self.fonts['default'] = default_font + self._fonts['default'] = default_font def destroy(self): self.glyphd = None - for cached_font in self.fonts.values(): - cached_font.charmap = None - cached_font.glyphmap = None - cached_font.font = None Fonts.destroy(self) - + def _get_font(self, font): """Looks up a CachedFont with its charmap and inverse charmap. font may be a TeX font name (cal, rm, it etc.), or postscript name.""" @@ -540,16 +537,16 @@ else: basename = font - cached_font = self.fonts.get(basename) + cached_font = self._fonts.get(basename) if cached_font is None: try: font = FT2Font(basename) except RuntimeError: return None cached_font = self.CachedFont(font) - self.fonts[basename] = cached_font - self.fonts[font.postscript_name] = cached_font - self.fonts[font.postscript_name.lower()] = cached_font + self._fonts[basename] = cached_font + self._fonts[font.postscript_name] = cached_font + self._fonts[font.postscript_name.lower()] = cached_font return cached_font def _get_offset(self, cached_font, glyph, fontsize, dpi): Modified: branches/transforms/setupext.py =================================================================== --- branches/transforms/setupext.py 2007-11-26 14:08:30 UTC (rev 4436) +++ branches/transforms/setupext.py 2007-11-26 14:10:11 UTC (rev 4437) @@ -51,7 +51,7 @@ 'linux' : ['/usr/local', '/usr',], 'cygwin' : ['/usr/local', '/usr',], 'darwin' : ['/sw/lib/freetype2', '/sw/lib/freetype219', '/usr/local', - '/usr', '/sw'], + '/usr', '/sw', '/usr/X11R6'], 'freebsd4' : ['/usr/local', '/usr'], 'freebsd5' : ['/usr/local', '/usr'], 'freebsd6' : ['/usr/local', '/usr'], This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-11-26 15:46:30
|
Revision: 4444 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4444&view=rev Author: mdboom Date: 2007-11-26 07:46:17 -0800 (Mon, 26 Nov 2007) Log Message: ----------- Merged revisions 4437-4443 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r4438 | mdboom | 2007-11-26 09:29:49 -0500 (Mon, 26 Nov 2007) | 2 lines Minor speed improvements in mathtext. Removing trailing whitespace. ........ r4441 | mdboom | 2007-11-26 10:31:54 -0500 (Mon, 26 Nov 2007) | 2 lines Fix colored text in SVG backend. ........ r4442 | mdboom | 2007-11-26 10:42:10 -0500 (Mon, 26 Nov 2007) | 2 lines Reduce SVG file sizes. ........ r4443 | mdboom | 2007-11-26 10:43:26 -0500 (Mon, 26 Nov 2007) | 2 lines One more SVG color detail (in mathtext) ........ Modified Paths: -------------- branches/transforms/lib/matplotlib/backends/backend_svg.py branches/transforms/lib/matplotlib/mathtext.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-4436 + /trunk/matplotlib:1-4443 Modified: branches/transforms/lib/matplotlib/backends/backend_svg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_svg.py 2007-11-26 15:43:26 UTC (rev 4443) +++ branches/transforms/lib/matplotlib/backends/backend_svg.py 2007-11-26 15:46:17 UTC (rev 4444) @@ -29,7 +29,7 @@ _capstyle_d = {'projecting' : 'square', 'butt' : 'butt', 'round': 'round',} class RendererSVG(RendererBase): - FONT_SCALE = 1200.0 + FONT_SCALE = 100.0 def __init__(self, width, height, svgwriter, basename=None): self.width=width @@ -293,7 +293,6 @@ color = rgb2hex(gc.get_rgb()[:3]) if rcParams['svg.embed_char_paths']: - svg = ['<g style="fill: %s" transform="' % color] if angle != 0: svg.append('translate(%s,%s)rotate(%1.1f)' % (x,y,-angle)) @@ -453,7 +452,7 @@ svg.append('</text>\n') if len(svg_rects): - style = "fill: black; stroke: none" + style = "fill: %s; stroke: none" % color svg.append('<g style="%s" transform="' % style) if angle != 0: svg.append('translate(%s,%s) rotate(%1.1f)' Modified: branches/transforms/lib/matplotlib/mathtext.py =================================================================== --- branches/transforms/lib/matplotlib/mathtext.py 2007-11-26 15:43:26 UTC (rev 4443) +++ branches/transforms/lib/matplotlib/mathtext.py 2007-11-26 15:46:17 UTC (rev 4444) @@ -208,7 +208,7 @@ class MathtextBackendBbox(MathtextBackend): """A backend whose only purpose is to get a precise bounding box. Only required for the Agg backend.""" - + def __init__(self, real_backend): MathtextBackend.__init__(self) self.bbox = [0, 0, 0, 0] @@ -219,7 +219,7 @@ min(self.bbox[1], y1), max(self.bbox[2], x2), max(self.bbox[3], y2)] - + def render_glyph(self, ox, oy, info): self._update_bbox(ox + info.metrics.xmin, oy - info.metrics.ymax, @@ -251,14 +251,14 @@ self.real_backend.fonts_object = self.fonts_object self.real_backend.ox = self.bbox[0] self.real_backend.oy = self.bbox[1] - + class MathtextBackendAggRender(MathtextBackend): def __init__(self): self.ox = 0 self.oy = 0 self.image = None MathtextBackend.__init__(self) - + def set_canvas_size(self, w, h, d): MathtextBackend.set_canvas_size(self, w, h, d) self.image = FT2Image(ceil(w), ceil(h + d)) @@ -284,11 +284,11 @@ def MathtextBackendAgg(): return MathtextBackendBbox(MathtextBackendAggRender()) - + class MathtextBackendBitmapRender(MathtextBackendAggRender): def get_results(self, box): return self.image - + def MathtextBackendBitmap(): return MathtextBackendBbox(MathtextBackendBitmapRender()) @@ -310,7 +310,7 @@ """ % locals() self.lastfont = postscript_name, fontsize self.pswriter.write(ps) - + ps = """%(ox)f %(oy)f moveto /%(symbol_name)s glyphshow\n """ % locals() @@ -426,7 +426,7 @@ """Fix any cyclical references before the object is about to be destroyed.""" self.used_characters = None - + def get_kern(self, font1, sym1, fontsize1, font2, sym2, fontsize2, dpi): """ @@ -737,7 +737,7 @@ fontmap = {} use_cmex = True - + def __init__(self, *args, **kwargs): # This must come first so the backend's owner is set correctly if rcParams['mathtext.fallback_to_cm']: @@ -758,7 +758,7 @@ def _map_virtual_font(self, fontname, font_class, uniindex): return fontname, uniindex - + def _get_glyph(self, fontname, font_class, sym, fontsize): found_symbol = False @@ -767,7 +767,7 @@ if uniindex is not None: fontname = 'ex' found_symbol = True - + if not found_symbol: try: uniindex = get_unicode_index(sym) @@ -780,7 +780,7 @@ fontname, uniindex = self._map_virtual_font( fontname, font_class, uniindex) - + # Only characters in the "Letter" class should be italicized in 'it' # mode. Greek capital letters should be Roman. if found_symbol: @@ -830,13 +830,16 @@ return [(fontname, sym)] class StixFonts(UnicodeFonts): + """ + A font handling class for the STIX fonts + """ _fontmap = { 'rm' : 'STIXGeneral', 'it' : 'STIXGeneralItalic', 'bf' : 'STIXGeneralBol', 'nonunirm' : 'STIXNonUni', 'nonuniit' : 'STIXNonUniIta', 'nonunibf' : 'STIXNonUniBol', - + 0 : 'STIXGeneral', 1 : 'STIXSiz1Sym', 2 : 'STIXSiz2Sym', @@ -849,7 +852,6 @@ cm_fallback = False def __init__(self, *args, **kwargs): - self._sans = kwargs.pop("sans", False) TruetypeFonts.__init__(self, *args, **kwargs) if not len(self.fontmap): for key, name in self._fontmap.iteritems(): @@ -891,14 +893,14 @@ # This will generate a dummy character uniindex = 0x1 fontname = 'it' - + # Handle private use area glyphs if (fontname in ('it', 'rm', 'bf') and uniindex >= 0xe000 and uniindex <= 0xf8ff): fontname = 'nonuni' + fontname return fontname, uniindex - + _size_alternatives = {} def get_sized_alternatives_for_symbol(self, fontname, sym): alternatives = self._size_alternatives.get(sym) @@ -919,7 +921,14 @@ self._size_alternatives[sym] = alternatives return alternatives - + +class StixSansFonts(StixFonts): + """ + A font handling class for the STIX fonts (using sans-serif + characters by default). + """ + _sans = True + class StandardPsFonts(Fonts): """ Use the standard postscript fonts for rendering to backend_ps @@ -1085,7 +1094,8 @@ # Note that (as TeX) y increases downward, unlike many other parts of # matplotlib. -# How much text shrinks when going to the next-smallest level +# How much text shrinks when going to the next-smallest level. GROW_FACTOR +# must be the inverse of SHRINK_FACTOR. SHRINK_FACTOR = 0.7 GROW_FACTOR = 1.0 / SHRINK_FACTOR # The number of different sizes of chars to use, beyond which they will not @@ -1160,10 +1170,16 @@ pass class Vbox(Box): + """ + A box with only height (zero width). + """ def __init__(self, height, depth): Box.__init__(self, 0., height, depth) class Hbox(Box): + """ + A box with only width (zero height and depth). + """ def __init__(self, width): Box.__init__(self, width, 0., 0.) @@ -1241,8 +1257,9 @@ self.depth *= GROW_FACTOR class Accent(Char): - """The font metrics need to be dealt with differently for accents, since they - are already offset correctly from the baseline in TrueType fonts.""" + """The font metrics need to be dealt with differently for accents, + since they are already offset correctly from the baseline in + TrueType fonts.""" def _update_metrics(self): metrics = self._metrics = self.font_output.get_metrics( self.font, self.font_class, self.c, self.fontsize, self.dpi) @@ -1741,7 +1758,7 @@ self.cur_s += 1 self.max_push = max(self.cur_s, self.max_push) clamp = self.clamp - + for p in box.children: if isinstance(p, Char): p.render(self.cur_h + self.off_h, self.cur_v + self.off_v) @@ -1864,7 +1881,7 @@ empty = Empty() empty.setParseAction(raise_error) return empty - + class Parser(object): _binary_operators = Set(r''' + * @@ -1922,7 +1939,7 @@ _dropsub_symbols = Set(r'''\int \oint'''.split()) _fontnames = Set("rm cal it tt sf bf default bb frak circled scr".split()) - + _function_names = Set(""" arccos csc ker min arcsin deg lg Pr arctan det lim sec arg dim liminf sin cos exp limsup sinh cosh gcd ln sup cot hom log tan @@ -1935,7 +1952,7 @@ _leftDelim = Set(r"( [ { \lfloor \langle \lceil".split()) _rightDelim = Set(r") ] } \rfloor \rangle \rceil".split()) - + def __init__(self): # All forward declarations are here font = Forward().setParseAction(self.font).setName("font") @@ -1947,7 +1964,7 @@ self._expression = Forward().setParseAction(self.finish).setName("finish") float = Regex(r"-?[0-9]+\.?[0-9]*") - + lbrace = Literal('{').suppress() rbrace = Literal('}').suppress() start_group = (Optional(latexfont) + lbrace) @@ -1993,7 +2010,7 @@ c_over_c =(Suppress(bslash) + oneOf(self._char_over_chars.keys()) ).setParseAction(self.char_over_chars) - + accent = Group( Suppress(bslash) + accent @@ -2055,7 +2072,7 @@ ) | Error("Expected symbol or group") simple <<(space - | customspace + | customspace | font | subsuper ) @@ -2105,11 +2122,11 @@ + (Suppress(math_delim) | Error("Expected end of math '$'")) + non_math - ) + ) ) + StringEnd() self._expression.enablePackrat() - + self.clear() def clear(self): @@ -2156,7 +2173,7 @@ self.font_class = name self._font = name font = property(_get_font, _set_font) - + def get_state(self): return self._state_stack[-1] @@ -2214,7 +2231,7 @@ def customspace(self, s, loc, toks): return [self._make_space(float(toks[1]))] - + def symbol(self, s, loc, toks): # print "symbol", toks c = toks[0] @@ -2240,7 +2257,7 @@ # (in multiples of underline height) r'AA' : ( ('rm', 'A', 1.0), (None, '\circ', 0.5), 0.0), } - + def char_over_chars(self, s, loc, toks): sym = toks[0] state = self.get_state() @@ -2251,7 +2268,7 @@ self._char_over_chars.get(sym, (None, None, 0.0)) if under_desc is None: raise ParseFatalException("Error parsing symbol") - + over_state = state.copy() if over_desc[0] is not None: over_state.font = over_desc[0] @@ -2265,19 +2282,19 @@ under = Char(under_desc[1], under_state) width = max(over.width, under.width) - + over_centered = HCentered([over]) over_centered.hpack(width, 'exactly') under_centered = HCentered([under]) under_centered.hpack(width, 'exactly') - + return Vlist([ over_centered, Vbox(0., thickness * space), under_centered ]) - + _accent_map = { r'hat' : r'\circumflexaccent', r'breve' : r'\combiningbreve', @@ -2601,7 +2618,7 @@ return is width, height, fonts """ _parser = None - + _backend_mapping = { 'Bitmap': MathtextBackendBitmap, 'Agg' : MathtextBackendAgg, @@ -2611,6 +2628,13 @@ 'Cairo' : MathtextBackendCairo } + _font_type_mapping = { + 'cm' : BakomaFonts, + 'stix' : StixFonts, + 'stixsans' : StixSansFonts, + 'custom' : UnicodeFonts + } + def __init__(self, output): self._output = output self._cache = {} @@ -2618,7 +2642,7 @@ def parse(self, s, dpi = 72, prop = None): if prop is None: prop = FontProperties() - + cacheKey = (s, dpi, hash(prop)) result = self._cache.get(cacheKey) if result is not None: @@ -2629,16 +2653,13 @@ else: backend = self._backend_mapping[self._output]() fontset = rcParams['mathtext.fontset'] - if fontset == 'cm': - font_output = BakomaFonts(prop, backend) - elif fontset == 'stix': - font_output = StixFonts(prop, backend) - elif fontset == 'stixsans': - font_output = StixFonts(prop, backend, sans=True) - elif fontset == 'custom': - font_output = UnicodeFonts(prop, backend) + fontset_class = self._font_type_mapping.get(fontset) + if fontset_class is not None: + font_output = fontset_class(prop, backend) else: - raise ValueError("mathtext.fontset must be either 'cm', 'stix', 'stixsans', or 'custom'") + raise ValueError( + "mathtext.fontset must be either 'cm', 'stix', " + "'stixsans', or 'custom'") fontsize = prop.get_size_in_points() @@ -2646,7 +2667,7 @@ # with each request. if self._parser is None: self.__class__._parser = Parser() - + box = self._parser.parse(s, font_output, fontsize, dpi) font_output.set_canvas_size(box.width, box.height, box.depth) result = font_output.get_results(box) @@ -2658,5 +2679,5 @@ font_output.destroy() font_output.mathtext_backend.fonts_object = None font_output.mathtext_backend = None - + return result This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-11-27 17:40:47
|
Revision: 4469 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4469&view=rev Author: mdboom Date: 2007-11-27 09:40:45 -0800 (Tue, 27 Nov 2007) Log Message: ----------- Fix memory leak and increase performance in quadmesh drawing (Agg) Modified Paths: -------------- branches/transforms/lib/matplotlib/collections.py branches/transforms/src/_backend_agg.cpp Modified: branches/transforms/lib/matplotlib/collections.py =================================================================== --- branches/transforms/lib/matplotlib/collections.py 2007-11-27 17:34:20 UTC (rev 4468) +++ branches/transforms/lib/matplotlib/collections.py 2007-11-27 17:40:45 UTC (rev 4469) @@ -163,10 +163,8 @@ xs = self.convert_xunits(self._offsets[:0]) ys = self.convert_yunits(self._offsets[:1]) offsets = zip(xs, ys) - if len(offsets) == 0: - offsets = npy.array([], npy.float_) - else: - offsets = npy.asarray(offsets, npy.float_) + + offsets = npy.asarray(offsets, npy.float_) self.update_scalarmappable() @@ -389,10 +387,12 @@ self._bbox = transforms.Bbox.unit() self._bbox.update_from_data_xy(coordinates.reshape( ((meshWidth + 1) * (meshHeight + 1), 2))) + + # By converting to floats now, we can avoid that on every draw. + self._coordinates = self._coordinates.reshape((meshHeight + 1, meshWidth + 1, 2)) + self._coordinates = npy.array(self._coordinates, npy.float_) def get_paths(self, dataTrans=None): - import pdb - pdb.set_trace() if self._paths is None: self._paths = self.convert_mesh_to_paths( self._meshWidth, self._meshHeight, self._coordinates) @@ -402,7 +402,7 @@ def convert_mesh_to_paths(meshWidth, meshHeight, coordinates): Path = mpath.Path - c = coordinates.reshape((meshHeight + 1, meshWidth + 1, 2)) + c = coordinates # We could let the Path constructor generate the codes for us, # but this is faster, since we know they'll always be the same codes = npy.array( @@ -436,10 +436,7 @@ ys = self.convert_yunits(self._offsets[:1]) offsets = zip(xs, ys) - if len(offsets) == 0: - offsets = npy.array([], npy.float_) - else: - offsets = npy.asarray(offsets, npy.float_) + offsets = npy.asarray(offsets, npy.float_) if self.check_update('array'): self.update_scalarmappable() Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-11-27 17:34:20 UTC (rev 4468) +++ branches/transforms/src/_backend_agg.cpp 2007-11-27 17:40:45 UTC (rev 4469) @@ -1113,8 +1113,9 @@ inline unsigned vertex(unsigned idx, double* x, double* y) { size_t m = m_m + offsets[idx][0]; size_t n = m_n + offsets[idx][1]; - *x = *(double*)PyArray_GETPTR3(m_coordinates, m, n, 0); - *y = *(double*)PyArray_GETPTR3(m_coordinates, m, n, 1); + double* pair = (double*)PyArray_GETPTR2(m_coordinates, m, n); + *x = *pair++; + *y = *pair; return (idx == 0) ? agg::path_cmd_move_to : agg::path_cmd_line_to; } @@ -1130,10 +1131,6 @@ inline unsigned total_vertices() { return 5; } - - inline bool has_curves() { - return false; - } }; public: @@ -1146,11 +1143,7 @@ throw Py::ValueError("Invalid coordinates array."); } - PyArray_Dims shape; - npy_intp dims[] = { meshHeight + 1, meshWidth + 1, 2 }; - shape.ptr = dims; - shape.len = 3; - m_coordinates = (PyArrayObject*)PyArray_Newshape(coordinates_array, &shape, PyArray_CORDER); + m_coordinates = coordinates_array; } inline ~QuadMeshGenerator() { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-11-28 13:42:46
|
Revision: 4481 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4481&view=rev Author: mdboom Date: 2007-11-28 05:42:39 -0800 (Wed, 28 Nov 2007) Log Message: ----------- Major speed improvements for auto-placing of legends. Modified Paths: -------------- branches/transforms/lib/matplotlib/legend.py branches/transforms/lib/matplotlib/lines.py branches/transforms/lib/matplotlib/path.py branches/transforms/lib/matplotlib/transforms.py branches/transforms/src/_path.cpp Modified: branches/transforms/lib/matplotlib/legend.py =================================================================== --- branches/transforms/lib/matplotlib/legend.py 2007-11-28 13:40:54 UTC (rev 4480) +++ branches/transforms/lib/matplotlib/legend.py 2007-11-28 13:42:39 UTC (rev 4481) @@ -36,33 +36,6 @@ from text import Text from transforms import Affine2D, Bbox, BboxTransformTo -def line_cuts_bbox(line, bbox): - """ Return True if and only if line cuts bbox. """ - minx, miny, width, height = bbox.bounds - maxx = minx + width - maxy = miny + height - - n = len(line) - if n == 0: - return False - - if n == 1: - return bbox.contains(line[0][0], line[0][1]) - p1 = line[0] - for p2 in line[1:]: - segment = (p1, p2) - # See if the segment cuts any of the edges of bbox - for edge in (((minx, miny), (minx, maxy)), - ((minx, miny), (maxx, miny)), - ((maxx, miny), (maxx, maxy)), - ((minx, maxy), (maxx, maxy))): - if segments_intersect(segment, edge): - return True - p1=p2 - - return False - - class Legend(Artist): """ Place a legend on the axes at location loc. Labels are a @@ -344,11 +317,11 @@ for handle in ax.lines: assert isinstance(handle, Line2D) - data = handle.get_xydata() + path = handle.get_path() trans = handle.get_transform() - tdata = trans.transform(data) - averts = inverse_transform.transform(tdata) - lines.append(averts) + tpath = trans.transform_path(path) + apath = inverse_transform.transform_path(tpath) + lines.append(apath) for handle in ax.patches: assert isinstance(handle, Patch) @@ -435,7 +408,7 @@ badness = legendBox.count_contains(verts) badness += legendBox.count_overlaps(bboxes) for line in lines: - if line_cuts_bbox(line, legendBox): + if line.intersects_bbox(legendBox): badness += 1 ox, oy = l-tx, b-ty Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-11-28 13:40:54 UTC (rev 4480) +++ branches/transforms/lib/matplotlib/lines.py 2007-11-28 13:42:39 UTC (rev 4481) @@ -285,6 +285,7 @@ self._xorig = npy.asarray([]) self._yorig = npy.asarray([]) + self._invalid = True self.set_data(xdata, ydata) def contains(self, mouseevent): @@ -353,7 +354,7 @@ def get_window_extent(self, renderer): bbox = Bbox.unit() - bbox.update_from_data_xy(self.get_transform().transform(self._xy), + bbox.update_from_data_xy(self.get_transform().transform(self.get_xydata()), ignore=True) # correct for marker size, if any if self._marker is not None: @@ -394,9 +395,10 @@ (y.shape != self._yorig.shape or npy.any(y != self._yorig)))): self._xorig = x self._yorig = y - self.recache() + self._invalid = True else: - self._transformed_path._invalid = self._transformed_path.INVALID_NON_AFFINE + if hasattr(self, "_transformed_path"): + self._transformed_path._invalid = self._transformed_path.INVALID_NON_AFFINE def recache(self): #if self.axes is None: print 'recache no axes' @@ -434,6 +436,7 @@ self._path = Path(self._xy) self._transformed_path = TransformedPath(self._path, self.get_transform()) + self._invalid = False def set_transform(self, t): """ @@ -442,7 +445,8 @@ ACCEPTS: a matplotlib.transforms.Transform instance """ Artist.set_transform(self, t) - self._transformed_path = TransformedPath(self._path, self.get_transform()) + self._invalid = True + # self._transformed_path = TransformedPath(self._path, self.get_transform()) def _is_sorted(self, x): "return true if x is sorted" @@ -450,6 +454,9 @@ return npy.alltrue(x[1:]-x[0:-1]>=0) def draw(self, renderer): + if self._invalid: + self.recache() + renderer.open_group('line2d') if not self._visible: return @@ -531,6 +538,8 @@ """ if orig: return self._xorig + if self._invalid: + self.recache() return self._x def get_ydata(self, orig=True): @@ -540,9 +549,21 @@ """ if orig: return self._yorig + if self._invalid: + self.recache() return self._y + def get_path(self): + """ + Return the Path object associated with this line. + """ + if self._invalid: + self.recache() + return self._path + def get_xydata(self): + if self._invalid: + self.recache() return self._xy def set_antialiased(self, b): Modified: branches/transforms/lib/matplotlib/path.py =================================================================== --- branches/transforms/lib/matplotlib/path.py 2007-11-28 13:40:54 UTC (rev 4480) +++ branches/transforms/lib/matplotlib/path.py 2007-11-28 13:42:39 UTC (rev 4481) @@ -12,7 +12,7 @@ from matplotlib._path import point_in_path, get_path_extents, \ point_in_path_collection, get_path_collection_extents, \ - path_in_path + path_in_path, path_intersects_path from matplotlib.cbook import simple_linear_interpolation KAPPA = 4.0 * (npy.sqrt(2) - 1) / 3.0 @@ -237,6 +237,22 @@ transform = Affine2D() return Bbox.from_extents(*get_path_extents(self, transform)) + def intersects_path(self, other): + """ + Returns True if this path intersects another given path. + """ + return path_intersects_path(self, other) + + def intersects_bbox(self, bbox): + """ + Returns True if this path intersects a given Bbox. + """ + from transforms import BboxTransformTo + rectangle = self.unit_rectangle().transformed( + BboxTransformTo(bbox)) + result = self.intersects_path(rectangle) + return result + def interpolated(self, steps): """ Returns a new path resampled to length N x steps. Modified: branches/transforms/lib/matplotlib/transforms.py =================================================================== --- branches/transforms/lib/matplotlib/transforms.py 2007-11-28 13:40:54 UTC (rev 4480) +++ branches/transforms/lib/matplotlib/transforms.py 2007-11-28 13:42:39 UTC (rev 4481) @@ -508,26 +508,8 @@ bboxes is a sequence of Bbox objects """ - ax1, ay1, ax2, ay2 = self._get_extents() - if ax2 < ax1: - ax2, ax1 = ax1, ax2 - if ay2 < ay1: - ay2, ay1 = ay1, ay2 + return count_bboxes_overlapping_bbox(self, bboxes) - count = 0 - for bbox in bboxes: - # bx1, by1, bx2, by2 = bbox._get_extents() ... inlined... - bx1, by1, bx2, by2 = bbox.get_points().flatten() - if bx2 < bx1: - bx2, bx1 = bx1, bx2 - if by2 < by1: - by2, by1 = by1, by2 - count += (not ((bx2 <= ax1) or - (by2 <= ay1) or - (bx1 >= ax2) or - (by1 >= ay2))) - return count - def expanded(self, sw, sh): """ Return a new Bbox which is this Bbox expanded around its Modified: branches/transforms/src/_path.cpp =================================================================== --- branches/transforms/src/_path.cpp 2007-11-28 13:40:54 UTC (rev 4480) +++ branches/transforms/src/_path.cpp 2007-11-28 13:42:39 UTC (rev 4481) @@ -36,13 +36,15 @@ add_varargs_method("point_in_path_collection", &_path_module::point_in_path_collection, "point_in_path_collection(x, y, r, trans, paths, transforms, offsets, offsetTrans, filled)"); add_varargs_method("path_in_path", &_path_module::path_in_path, - "point_in_path_collection(a, atrans, b, btrans)"); + "path_in_path(a, atrans, b, btrans)"); add_varargs_method("clip_path_to_rect", &_path_module::clip_path_to_rect, "clip_path_to_rect(path, bbox, inside)"); add_varargs_method("affine_transform", &_path_module::affine_transform, "affine_transform(vertices, transform)"); add_varargs_method("count_bboxes_overlapping_bbox", &_path_module::count_bboxes_overlapping_bbox, "count_bboxes_overlapping_bbox(bbox, bboxes)"); + add_varargs_method("path_intersects_path", &_path_module::path_intersects_path, + "path_intersects_path(p1, p2)"); initialize("Helper functions for paths"); } @@ -60,6 +62,7 @@ Py::Object clip_path_to_rect(const Py::Tuple& args); Py::Object affine_transform(const Py::Tuple& args); Py::Object count_bboxes_overlapping_bbox(const Py::Tuple& args); + Py::Object path_intersects_path(const Py::Tuple& args); }; // @@ -673,7 +676,8 @@ transform = (PyArrayObject*) PyArray_FromObject (transform_obj.ptr(), PyArray_DOUBLE, 2, 2); - if (!transform || PyArray_NDIM(transform) != 2 || PyArray_DIM(transform, 0) != 3 || PyArray_DIM(transform, 1) != 3) + if (!transform || PyArray_NDIM(transform) != 2 || + PyArray_DIM(transform, 0) != 3 || PyArray_DIM(transform, 1) != 3) throw Py::ValueError("Invalid transform."); double a, b, c, d, e, f; @@ -783,6 +787,70 @@ return Py::Int(count); } +bool segments_intersect(const double& x1, const double &y1, + const double& x2, const double &y2, + const double& x3, const double &y3, + const double& x4, const double &y4) { + double den = ((y4-y3) * (x2-x1)) - ((x4-x3)*(y2-y1)); + if (den == 0.0) + return false; + + double n1 = ((x4-x3) * (y1-y3)) - ((y4-y3)*(x1-x3)); + double n2 = ((x2-x1) * (y1-y3)) - ((y2-y1)*(x1-x3)); + + double u1 = n1/den; + double u2 = n2/den; + + return (u1 >= 0.0 && u1 <= 1.0 && + u2 >= 0.0 && u2 <= 1.0); +} + +bool path_intersects_path(PathIterator& p1, PathIterator& p2) { + typedef agg::conv_curve<PathIterator> curve_t; + + if (p1.total_vertices() < 2 || p2.total_vertices() < 2) + return false; + + curve_t c1(p1); + curve_t c2(p2); + + double x11, y11, x12, y12; + double x21, y21, x22, y22; + + c1.vertex(&x11, &y11); + while (c1.vertex(&x12, &y12) != agg::path_cmd_stop) { + c2.rewind(0); + c2.vertex(&x21, &y21); + while (c2.vertex(&x22, &y22) != agg::path_cmd_stop) { + if (segments_intersect(x11, y11, x12, y12, x21, y21, x22, y22)) + return true; + x21 = x22; y21 = y22; + } + x11 = x12; y11 = y12; + } + + return false; +} + +Py::Object _path_module::path_intersects_path(const Py::Tuple& args) { + args.verify_length(2); + + PathIterator p1(args[0]); + PathIterator p2(args[1]); + + bool intersects = ::path_intersects_path(p1, p2); + if (!intersects) { + intersects = ::path_in_path(p1, agg::trans_affine(), p2, agg::trans_affine()); + if (!intersects) { + intersects = ::path_in_path(p2, agg::trans_affine(), p1, agg::trans_affine()); + if (!intersects) { + return Py::Int(0); + } + } + } + return Py::Int(1); +} + extern "C" DL_EXPORT(void) init_path(void) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-11-28 18:27:50
|
Revision: 4489 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4489&view=rev Author: mdboom Date: 2007-11-28 10:27:43 -0800 (Wed, 28 Nov 2007) Log Message: ----------- Speed improvements -- determine path extents in C Modified Paths: -------------- branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/colorbar.py branches/transforms/lib/matplotlib/path.py branches/transforms/lib/matplotlib/text.py branches/transforms/lib/matplotlib/transforms.py branches/transforms/src/_path.cpp Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-11-28 18:26:40 UTC (rev 4488) +++ branches/transforms/lib/matplotlib/axes.py 2007-11-28 18:27:43 UTC (rev 4489) @@ -425,10 +425,10 @@ """ name = "rectilinear" - + _shared_x_axes = cbook.Grouper() _shared_y_axes = cbook.Grouper() - + def __str__(self): return "Axes(%g,%g;%gx%g)" % tuple(self._position.bounds) def __init__(self, fig, rect, @@ -496,7 +496,7 @@ # this call may differ for non-sep axes, eg polar self._init_axis() - + if axisbg is None: axisbg = rcParams['axes.facecolor'] self._axisbg = axisbg self._frameon = frameon @@ -679,12 +679,12 @@ return (self._yaxis_transform + mtransforms.Affine2D().translate(pad_pixels, 0), "center", "left") - + def _update_transScale(self): self.transScale.set( mtransforms.blended_transform_factory( self.xaxis.get_transform(), self.yaxis.get_transform())) - + def get_position(self, original=False): 'Return the a copy of the axes rectangle as a Bbox' if original: @@ -692,7 +692,7 @@ else: return self._position.frozen() - + def set_position(self, pos, which='both'): """ Set the axes position with pos = [left, bottom, width, height] @@ -734,7 +734,7 @@ Intended to be overridden by new projection types. """ return mpatches.Rectangle((0.0, 0.0), 1.0, 1.0) - + def cla(self): 'Clear the current axes' @@ -780,7 +780,7 @@ self.title.set_clip_box(None) self._set_artist_props(self.title) - + self.axesPatch = self.get_axes_patch() self.axesPatch.set_figure(self.figure) self.axesPatch.set_facecolor(self._axisbg) @@ -904,7 +904,7 @@ ymin,ymax = self.get_ybound() ysize = max(math.fabs(ymax-ymin), 1e-30) return ysize/xsize - + def apply_aspect(self): ''' Use self._aspect and self._adjustable to modify the @@ -938,7 +938,7 @@ xsize = max(math.fabs(xmax-xmin), 1e-30) ymin,ymax = self.get_ybound() ysize = max(math.fabs(ymax-ymin), 1e-30) - + l,b,w,h = self.get_position(original=True).bounds box_aspect = fig_aspect * (h/w) data_ratio = box_aspect / A @@ -1125,7 +1125,6 @@ a.set_axes(self) self.artists.append(a) self._set_artist_props(a) - # MGDTODO: We may not want to do this -- the old trunk didn't a.set_clip_path(self.axesPatch) a._remove_method = lambda h: self.artists.remove(h) @@ -1168,7 +1167,7 @@ self._update_patch_limits(p) self.patches.append(p) p._remove_method = lambda h: self.patches.remove(h) - + def _update_patch_limits(self, p): 'update the datalimits for patch p' vertices = p.get_patch_transform().transform(p.get_path().vertices) @@ -1181,7 +1180,6 @@ 'Add a table instance to the list of axes tables' self._set_artist_props(tab) self.tables.append(tab) - # MGDTODO: We may not want to do this (the old version in trunk didn't) tab.set_clip_path(self.axesPatch) tab._remove_method = lambda h: self.tables.remove(h) @@ -1202,7 +1200,8 @@ # and the data in xydata if not ma.isMaskedArray(xys): xys = npy.asarray(xys) - self.update_datalim_numerix(xys[:, 0], xys[:, 1]) + self.dataLim.update_from_data_xy(xys, self.ignore_existing_data_limits) + self.ignore_existing_data_limits = False def update_datalim_numerix(self, x, y): 'Update the data lim bbox with seq of xy tups' @@ -1216,7 +1215,7 @@ def update_datalim_bounds(self, bounds): 'Update the datalim to include the given Bbox' self.dataLim.set(Bbox.union([self.dataLim, bounds])) - + def _process_unit_info(self, xdata=None, ydata=None, kwargs=None): 'look for unit kwargs and update the axis instances as necessary' @@ -1303,7 +1302,7 @@ if self.axison and self._frameon: self.axesPatch.draw(renderer) - + artists = [] if len(self.images)<=1 or renderer.option_image_nocomposite(): @@ -1513,7 +1512,7 @@ self.axesPatch.set_facecolor(color) ### data limits, ticks, tick labels, and formatting - + def invert_xaxis(self): "Invert the x-axis." left, right = self.get_xlim() @@ -1601,7 +1600,7 @@ xmin, xmax = self.xaxis.limit_range_for_scale(xmin, xmax) self.viewLim.intervalx = (xmin, xmax) - + if emit: self.callbacks.process('xlim_changed', self) # Call all of the other x-axes that are shared with this one @@ -1610,7 +1609,7 @@ other.set_xlim(self.viewLim.intervalx, emit=False) if other.figure != self.figure and other.figure.canvas is not None: other.figure.canvas.draw_idle() - + return xmin, xmax def get_xscale(self): @@ -1638,7 +1637,7 @@ """ % {'scale': ' | '.join([repr(x) for x in mscale.get_scale_names()])} self.xaxis.set_scale(value, **kwargs) self._update_transScale() - + def get_xticks(self, minor=False): 'Return the x ticks as a list of locations' return self.xaxis.get_ticklocs(minor=minor) @@ -1777,7 +1776,7 @@ 'return the xaxis scale string: %s' % ( ", ".join(mscale.get_scale_names())) return self.yaxis.get_scale() - + def set_yscale(self, value, **kwargs): """ SET_YSCALE(value, basey=10, subsy=None) @@ -1798,7 +1797,7 @@ """ % {'scale': ' | '.join([repr(x) for x in mscale.get_scale_names()])} self.yaxis.set_scale(value, **kwargs) self._update_transScale() - + def get_yticks(self, minor=False): 'Return the y ticks as a list of locations' return self.yaxis.get_ticklocs(minor=minor) @@ -1903,7 +1902,7 @@ xs = self.format_xdata(x) ys = self.format_ydata(y) return 'x=%s, y=%s'%(xs,ys) - + #### Interactive manipulation def can_zoom(self): @@ -1911,7 +1910,7 @@ Return True if this axes support the zoom box """ return True - + def get_navigate(self): """ Get whether the axes responds to navigation commands @@ -1949,7 +1948,7 @@ 1: LEFT 2: MIDDLE 3: RIGHT - + Intended to be overridden by new projection types. """ self._pan_start = cbook.Bunch( @@ -1968,7 +1967,7 @@ Intended to be overridden by new projection types. """ del self._pan_start - + def drag_pan(self, button, key, x, y): """ Called when the mouse moves during a pan operation. @@ -2029,10 +2028,10 @@ except OverflowError: warnings.warn('Overflow while panning') return - + self.set_xlim(*result.intervalx) self.set_ylim(*result.intervaly) - + def get_cursor_props(self): """return the cursor props as a linewidth, color tuple where linewidth is a float and color is an RGBA tuple""" @@ -3158,7 +3157,7 @@ if where not in ('pre', 'post', 'mid'): raise ValueError("'where' argument to step must be 'pre', 'post' or 'mid'") kwargs['linestyle'] = 'steps-' + where - + return self.plot(x, y, *args, **kwargs) @@ -3828,7 +3827,7 @@ # using list comps rather than arrays to preserve units lower = [thisy-thiserr for (thisy, thiserr) in cbook.safezip(y,yerr)] upper = [thisy+thiserr for (thisy, thiserr) in cbook.safezip(y,yerr)] - + barcols.append( self.vlines(x, lower, upper, **lines_kw) ) if capsize > 0: @@ -4334,7 +4333,7 @@ def quiver(self, *args, **kw): """ - MGDTODO: Document me + TODO: Document me """ q = mquiver.Quiver(self, *args, **kw) self.add_collection(q, False) @@ -4516,7 +4515,7 @@ return im - + def _pcolorargs(self, funcname, *args): if len(args)==1: C = args[0] @@ -4790,7 +4789,7 @@ shading = kwargs.pop('shading', 'flat') edgecolors = kwargs.pop('edgecolors', 'None') antialiased = kwargs.pop('antialiased', False) - + X, Y, C = self._pcolorargs('pcolormesh', *args) Ny, Nx = X.shape @@ -5519,7 +5518,7 @@ # _axes_class is set in the subplot_class_factory self._axes_class.__init__(self, fig, self.figbox, **kwargs) - + def get_geometry(self): 'get the subplot geometry, eg 2,2,3' return self._rows, self._cols, self._num+1 @@ -5608,24 +5607,24 @@ for label in self.get_yticklabels(): label.set_visible(firstcol) -_subplot_classes = {} +_subplot_classes = {} def subplot_class_factory(axes_class=None): # This makes a new class that inherits from SubclassBase and the # given axes_class (which is assumed to be a subclass of Axes). - + # This is perhaps a little bit roundabout to make a new class on # the fly like this, but it means that a new Subplot class does # not have to be created for every type of Axes. if axes_class is None: axes_class = Axes - + new_class = _subplot_classes.get(axes_class) if new_class is None: new_class = new.classobj("%sSubplot" % (axes_class.__name__), (SubplotBase, axes_class), {'_axes_class': axes_class}) _subplot_classes[axes_class] = new_class - + return new_class # This is provided for backward compatibility Modified: branches/transforms/lib/matplotlib/colorbar.py =================================================================== --- branches/transforms/lib/matplotlib/colorbar.py 2007-11-28 18:26:40 UTC (rev 4488) +++ branches/transforms/lib/matplotlib/colorbar.py 2007-11-28 18:27:43 UTC (rev 4489) @@ -198,17 +198,17 @@ ax = self.ax ax.set_frame_on(False) ax.set_navigate(False) - x, y = self._outline(X, Y) - ax.set_xlim(npy.amin(x), npy.amax(x)) - ax.set_ylim(npy.amin(y), npy.amax(y)) - ax.update_datalim_numerix(x, y) - self.outline = lines.Line2D(x, y, color=mpl.rcParams['axes.edgecolor'], + xy = self._outline(X, Y) + ax.update_datalim(xy) + ax.set_xlim(*ax.dataLim.intervalx) + ax.set_ylim(*ax.dataLim.intervaly) + self.outline = lines.Line2D(xy[:, 0], xy[:, 1], color=mpl.rcParams['axes.edgecolor'], linewidth=mpl.rcParams['axes.linewidth']) ax.add_artist(self.outline) self.outline.set_clip_box(None) self.outline.set_clip_path(None) c = mpl.rcParams['axes.facecolor'] - self.patch = patches.Polygon(zip(x,y), edgecolor=c, + self.patch = patches.Polygon(xy, edgecolor=c, facecolor=c, linewidth=0.01, zorder=-1) @@ -250,9 +250,11 @@ ii = [0, 1, N-2, N-1, 2*N-1, 2*N-2, N+1, N, 0] x = npy.take(npy.ravel(npy.transpose(X)), ii) y = npy.take(npy.ravel(npy.transpose(Y)), ii) + x = x.reshape((len(x), 1)) + y = y.reshape((len(y), 1)) if self.orientation == 'horizontal': - return y,x - return x,y + return npy.hstack((y, x)) + return npy.hstack((x, y)) def _edges(self, X, Y): ''' @@ -510,7 +512,7 @@ N = len(b) ii = npy.minimum(npy.searchsorted(b, xn), N-1) i0 = npy.maximum(ii - 1, 0) - #db = b[ii] - b[i0] + #db = b[ii] - b[i0] db = npy.take(b, ii) - npy.take(b, i0) db = npy.where(i0==ii, 1.0, db) #dy = y[ii] - y[i0] Modified: branches/transforms/lib/matplotlib/path.py =================================================================== --- branches/transforms/lib/matplotlib/path.py 2007-11-28 18:26:40 UTC (rev 4488) +++ branches/transforms/lib/matplotlib/path.py 2007-11-28 18:27:43 UTC (rev 4489) @@ -38,10 +38,10 @@ MOVETO : 1 vertex Pick up the pen and move to the given vertex. - + LINETO : 1 vertex Draw a line from the current position to the given vertex. - + CURVE3 : 1 control point, 1 endpoint Draw a quadratic Bezier curve from the current position, with the given control point, to the given end point. @@ -60,7 +60,7 @@ store a codes array at all, but have a default one provided for them by iter_segments. """ - + # Path codes STOP = 0 # 1 vertex MOVETO = 1 # 1 vertex @@ -70,7 +70,7 @@ CLOSEPOLY = 5 # 1 vertex NUM_VERTICES = [1, 1, 1, 2, 3, 1] - + code_type = npy.uint8 def __init__(self, vertices, codes=None): @@ -124,7 +124,7 @@ assert vertices.ndim == 2 assert vertices.shape[1] == 2 - + self.codes = codes self.vertices = vertices @@ -142,22 +142,22 @@ vertices = npy.vstack([x.vertices for x in args]) vertices.reshape((total_length, 2)) - + codes = Path.LINETO * npy.ones(total_length) i = 0 for length in lengths: codes[i] = Path.MOVETO i += length - + return Path(vertices, codes) make_compound_path = staticmethod(make_compound_path) - + def __repr__(self): return "Path(%s, %s)" % (self.vertices, self.codes) def __len__(self): return len(self.vertices) - + def iter_segments(self): """ Iterates over all of the curve segments in the path. @@ -171,10 +171,10 @@ LINETO = self.LINETO CLOSEPOLY = self.CLOSEPOLY STOP = self.STOP - + if not len(vertices): return - + if codes is None: yield vertices[0], MOVETO for v in vertices[1:]: @@ -192,7 +192,7 @@ num_vertices = NUM_VERTICES[code] yield vertices[i:i+num_vertices].flatten(), code i += num_vertices - + def transformed(self, transform): """ Return a transformed copy of the path. @@ -223,7 +223,7 @@ from transforms import IdentityTransform transform = IdentityTransform() return path_in_path(self, IdentityTransform(), path, transform) - + def get_extents(self, transform=None): """ Returns the extents (xmin, ymin, xmax, ymax) of the path. @@ -235,7 +235,7 @@ from transforms import Affine2D, Bbox if transform is None: transform = Affine2D() - return Bbox.from_extents(*get_path_extents(self, transform)) + return Bbox(get_path_extents(self, transform)) def intersects_path(self, other): """ @@ -252,7 +252,7 @@ BboxTransformTo(bbox)) result = self.intersects_path(rectangle) return result - + def interpolated(self, steps): """ Returns a new path resampled to length N x steps. @@ -266,7 +266,7 @@ else: new_codes = None return Path(vertices, new_codes) - + _unit_rectangle = None #@classmethod def unit_rectangle(cls): @@ -329,7 +329,7 @@ """ return cls.unit_regular_star(numVertices, 0.0) unit_regular_asterisk = classmethod(unit_regular_asterisk) - + _unit_circle = None #@classmethod def unit_circle(cls): @@ -341,19 +341,19 @@ offset = KAPPA vertices = npy.array( [[-1.0, 0.0], - + [-1.0, offset], [-offset, 1.0], [0.0, 1.0], - + [offset, 1.0], [1.0, offset], [1.0, 0.0], - + [1.0, -offset], [offset, -1.0], [0.0, -1.0], - + [-offset, -1.0], [-1.0, -offset], [-1.0, 0.0], @@ -383,10 +383,10 @@ # degrees to radians theta1 *= math.pi / 180.0 theta2 *= math.pi / 180.0 - + twopi = math.pi * 2.0 halfpi = math.pi * 0.5 - + eta1 = math.atan2(math.sin(theta1), math.cos(theta1)) eta2 = math.atan2(math.sin(theta2), math.cos(theta2)) eta2 -= twopi * math.floor((eta2 - eta1) / twopi) @@ -423,13 +423,13 @@ t = math.tan(0.5 * deta) alpha = math.sin(deta) * (math.sqrt(4.0 + 3.0 * t * t) - 1) / 3.0 - + for i in xrange(n): xA = xB yA = yB xA_dot = xB_dot yA_dot = yB_dot - + etaB += deta cos_etaB = math.cos(etaB) sin_etaB = math.sin(etaB) @@ -446,7 +446,7 @@ if is_wedge: codes[-2:] = [Path.LINETO, Path.CLOSEPOLY] - + return Path(vertices, codes) arc = classmethod(arc) Modified: branches/transforms/lib/matplotlib/text.py =================================================================== --- branches/transforms/lib/matplotlib/text.py 2007-11-28 18:26:40 UTC (rev 4488) +++ branches/transforms/lib/matplotlib/text.py 2007-11-28 18:27:43 UTC (rev 4489) @@ -258,7 +258,7 @@ xys -= (offsetx, offsety) xs, ys = xys[:, 0], xys[:, 1] - + ret = bbox, zip(lines, whs, xs, ys) self.cached[key] = ret return ret @@ -274,7 +274,6 @@ """ self._bbox = rectprops - # MGDTODO: The clipping here could be generalized def draw(self, renderer): #return if renderer is not None: @@ -297,7 +296,7 @@ posx, posy = self.get_position() posx, posy = trans.transform_point((posx, posy)) canvasw, canvash = renderer.get_canvas_width_height() - + if rcParams['text.usetex']: for line, wh, x, y in info: x = x + posx @@ -314,11 +313,11 @@ y = y + posy if renderer.flipy(): y = canvash-y - + renderer.draw_text(gc, x, y, line, self._fontproperties, angle, ismath=self.is_math_text(line)) - + def get_color(self): "Return the color of the text" return self._color @@ -1035,7 +1034,6 @@ """ Text.set_clip_box(self, clipbox) - # MGDTODO: Abstract this out -- this seems weird to have this big "switch" here def _get_xy(self, x, y, s): if s=='data': trans = self.axes.transData Modified: branches/transforms/lib/matplotlib/transforms.py =================================================================== --- branches/transforms/lib/matplotlib/transforms.py 2007-11-28 18:26:40 UTC (rev 4488) +++ branches/transforms/lib/matplotlib/transforms.py 2007-11-28 18:27:43 UTC (rev 4489) @@ -29,17 +29,18 @@ from numpy.linalg import inv from weakref import WeakKeyDictionary +import warnings import cbook from path import Path -from _path import count_bboxes_overlapping_bbox +from _path import count_bboxes_overlapping_bbox, update_path_extents DEBUG = False if DEBUG: import warnings MaskedArray = ma.MaskedArray - + class TransformNode(object): """ TransformNode is the base class for anything that participates in @@ -56,7 +57,7 @@ INVALID_NON_AFFINE = 1 INVALID_AFFINE = 2 INVALID = INVALID_NON_AFFINE | INVALID_AFFINE - + # Some metadata about the transform, used to determine whether an # invalidation is affine-only is_affine = False @@ -65,7 +66,7 @@ # If pass_through is True, all ancestors will always be # invalidated, even if 'self' is already invalid. pass_through = False - + def __init__(self): """ Creates a new TransformNode. @@ -79,16 +80,12 @@ # computed for the first time. self._invalid = 1 - # A list of the children is kept around for debugging purposes - # only. - self._children = [] - def __copy__(self, *args): raise NotImplementedError( "TransformNode instances can not be copied. " + "Consider using frozen() instead.") __deepcopy__ = __copy__ - + def invalidate(self): """ Invalidate this transform node and all of its parents. Should @@ -104,7 +101,7 @@ # are as well, so we don't need to do anything. if self._invalid == value or not len(self._parents): return - + # Invalidate all ancestors of self using pseudo-recursion. parent = None stack = [self] @@ -122,8 +119,13 @@ """ for child in children: child._parents[self] = None - self._children = children + if DEBUG: + _set_children = set_children + def set_children(self, *children): + self._set_children(*children) + self._children = children + def frozen(self): """ Returns a frozen copy of this transform node. The frozen copy @@ -169,17 +171,18 @@ fobj.write('%s [%s];\n' % (hash(root), props)) - for child in root._children: - name = '?' - for key, val in root.__dict__.items(): - if val is child: - name = key - break - fobj.write('%s -> %s [label="%s", fontsize=10];\n' % ( - hash(root), - hash(child), - name)) - recurse(child) + if hasattr(root, '_children'): + for child in root._children: + name = '?' + for key, val in root.__dict__.items(): + if val is child: + name = key + break + fobj.write('%s -> %s [label="%s", fontsize=10];\n' % ( + hash(root), + hash(child), + name)) + recurse(child) fobj.write("digraph G {\n") recurse(self) @@ -187,8 +190,8 @@ else: def write_graphviz(self, fobj, highlight=[]): return - - + + class BboxBase(TransformNode): """ This is the base class of all bounding boxes, and provides @@ -209,21 +212,21 @@ points[1,1] - points[0,1] == 0): warnings.warn("Singular Bbox.") _check = staticmethod(_check) - + def frozen(self): return Bbox(self.get_points().copy()) frozen.__doc__ = TransformNode.__doc__ - + def __array__(self, *args, **kwargs): return self.get_points() def is_unit(self): return list(self.get_points().flatten()) == [0., 0., 1., 1.] - + def _get_x0(self): return self.get_points()[0, 0] x0 = property(_get_x0) - + def _get_y0(self): return self.get_points()[0, 1] y0 = property(_get_y0) @@ -243,7 +246,7 @@ def _get_p1(self): return self.get_points()[1] p1 = property(_get_p1) - + def _get_xmin(self): return min(self.get_points()[:, 0]) xmin = property(_get_xmin) @@ -259,17 +262,17 @@ def _get_ymax(self): return max(self.get_points()[:, 1]) ymax = property(_get_ymax) - + def _get_min(self): return [min(self.get_points()[:, 0]), min(self.get_points()[:, 1])] min = property(_get_min) - + def _get_max(self): return [max(self.get_points()[:, 0]), max(self.get_points()[:, 1])] max = property(_get_max) - + def _get_intervalx(self): return self.get_points()[:, 0] intervalx = property(_get_intervalx) @@ -277,7 +280,7 @@ def _get_intervaly(self): return self.get_points()[:, 1] intervaly = property(_get_intervaly) - + def _get_width(self): points = self.get_points() return points[1, 0] - points[0, 0] @@ -292,7 +295,7 @@ points = self.get_points() return points[1] - points[0] size = property(_get_size) - + def _get_bounds(self): x0, y0, x1, y1 = self.get_points().flatten() return (x0, y0, x1 - x0, y1 - y0) @@ -301,10 +304,10 @@ def _get_extents(self): return self.get_points().flatten().copy() extents = property(_get_extents) - + def get_points(self): return NotImplementedError() - + def containsx(self, x): x0, x1 = self.intervalx return ((x0 < x1 @@ -316,7 +319,7 @@ return ((y0 < y1 and (y >= y0 and y <= y1)) or (y >= y1 and y <= y0)) - + def contains(self, x, y): return self.containsx(x) and self.containsy(y) @@ -337,7 +340,7 @@ (by2 < ay1) or (bx1 > ax2) or (by1 > ay2)) - + def fully_containsx(self, x): x0, x1 = self.intervalx return ((x0 < x1 @@ -349,7 +352,7 @@ return ((y0 < y1 and (x > y0 and x < y1)) or (x > y1 and x < y0)) - + def fully_contains(self, x, y): return self.fully_containsx(x) \ and self.fully_containsy(y) @@ -529,7 +532,7 @@ """ points = self._points return Bbox(points + [[-p, -p], [p, p]]) - + def translated(self, tx, ty): """ Return a copy of the Bbox, translated by tx and ty. @@ -543,7 +546,7 @@ """ l, b, r, t = self.get_points().flatten() return npy.array([[l, b], [l, t], [r, b], [r, t]]) - + def rotated(self, radians): """ Return a new bounding box that bounds a rotated version of this @@ -555,7 +558,7 @@ bbox = Bbox.unit() bbox.update_from_data(corners_rotated, ignore=True) return bbox - + #@staticmethod def union(bboxes): """ @@ -582,8 +585,8 @@ return Bbox.from_extents(x0, y0, x1, y1) union = staticmethod(union) - - + + class Bbox(BboxBase): def __init__(self, points): """ @@ -598,13 +601,13 @@ self._points = npy.asarray(points, npy.float_) self._minpos = npy.array([0.0000001, 0.0000001]) self._ignore = True - + if DEBUG: ___init__ = __init__ def __init__(self, points): self._check(points) self.___init__(points) - + def invalidate(self): self._check(self._points) TransformNode.invalidate(self) @@ -638,7 +641,7 @@ points = npy.array(args, dtype=npy.float_).reshape(2, 2) return Bbox(points) from_extents = staticmethod(from_extents) - + def __repr__(self): return 'Bbox(%s)' % repr(self._points) __str__ = __repr__ @@ -654,7 +657,7 @@ include the existing bounds of the Bbox. """ self._ignore = value - + def update_from_data(self, x, y, ignore=None): """ Update the bounds of the Bbox based on the passed in data. @@ -666,45 +669,10 @@ when False, include the existing bounds of the Bbox. when None, use the last value passed to Bbox.ignore(). """ - if ignore is None: - ignore = self._ignore + warnings.warn("update_from_data requires a memory copy -- please replace with update_from_data_xy") + xy = npy.hstack((x.reshape((len(x), 1)), y.reshape((len(y), 1)))) + return self.update_from_data_xy(xy, ignore) - if len(x) == 0 or len(y) == 0: - return - - if ma.isMaskedArray(x) or ma.isMaskedArray(y): - xpos = ma.where(x > 0.0, x, npy.inf) - ypos = ma.where(y > 0.0, y, npy.inf) - else: - xpos = npy.where(x > 0.0, x, npy.inf) - ypos = npy.where(y > 0.0, y, npy.inf) - if len(xpos) and len(ypos): - minpos = npy.array( - [xpos.min(), - ypos.min()], - npy.float_) - else: - minpos = npy.array([-npy.inf, -npy.inf], npy.float_) - - if ignore: - points = npy.array( - [[x.min(), y.min()], [x.max(), y.max()]], - npy.float_) - self._minpos = minpos - else: - x0, y0, x1, y1 = self._get_extents() - points = npy.array( - [[min(x.min(), x0, x1), - min(y.min(), y0, y1)], - [max(x.max(), x0, x1), - max(y.max(), y0, y1)]], - npy.float_) - self._minpos = npy.minimum(minpos, self._minpos) - - if npy.any(self._points != points): - self._points = points - self.invalidate() - def update_from_data_xy(self, xy, ignore=None): """ Update the bounds of the Bbox based on the passed in data. @@ -715,8 +683,20 @@ when False, include the existing bounds of the Bbox. when None, use the last value passed to Bbox.ignore(). """ - return self.update_from_data(xy[:, 0], xy[:, 1], ignore) - + if ignore is None: + ignore = self._ignore + + if len(xy) == 0: + return + + points, minpos, changed = update_path_extents( + Path(xy), None, self._points, self._minpos, ignore) + + if changed: + self._points = points + self._minpos = minpos + self.invalidate() + def _set_x0(self, val): self._points[0, 0] = val self.invalidate() @@ -746,7 +726,7 @@ self._points[1] = val self.invalidate() p1 = property(BboxBase._get_p1, _set_p1) - + def _set_intervalx(self, interval): self._points[:, 0] = interval self.invalidate() @@ -776,7 +756,7 @@ def _get_minposy(self): return self._minpos[1] minposy = property(_get_minposy) - + def get_points(self): """ Set the points of the bounding box directly as a numpy array @@ -803,7 +783,7 @@ self._points = other.get_points() self.invalidate() - + class TransformedBbox(BboxBase): """ A Bbox that is automatically transformed by a given Transform. When @@ -829,7 +809,7 @@ def __repr__(self): return "TransformedBbox(%s, %s)" % (self._bbox, self._transform) __str__ = __repr__ - + def get_points(self): if self._invalid: points = self._transform.transform(self._bbox.get_points()) @@ -846,7 +826,7 @@ points = self._get_points() self._check(points) return points - + class Transform(TransformNode): """ The base class of all TransformNodes that actually perform a @@ -854,7 +834,7 @@ All non-affine transformations should be subclass this class. New affine transformations should subclass Affine2D. - + Subclasses of this class should override the following members (at minimum): @@ -907,28 +887,28 @@ Used by C/C++ -based backends to get at the array matrix data. """ return self.frozen().__array__() - + def transform(self, values): """ Performs the transformation on the given array of values. - + Accepts a numpy array of shape (N x self.input_dims) and returns a numpy array of shape (N x self.output_dims). """ raise NotImplementedError() - + def transform_affine(self, values): """ Performs only the affine part of this transformation on the given array of values. - + transform(values) is equivalent to transform_affine(transform_non_affine(values)). In non-affine transformations, this is generally a no-op. In affine transformations, this is equivalent to transform(values). - + Accepts a numpy array of shape (N x self.input_dims) and returns a numpy array of shape (N x self.output_dims). """ @@ -944,7 +924,7 @@ In non-affine transformations, this is generally equivalent to transform(values). In affine transformations, this is a no-op. - + Accepts a numpy array of shape (N x self.input_dims) and returns a numpy array of shape (N x self.output_dims). """ @@ -955,7 +935,7 @@ Get the affine part of this transform. """ return IdentityTransform() - + def transform_point(self, point): """ A convenience function that returns the transformed copy of a @@ -973,7 +953,7 @@ Returns a transformed copy of path. path: a Path instance. - + In some cases, this transform may insert curves into the path that began as line segments. """ @@ -1002,7 +982,7 @@ transform_path_affine(transform_path_non_affine(values)). """ return Path(self.transform_non_affine(path.vertices), path.codes) - + def inverted(self): """ Return the corresponding inverse transformation. @@ -1036,7 +1016,7 @@ with set(). """ assert isinstance(child, Transform) - + Transform.__init__(self) self.input_dims = child.input_dims self.output_dims = child.output_dims @@ -1063,7 +1043,7 @@ self.transform_path_non_affine = child.transform_path_non_affine self.get_affine = child.get_affine self.inverted = child.inverted - + def set(self, child): """ Replace the current child of this transform with another one. @@ -1075,11 +1055,11 @@ assert child.output_dims == self.output_dims self._set(child) - + self._invalid = 0 self.invalidate() self._invalid = 0 - + def _get_is_affine(self): return self._child.is_affine is_affine = property(_get_is_affine) @@ -1091,22 +1071,22 @@ def _get_has_inverse(self): return self._child.has_inverse has_inverse = property(_get_has_inverse) - - + + class AffineBase(Transform): """ The base class of all affine transformations of any number of dimensions. """ is_affine = True - + def __init__(self): Transform.__init__(self) self._inverted = None def __array__(self, *args, **kwargs): return self.get_matrix() - + #@staticmethod def _concat(a, b): """ @@ -1133,28 +1113,28 @@ def transform_path_non_affine(self, path): return path transform_path_non_affine.__doc__ = Transform.transform_path_non_affine.__doc__ - + def get_affine(self): return self get_affine.__doc__ = Transform.get_affine.__doc__ - + class Affine2DBase(AffineBase): """ The base class of all 2D affine transformations. 2D affine transformations are performed using a 3x3 numpy array: - + a c e b d f 0 0 1 - + Provides the read-only interface. Subclasses of this class will generally only need to override a constructor and 'get_matrix' that generates a custom 3x3 matrix. """ - + input_dims = 2 output_dims = 2 @@ -1166,22 +1146,22 @@ def frozen(self): return Affine2D(self.get_matrix().copy()) frozen.__doc__ = AffineBase.frozen.__doc__ - + def _get_is_separable(self): mtx = self.get_matrix() return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0 is_separable = property(_get_is_separable) - + def __array__(self, *args, **kwargs): return self.get_matrix() - + def to_values(self): """ Return the values of the matrix as a sequence (a,b,c,d,e,f) """ mtx = self.get_matrix() return tuple(mtx[:2].swapaxes(0, 1).flatten()) - + #@staticmethod def matrix_from_values(a, b, c, d, e, f): """ @@ -1204,7 +1184,7 @@ def transform_point(self, point): mtx = self.get_matrix() return affine_transform(point, mtx) - + if DEBUG: _transform = transform def transform(self, points): @@ -1219,10 +1199,10 @@ % type(values)) return self._transform(points) transform.__doc__ = AffineBase.transform.__doc__ - + transform_affine = transform transform_affine.__doc__ = AffineBase.transform_affine.__doc__ - + def inverted(self): if self._inverted is None or self._invalid: mtx = self.get_matrix() @@ -1230,13 +1210,13 @@ self._invalid = 0 return self._inverted inverted.__doc__ = AffineBase.inverted.__doc__ - - + + class Affine2D(Affine2DBase): def __init__(self, matrix = None): """ Initialize an Affine transform from a 3x3 numpy float array: - + a c e b d f 0 0 1 @@ -1261,7 +1241,7 @@ (self.get_matrix() == other.get_matrix()).all()): return 0 return -1 - + #@staticmethod def from_values(a, b, c, d, e, f): """ @@ -1306,7 +1286,7 @@ assert isinstance(other, Affine2DBase) self._mtx = other.get_matrix() self.invalidate() - + #@staticmethod def identity(): """ @@ -1325,7 +1305,7 @@ self._mtx = npy.identity(3) self.invalidate() return self - + def rotate(self, theta): """ Add a rotation (in radians) to this transform in place. @@ -1368,7 +1348,7 @@ calls to rotate(), rotate_deg(), translate() and scale(). """ return self.translate(-x, -y).rotate_deg(degrees).translate(x, y) - + def translate(self, tx, ty): """ Adds a translation in place. @@ -1407,7 +1387,7 @@ return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0 is_separable = property(_get_is_separable) - + class IdentityTransform(Affine2DBase): """ A special class that does on thing, the identity transform, in a @@ -1418,19 +1398,19 @@ def frozen(self): return self frozen.__doc__ = Affine2DBase.frozen.__doc__ - + def __repr__(self): return "IdentityTransform()" __str__ = __repr__ - + def get_matrix(self): return self._mtx get_matrix.__doc__ = Affine2DBase.get_matrix.__doc__ - + def transform(self, points): return points transform.__doc__ = Affine2DBase.transform.__doc__ - + transform_affine = transform transform_affine.__doc__ = Affine2DBase.transform_affine.__doc__ @@ -1443,18 +1423,18 @@ transform_path_affine = transform_path transform_path_affine.__doc__ = Affine2DBase.transform_path_affine.__doc__ - + transform_path_non_affine = transform_path transform_path_non_affine.__doc__ = Affine2DBase.transform_path_non_affine.__doc__ - + def get_affine(self): return self get_affine.__doc__ = Affine2DBase.get_affine.__doc__ - + inverted = get_affine inverted.__doc__ = Affine2DBase.inverted.__doc__ - - + + class BlendedGenericTransform(Transform): """ A "blended" transform uses one transform for the x-direction, and @@ -1467,7 +1447,7 @@ output_dims = 2 is_separable = True pass_through = True - + def __init__(self, x_transform, y_transform): """ Create a new "blended" transform using x_transform to @@ -1479,13 +1459,13 @@ create. """ # Here we ask: "Does it blend?" - + Transform.__init__(self) self._x = x_transform self._y = y_transform self.set_children(x_transform, y_transform) self._affine = None - + def _get_is_affine(self): return self._x.is_affine and self._y.is_affine is_affine = property(_get_is_affine) @@ -1493,7 +1473,7 @@ def frozen(self): return blended_transform_factory(self._x.frozen(), self._y.frozen()) frozen.__doc__ = Transform.frozen.__doc__ - + def __repr__(self): return "BlendedGenericTransform(%s,%s)" % (self._x, self._y) __str__ = __repr__ @@ -1510,7 +1490,7 @@ else: x_points = x.transform(points[:, 0]) x_points = x_points.reshape((len(x_points), 1)) - + if y.input_dims == 2: y_points = y.transform(points)[:, 1:] else: @@ -1555,8 +1535,8 @@ self._invalid = 0 return self._affine get_affine.__doc__ = Transform.get_affine.__doc__ - - + + class BlendedAffine2D(Affine2DBase): """ A "blended" transform uses one transform for the x-direction, and @@ -1567,14 +1547,14 @@ """ is_separable = True - + def __init__(self, x_transform, y_transform): """ Create a new "blended" transform using x_transform to transform the x-axis and y_transform to transform the y_axis. Both x_transform and y_transform must be 2D affine transforms. - + You will generally not call this constructor directly but use the blended_transform_factory function instead, which can determine automatically which kind of blended transform to @@ -1589,14 +1569,14 @@ self._x = x_transform self._y = y_transform self.set_children(x_transform, y_transform) - + Affine2DBase.__init__(self) self._mtx = None def __repr__(self): return "BlendedAffine2D(%s,%s)" % (self._x, self._y) __str__ = __repr__ - + def get_matrix(self): if self._invalid: if self._x == self._y: @@ -1612,8 +1592,8 @@ self._invalid = 0 return self._mtx get_matrix.__doc__ = Affine2DBase.get_matrix.__doc__ - - + + def blended_transform_factory(x_transform, y_transform): """ Create a new "blended" transform using x_transform to @@ -1635,7 +1615,7 @@ This "generic" version can handle any two arbitrary transformations. """ pass_through = True - + def __init__(self, a, b): """ Create a new composite transform that is the result of @@ -1649,7 +1629,7 @@ assert a.output_dims == b.input_dims self.input_dims = a.input_dims self.output_dims = b.output_dims - + Transform.__init__(self) self._a = a self._b = b @@ -1662,15 +1642,15 @@ return frozen.frozen() return frozen frozen.__doc__ = Transform.frozen.__doc__ - + def _get_is_affine(self): return self._a.is_affine and self._b.is_affine is_affine = property(_get_is_affine) - + def _get_is_separable(self): return self._a.is_separable and self._b.is_separable is_separable = property(_get_is_separable) - + def __repr__(self): return "CompositeGenericTransform(%s, %s)" % (self._a, self._b) __str__ = __repr__ @@ -1679,7 +1659,7 @@ return self._b.transform( self._a.transform(points)) transform.__doc__ = Transform.transform.__doc__ - + def transform_affine(self, points): return self.get_affine().transform(points) transform_affine.__doc__ = Transform.transform_affine.__doc__ @@ -1695,7 +1675,7 @@ return self._b.transform_path( self._a.transform_path(path)) transform_path.__doc__ = Transform.transform_path.__doc__ - + def transform_path_affine(self, path): return self._b.transform_path_affine( self._a.transform_path(path)) @@ -1707,7 +1687,7 @@ return self._b.transform_path_non_affine( self._a.transform_path(path)) transform_path_non_affine.__doc__ = Transform.transform_path_non_affine.__doc__ - + def get_affine(self): if self._a.is_affine and self._b.is_affine: return Affine2D(npy.dot(self._b.get_affine().get_matrix(), @@ -1715,12 +1695,12 @@ else: return self._b.get_affine() get_affine.__doc__ = Transform.get_affine.__doc__ - + def inverted(self): return CompositeGenericTransform(self._b.inverted(), self._a.inverted()) inverted.__doc__ = Transform.inverted.__doc__ - + class CompositeAffine2D(Affine2DBase): """ A composite transform formed by applying transform a then transform b. @@ -1734,7 +1714,7 @@ applying transform a then transform b. Both a and b must be instances of Affine2DBase. - + You will generally not call this constructor directly but use the composite_transform_factory function instead, which can automatically choose the best kind of composite transform @@ -1765,8 +1745,8 @@ self._invalid = 0 return self._mtx get_matrix.__doc__ = Affine2DBase.get_matrix.__doc__ - - + + def composite_transform_factory(a, b): """ Create a new composite transform that is the result of applying @@ -1787,8 +1767,8 @@ elif isinstance(a, AffineBase) and isinstance(b, AffineBase): return CompositeAffine2D(a, b) return CompositeGenericTransform(a, b) - - + + class BboxTransform(Affine2DBase): """ BboxTransform linearly transforms points from one Bbox to another Bbox. @@ -1802,7 +1782,7 @@ """ assert boxin.is_bbox assert boxout.is_bbox - + Affine2DBase.__init__(self) self._boxin = boxin self._boxout = boxout @@ -1813,7 +1793,7 @@ def __repr__(self): return "BboxTransform(%s, %s)" % (self._boxin, self._boxout) __str__ = __repr__ - + def get_matrix(self): if self._invalid: inl, inb, inw, inh = self._boxin.bounds @@ -1845,7 +1825,7 @@ from the unit Bbox to boxout. """ assert boxout.is_bbox - + Affine2DBase.__init__(self) self._boxout = boxout self.set_children(boxout) @@ -1855,7 +1835,7 @@ def __repr__(self): return "BboxTransformTo(%s)" % (self._boxout) __str__ = __repr__ - + def get_matrix(self): if self._invalid: outl, outb, outw, outh = self._boxout.bounds @@ -1884,7 +1864,7 @@ from boxin to the unit Bbox. """ assert boxin.is_bbox - + Affine2DBase.__init__(self) self._boxin = boxin self.set_children(boxin) @@ -1894,7 +1874,7 @@ def __repr__(self): return "BboxTransformFrom(%s)" % (self._boxin) __str__ = __repr__ - + def get_matrix(self): if self._invalid: inl, inb, inw, inh = self._boxin.bounds @@ -1910,8 +1890,8 @@ self._invalid = 0 return self._mtx get_matrix.__doc__ = Affine2DBase.get_matrix.__doc__ - + class TransformedPath(TransformNode): """ A TransformedPath caches a non-affine transformed copy of the @@ -1924,7 +1904,7 @@ """ assert isinstance(transform, Transform) TransformNode.__init__(self) - + self._path = path self._transform = transform self.set_children(transform) @@ -1957,7 +1937,7 @@ def get_affine(self): return self._transform.get_affine() - + def nonsingular(vmin, vmax, expander=0.001, tiny=1e-15, increasing=True): ''' Ensure the endpoints of a range are not too close together. @@ -1996,7 +1976,7 @@ return ( ((a < b) and (a < val and b > val)) or (b < val and a > val)) - + if __name__ == '__main__': import copy from random import random @@ -2019,10 +1999,10 @@ assert bbox.bounds == (10, 15, 10, 10) assert tuple(npy.asarray(bbox).flatten()) == (10, 15, 20, 25) - + bbox.intervalx = (11, 21) bbox.intervaly = (16, 26) - + assert bbox.bounds == (11, 16, 10, 10) bbox.x0 = 12 @@ -2040,7 +2020,7 @@ bbox_copy.p1 = (14, 15) assert bbox.bounds == (10, 11, 12, 13) assert bbox_copy.bounds == (10, 11, 4, 4) - + bbox1 = Bbox([[10., 15.], [20., 25.]]) bbox2 = Bbox([[30., 35.], [40., 45.]]) trans = BboxTransform(bbox1, bbox2) @@ -2055,7 +2035,7 @@ assert rotation.to_values() == (0.86602540378443871, 0.49999999999999994, -0.49999999999999994, 0.86602540378443871, 0.0, 0.0) - + points = npy.array([[1, 2], [3, 4], [5, 6], [7, 8]], npy.float_) translated_points = translation.transform(points) assert (translated_points == [[11., 22.], [13., 24.], [15., 26.], [17., 28.]]).all() @@ -2071,7 +2051,7 @@ assert (tpoints1.round() == tpoints2.round()).all() print points - + # Here are some timing tests points = npy.asarray([(random(), random()) for i in xrange(10000)]) t = timeit.Timer("trans_sum.transform(points)", "from __main__ import trans_sum, points") Modified: branches/transforms/src/_path.cpp =================================================================== --- branches/transforms/src/_path.cpp 2007-11-28 18:26:40 UTC (rev 4488) +++ branches/transforms/src/_path.cpp 2007-11-28 18:27:43 UTC (rev 4489) @@ -31,6 +31,8 @@ "point_on_path(x, y, r, path, trans)"); add_varargs_method("get_path_extents", &_path_module::get_path_extents, "get_path_extents(path, trans)"); + add_varargs_method("update_path_extents", &_path_module::update_path_extents, + "update_path_extents(path, trans, bbox, minpos)"); add_varargs_method("get_path_collection_extents", &_path_module::get_path_collection_extents, "get_path_collection_extents(trans, paths, transforms, offsets, offsetTrans)"); add_varargs_method("point_in_path_collection", &_path_module::point_in_path_collection, @@ -45,7 +47,7 @@ "count_bboxes_overlapping_bbox(bbox, bboxes)"); add_varargs_method("path_intersects_path", &_path_module::path_intersects_path, "path_intersects_path(p1, p2)"); - + initialize("Helper functions for paths"); } @@ -56,6 +58,7 @@ Py::Object point_in_path(const Py::Tuple& args); Py::Object point_on_path(const Py::Tuple& args); Py::Object get_path_extents(const Py::Tuple& args); + Py::Object update_path_extents(const Py::Tuple& args); Py::Object get_path_collection_extents(const Py::Tuple& args); Py::Object point_in_path_collection(const Py::Tuple& args); Py::Object path_in_path(const Py::Tuple& args); @@ -71,7 +74,7 @@ // just polygons. The original comments have been kept intact. // -- Michael Droettboom 2007-10-02 // -//======= Crossings Multiply algorithm of InsideTest ======================== +//======= Crossings Multiply algorithm of InsideTest ======================== // // By Eric Haines, 3D/Eye Inc, er...@ey... // @@ -164,10 +167,10 @@ yflag0 = yflag1; vtx0 = vtx1; vty0 = vty1; - + vtx1 = x; vty1 = y; - } while (code != agg::path_cmd_stop && + } while (code != agg::path_cmd_stop && (code & agg::path_cmd_end_poly) != agg::path_cmd_end_poly); yflag1 = (vty1 >= ty); @@ -188,7 +191,7 @@ inline bool point_in_path(double x, double y, PathIterator& path, const agg::trans_affine& trans) { typedef agg::conv_transform<PathIterator> transformed_path_t; typedef agg::conv_curve<transformed_path_t> curve_t; - + if (path.total_vertices() < 3) return false; @@ -211,7 +214,7 @@ Py::Object _path_module::point_in_path(const Py::Tuple& args) { args.verify_length(4); - + double x = Py::Float(args[0]); double y = Py::Float(args[1]); PathIterator path(args[2]); @@ -224,7 +227,7 @@ Py::Object _path_module::point_on_path(const Py::Tuple& args) { args.verify_length(5); - + double x = Py::Float(args[0]); double y = Py::Float(args[1]); double r = Py::Float(args[2]); @@ -236,8 +239,9 @@ return Py::Int(0); } -void get_path_extents(PathIterator& path, const agg::trans_affine& trans, - double* x0, double* y0, double* x1, double* y1) { +void get_path_extents(PathIterator& path, const agg::trans_affine& trans, + double* x0, double* y0, double* x1, double* y1, + double* xm, double* ym) { typedef agg::conv_transform<PathIterator> transformed_path_t; typedef agg::conv_curve<transformed_path_t> curve_t; double x, y; @@ -251,8 +255,16 @@ while ((code = curved_path.vertex(&x, &y)) != agg::path_cmd_stop) { if ((code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) continue; - if (x < *x0) *x0 = x; - if (y < *y0) *y0 = y; + if (x < *x0) { + *x0 = x; + if (x > 0.0) + *xm = x; + } + if (y < *y0) { + *y0 = y; + if (y > 0.0) + *ym = y; + } if (x > *x1) *x1 = x; if (y > *y1) *y1 = y; } @@ -260,22 +272,121 @@ Py::Object _path_module::get_path_extents(const Py::Tuple& args) { args.verify_length(2); - + PathIterator path(args[0]); - agg::trans_affine trans = py_to_agg_transformation_matrix(args[1]); + agg::trans_affine trans = py_to_agg_transformation_matrix(args[1], false); - double x0 = std::numeric_limits<double>::infinity(); - double y0 = std::numeric_limits<double>::infinity(); - double x1 = -std::numeric_limits<double>::infinity(); - double y1 = -std::numeric_limits<double>::infinity(); + npy_intp extent_dims[] = { 2, 2, 0 }; + double* extents_data = new double[4]; + double xm, ym; + PyArrayObject* extents = NULL; + try { + extents_data[0] = std::numeric_limits<double>::infinity(); + extents_data[1] = std::numeric_limits<double>::infinity(); + extents_data[2] = -std::numeric_limits<double>::infinity(); + extents_data[3] = -std::numeric_limits<double>::infinity(); - ::get_path_extents(path, trans, &x0, &y0, &x1, &y1); + ::get_path_extents(path, trans, + &extents_data[0], &extents_data[1], &extents_data[2], &extents_data[3], + &xm, &ym); - Py::Tuple result(4); - result[0] = Py::Float(x0); - result[1] = Py::Float(y0); - result[2] = Py::Float(x1); - result[3] = Py::Float(y1); + extents = (PyArrayObject*)PyArray_SimpleNewFromData + (2, extent_dims, PyArray_DOUBLE, extents_data); + } catch (...) { + if (extents) + Py_XDECREF(extents); + else + delete[] extents_data; + throw; + } + + return Py::Object((PyObject*)extents); +} + +Py::Object _path_module::update_path_extents(const Py::Tuple& args) { + args.verify_length(5); + + double x0, y0, x1, y1; + PathIterator path(args[0]); + agg::trans_affine trans = py_to_agg_transformation_matrix(args[1], false); + if (!py_convert_bbox(args[2].ptr(), x0, y0, x1, y1)) { + throw Py::ValueError("Must pass Bbox object as arg 3 of update_path_extents"); + } + Py::Object minpos_obj = args[3]; + bool ignore = bool(Py::Int(args[4])); + + double xm, ym; + PyArrayObject* input_minpos = NULL; + try { + input_minpos = (PyArrayObject*)PyArray_FromObject(minpos_obj.ptr(), PyArray_DOUBLE, 1, 1); + if (!input_minpos || PyArray_DIM(input_minpos, 0) != 2) { + throw Py::TypeError("Argument 4 to update_path_extents must be a length-2 numpy array."); + } + xm = *(double*)PyArray_GETPTR1(input_minpos, 0); + ym = *(double*)PyArray_GETPTR1(input_minpos, 1); + } catch (...) { + Py_XDECREF(input_minpos); + throw; + } + Py_XDECREF(input_minpos); + + npy_intp extent_dims[] = { 2, 2, 0 }; + double* extents_data = new double[4]; + npy_intp minpos_dims[] = { 2, 0 }; + double* minpos_data = new double[2]; + PyArrayObject* extents = NULL; + PyArrayObject* minpos = NULL; + bool changed = false; + + try { + if (ignore) { + extents_data[0] = std::numeric_limits<double>::infinity(); + extents_data[1] = std::numeric_limits<double>::infinity(); + extents_data[2] = -std::numeric_limits<double>::infinity(); + extents_data[3] = -std::numeric_limits<double>::infinity(); + minpos_data[0] = std::numeric_limits<double>::infinity(); + minpos_data[1] = std::numeric_limits<double>::infinity(); + } else { + extents_data[0] = std::min(x0, x1); + extents_data[1] = std::min(y0, y1); + extents_data[2] = std::max(x0, x1); + extents_data[3] = std::max(y0, y1); + minpos_data[0] = xm; + minpos_data[1] = ym; + } + + ::get_path_extents(path, trans, + &extents_data[0], &extents_data[1], &extents_data[2], &extents_data[3], + &minpos_data[0], &minpos_data[1]); + + changed = (extents_data[0] != x0 || + extents_data[1] != y0 || + extents_data[2] != x1 || + extents_data[3] != y1 || + minpos_data[0] != xm || + minpos_data[1] != ym); + + extents = (PyArrayObject*)PyArray_SimpleNewFromData + (2, extent_dims, PyArray_DOUBLE, extents_data); + minpos = (PyArrayObject*)PyArray_SimpleNewFromData + (1, minpos_dims, PyArray_DOUBLE, minpos_data); + } catch(...) { + if (extents) + Py_XDECREF(extents); + else + delete[] extents_data; + if (minpos) + Py_XDECREF(minpos); + else + delete[] minpos_data; + throw; + } + + Py::Tuple result(3); + result[0] = Py::Object((PyObject*) extents); + result[1] = Py::Object((PyObject*) minpos); + result[2] = Py::Int(changed ? 1 : 0); + return result; } @@ -290,12 +401,12 @@ agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[4], false); PyArrayObject* offsets = NULL; - double x0, y0, x1, y1; + double x0, y0, x1, y1, xm, ym; try { offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj.ptr(), PyArray_DOUBLE, 0, 2); - if (!offsets || - (PyArray_NDIM(offsets) == 2 && PyArray_DIM(offsets, 1) != 2) || + if (!offsets || + (PyArray_NDIM(offsets) == 2 && PyArray_DIM(offsets, 1) != 2) || (PyArray_NDIM(offsets) == 1 && PyArray_DIM(offsets, 0) != 0)) { throw Py::ValueError("Offsets array must be Nx2"); } @@ -316,7 +427,7 @@ trans *= master_transform; transforms.push_back(trans); } - + // The offset each of those and collect the mins/maxs x0 = std::numeric_limits<double>::infinity(); y0 = std::numeric_limits<double>::infinity(); @@ -339,7 +450,7 @@ trans *= agg::trans_affine_translation(xo, yo); } - ::get_path_extents(path, trans, &x0, &y0, &x1, &y1); + ::get_path_extents(path, trans, &x0, &y0, &x1, &y1, &xm, &ym); } } catch (...) { Py_XDECREF(offsets); @@ -369,10 +480,10 @@ Py::SeqBase<Py::Object> offsets_obj = args[6]; agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[7]); bool filled = Py::Int(args[8]); - + PyArrayObject* offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj.ptr(), PyArray_DOUBLE, 0, 2); - if (!offsets || - (PyArray_NDIM(offsets) == 2 && PyArray_DIM(offsets, 1) !=... [truncated message content] |
From: <md...@us...> - 2007-11-28 18:30:12
|
Revision: 4491 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4491&view=rev Author: mdboom Date: 2007-11-28 10:30:10 -0800 (Wed, 28 Nov 2007) Log Message: ----------- Merged revisions 4444-4490 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r4457 | jdh2358 | 2007-11-26 16:53:01 -0500 (Mon, 26 Nov 2007) | 2 lines fixed a bug in unit processing -- thanks chris ........ r4461 | efiring | 2007-11-26 21:24:22 -0500 (Mon, 26 Nov 2007) | 5 lines Fixed pcolormesh bug Integer X input was causing Y to be turned into an integer as well. ........ r4472 | jdh2358 | 2007-11-27 13:34:38 -0500 (Tue, 27 Nov 2007) | 2 lines tagged version 91.0 for release ........ r4474 | cmoad | 2007-11-27 20:31:59 -0500 (Tue, 27 Nov 2007) | 1 line version bumps ........ r4475 | cmoad | 2007-11-27 20:33:15 -0500 (Tue, 27 Nov 2007) | 1 line rev typo fixed for 0.91 release ........ r4476 | cmoad | 2007-11-27 21:24:40 -0500 (Tue, 27 Nov 2007) | 1 line CXX/WrapPython.h was missing from sdist build ........ r4477 | cmoad | 2007-11-27 21:25:06 -0500 (Tue, 27 Nov 2007) | 1 line rev bump for new bug ........ r4478 | cmoad | 2007-11-27 21:48:38 -0500 (Tue, 27 Nov 2007) | 1 line reverting WrapPython.h inclusion ........ r4482 | mdboom | 2007-11-28 10:18:41 -0500 (Wed, 28 Nov 2007) | 2 lines Remove fonts/otf directory in list of data files. ........ r4486 | jdh2358 | 2007-11-28 13:11:27 -0500 (Wed, 28 Nov 2007) | 2 lines updated coding guide with trailing whitespace config suggestion ........ r4490 | jdh2358 | 2007-11-28 13:28:19 -0500 (Wed, 28 Nov 2007) | 2 lines fixed coding guide bug for trailing whitespace ........ Modified Paths: -------------- branches/transforms/API_CHANGES branches/transforms/CHANGELOG branches/transforms/CODING_GUIDE branches/transforms/lib/matplotlib/__init__.py branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/mlab.py branches/transforms/license/LICENSE branches/transforms/setup.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-4443 + /trunk/matplotlib:1-4490 Modified: branches/transforms/API_CHANGES =================================================================== --- branches/transforms/API_CHANGES 2007-11-28 18:28:19 UTC (rev 4490) +++ branches/transforms/API_CHANGES 2007-11-28 18:30:10 UTC (rev 4491) @@ -33,11 +33,11 @@ Bbox.height() Bbox.height Bbox.intervalx().get_bounds() Bbox.intervalx - Bbox.intervalx().set_bounds() + Bbox.intervalx().set_bounds() [Bbox.intervalx is now a property.] Bbox.intervaly().get_bounds() Bbox.intervaly - Bbox.intervaly().set_bounds() + Bbox.intervaly().set_bounds() [Bbox.intervaly is now a property.] Bbox.xmin() Bbox.x0 or Bbox.xmin @@ -84,7 +84,7 @@ [Axes.set_position() now accepts either four scalars or a transforms Bbox instance.] - [also returns a Bbox] + [also returns a Bbox] Axes.toggle_log_lineary() Axes.set_yscale() [Since the recfactoring allows for more than two scale types ('log' or 'linear'), it no longer makes sense to have a @@ -119,10 +119,10 @@ contour.py Contour._segments Contour.get_paths() - [Contour.get_paths() now returns a list of path.Path instances.] + [Contour.get_paths() now returns a list of path.Path instances.] figure.py - Figure.dpi.get()/set() Figure.dpi (a property) + Figure.dpi.get()/set() Figure.dpi (a property) patches.py get_verts() get_path() @@ -150,9 +150,9 @@ offsetTrans, facecolors, edgecolors, linewidths, linestyles, antialiaseds) [optional] - + **changed methods** ---> - draw_image(self, x, y, im, bbox) draw_image(self, x, y, im, bbox, + draw_image(self, x, y, im, bbox) draw_image(self, x, y, im, bbox, clippath, clippath_trans) **removed methods** ---> @@ -166,9 +166,11 @@ draw_polygon draw_rectangle draw_regpoly_collection - + END OF TRANSFORMS REFACTORING +0.91.0 Released + Changed cbook.is_file_like to cbook.is_writable_file_like and corrected behavior. Modified: branches/transforms/CHANGELOG =================================================================== --- branches/transforms/CHANGELOG 2007-11-28 18:28:19 UTC (rev 4490) +++ branches/transforms/CHANGELOG 2007-11-28 18:30:10 UTC (rev 4491) @@ -1,3 +1,6 @@ +=============================================================== +2007-11-27 Released 0.91.0 at revision 4478 + 2007-11-13 All backends now support writing to a file-like object, not just a regular file. savefig() can be passed a file-like object in place of a file path. - MGD Modified: branches/transforms/CODING_GUIDE =================================================================== --- branches/transforms/CODING_GUIDE 2007-11-28 18:28:19 UTC (rev 4490) +++ branches/transforms/CODING_GUIDE 2007-11-28 18:30:10 UTC (rev 4491) @@ -39,6 +39,8 @@ * If you have altered extension code, do you pass unit/memleak_hawaii.py? + + == Importing and name spaces == For numpy, use: @@ -103,7 +105,27 @@ to replace a single long line with two shorter and more readable lines. +Please do not commit lines with trailing white space, as it causes +noise in svn diffs. If you are an emacs user, the following in your +.emacs will cause emacs to strip trailing white space on save for +python, C and C++ +; and similarly for c++-mode-hook and c-mode-hook +(add-hook 'python-mode-hook + (lambda () + (add-hook 'write-file-functions 'delete-trailing-whitespace))) + + + +for older versions of emacs (emacs<22) you may need to do + +(add-hook 'python-mode-hook + (lambda () + (add-hook 'local-write-file-hooks 'delete-trailing-whitespace))) + + + + == Licenses == matplotlib only uses BSD compatible code. If you bring in code from Modified: branches/transforms/lib/matplotlib/__init__.py =================================================================== --- branches/transforms/lib/matplotlib/__init__.py 2007-11-28 18:28:19 UTC (rev 4490) +++ branches/transforms/lib/matplotlib/__init__.py 2007-11-28 18:30:10 UTC (rev 4491) @@ -51,11 +51,11 @@ pylab (if pylab is imported). matplotlib is written by John D. Hunter (jdh2358 at -gmail.com). +gmail.com and a host of others). """ from __future__ import generators -__version__ = '0.90.1' +__version__ = '0.91.0' __revision__ = '$Revision$' __date__ = '$Date$' Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-11-28 18:28:19 UTC (rev 4490) +++ branches/transforms/lib/matplotlib/axes.py 2007-11-28 18:30:10 UTC (rev 4491) @@ -180,7 +180,7 @@ def __call__(self, *args, **kwargs): - if self.axes.xaxis is not None and self.axes.xaxis is not None: + if self.axes.xaxis is not None and self.axes.yaxis is not None: xunits = kwargs.pop( 'xunits', self.axes.xaxis.units) yunits = kwargs.pop( 'yunits', self.axes.yaxis.units) if xunits!=self.axes.xaxis.units: @@ -1305,6 +1305,8 @@ artists = [] + + if len(self.images)<=1 or renderer.option_image_nocomposite(): for im in self.images: im.draw(renderer) @@ -4798,7 +4800,7 @@ X = X.ravel() Y = Y.ravel() - coords = npy.zeros(((Nx * Ny), 2), X.dtype) + coords = npy.zeros(((Nx * Ny), 2), dtype=float) coords[:, 0] = X coords[:, 1] = Y Modified: branches/transforms/lib/matplotlib/mlab.py =================================================================== --- branches/transforms/lib/matplotlib/mlab.py 2007-11-28 18:28:19 UTC (rev 4490) +++ branches/transforms/lib/matplotlib/mlab.py 2007-11-28 18:30:10 UTC (rev 4491) @@ -14,10 +14,7 @@ * find - Return the indices where some condition is true; numpy.nonzero is similar but more general. - * polyfit - least squares best polynomial fit of x to y - * polyval - evaluate a vector for a vector of polynomial coeffs - * prctile - find the percentiles of a sequence * prepca - Principal Component Analysis @@ -29,11 +26,14 @@ The following are deprecated; please import directly from numpy (with care--function signatures may differ): + * conv - convolution (numpy.convolve) * corrcoef - The matrix of correlation coefficients * hist -- Histogram (numpy.histogram) * linspace -- Linear spaced array from min to max * meshgrid + * polyfit - least squares best polynomial fit of x to y + * polyval - evaluate a vector for a vector of polynomial coeffs * trapz - trapeziodal integration (trapz(x,y) -> numpy.trapz(y,x)) * vander - the Vandermonde matrix @@ -46,13 +46,13 @@ = record array helper functions = - rec2csv : store record array in CSV file - rec2excel : store record array in excel worksheet - required pyExcelerator - rec2gtk : put record array in GTK treeview - requires gtk - csv2rec : import record array from CSV file with type inspection - rec_append_field : add a field/array to record array - rec_drop_fields : drop fields from record array - rec_join : join two record arrays on sequence of fields + * rec2csv : store record array in CSV file + * rec2excel : store record array in excel worksheet - required pyExcelerator + * rec2gtk : put record array in GTK treeview - requires gtk + * csv2rec : import record array from CSV file with type inspection + * rec_append_field : add a field/array to record array + * rec_drop_fields : drop fields from record array + * rec_join : join two record arrays on sequence of fields For the rec viewer clases (rec2csv, rec2excel and rec2gtk), there are a bunch of Format objects you can pass into the functions that will do Modified: branches/transforms/license/LICENSE =================================================================== --- branches/transforms/license/LICENSE 2007-11-28 18:28:19 UTC (rev 4490) +++ branches/transforms/license/LICENSE 2007-11-28 18:30:10 UTC (rev 4491) @@ -1,4 +1,4 @@ -LICENSE AGREEMENT FOR MATPLOTLIB 0.90 +LICENSE AGREEMENT FOR MATPLOTLIB 0.91 -------------------------------------- 1. This LICENSE AGREEMENT is between John D. Hunter ("JDH"), and the @@ -9,30 +9,30 @@ 2. Subject to the terms and conditions of this License Agreement, JDH hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare -derivative works, distribute, and otherwise use matplotlib 0.90 +derivative works, distribute, and otherwise use matplotlib 0.91 alone or in any derivative version, provided, however, that JDH's License Agreement and JDH's notice of copyright, i.e., "Copyright (c) 2002-2007 John D. Hunter; All Rights Reserved" are retained in -matplotlib 0.90 alone or in any derivative version prepared by +matplotlib 0.91 alone or in any derivative version prepared by Licensee. 3. In the event Licensee prepares a derivative work that is based on or -incorporates matplotlib 0.90 or any part thereof, and wants to +incorporates matplotlib 0.91 or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of -the changes made to matplotlib 0.90. +the changes made to matplotlib 0.91. -4. JDH is making matplotlib 0.90 available to Licensee on an "AS +4. JDH is making matplotlib 0.91 available to Licensee on an "AS IS" basis. JDH MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, JDH MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB 0.90 +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB 0.91 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 5. JDH SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB -0.90 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR +0.91 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING -MATPLOTLIB 0.90, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF +MATPLOTLIB 0.91, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 6. This License Agreement will automatically terminate upon a material @@ -44,6 +44,6 @@ trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. -8. By copying, installing or otherwise using matplotlib 0.90, +8. By copying, installing or otherwise using matplotlib 0.91, Licensee agrees to be bound by the terms and conditions of this License Agreement. Modified: branches/transforms/setup.py =================================================================== --- branches/transforms/setup.py 2007-11-28 18:28:19 UTC (rev 4490) +++ branches/transforms/setup.py 2007-11-28 18:30:10 UTC (rev 4491) @@ -88,7 +88,6 @@ 'mpl-data/fonts/pdfcorefonts/*.afm', 'mpl-data/fonts/pdfcorefonts/*.txt', 'mpl-data/fonts/ttf/*.ttf', - 'mpl-data/fonts/otf/*.otf', 'mpl-data/images/*.xpm', 'mpl-data/images/*.svg', 'mpl-data/images/*.png', This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-11-28 20:41:23
|
Revision: 4496 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4496&view=rev Author: mdboom Date: 2007-11-28 12:41:15 -0800 (Wed, 28 Nov 2007) Log Message: ----------- Merged revisions 4491-4495 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r4492 | mdboom | 2007-11-28 15:13:47 -0500 (Wed, 28 Nov 2007) | 2 lines Fix bug using stix fonts. ........ Modified Paths: -------------- branches/transforms/lib/matplotlib/mathtext.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-4490 + /trunk/matplotlib:1-4495 Modified: branches/transforms/lib/matplotlib/mathtext.py =================================================================== --- branches/transforms/lib/matplotlib/mathtext.py 2007-11-28 20:37:04 UTC (rev 4495) +++ branches/transforms/lib/matplotlib/mathtext.py 2007-11-28 20:41:15 UTC (rev 4496) @@ -850,6 +850,7 @@ fontmap = {} use_cmex = False cm_fallback = False + _sans = False def __init__(self, *args, **kwargs): TruetypeFonts.__init__(self, *args, **kwargs) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-11-28 21:01:17
|
Revision: 4499 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4499&view=rev Author: mdboom Date: 2007-11-28 13:01:01 -0800 (Wed, 28 Nov 2007) Log Message: ----------- Merged revisions 4496-4498 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r4497 | mdboom | 2007-11-28 15:43:01 -0500 (Wed, 28 Nov 2007) | 2 lines Minor fix -- updating old \rm{} syntax to \mathrm{} syntax. ........ r4498 | mdboom | 2007-11-28 15:58:06 -0500 (Wed, 28 Nov 2007) | 2 lines Fix for STIX fonts with PDF backend. ........ Modified Paths: -------------- branches/transforms/examples/mathtext_demo.py branches/transforms/lib/matplotlib/backends/backend_pdf.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-4495 + /trunk/matplotlib:1-4498 Modified: branches/transforms/examples/mathtext_demo.py =================================================================== --- branches/transforms/examples/mathtext_demo.py 2007-11-28 20:58:06 UTC (rev 4498) +++ branches/transforms/examples/mathtext_demo.py 2007-11-28 21:01:01 UTC (rev 4499) @@ -22,7 +22,7 @@ ax.legend(("Foo", "Testing $x^2$")) -ax.set_title(r'$\Delta_i^j \hspace{0.4} \rm{versus} \hspace{0.4} \Delta_{i+1}^j$', fontsize=20) +ax.set_title(r'$\Delta_i^j \hspace{0.4} \mathrm{versus} \hspace{0.4} \Delta_{i+1}^j$', fontsize=20) #fig.savefig('mathtext_demo') show() Modified: branches/transforms/lib/matplotlib/backends/backend_pdf.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-11-28 20:58:06 UTC (rev 4498) +++ branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-11-28 21:01:01 UTC (rev 4499) @@ -719,7 +719,7 @@ charprocDict['Type'] = Name('XObject') charprocDict['Subtype'] = Name('Form') charprocDict['BBox'] = bbox - charprocObject = self.reserveObject('charProc for %s' % name) + charprocObject = self.reserveObject('charProc') self.beginStream(charprocObject.id, None, charprocDict) self.currentstream.write(stream) self.endStream() @@ -1308,6 +1308,7 @@ fonttype = global_fonttype if fonttype == 3 and num > 255: + self.file.fontName(fontname) self.file.output(Op.gsave, 0.001 * fontsize, 0, 0, 0.001 * fontsize, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-11-29 19:56:58
|
Revision: 4506 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4506&view=rev Author: mdboom Date: 2007-11-29 11:56:10 -0800 (Thu, 29 Nov 2007) Log Message: ----------- Merged revisions 4499-4505 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r4504 | jdh2358 | 2007-11-29 14:43:20 -0500 (Thu, 29 Nov 2007) | 1 line minor changes for htdocs ........ r4505 | jdh2358 | 2007-11-29 14:44:49 -0500 (Thu, 29 Nov 2007) | 1 line minor changes for htdocs ........ Modified Paths: -------------- branches/transforms/lib/matplotlib/mathtext.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-4498 + /trunk/matplotlib:1-4505 Modified: branches/transforms/lib/matplotlib/mathtext.py =================================================================== --- branches/transforms/lib/matplotlib/mathtext.py 2007-11-29 19:44:49 UTC (rev 4505) +++ branches/transforms/lib/matplotlib/mathtext.py 2007-11-29 19:56:10 UTC (rev 4506) @@ -1090,7 +1090,7 @@ # Typesetting math formulas # # Many of the docstrings below refer to a numbered "node" in that -# book, e.g. @123 +# book, e.g. node123 # # Note that (as TeX) y increases downward, unlike many other parts of # matplotlib. @@ -1118,7 +1118,7 @@ class Node(object): """A node in the TeX box model - @133 + node133 """ def __init__(self): self.size = 0 @@ -1147,7 +1147,7 @@ class Box(Node): """Represents any node with a physical location. - @135""" + node135""" def __init__(self, width, height, depth): Node.__init__(self) self.width = width @@ -1193,7 +1193,7 @@ The metrics must be converted to the TeX way, and the advance (if different from width) must be converted into a Kern node when the Char is added to its parent Hlist. - @134""" + node134""" def __init__(self, c, state): Node.__init__(self) self.c = c @@ -1284,7 +1284,7 @@ class List(Box): """A list of nodes (either horizontal or vertical). - @135""" + node135""" def __init__(self, elements): Box.__init__(self, 0., 0., 0.) self.shift_amount = 0. # An arbitrary offset @@ -1342,7 +1342,7 @@ class Hlist(List): """A horizontal list of boxes. - @135""" + node135""" def __init__(self, elements, w=0., m='additional', do_kern=True): List.__init__(self, elements) if do_kern: @@ -1385,7 +1385,7 @@ Thus, hpack(w, exactly) produces a box whose width is exactly w, while hpack (w, additional ) yields a box whose width is the natural width plus w. The default values produce a box with the natural width. - @644, @649""" + node644, node649""" # I don't know why these get reset in TeX. Shift_amount is pretty # much useless if we do. #self.shift_amount = 0. @@ -1432,7 +1432,7 @@ class Vlist(List): """A vertical list of boxes. - @137""" + node137""" def __init__(self, elements, h=0., m='additional'): List.__init__(self, elements) self.vpack() @@ -1449,7 +1449,7 @@ Thus, vpack(h, exactly) produces a box whose width is exactly w, while vpack(w, additional) yields a box whose width is the natural width plus w. The default values produce a box with the natural width. - @644, @668""" + node644, node668""" # I don't know why these get reset in TeX. Shift_amount is pretty # much useless if we do. # self.shift_amount = 0. @@ -1508,7 +1508,7 @@ rule up to the boundary of the innermost enclosing box. This is called a "running dimension." The width is never running in an Hlist; the height and depth are never running in a Vlist. - @138""" + node138""" def __init__(self, width, height, depth, state): Box.__init__(self, width, height, depth) self.font_output = state.font_output @@ -1536,7 +1536,7 @@ GlueSpec class, which is shared between multiple glue objects. (This is a memory optimization which probably doesn't matter anymore, but it's easier to stick to what TeX does.) - @149, @152""" + node149, node152""" def __init__(self, glue_type, copy=False): Node.__init__(self) self.glue_subtype = 'normal' @@ -1564,7 +1564,7 @@ self.glue_spec.width *= GROW_FACTOR class GlueSpec(object): - """@150, @151""" + """node150, node151""" def __init__(self, width=0., stretch=0., stretch_order=0, shrink=0., shrink_order=0): self.width = width self.stretch = stretch @@ -1645,7 +1645,7 @@ better to move them closer together or further apart. A kern node can also appear in a vertical list, when its 'width' denotes additional spacing in the vertical direction. - @155""" + node155""" def __init__(self, width): Node.__init__(self) self.width = width @@ -1731,7 +1731,7 @@ and vlist_out , which traverse the Hlists and Vlists inside of horizontal and vertical boxes. The global variables used in TeX to store state as it processes have become member variables here. - @592.""" + node592.""" def __call__(self, ox, oy, box): self.max_push = 0 # Deepest nesting of push commands so far self.cur_s = 0 @@ -1767,7 +1767,7 @@ elif isinstance(p, Kern): self.cur_h += p.width elif isinstance(p, List): - # @623 + # node623 if len(p.children) == 0: self.cur_h += p.width else: @@ -1781,7 +1781,7 @@ self.cur_h = edge + p.width self.cur_v = base_line elif isinstance(p, Box): - # @624 + # node624 rule_height = p.height rule_depth = p.depth rule_width = p.width @@ -1797,7 +1797,7 @@ self.cur_v = baseline self.cur_h += rule_width elif isinstance(p, Glue): - # @625 + # node625 glue_spec = p.glue_spec rule_width = glue_spec.width - cur_g if glue_sign != 0: # normal @@ -2468,7 +2468,7 @@ else: shift_down = SUBDROP * xHeight if super is None: - # @757 + # node757 sub.shrink() x = Hlist([sub]) # x.width += SCRIPT_SPACE * xHeight This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-11-30 15:07:00
|
Revision: 4521 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4521&view=rev Author: mdboom Date: 2007-11-30 07:06:56 -0800 (Fri, 30 Nov 2007) Log Message: ----------- Get Gtk backend working. Modified Paths: -------------- branches/transforms/lib/matplotlib/axis.py branches/transforms/lib/matplotlib/backends/backend_gdk.py branches/transforms/lib/matplotlib/path.py branches/transforms/src/_path.cpp Modified: branches/transforms/lib/matplotlib/axis.py =================================================================== --- branches/transforms/lib/matplotlib/axis.py 2007-11-30 14:43:11 UTC (rev 4520) +++ branches/transforms/lib/matplotlib/axis.py 2007-11-30 15:06:56 UTC (rev 4521) @@ -87,7 +87,7 @@ self._size = size self._padPixels = self.figure.dpi * self._pad * (1/72.0) - + self.tick1line = self._get_tick1line() self.tick2line = self._get_tick2line() self.gridline = self._get_gridline() @@ -97,7 +97,7 @@ self.label2 = self._get_text2() self.update_position(loc) - + self.gridOn = gridOn self.tick1On = tick1On self.tick2On = tick2On @@ -114,7 +114,7 @@ #self.tick2line.set_clip_path(clippath, transform) self.gridline.set_clip_path(clippath, transform) set_clip_path.__doc__ = Artist.set_clip_path.__doc__ - + def contains(self, mouseevent): """Test whether the mouse event occured in the Tick marks. @@ -189,7 +189,7 @@ """ self.label1.set_text(s) set_label = set_label1 - + def set_label2(self, s): """ Set the text of ticklabel2 @@ -209,7 +209,7 @@ def set_view_interval(self, vmin, vmax, ignore=False): raise NotImplementedError('Derived must override') - + class XTick(Tick): """ Contains all the Artists needed to make an x tick - the tick line, @@ -223,7 +223,7 @@ # x in data coords, y in axes coords #t = Text( trans, vert, horiz = self.axes.get_xaxis_text1_transform(self._padPixels) - + t = TextWithDash( x=0, y=0, fontproperties=FontProperties(size=rcParams['xtick.labelsize']), @@ -320,10 +320,10 @@ else: Vmin, Vmax = self.get_view_interval() self.axes.viewLim.intervalx = min(vmin, Vmin), max(vmax, Vmax) - + def get_minpos(self): return self.axes.dataLim.minposx - + def get_data_interval(self): 'return the Interval instance for this axis data limits' return self.axes.dataLim.intervalx @@ -428,7 +428,7 @@ self._loc = loc - + def get_view_interval(self): 'return the Interval instance for this axis view limits' return self.axes.viewLim.intervaly @@ -439,10 +439,10 @@ else: Vmin, Vmax = self.get_view_interval() self.axes.viewLim.intervaly = min(vmin, Vmin), max(vmax, Vmax) - + def get_minpos(self): return self.axes.dataLim.minposy - + def get_data_interval(self): 'return the Interval instance for this axis data limits' return self.axes.dataLim.intervaly @@ -465,7 +465,7 @@ """ LABELPAD = 5 OFFSETTEXTPAD = 3 - + def __str__(self): return str(self.__class__).split('.')[-1] \ + "(%d,%d)"%self.axes.transAxes.xy_tup((0,0)) @@ -493,23 +493,23 @@ self.majorTicks = [] self.minorTicks = [] self.pickradius = pickradius - + self.cla() self.set_scale('linear') - + def get_transform(self): return self._scale.get_transform() def get_scale(self): return self._scale.name - + def set_scale(self, value, **kwargs): self._scale = scale_factory(value, self, **kwargs) self._scale.set_default_locators_and_formatters(self) def limit_range_for_scale(self, vmin, vmax): return self._scale.limit_range_for_scale(vmin, vmax, self.get_minpos()) - + def get_children(self): children = [self.label] majorticks = self.get_major_ticks() @@ -547,7 +547,7 @@ self.minorTicks.extend([self._get_tick(major=False)]) self._lastNumMajorTicks = 1 self._lastNumMinorTicks = 1 - + self.converter = None self.units = None self.set_units(None) @@ -555,17 +555,17 @@ def set_clip_path(self, clippath, transform=None): Artist.set_clip_path(self, clippath, transform) majorticks = self.get_major_ticks() - minorticks = self.get_minor_ticks() + minorticks = self.get_minor_ticks() for child in self.majorTicks + self.minorTicks: child.set_clip_path(clippath, transform) - + def get_view_interval(self): 'return the Interval instance for this axis view limits' raise NotImplementedError('Derived must override') def set_view_interval(self, vmin, vmax, ignore=False): raise NotImplementedError('Derived must override') - + def get_data_interval(self): 'return the Interval instance for this axis data limits' raise NotImplementedError('Derived must override') @@ -573,7 +573,7 @@ def set_data_interval(self): 'Set the axis data limits' raise NotImplementedError('Derived must override') - + def _set_artist_props(self, a): if a is None: return a.set_figure(self.figure) @@ -774,7 +774,7 @@ for i in range(numticks - len(self.majorTicks)): tick = self._get_tick(major=True) self.majorTicks.append(tick) - + if self._lastNumMajorTicks < numticks: protoTick = self.majorTicks[0] for i in range(self._lastNumMajorTicks, len(self.majorTicks)): @@ -798,7 +798,7 @@ for i in range(numticks - len(self.minorTicks)): tick = self._get_tick(major=False) self.minorTicks.append(tick) - + if self._lastNumMinorTicks < numticks: protoTick = self.minorTicks[0] for i in range(self._lastNumMinorTicks, len(self.minorTicks)): @@ -1039,7 +1039,7 @@ class XAxis(Axis): __name__ = 'xaxis' axis_name = 'x' - + def contains(self,mouseevent): """Test whether the mouse event occured in the x axis. """ @@ -1120,7 +1120,7 @@ bbox = Bbox.union(bboxes) bottom = bbox.y0 self.label.set_position( (x, bottom - self.LABELPAD*self.figure.dpi / 72.0)) - + else: if not len(bboxes2): top = self.axes.bbox.ymax @@ -1141,7 +1141,7 @@ bbox = Bbox.union(bboxes) bottom = bbox.y0 self.offsetText.set_position((x, bottom-self.OFFSETTEXTPAD*self.figure.dpi/72.0)) - + def set_ticks_position(self, position): """ Set the ticks position (top, bottom, both, default or none) @@ -1224,10 +1224,10 @@ else: Vmin, Vmax = self.get_view_interval() self.axes.viewLim.intervalx = min(vmin, Vmin), max(vmax, Vmax) - + def get_minpos(self): return self.axes.dataLim.minposx - + def get_data_interval(self): 'return the Interval instance for this axis data limits' return self.axes.dataLim.intervalx @@ -1244,7 +1244,7 @@ class YAxis(Axis): __name__ = 'yaxis' axis_name = 'y' - + def contains(self,mouseevent): """Test whether the mouse event occurred in the y axis. @@ -1331,7 +1331,7 @@ left = bbox.x0 self.label.set_position( (left-self.LABELPAD*self.figure.dpi/72.0, y)) - + else: if not len(bboxes2): right = self.axes.bbox.xmax @@ -1349,7 +1349,7 @@ x,y = self.offsetText.get_position() top = self.axes.bbox.ymax self.offsetText.set_position((x, top+self.OFFSETTEXTPAD*self.figure.dpi/72.0)) - + def set_offset_position(self, position): assert position == 'left' or position == 'right' @@ -1445,10 +1445,10 @@ else: Vmin, Vmax = self.get_view_interval() self.axes.viewLim.intervaly = min(vmin, Vmin), max(vmax, Vmax) - + def get_minpos(self): return self.axes.dataLim.minposy - + def get_data_interval(self): 'return the Interval instance for this axis data limits' return self.axes.dataLim.intervaly Modified: branches/transforms/lib/matplotlib/backends/backend_gdk.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_gdk.py 2007-11-30 14:43:11 UTC (rev 4520) +++ branches/transforms/lib/matplotlib/backends/backend_gdk.py 2007-11-30 15:06:56 UTC (rev 4521) @@ -25,7 +25,7 @@ from matplotlib.cbook import is_string_like, enumerate from matplotlib.figure import Figure from matplotlib.mathtext import MathTextParser - +from matplotlib.transforms import Affine2D from matplotlib.backends._backend_gdk import pixbuf_get_pixels_array @@ -81,23 +81,25 @@ """ self.width, self.height = width, height - def draw_arc(self, gc, rgbFace, x, y, width, height, angle1, angle2, rotation): - x, y = int(x-0.5*width), self.height-int(y+0.5*height) - w, h = int(width)+1, int(height)+1 - a1, a2 = int(angle1*64), int(angle2*64) + def draw_path(self, gc, path, transform, rgbFace=None): + transform = transform + Affine2D(). \ + scale(1.0, -1.0).translate(0, self.height) + polygons = path.to_polygons(transform) + for polygon in polygons: + # draw_polygon won't take an arbitrary sequence -- it must be a list + # of tuples + polygon = [(int(round(x)), int(round(y))) for x, y in polygon] + if rgbFace is not None: + saveColor = gc.gdkGC.foreground + gc.gdkGC.foreground = gc.rgb_to_gdk_color(rgbFace) + self.gdkDrawable.draw_polygon(gc.gdkGC, True, polygon) + gc.gdkGC.foreground = saveColor + if gc.gdkGC.line_width > 0: + self.gdkDrawable.draw_lines(gc.gdkGC, polygon) - if rgbFace: - saveColor = gc.gdkGC.foreground - gc.gdkGC.foreground = gc.rgb_to_gdk_color(rgbFace) - self.gdkDrawable.draw_arc(gc.gdkGC, True, x, y, w, h, a1, a2) - gc.gdkGC.foreground = saveColor - if gc.gdkGC.line_width > 0: - self.gdkDrawable.draw_arc(gc.gdkGC, False, x, y, w, h, a1, a2) - - - def draw_image(self, x, y, im, bbox): + def draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None): if bbox != None: - l,b,w,h = bbox.get_bounds() + l,b,w,h = bbox.bounds #rectangle = (int(l), self.height-int(b+h), # int(w), int(h)) # set clip rect? @@ -135,48 +137,6 @@ im.flipud_out() - def draw_line(self, gc, x1, y1, x2, y2): - if gc.gdkGC.line_width > 0: - self.gdkDrawable.draw_line(gc.gdkGC, int(x1), self.height-int(y1), - int(x2), self.height-int(y2)) - - - def draw_lines(self, gc, x, y, transform=None): - if gc.gdkGC.line_width > 0: - x = x.astype(npy.int16) - y = self.height - y.astype(npy.int16) - self.gdkDrawable.draw_lines(gc.gdkGC, zip(x,y)) - - - def draw_point(self, gc, x, y): - self.gdkDrawable.draw_point(gc.gdkGC, int(x), self.height-int(y)) - - - def draw_polygon(self, gc, rgbFace, points): - points = [(int(x), self.height-int(y)) for x,y in points] - if rgbFace: - saveColor = gc.gdkGC.foreground - gc.gdkGC.foreground = gc.rgb_to_gdk_color(rgbFace) - self.gdkDrawable.draw_polygon(gc.gdkGC, True, points) - gc.gdkGC.foreground = saveColor - if gc.gdkGC.line_width > 0: - self.gdkDrawable.draw_polygon(gc.gdkGC, False, points) - - - def draw_rectangle(self, gc, rgbFace, x, y, width, height): - x, y = int(x), self.height-int(y+height) - #x, y = int(x), self.height-int(math.ceil(y+height)) - w, h = int(math.ceil(width)), int(math.ceil(height)) - - if rgbFace: - saveColor = gc.gdkGC.foreground - gc.gdkGC.foreground = gc.rgb_to_gdk_color(rgbFace) - self.gdkDrawable.draw_rectangle(gc.gdkGC, True, x, y, w, h) - gc.gdkGC.foreground = saveColor - if gc.gdkGC.line_width > 0: - self.gdkDrawable.draw_rectangle(gc.gdkGC, False, x, y, w, h) - - def draw_text(self, gc, x, y, s, prop, angle, ismath): x, y = int(x), int(y) @@ -200,7 +160,7 @@ def _draw_mathtext(self, gc, x, y, s, prop, angle): ox, oy, width, height, descent, font_image, used_characters = \ - self.mathtext_parser.parse(s, self.dpi.get(), prop) + self.mathtext_parser.parse(s, self.dpi, prop) if angle==90: width, height = height, width @@ -213,7 +173,7 @@ # a numpixels by num fonts array Xall = npy.zeros((N,1), npy.uint8) - + image_str = font_image.as_str() Xall[:,0] = npy.fromstring(image_str, npy.uint8) @@ -310,12 +270,12 @@ # two (not one) layouts are created for every text item s (then they # are cached) - why? - key = self.dpi.get(), s, hash(prop) + key = self.dpi, s, hash(prop) value = self.layoutd.get(key) if value != None: return value - size = prop.get_size_in_points() * self.dpi.get() / 96.0 + size = prop.get_size_in_points() * self.dpi / 96.0 size = round(size) font_str = '%s, %s %i' % (prop.get_name(), prop.get_style(), size,) @@ -341,7 +301,7 @@ def get_text_width_height_descent(self, s, prop, ismath): if ismath: ox, oy, width, height, descent, font_image, used_characters = \ - self.mathtext_parser.parse(s, self.dpi.get(), prop) + self.mathtext_parser.parse(s, self.dpi, prop) return width, height, descent layout, inkRect, logicalRect = self._get_pango_layout(s, prop) @@ -386,9 +346,9 @@ return an allocated gtk.gdk.Color """ try: - return self._cached[rgb] + return self._cached[tuple(rgb)] except KeyError: - color = self._cached[rgb] = \ + color = self._cached[tuple(rgb)] = \ self._cmap.alloc_color( int(rgb[0]*65535),int(rgb[1]*65535),int(rgb[2]*65535)) return color @@ -404,14 +364,15 @@ def set_clip_rectangle(self, rectangle): GraphicsContextBase.set_clip_rectangle(self, rectangle) - l,b,w,h = rectangle + if rectangle is None: + return + l,b,w,h = rectangle.bounds rectangle = (int(l), self.renderer.height-int(b+h)+1, int(w), int(h)) #rectangle = (int(l), self.renderer.height-int(b+h), # int(w+1), int(h+2)) self.gdkGC.set_clip_rectangle(rectangle) - def set_dashes(self, dash_offset, dash_list): GraphicsContextBase.set_dashes(self, dash_offset, dash_list) @@ -486,7 +447,7 @@ def print_png(self, filename, *args, **kwargs): return self._print_image(filename, 'png') - + def _print_image(self, filename, format, *args, **kwargs): width, height = self.get_width_height() pixmap = gtk.gdk.Pixmap (None, width, height, depth=24) @@ -500,4 +461,6 @@ 0, 0, 0, 0, width, height) pixbuf.save(filename, format) - + + def get_default_filetype(self): + return 'png' Modified: branches/transforms/lib/matplotlib/path.py =================================================================== --- branches/transforms/lib/matplotlib/path.py 2007-11-30 14:43:11 UTC (rev 4520) +++ branches/transforms/lib/matplotlib/path.py 2007-11-30 15:06:56 UTC (rev 4521) @@ -12,7 +12,7 @@ from matplotlib._path import point_in_path, get_path_extents, \ point_in_path_collection, get_path_collection_extents, \ - path_in_path, path_intersects_path + path_in_path, path_intersects_path, convert_path_to_polygons from matplotlib.cbook import simple_linear_interpolation KAPPA = 4.0 * (npy.sqrt(2) - 1) / 3.0 @@ -210,19 +210,17 @@ If transform is not None, the path will be transformed before performing the test. """ - if transform is None: - from transforms import IdentityTransform - transform = IdentityTransform() - return point_in_path(point[0], point[1], self, transform.frozen()) + if transform is not None: + transform = transform.frozen() + return point_in_path(point[0], point[1], self, transform) def contains_path(self, path, transform=None): """ Returns True if this path completely contains the given path. """ - if transform is None: - from transforms import IdentityTransform - transform = IdentityTransform() - return path_in_path(self, IdentityTransform(), path, transform) + if transform is not None: + transform = transform.frozen() + return path_in_path(self, None, path, transform) def get_extents(self, transform=None): """ @@ -232,9 +230,9 @@ algorithm will take into account the curves and deal with control points appropriately. """ - from transforms import Affine2D, Bbox - if transform is None: - transform = Affine2D() + from transforms import Bbox + if transform is not None: + transform = transform.frozen() return Bbox(get_path_extents(self, transform)) def intersects_path(self, other): @@ -267,6 +265,23 @@ new_codes = None return Path(vertices, new_codes) + def to_polygons(self, transform=None): + """ + Convert this path to a list of polygons. Each polygon is an + Nx2 array of vertices. In other words, each polygon has no + "move to" instructions or curves. + """ + if transform is not None: + transform = transform.frozen() + # Deal with the common and simple case + if self.codes is None: + if len(self.vertices): + return [transform.transform(self.vertices)] + return [] + # Deal with the case where there are curves and/or multiple + # subpaths (using extension code) + return convert_path_to_polygons(self, transform) + _unit_rectangle = None #@classmethod def unit_rectangle(cls): Modified: branches/transforms/src/_path.cpp =================================================================== --- branches/transforms/src/_path.cpp 2007-11-30 14:43:11 UTC (rev 4520) +++ branches/transforms/src/_path.cpp 2007-11-30 15:06:56 UTC (rev 4521) @@ -48,6 +48,8 @@ "count_bboxes_overlapping_bbox(bbox, bboxes)"); add_varargs_method("path_intersects_path", &_path_module::path_intersects_path, "path_intersects_path(p1, p2)"); + add_varargs_method("convert_path_to_polygons", &_path_module::convert_path_to_polygons, + "convert_path_to_polygons(path, trans)"); initialize("Helper functions for paths"); } @@ -66,6 +68,7 @@ Py::Object affine_transform(const Py::Tuple& args); Py::Object count_bboxes_overlapping_bbox(const Py::Tuple& args); Py::Object path_intersects_path(const Py::Tuple& args); + Py::Object convert_path_to_polygons(const Py::Tuple& args); }; // @@ -137,7 +140,7 @@ code = path.vertex(&x, &y); // The following cases denote the beginning on a new subpath - if (code == agg::path_cmd_stop || + if (code == agg::path_cmd_stop || (code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) { x = sx; @@ -234,7 +237,7 @@ double x = Py::Float(args[0]); double y = Py::Float(args[1]); PathIterator path(args[2]); - agg::trans_affine trans = py_to_agg_transformation_matrix(args[3]); + agg::trans_affine trans = py_to_agg_transformation_matrix(args[3], false); if (::point_in_path(x, y, path, trans)) return Py::Int(1); @@ -623,9 +626,9 @@ args.verify_length(4); PathIterator a(args[0]); - agg::trans_affine atrans = py_to_agg_transformation_matrix(args[1]); + agg::trans_affine atrans = py_to_agg_transformation_matrix(args[1], false); PathIterator b(args[2]); - agg::trans_affine btrans = py_to_agg_transformation_matrix(args[3]); + agg::trans_affine btrans = py_to_agg_transformation_matrix(args[3], false); return Py::Int(::path_in_path(a, atrans, b, btrans)); } @@ -1091,6 +1094,68 @@ return Py::Int(1); } +void _add_polygon(Py::List& polygons, const std::vector<double>& polygon) { + if (polygon.size() == 0) + return; + npy_intp polygon_dims[] = { polygon.size() / 2, 2, 0 }; + double* polygon_data = new double[polygon.size()]; + memcpy(polygon_data, &polygon[0], polygon.size() * sizeof(double)); + PyArrayObject* polygon_array = NULL; + polygon_array = (PyArrayObject*)PyArray_SimpleNewFromData + (2, polygon_dims, PyArray_DOUBLE, polygon_data); + if (!polygon_array) + { + delete[] polygon_data; + throw Py::RuntimeError("Error creating polygon array"); + } + polygons.append(Py::Object((PyObject*)polygon_array)); +} + +Py::Object _path_module::convert_path_to_polygons(const Py::Tuple& args) +{ + typedef agg::conv_transform<PathIterator> transformed_path_t; + typedef agg::conv_curve<transformed_path_t> curve_t; + + typedef std::vector<double> vertices_t; + + args.verify_length(2); + + PathIterator path(args[0]); + agg::trans_affine trans = py_to_agg_transformation_matrix(args[1], false); + + transformed_path_t tpath(path, trans); + curve_t curve(tpath); + + Py::List polygons; + vertices_t polygon; + double x, y; + unsigned code; + + while ((code = curve.vertex(&x, &y)) != agg::path_cmd_stop) + { + if ((code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) { + if (polygon.size() >= 2) + { + polygon.push_back(polygon[0]); + polygon.push_back(polygon[1]); + _add_polygon(polygons, polygon); + } + polygon.clear(); + } else { + if (code == agg::path_cmd_move_to) { + _add_polygon(polygons, polygon); + polygon.clear(); + } + polygon.push_back(x); + polygon.push_back(y); + } + } + + _add_polygon(polygons, polygon); + + return polygons; +} + extern "C" DL_EXPORT(void) init_path(void) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-12-03 15:27:46
|
Revision: 4562 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4562&view=rev Author: mdboom Date: 2007-12-03 07:27:33 -0800 (Mon, 03 Dec 2007) Log Message: ----------- Merged revisions 4506-4561 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r4507 | jdh2358 | 2007-11-29 15:16:48 -0500 (Thu, 29 Nov 2007) | 2 lines Applied Ludwigs build tkagg w/o x11 server patch ........ r4509 | jdh2358 | 2007-11-29 17:19:26 -0500 (Thu, 29 Nov 2007) | 2 lines commited ludwigs axes3d patch ........ r4512 | cmoad | 2007-11-29 21:40:30 -0500 (Thu, 29 Nov 2007) | 1 line minor rev bump ........ r4513 | cmoad | 2007-11-29 21:41:01 -0500 (Thu, 29 Nov 2007) | 1 line minor rev bump ........ r4514 | cmoad | 2007-11-29 21:47:06 -0500 (Thu, 29 Nov 2007) | 1 line minor rev bump ........ r4515 | cmoad | 2007-11-29 22:42:35 -0500 (Thu, 29 Nov 2007) | 1 line CXX/WrapPython.h missing from MANIFEST ........ r4516 | cmoad | 2007-11-29 23:00:16 -0500 (Thu, 29 Nov 2007) | 1 line ttconv missing from MANFEST ........ r4517 | cmoad | 2007-11-29 23:09:48 -0500 (Thu, 29 Nov 2007) | 1 line added setup.cfg.template ........ r4532 | mdboom | 2007-11-30 14:48:41 -0500 (Fri, 30 Nov 2007) | 2 lines Fix mathtext in example. ........ r4537 | astraw | 2007-12-01 15:12:05 -0500 (Sat, 01 Dec 2007) | 2 lines Fix loading of AAPL data in get_two_stock_data() ........ r4557 | mdboom | 2007-12-03 08:20:19 -0500 (Mon, 03 Dec 2007) | 2 lines Fix missing font file error. ........ r4560 | jdh2358 | 2007-12-03 10:23:32 -0500 (Mon, 03 Dec 2007) | 2 lines fixed a gtk import else block in mlab ........ r4561 | mdboom | 2007-12-03 10:23:47 -0500 (Mon, 03 Dec 2007) | 3 lines Remove paragraph about MATPLOTLIBDATA environment variable, since it doesn't really apply anymore. ........ Modified Paths: -------------- branches/transforms/API_CHANGES branches/transforms/CHANGELOG branches/transforms/CODING_GUIDE branches/transforms/INSTALL branches/transforms/MANIFEST.in branches/transforms/examples/data_helper.py branches/transforms/examples/loadrec.py branches/transforms/examples/text_themes.py branches/transforms/lib/matplotlib/__init__.py branches/transforms/lib/matplotlib/axes3d.py branches/transforms/lib/matplotlib/mathtext.py branches/transforms/setupext.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-4505 + /trunk/matplotlib:1-4561 Modified: branches/transforms/API_CHANGES =================================================================== --- branches/transforms/API_CHANGES 2007-12-03 15:23:47 UTC (rev 4561) +++ branches/transforms/API_CHANGES 2007-12-03 15:27:33 UTC (rev 4562) @@ -169,6 +169,8 @@ END OF TRANSFORMS REFACTORING +0.91.1 Released + 0.91.0 Released Changed cbook.is_file_like to cbook.is_writable_file_like and Modified: branches/transforms/CHANGELOG =================================================================== --- branches/transforms/CHANGELOG 2007-12-03 15:23:47 UTC (rev 4561) +++ branches/transforms/CHANGELOG 2007-12-03 15:27:33 UTC (rev 4562) @@ -1,4 +1,7 @@ =============================================================== +2007-11-27 Released 0.91.1 at revision 4517 + +=============================================================== 2007-11-27 Released 0.91.0 at revision 4478 2007-11-13 All backends now support writing to a file-like object, not Modified: branches/transforms/CODING_GUIDE =================================================================== --- branches/transforms/CODING_GUIDE 2007-12-03 15:23:47 UTC (rev 4561) +++ branches/transforms/CODING_GUIDE 2007-12-03 15:27:33 UTC (rev 4562) @@ -117,7 +117,7 @@ -for older versions of emacs (emacs<22) you may need to do +for older versions of emacs (emacs<22) you need to do (add-hook 'python-mode-hook (lambda () Modified: branches/transforms/INSTALL =================================================================== --- branches/transforms/INSTALL 2007-12-03 15:23:47 UTC (rev 4561) +++ branches/transforms/INSTALL 2007-12-03 15:27:33 UTC (rev 4562) @@ -14,7 +14,7 @@ more. If you want to produce PNGs or GUI images that support all of matplotlib's features, you should compile matplotlib with agg support and use one of the GUI agg backends: GTKAgg, WXAgg, TkAgg or - FLTKAgg. + FLTKAgg. COMPILING @@ -36,7 +36,7 @@ As discussed above, most users will want to set 'BUILD_AGG = 1' and one or more of the GUI backends to True. Exceptions to this are if you know you don't need a GUI (eg a web server) or you only want to - produce vector graphics. + produce vector graphics. If you have installed prerequisites to nonstandard places and need to inform matplotlib where they are, edit setupext.py an add the @@ -53,16 +53,12 @@ with matplotlib, it is important that you have *both* present and in your PYTHONPATH when you compile matplotlib. - Note that if you install matplotlib anywhere other than the default - location, you will need to set the MATPLOTLIBDATA environment - variable to point to the install base dir. - Once you have everything above set to your liking, just do the usual thing python setup.py build python setup.py install - + WINDOWS If you don't already have python installed, you may want to consider @@ -106,7 +102,7 @@ To build all the backends on a binary linux distro such as redhat, you need to install a number of the devel libs (and whatever dependencies they require), I suggest - + matplotlib core: zlib, zlib-devel, libpng, libpng-devel, freetype, freetype-devel, freetype-utils @@ -134,7 +130,7 @@ http://www.freshports.org/math/py-matplotlib/ Gentoo - + http://www.gentoo-portage.com/dev-python/matplotlib OS X Modified: branches/transforms/MANIFEST.in =================================================================== --- branches/transforms/MANIFEST.in 2007-12-03 15:23:47 UTC (rev 4561) +++ branches/transforms/MANIFEST.in 2007-12-03 15:27:33 UTC (rev 4562) @@ -1,7 +1,7 @@ include API_CHANGES CHANGELOG KNOWN_BUGS INSTALL NUMARRAY_ISSUES include INTERACTIVE TODO include Makefile MANIFEST.in MANIFEST -include matplotlibrc.template matplotlibrc +include matplotlibrc.template matplotlibrc setup.cfg.template include __init__.py setupext.py setup.py setupegg.py makeswig.py include examples/data/* include lib/matplotlib/toolkits @@ -12,7 +12,8 @@ recursive-include examples README *.py prune examples/_tmp_* recursive-include src *.cpp *.c *.h -recursive-include CXX *.cxx *.hxx *.c +recursive-include CXX *.cxx *.hxx *.c *.h recursive-include agg23 * recursive-include lib * recursive-include swig * +recursive-include ttconv *.cpp *.h Modified: branches/transforms/examples/data_helper.py =================================================================== --- branches/transforms/examples/data_helper.py 2007-12-03 15:23:47 UTC (rev 4561) +++ branches/transforms/examples/data_helper.py 2007-12-03 15:27:33 UTC (rev 4562) @@ -15,7 +15,7 @@ M1 = resize(M1, (M1.shape[0]/2,2) ) M2 = fromstring( file('data/%s.dat' % ticker2, 'rb').read(), '<d') - M2 = resize(M1, (M2.shape[0]/2,2) ) + M2 = resize(M2, (M2.shape[0]/2,2) ) d1, p1 = M1[:,0], M1[:,1] d2, p2 = M2[:,0], M2[:,1] Modified: branches/transforms/examples/loadrec.py =================================================================== --- branches/transforms/examples/loadrec.py 2007-12-03 15:23:47 UTC (rev 4561) +++ branches/transforms/examples/loadrec.py 2007-12-03 15:27:33 UTC (rev 4562) @@ -2,6 +2,7 @@ from pylab import figure, show a = mlab.csv2rec('data/msft.csv') +a.sort() print a.dtype fig = figure() Modified: branches/transforms/examples/text_themes.py =================================================================== --- branches/transforms/examples/text_themes.py 2007-12-03 15:23:47 UTC (rev 4561) +++ branches/transforms/examples/text_themes.py 2007-12-03 15:27:33 UTC (rev 4562) @@ -17,7 +17,7 @@ plot(t1, f(t1), 'bo', t2, f(t2), 'k') title('Damped exponential decay', font, size='large', color='r') -text(2, 0.65, 'cos(2 pi t) exp(-t)', font, color='k', family='monospace' ) +text(2, 0.65, r'$\cos(2 \pi t) \exp(-t)$', color='k') xlabel('time (s)', font, style='italic') ylabel('voltage (mV)', font) Modified: branches/transforms/lib/matplotlib/__init__.py =================================================================== --- branches/transforms/lib/matplotlib/__init__.py 2007-12-03 15:23:47 UTC (rev 4561) +++ branches/transforms/lib/matplotlib/__init__.py 2007-12-03 15:27:33 UTC (rev 4562) @@ -55,7 +55,7 @@ """ from __future__ import generators -__version__ = '0.91.0' +__version__ = '0.91.1' __revision__ = '$Revision$' __date__ = '$Date$' Modified: branches/transforms/lib/matplotlib/axes3d.py =================================================================== --- branches/transforms/lib/matplotlib/axes3d.py 2007-12-03 15:23:47 UTC (rev 4561) +++ branches/transforms/lib/matplotlib/axes3d.py 2007-12-03 15:27:33 UTC (rev 4562) @@ -313,9 +313,10 @@ def mouse_init(self): self.button_pressed = None - self.figure.canvas.mpl_connect('motion_notify_event', self.on_move) - self.figure.canvas.mpl_connect('button_press_event', self.button_press) - self.figure.canvas.mpl_connect('button_release_event', self.button_release) + if self.figure.canvas != None: + self.figure.canvas.mpl_connect('motion_notify_event', self.on_move) + self.figure.canvas.mpl_connect('button_press_event', self.button_press) + self.figure.canvas.mpl_connect('button_release_event', self.button_release) def button_press(self, event): self.button_pressed = event.button Modified: branches/transforms/lib/matplotlib/mathtext.py =================================================================== --- branches/transforms/lib/matplotlib/mathtext.py 2007-12-03 15:23:47 UTC (rev 4561) +++ branches/transforms/lib/matplotlib/mathtext.py 2007-12-03 15:27:33 UTC (rev 4562) @@ -16,8 +16,19 @@ s = r'$\mathcal{R}\prod_{i=\alpha\mathcal{B}}^\infty a_i\sin(2 \pi f x_i)$' - The fonts \cal, \rm, \it, and \tt are allowed. + Different fonts may be selected: + \mathcal Calligraphic fonts + \mathrm Roman (upright) font + \mathit Italic font + \mathtt Typewriter (monospaced) font, similar to Courier + Additionally, if using the STIX fonts: + \mathbb Blackboard (double-struck) font + \mathcircled Circled characters + \mathfrak Fraktur (Gothic-style) font + \mathscr Script (cursive) font + \mathsf Sans-serif font + The following accents are provided: \hat, \breve, \grave, \bar, \acute, \tilde, \vec, \dot, \ddot. All of them have the same syntax, eg to make an overbar you do \bar{o} or to make an o umlaut @@ -539,10 +550,7 @@ cached_font = self._fonts.get(basename) if cached_font is None: - try: - font = FT2Font(basename) - except RuntimeError: - return None + font = FT2Font(basename) cached_font = self.CachedFont(font) self._fonts[basename] = cached_font self._fonts[font.postscript_name] = cached_font @@ -650,13 +658,20 @@ if fontname in self.fontmap and latex_to_bakoma.has_key(sym): basename, num = latex_to_bakoma[sym] slanted = (basename == "cmmi10") or sym in self._slanted_symbols - cached_font = self._get_font(basename) - symbol_name = cached_font.font.get_glyph_name(num) - num = cached_font.glyphmap[num] + try: + cached_font = self._get_font(basename) + except RuntimeError: + pass + else: + symbol_name = cached_font.font.get_glyph_name(num) + num = cached_font.glyphmap[num] elif len(sym) == 1: slanted = (fontname == "it") - cached_font = self._get_font(fontname) - if cached_font is not None: + try: + cached_font = self._get_font(fontname) + except RuntimeError: + pass + else: num = ord(sym) gid = cached_font.charmap.get(num) if gid is not None: @@ -793,9 +808,12 @@ new_fontname = 'rm' slanted = (new_fontname == 'it') or sym in self._slanted_symbols - cached_font = self._get_font(new_fontname) found_symbol = False - if cached_font is not None: + try: + cached_font = self._get_font(new_fontname) + except RuntimeError: + pass + else: try: glyphindex = cached_font.charmap[uniindex] found_symbol = True Modified: branches/transforms/setupext.py =================================================================== --- branches/transforms/setupext.py 2007-12-03 15:23:47 UTC (rev 4561) +++ branches/transforms/setupext.py 2007-12-03 15:27:33 UTC (rev 4562) @@ -94,25 +94,26 @@ BUILT_PATH = False AGG_VERSION = 'agg24' +TCL_TK_CACHE = None # for nonstandard installation/build with --prefix variable numpy_inc_dirs = [] # matplotlib build options, which can be altered using setup.cfg -options = {'display_status': True, - 'verbose': False, - 'provide_pytz': 'auto', - 'provide_dateutil': 'auto', - 'provide_configobj': 'auto', - 'provide_traits': 'auto', - 'build_agg': True, - 'build_gtk': 'auto', - 'build_gtkagg': 'auto', - 'build_tkagg': 'auto', - 'build_wxagg': 'auto', - 'build_image': True, - 'build_windowing': True, - 'backend': None, +options = {'display_status': True, + 'verbose': False, + 'provide_pytz': 'auto', + 'provide_dateutil': 'auto', + 'provide_configobj': 'auto', + 'provide_traits': 'auto', + 'build_agg': True, + 'build_gtk': 'auto', + 'build_gtkagg': 'auto', + 'build_tkagg': 'auto', + 'build_wxagg': 'auto', + 'build_image': True, + 'build_windowing': True, + 'backend': None, 'numerix': None} # Based on the contents of setup.cfg, determine the build options @@ -799,51 +800,6 @@ # or else you'll build for a wrong version of the Tcl # interpreter (leading to nasty segfaults). -class FoundTclTk: - pass - -def find_tcltk(): - """Finds Tcl/Tk includes/libraries/version by interrogating Tkinter.""" - # By this point, we already know that Tkinter imports correctly - import Tkinter - o = FoundTclTk() - try: - tk=Tkinter.Tk() - except Tkinter.TclError: - o.tcl_lib = "/usr/local/lib" - o.tcl_inc = "/usr/local/include" - o.tk_lib = "/usr/local/lib" - o.tk_inc = "/usr/local/include" - o.tkv = "" - else: - tk.withdraw() - o.tcl_lib = os.path.normpath(os.path.join(str(tk.getvar('tcl_library')), '../')) - o.tk_lib = os.path.normpath(os.path.join(str(tk.getvar('tk_library')), '../')) - o.tkv = str(Tkinter.TkVersion)[:3] - o.tcl_inc = os.path.normpath(os.path.join(str(tk.getvar('tcl_library')), - '../../include/tcl'+o.tkv)) - if not os.path.exists(o.tcl_inc): - o.tcl_inc = os.path.normpath(os.path.join(str(tk.getvar('tcl_library')), - '../../include')) - o.tk_inc = os.path.normpath(os.path.join(str(tk.getvar('tk_library')), - '../../include/tk'+o.tkv)) - if not os.path.exists(o.tk_inc): - o.tk_inc = os.path.normpath(os.path.join(str(tk.getvar('tk_library')), - '../../include')) - - if ((not os.path.exists(os.path.join(o.tk_inc,'tk.h'))) and - os.path.exists(os.path.join(o.tcl_inc,'tk.h'))): - o.tk_inc = o.tcl_inc - - if not os.path.exists(o.tcl_inc): - # this is a hack for suse linux, which is broken - if (sys.platform.startswith('linux') and - os.path.exists('/usr/include/tcl.h') and - os.path.exists('/usr/include/tk.h')): - o.tcl_inc = '/usr/include/' - o.tk_inc = '/usr/include/' - return o - def check_for_tk(): gotit = False explanation = None @@ -855,28 +811,26 @@ explanation = 'Tkinter present but import failed' else: if Tkinter.TkVersion < 8.3: - explanation = "Tcl/Tk v8.3 or later required\n" - sys.exit(1) + explanation = "Tcl/Tk v8.3 or later required" else: - try: - tk = Tkinter.Tk() - tk.withdraw() - except Tkinter.TclError: - explanation = """\ -Using default library and include directories for Tcl and Tk because a -Tk window failed to open. You may need to define DISPLAY for Tk to work -so that setup can determine where your libraries are located.""" gotit = True if gotit: module = Extension('test', []) try: - add_tk_flags(module) + explanation = add_tk_flags(module) except RuntimeError, e: explanation = str(e) gotit = False - if not find_include_file(module.include_dirs, "tk.h"): - explanation = 'Tkinter present, but header files are not installed. You may need to install development packages.' + else: + if not find_include_file(module.include_dirs, "tk.h"): + message = 'Tkinter present, but header files are not found. ' + \ + 'You may need to install development packages.' + if explanation is not None: + explanation += '\n' + message + else: + explanation = message + gotit = False if gotit: print_status("Tkinter", "Tkinter: %s, Tk: %s, Tcl: %s" % @@ -887,22 +841,62 @@ print_message(explanation) return gotit +def query_tcltk(): + """Tries to open a Tk window in order to query the Tk object about its library paths. + This should never be called more than once by the same process, as Tk intricacies + may cause the Python interpreter to hang. The function also has a workaround if + no X server is running (useful for autobuild systems).""" + global TCL_TK_CACHE + # Use cached values if they exist, which ensures this function only executes once + if TCL_TK_CACHE is not None: + return TCL_TK_CACHE + + # By this point, we already know that Tkinter imports correctly + import Tkinter + tcl_lib_dir = '' + tk_lib_dir = '' + # First try to open a Tk window (requires a running X server) + try: + tk = Tkinter.Tk() + except Tkinter.TclError: + # Next, start Tcl interpreter without opening a Tk window (no need for X server) + # This feature is available in python version 2.4 and up + try: + tcl = Tkinter.Tcl() + except AttributeError: # Python version not high enough + pass + except Tkinter.TclError: # Something went wrong while opening Tcl + pass + else: + tcl_lib_dir = str(tcl.getvar('tcl_library')) + # Guess Tk location based on Tcl location + tk_lib_dir = tcl_lib_dir.replace('Tcl', 'Tk').replace('tcl', 'tk') + else: + # Obtain Tcl and Tk locations from Tk widget + tk.withdraw() + tcl_lib_dir = str(tk.getvar('tcl_library')) + tk_lib_dir = str(tk.getvar('tk_library')) + + # Save directories and version string to cache + TCL_TK_CACHE = tcl_lib_dir, tk_lib_dir, str(Tkinter.TkVersion)[:3] + return TCL_TK_CACHE + def add_tk_flags(module): 'Add the module flags to build extensions which use tk' - if sys.platform=='win32': + message = None + if sys.platform == 'win32': major, minor1, minor2, s, tmp = sys.version_info - if major==2 and minor1 in [3, 4, 5]: + if major == 2 and minor1 in [3, 4, 5]: module.include_dirs.extend(['win32_static/include/tcl8.4']) module.libraries.extend(['tk84', 'tcl84']) - elif major==2 and minor1==2: + elif major == 2 and minor1 == 2: module.include_dirs.extend(['win32_static/include/tcl8.3']) module.libraries.extend(['tk83', 'tcl83']) else: raise RuntimeError('No tk/win32 support for this python version yet') module.library_dirs.extend([os.path.join(sys.prefix, 'dlls')]) - return - elif sys.platform == 'darwin' : + elif sys.platform == 'darwin': # this config section lifted directly from Imaging - thanks to # the effbot! @@ -914,7 +908,7 @@ join(os.getenv('HOME'), '/Library/Frameworks') ] - # Find the directory that contains the Tcl.framwork and Tk.framework + # Find the directory that contains the Tcl.framework and Tk.framework # bundles. # XXX distutils should support -F! tk_framework_found = 0 @@ -947,15 +941,55 @@ module.include_dirs.extend(tk_include_dirs) module.extra_link_args.extend(frameworks) module.extra_compile_args.extend(frameworks) - return - # you're still here? ok we'll try it this way - o = find_tcltk() # todo: try/except - module.include_dirs.extend([o.tcl_inc, o.tk_inc]) - module.library_dirs.extend([o.tcl_lib, o.tk_lib]) - module.libraries.extend(['tk'+o.tkv, 'tcl'+o.tkv]) + # you're still here? ok we'll try it this way... + else: + # Query Tcl/Tk system for library paths and version string + tcl_lib_dir, tk_lib_dir, tk_ver = query_tcltk() # todo: try/except + # Process base directories to obtain include + lib dirs + if tcl_lib_dir != '' and tk_lib_dir != '': + tcl_lib = os.path.normpath(os.path.join(tcl_lib_dir, '../')) + tk_lib = os.path.normpath(os.path.join(tk_lib_dir, '../')) + tcl_inc = os.path.normpath(os.path.join(tcl_lib_dir, + '../../include/tcl' + tk_ver)) + if not os.path.exists(tcl_inc): + tcl_inc = os.path.normpath(os.path.join(tcl_lib_dir, + '../../include')) + tk_inc = os.path.normpath(os.path.join(tk_lib_dir, + '../../include/tk' + tk_ver)) + if not os.path.exists(tk_inc): + tk_inc = os.path.normpath(os.path.join(tk_lib_dir, + '../../include')) + if ((not os.path.exists(os.path.join(tk_inc,'tk.h'))) and + os.path.exists(os.path.join(tcl_inc,'tk.h'))): + tk_inc = tcl_inc + + if not os.path.exists(tcl_inc): + # this is a hack for suse linux, which is broken + if (sys.platform.startswith('linux') and + os.path.exists('/usr/include/tcl.h') and + os.path.exists('/usr/include/tk.h')): + tcl_inc = '/usr/include' + tk_inc = '/usr/include' + else: + message = """\ +Using default library and include directories for Tcl and Tk because a +Tk window failed to open. You may need to define DISPLAY for Tk to work +so that setup can determine where your libraries are located.""" + tcl_inc = "/usr/local/include" + tk_inc = "/usr/local/include" + tcl_lib = "/usr/local/lib" + tk_lib = "/usr/local/lib" + tk_ver = "" + # Add final versions of directories and libraries to module lists + module.include_dirs.extend([tcl_inc, tk_inc]) + module.library_dirs.extend([tcl_lib, tk_lib]) + module.libraries.extend(['tk' + tk_ver, 'tcl' + tk_ver]) + + return message + def add_windowing_flags(module): 'Add the module flags to build extensions using windowing api' module.include_dirs.extend(['C:/include']) @@ -1019,7 +1053,7 @@ add_ft2font_flags(module) add_pygtk_flags(module) add_numpy_flags(module) - + ext_modules.append(module) BUILT_GTKAGG = True @@ -1034,9 +1068,6 @@ deps, ) - # add agg flags before pygtk because agg only supports freetype1 - # and pygtk includes freetype2. This is a bit fragile. - add_tk_flags(module) # do this first add_agg_flags(module) add_ft2font_flags(module) @@ -1130,7 +1161,7 @@ ext_modules.append(module) BUILT_PATH = True - + def build_image(ext_modules, packages): global BUILT_IMAGE if BUILT_IMAGE: return # only build it if you you haven't already This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-12-03 19:07:38
|
Revision: 4568 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4568&view=rev Author: mdboom Date: 2007-12-03 11:07:36 -0800 (Mon, 03 Dec 2007) Log Message: ----------- Fix image interpolation edges for Agg 2.4. It no longer needs funny workarounds with memory copies to interpolate the edges of the image correctly. Modified Paths: -------------- branches/transforms/lib/matplotlib/image.py branches/transforms/src/_image.cpp Modified: branches/transforms/lib/matplotlib/image.py =================================================================== --- branches/transforms/lib/matplotlib/image.py 2007-12-03 17:30:46 UTC (rev 4567) +++ branches/transforms/lib/matplotlib/image.py 2007-12-03 19:07:36 UTC (rev 4568) @@ -156,9 +156,6 @@ sx = dxintv/self.axes.viewLim.width sy = dyintv/self.axes.viewLim.height - if im.get_interpolation()!=_image.NEAREST: - im.apply_translation(-1, -1) - # the viewport translation tx = (xmin-self.axes.viewLim.x0)/dxintv * numcols ty = (ymin-self.axes.viewLim.y0)/dyintv * numrows @@ -382,7 +379,7 @@ if s != None and s != 'nearest': raise NotImplementedError('Only nearest neighbor supported') AxesImage.set_interpolation(self, s) - + def get_extent(self): if self._A is None: raise RuntimeError('Must set data first') Modified: branches/transforms/src/_image.cpp =================================================================== --- branches/transforms/src/_image.cpp 2007-12-03 17:30:46 UTC (rev 4567) +++ branches/transforms/src/_image.cpp 2007-12-03 19:07:36 UTC (rev 4568) @@ -379,57 +379,11 @@ double x0, y0, x1, y1; - if (interpolation==NEAREST) { - x0 = 0.0; - x1 = colsIn; - y0 = 0.0; - y1 = rowsIn; - } - else { - // if interpolation != nearest, create a new input buffer with the - // edges mirrored on all size. Then new buffer size is colsIn+2 by - // rowsIn+2 + x0 = 0.0; + x1 = colsIn; + y0 = 0.0; + y1 = rowsIn; - x0 = 1.0; - x1 = colsIn+1; - y0 = 1.0; - y1 = rowsIn+1; - - - bufferPad = new agg::int8u[(rowsIn+2) * (colsIn+2) * BPP]; - if (bufferPad ==NULL) - throw Py::MemoryError("Image::resize could not allocate memory"); - rbufPad.attach(bufferPad, colsIn+2, rowsIn+2, (colsIn+2) * BPP); - - pixfmt pixfpad(rbufPad); - renderer_base rbpad(pixfpad); - - pixfmt pixfin(*rbufIn); - renderer_base rbin(pixfin); - - rbpad.copy_from(*rbufIn, 0, 1, 1); - - agg::rect_base<int> firstrow(0, 0, colsIn-1, 0); - rbpad.copy_from(*rbufIn, &firstrow, 1, 0); - - agg::rect_base<int> lastrow(0, rowsIn-1, colsIn-1, rowsIn-1); - rbpad.copy_from(*rbufIn, &lastrow, 1, 2); - - agg::rect_base<int> firstcol(0, 0, 0, rowsIn-1); - rbpad.copy_from(*rbufIn, &firstcol, 0, 1); - - agg::rect_base<int> lastcol(colsIn-1, 0, colsIn-1, rowsIn-1); - rbpad.copy_from(*rbufIn, &lastcol, 2, 1); - - rbpad.copy_pixel(0, 0, rbin.pixel(0,0) ); - rbpad.copy_pixel(0, colsIn+1, rbin.pixel(0,colsIn-1) ); - rbpad.copy_pixel(rowsIn+1, 0, rbin.pixel(rowsIn-1,0) ); - rbpad.copy_pixel(rowsIn+1, colsIn+1, rbin.pixel(rowsIn-1,colsIn-1) ); - - - } - - path.move_to(x0, y0); path.line_to(x1, y0); path.line_to(x1, y1); @@ -439,7 +393,7 @@ ras.add_path(imageBox); typedef agg::image_accessor_clip<pixfmt> img_accessor_type; - + pixfmt pixfmtin(*rbufIn); img_accessor_type ia(pixfmtin, background); switch(interpolation) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-12-04 21:33:39
|
Revision: 4603 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4603&view=rev Author: mdboom Date: 2007-12-04 13:33:33 -0800 (Tue, 04 Dec 2007) Log Message: ----------- Add experimental support for auto-layout of axes on the figure, to prevent ticks and labels from overlapping things in other axes. Modified Paths: -------------- branches/transforms/examples/backend_driver.py branches/transforms/examples/colorbar_only.py branches/transforms/examples/figlegend_demo.py branches/transforms/examples/finance_demo.py branches/transforms/examples/mathtext_demo.py branches/transforms/examples/simple_plot.py branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/axis.py branches/transforms/lib/matplotlib/figure.py branches/transforms/lib/matplotlib/projections/polar.py branches/transforms/lib/matplotlib/rcsetup.py Added Paths: ----------- branches/transforms/examples/auto_layout.py Added: branches/transforms/examples/auto_layout.py =================================================================== --- branches/transforms/examples/auto_layout.py (rev 0) +++ branches/transforms/examples/auto_layout.py 2007-12-04 21:33:33 UTC (rev 4603) @@ -0,0 +1,34 @@ +#!/usr/bin/env python +""" +Example: simple line plot. +Show how to make and save a simple line plot with labels, title and grid +""" +from pylab import * + +t = arange(0.0, 1.0+0.01, 0.01) +s = cos(2*2*pi*t) +ax1 = subplot(211) +plot(t, s, '-', lw=2) + +xlabel('xlabel for bottom axes') +ylabel('ylabel on the right') +title('About as simple as it gets, folks') +grid(True) +ax1.yaxis.set_label_position('right') +ax1.xaxis.set_ticklabels(['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']) +for label in ax1.get_xticklabels(): + label.set_rotation(45) + +ax2 = subplot(212) +plot(t, s, '-', lw=2) +grid(True) +xlabel('xlabel for bottom axes (the ticks are on the top for no good reason)') +ylabel('I\'m a lefty') +ax2.xaxis.set_label_position('bottom') +ax2.xaxis.set_ticks_position('top') + + +#savefig('simple_plot.png') +savefig('simple_plot') + +show() Property changes on: branches/transforms/examples/auto_layout.py ___________________________________________________________________ Name: svn:executable + * Modified: branches/transforms/examples/backend_driver.py =================================================================== --- branches/transforms/examples/backend_driver.py 2007-12-04 21:30:06 UTC (rev 4602) +++ branches/transforms/examples/backend_driver.py 2007-12-04 21:33:33 UTC (rev 4603) @@ -23,6 +23,7 @@ 'alignment_test.py', 'arctest.py', 'arrow_demo.py', + 'auto_layout.py', 'axes_demo.py', 'axhspan_demo.py', 'bar_stacked.py', @@ -35,7 +36,7 @@ 'cohere_demo.py', 'contour_demo.py', 'contourf_demo.py', - 'csd_demo.py', + 'csd_demo.py', 'custom_ticker1.py', 'customize_rc.py', 'date_demo1.py', Modified: branches/transforms/examples/colorbar_only.py =================================================================== --- branches/transforms/examples/colorbar_only.py 2007-12-04 21:30:06 UTC (rev 4602) +++ branches/transforms/examples/colorbar_only.py 2007-12-04 21:33:33 UTC (rev 4603) @@ -7,7 +7,7 @@ # Make a figure and axes with dimensions as desired. fig = pylab.figure(figsize=(8,1.5)) -ax = fig.add_axes([0.05, 0.4, 0.9, 0.5]) +ax = fig.add_axes([0.05, 0.05, 0.9, 0.9]) # Set the colormap and norm to correspond to the data for which # the colorbar will be used. Modified: branches/transforms/examples/figlegend_demo.py =================================================================== --- branches/transforms/examples/figlegend_demo.py 2007-12-04 21:30:06 UTC (rev 4602) +++ branches/transforms/examples/figlegend_demo.py 2007-12-04 21:33:33 UTC (rev 4603) @@ -1,7 +1,7 @@ #!/usr/bin/env python from pylab import * -ax1 = axes([0.1, 0.1, 0.4, 0.7]) +ax1 = axes([0.05, 0.1, 0.4, 0.7]) ax2 = axes([0.55, 0.1, 0.4, 0.7]) x = arange(0.0, 2.0, 0.02) Modified: branches/transforms/examples/finance_demo.py =================================================================== --- branches/transforms/examples/finance_demo.py 2007-12-04 21:30:06 UTC (rev 4602) +++ branches/transforms/examples/finance_demo.py 2007-12-04 21:33:33 UTC (rev 4603) @@ -22,7 +22,7 @@ raise SystemExit fig = figure() -fig.subplots_adjust(bottom=0.2) +# fig.subplots_adjust(bottom=0.2) ax = fig.add_subplot(111) ax.xaxis.set_major_locator(mondays) ax.xaxis.set_minor_locator(alldays) Modified: branches/transforms/examples/mathtext_demo.py =================================================================== --- branches/transforms/examples/mathtext_demo.py 2007-12-04 21:30:06 UTC (rev 4602) +++ branches/transforms/examples/mathtext_demo.py 2007-12-04 21:33:33 UTC (rev 4603) @@ -7,7 +7,7 @@ from matplotlib.pyplot import figure, show fig = figure() -fig.subplots_adjust(bottom=0.2) +# fig.subplots_adjust(bottom=0.2) ax = fig.add_subplot(111, axisbg='y') ax.plot([1,2,3], 'r') Modified: branches/transforms/examples/simple_plot.py =================================================================== --- branches/transforms/examples/simple_plot.py 2007-12-04 21:30:06 UTC (rev 4602) +++ branches/transforms/examples/simple_plot.py 2007-12-04 21:33:33 UTC (rev 4603) @@ -13,6 +13,9 @@ ylabel('voltage (mV)') title('About as simple as it gets, folks') grid(True) +axes().xaxis.set_label_position('top') +axes().xaxis.set_ticks_position('top') +axes().yaxis.set_label_position('right') #savefig('simple_plot.png') savefig('simple_plot') Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-12-04 21:30:06 UTC (rev 4602) +++ branches/transforms/lib/matplotlib/axes.py 2007-12-04 21:33:33 UTC (rev 4603) @@ -770,13 +770,14 @@ self.grid(self._gridOn) props = font_manager.FontProperties(size=rcParams['axes.titlesize']) + self.titleOffsetTrans = mtransforms.Affine2D().translate(0.0, 10.0) self.title = mtext.Text( - x=0.5, y=1.02, text='', + x=0.5, y=1.0, text='', fontproperties=props, verticalalignment='bottom', horizontalalignment='center', ) - self.title.set_transform(self.transAxes) + self.title.set_transform(self.transAxes + self.titleOffsetTrans) self.title.set_clip_box(None) self._set_artist_props(self.title) @@ -800,6 +801,8 @@ self.xaxis.set_clip_path(self.axesPatch) self.yaxis.set_clip_path(self.axesPatch) + self.titleOffsetTrans.clear() + def clear(self): 'clear the axes' self.cla() @@ -905,14 +908,14 @@ ysize = max(math.fabs(ymax-ymin), 1e-30) return ysize/xsize - def apply_aspect(self): + def apply_aspect(self, position): ''' Use self._aspect and self._adjustable to modify the axes box or the view limits. ''' aspect = self.get_aspect() if aspect == 'auto': - self.set_position( self._originalPosition , 'active') + self.set_position( position , 'active') return if aspect == 'equal': @@ -929,7 +932,7 @@ fig_aspect = figH/figW if self._adjustable == 'box': box_aspect = A * self.get_data_ratio() - pb = self._originalPosition.frozen() + pb = position.frozen() pb1 = pb.shrunk_to_aspect(box_aspect, pb, fig_aspect) self.set_position(pb1.anchored(self.get_anchor(), pb), 'active') return @@ -939,7 +942,7 @@ ymin,ymax = self.get_ybound() ysize = max(math.fabs(ymax-ymin), 1e-30) - l,b,w,h = self.get_position(original=True).bounds + l,b,w,h = position.bounds box_aspect = fig_aspect * (h/w) data_ratio = box_aspect / A @@ -1014,7 +1017,7 @@ self.set_autoscale_on(True) self.set_aspect('auto') self.autoscale_view() - self.apply_aspect() + # self.apply_aspect() if s=='equal': self.set_aspect('equal', adjustable='datalim') elif s == 'scaled': @@ -1289,6 +1292,32 @@ YL = ylocator.autoscale() self.set_ybound(YL) + def update_layout(self, renderer): + pad_pixels = rcParams['xtick.major.pad'] * self.figure.dpi / 72.0 + inverse_transFigure = self.figure.transFigure.inverted() + t_text, b_text = self.xaxis.get_text_heights(renderer) + l_text, r_text = self.yaxis.get_text_widths(renderer) + title_height = self.title.get_window_extent(renderer).height + title_height += pad_pixels * 2.0 + original_t_text = t_text + + ((l_text, t_text), + (r_text, b_text), + (dummy, title_height)) = inverse_transFigure.transform( + ((l_text, t_text), + (r_text, b_text), + (0.0, title_height))) + x0, y0, x1, y1 = self.get_position(True).extents + # Adjust the title + self.titleOffsetTrans.clear().translate( + 0, original_t_text + pad_pixels * 2.0) + + new_position = mtransforms.Bbox.from_extents( + x0 + l_text, y0 + b_text, + x1 - r_text, y1 - t_text - title_height) + + self.set_position(new_position, 'active') + #### Drawing def draw(self, renderer=None, inframe=False): "Draw everything (plot lines, axes, labels)" @@ -1299,8 +1328,9 @@ raise RuntimeError('No renderer defined') if not self.get_visible(): return renderer.open_group('axes') - self.apply_aspect() + self.apply_aspect(self.get_position()) + if self.axison and self._frameon: self.axesPatch.draw(renderer) Modified: branches/transforms/lib/matplotlib/axis.py =================================================================== --- branches/transforms/lib/matplotlib/axis.py 2007-12-04 21:30:06 UTC (rev 4602) +++ branches/transforms/lib/matplotlib/axis.py 2007-12-04 21:33:33 UTC (rev 4603) @@ -130,11 +130,11 @@ ACCEPTS: float """ - self._pad.set(val) + self._pad = val def get_pad(self, val): 'Get the value of the tick label pad in points' - return self._pad.get() + return self._pad def _get_text1(self): 'Get the default Text 1 instance' @@ -578,30 +578,43 @@ if a is None: return a.set_figure(self.figure) - def draw(self, renderer, *args, **kwargs): - 'Draw the axis lines, grid lines, tick lines and labels' - if not self.get_visible(): return - renderer.open_group(__name__) - ticklabelBoxes = [] - ticklabelBoxes2 = [] - + def iter_ticks(self): + """ + Iterate through all of the major and minor ticks. + """ majorLocs = self.major.locator() majorTicks = self.get_major_ticks(len(majorLocs)) self.major.formatter.set_locs(majorLocs) majorLabels = [self.major.formatter(val, i) for i, val in enumerate(majorLocs)] + minorLocs = self.minor.locator() + minorTicks = self.get_minor_ticks(len(minorLocs)) + self.minor.formatter.set_locs(minorLocs) + minorLabels = [self.minor.formatter(val, i) for i, val in enumerate(minorLocs)] - seen = {} + major_minor = [ + (majorTicks, majorLocs, majorLabels), + (minorTicks, minorLocs, minorLabels)] + for group in major_minor: + for tick in zip(*group): + yield tick + + def get_ticklabel_extents(self, renderer): + """ + Get the extents of the tick labels on either side + of the axes. + """ + ticklabelBoxes = [] + ticklabelBoxes2 = [] + interval = self.get_view_interval() - for tick, loc, label in zip(majorTicks, majorLocs, majorLabels): + for tick, loc, label in self.iter_ticks(): if tick is None: continue if not interval_contains(interval, loc): continue - seen[loc] = 1 tick.update_position(loc) tick.set_label1(label) tick.set_label2(label) - tick.draw(renderer) if tick.label1On and tick.label1.get_visible(): extent = tick.label1.get_window_extent(renderer) ticklabelBoxes.append(extent) @@ -609,19 +622,30 @@ extent = tick.label2.get_window_extent(renderer) ticklabelBoxes2.append(extent) - minorLocs = self.minor.locator() - minorTicks = self.get_minor_ticks(len(minorLocs)) - self.minor.formatter.set_locs(minorLocs) - minorLabels = [self.minor.formatter(val, i) for i, val in enumerate(minorLocs)] + if len(ticklabelBoxes): + bbox = Bbox.union(ticklabelBoxes) + else: + bbox = Bbox.from_extents(0, 0, 0, 0) + if len(ticklabelBoxes2): + bbox2 = Bbox.union(ticklabelBoxes2) + else: + bbox2 = Bbox.from_extents(0, 0, 0, 0) + return bbox, bbox2 - for tick, loc, label in zip(minorTicks, minorLocs, minorLabels): + def draw(self, renderer, *args, **kwargs): + 'Draw the axis lines, grid lines, tick lines and labels' + ticklabelBoxes = [] + ticklabelBoxes2 = [] + + if not self.get_visible(): return + renderer.open_group(__name__) + interval = self.get_view_interval() + for tick, loc, label in self.iter_ticks(): if tick is None: continue if not interval_contains(interval, loc): continue - #if seen.has_key(loc): continue tick.update_position(loc) tick.set_label1(label) tick.set_label2(label) - tick.draw(renderer) if tick.label1On and tick.label1.get_visible(): extent = tick.label1.get_window_extent(renderer) @@ -1142,6 +1166,28 @@ bottom = bbox.y0 self.offsetText.set_position((x, bottom-self.OFFSETTEXTPAD*self.figure.dpi/72.0)) + def get_text_heights(self, renderer): + """ + Returns the amount of space one should reserve for text + above and below the axes. Returns a tuple (above, below) + """ + bbox, bbox2 = self.get_ticklabel_extents(renderer) + # MGDTODO: Need a better way to get the pad + padPixels = self.majorTicks[0]._padPixels + + above = 0.0 + if bbox2.height: + above += bbox2.height + padPixels + below = 0.0 + if bbox.height: + below += bbox.height + padPixels + + if self.get_label_position() == 'top': + above += self.label.get_window_extent(renderer).height + padPixels + else: + below += self.label.get_window_extent(renderer).height + padPixels + return above, below + def set_ticks_position(self, position): """ Set the ticks position (top, bottom, both, default or none) @@ -1360,6 +1406,24 @@ self.offsetText.set_ha(position) self.offsetText.set_position((x,y)) + def get_text_widths(self, renderer): + bbox, bbox2 = self.get_ticklabel_extents(renderer) + # MGDTODO: Need a better way to get the pad + padPixels = self.majorTicks[0]._padPixels + + left = 0.0 + if bbox.width: + left += bbox.width + padPixels + right = 0.0 + if bbox2.width: + right += bbox2.width + padPixels + + if self.get_label_position() == 'left': + left += self.label.get_window_extent(renderer).width + padPixels + else: + right += self.label.get_window_extent(renderer).width + padPixels + return left, right + def set_ticks_position(self, position): """ Set the ticks position (left, right, both or default) Modified: branches/transforms/lib/matplotlib/figure.py =================================================================== --- branches/transforms/lib/matplotlib/figure.py 2007-12-04 21:30:06 UTC (rev 4602) +++ branches/transforms/lib/matplotlib/figure.py 2007-12-04 21:33:33 UTC (rev 4603) @@ -6,7 +6,7 @@ import artist from artist import Artist from axes import Axes, SubplotBase, subplot_class_factory -from cbook import flatten, allequal, Stack, iterable, dedent +from cbook import flatten, allequal, Stack, iterable, dedent, set import _image import colorbar as cbar from image import FigureImage @@ -100,7 +100,7 @@ def __str__(self): return "Figure(%gx%g)" % tuple(self.bbox.size) - + def __init__(self, figsize = None, # defaults to rc figure.figsize dpi = None, # defaults to rc figure.dpi @@ -126,7 +126,7 @@ self.dpi = dpi self.bbox_inches = Bbox.from_bounds(0, 0, *figsize) self.bbox = TransformedBbox(self.bbox_inches, self._dpi_scale_trans) - + self.frameon = frameon self.transFigure = BboxTransformTo(self.bbox) @@ -158,7 +158,7 @@ self._dpi = dpi self._dpi_scale_trans.clear().scale(dpi, dpi) dpi = property(_get_dpi, _set_dpi) - + def autofmt_xdate(self, bottom=0.2, rotation=30, ha='right'): """ A common use case is a number of subplots with shared xaxes @@ -181,7 +181,7 @@ else: for label in ax.get_xticklabels(): label.set_visible(False) - self.subplots_adjust(bottom=bottom) + #self.subplots_adjust(bottom=bottom) def get_children(self): 'get a list of artists contained in the figure' @@ -322,7 +322,7 @@ dpival = self.dpi self.bbox_inches.p1 = w, h - + if forward: dpival = self.dpi canvasw = w*dpival @@ -389,7 +389,7 @@ ACCEPTS: float """ self.bbox_inches.x1 = val - + def set_figheight(self, val): """ Set the height of the figure in inches @@ -448,7 +448,7 @@ provided, which is equivalent to projection='polar'). Valid values for "projection" are: %s. Some of these projections support additional kwargs, which may be provided to add_axes. - + rect = l,b,w,h add_axes(rect) add_axes(rect, frameon=False, axisbg='g') @@ -469,7 +469,7 @@ add_axes(rect, label='axes2') The Axes instance will be returned - + The following kwargs are supported: %s """ % (", ".join(get_projection_names()), '%(Axes)s') @@ -496,7 +496,7 @@ "Only one of these arguments should be supplied." % projection) projection = 'polar' - + a = projection_factory(projection, self, rect, **kwargs) self.axes.append(a) @@ -524,7 +524,7 @@ be provided to add_axes. The Axes instance will be returned. - + If the figure already has a subplot with key *args, *kwargs then it will simply make that subplot current and return it @@ -623,7 +623,40 @@ renderer.draw_image(l, b, im, self.bbox, *self.get_transformed_clip_path_and_affine()) + # update the positions of the axes + # This gives each of the axes the opportunity to resize itself + # based on the tick and axis labels etc., and then makes sure + # that any axes that began life aligned to another axes remains + # aligned after these adjustments + if len(self.axes) > 1: + aligned_positions = [{}, {}, {}, {}] + for a in self.axes: + a.update_layout(renderer) + orig_pos = a.get_position(True) + curr_pos = a.get_position() + for pos, orig, curr in zip(aligned_positions, + orig_pos.get_points().flatten(), + curr_pos.get_points().flatten()): + if orig in pos: + pos[orig][0].append(a) + pos[orig][1].add(curr) + else: + pos[orig] = [[a], set([curr])] + for i, pos in enumerate(aligned_positions): + for axes, places in pos.values(): + if len(places) > 1: + if i < 2: + curr = max(places) + else: + curr = min(places) + for a in axes: + curr_pos = a.get_position().frozen() + curr_pos.get_points()[i/2, i%2] = curr + a.set_position(curr_pos, 'active') + else: + for a in self.axes: a.update_layout(renderer) + # render the axes for a in self.axes: a.draw(renderer) Modified: branches/transforms/lib/matplotlib/projections/polar.py =================================================================== --- branches/transforms/lib/matplotlib/projections/polar.py 2007-12-04 21:30:06 UTC (rev 4602) +++ branches/transforms/lib/matplotlib/projections/polar.py 2007-12-04 21:33:33 UTC (rev 4603) @@ -20,7 +20,7 @@ Theta starts pointing east and goes anti-clockwise. """ name = 'polar' - + class PolarTransform(Transform): """ The base polar transform. This handles projection theta and r into @@ -61,10 +61,10 @@ ipath = path.interpolated(self._resolution) return Path(self.transform(ipath.vertices), ipath.codes) transform_path.__doc__ = Transform.transform_path.__doc__ - + transform_path_non_affine = transform_path transform_path_non_affine.__doc__ = Transform.transform_path_non_affine.__doc__ - + def inverted(self): return PolarAxes.InvertedPolarTransform() inverted.__doc__ = Transform.inverted.__doc__ @@ -95,7 +95,7 @@ self._invalid = 0 return self._mtx get_matrix.__doc__ = Affine2DBase.get_matrix.__doc__ - + class InvertedPolarTransform(Transform): """ The inverse of the polar transform, mapping Cartesian @@ -130,7 +130,7 @@ class RadialLocator(Locator): """ Used to locate radius ticks. - + Ensures that all ticks are strictly positive. For all other tasks, it delegates to the base Locator (which may be different depending on the scale of the r-axis. @@ -155,12 +155,12 @@ return self.base.refresh() RESOLUTION = 75 - + def __init__(self, *args, **kwargs): """ Create a new Polar Axes for a polar plot. """ - + self._rpad = 0.05 Axes.__init__(self, *args, **kwargs) self.set_aspect('equal', adjustable='box', anchor='C') @@ -179,8 +179,6 @@ self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none') - self.title.set_y(1.06) - def _set_lim_and_transforms(self): self.dataLim = Bbox.unit() self.viewLim = Bbox.unit() @@ -239,9 +237,17 @@ self._yaxis_transform ) + def update_layout(self, renderer): + t_text, b_text = self.xaxis.get_text_heights(renderer) + l_text, r_text = self.yaxis.get_text_widths(renderer) + originalPosition = self.get_position(True) + title_offset = (b_text - originalPosition.transformed( + self.figure.transFigure).height) / 2.0 + self.titleOffsetTrans.clear().translate(0, title_offset) + def get_xaxis_transform(self): return self._xaxis_transform - + def get_xaxis_text1_transform(self, pixelPad): return self._xaxis_text1_transform, 'center', 'center' @@ -250,16 +256,16 @@ def get_yaxis_transform(self): return self._yaxis_transform - + def get_yaxis_text1_transform(self, pixelPad): return self._yaxis_text1_transform, 'center', 'center' def get_yaxis_text2_transform(self, pixelPad): return self._yaxis_text2_transform, 'center', 'center' - + def get_axes_patch(self): return Circle((0.5, 0.5), 0.5) - + def set_rmax(self, rmax): self.viewLim.y1 = rmax angle = self._r_label1_position.to_values()[4] @@ -275,7 +281,7 @@ Axes.set_yscale(self, *args, **kwargs) self.yaxis.set_major_locator( self.RadialLocator(self.yaxis.get_major_locator())) - + set_rscale = Axes.set_yscale set_rticks = Axes.set_yticks @@ -313,7 +319,7 @@ for t in self.xaxis.get_ticklabels(): t.update(kwargs) set_thetagrids.__doc__ = cbook.dedent(set_thetagrids.__doc__) % kwdocd - + def set_rgrids(self, radii, labels=None, angle=None, rpad=None, **kwargs): """ set the radial locations and labels of the r grids @@ -354,9 +360,9 @@ self._r_label2_position.clear().translate(angle, -self._rpad * rmax) for t in self.yaxis.get_ticklabels(): t.update(kwargs) - + set_rgrids.__doc__ = cbook.dedent(set_rgrids.__doc__) % kwdocd - + def set_xscale(self, scale, *args, **kwargs): if scale != 'linear': raise NotImplementedError("You can not set the xscale on a polar plot.") @@ -364,7 +370,7 @@ def set_xlim(self, *args, **kargs): # The xlim is fixed, no matter what you do self.viewLim.intervalx = (0.0, npy.pi * 2.0) - + def format_coord(self, theta, r): 'return a format string formatting the coordinate' theta /= math.pi @@ -387,7 +393,7 @@ Return True if this axes support the zoom box """ return False - + def start_pan(self, x, y, button): angle = self._r_label1_position.to_values()[4] / 180.0 * npy.pi mode = '' @@ -398,7 +404,7 @@ mode = 'drag_r_labels' elif button == 3: mode = 'zoom' - + self._pan_start = cbook.Bunch( rmax = self.get_rmax(), trans = self.transData.frozen(), @@ -411,14 +417,14 @@ def end_pan(self): del self._pan_start - + def drag_pan(self, button, key, x, y): p = self._pan_start - + if p.mode == 'drag_r_labels': startt, startr = p.trans_inverse.transform_point((p.x, p.y)) t, r = p.trans_inverse.transform_point((x, y)) - + # Deal with theta dt0 = t - startt dt1 = startt - t @@ -433,24 +439,24 @@ p.r_label_angle - dt, rpad) self._r_label2_position.clear().translate( p.r_label_angle - dt, -rpad) - + elif p.mode == 'zoom': startt, startr = p.trans_inverse.transform_point((p.x, p.y)) t, r = p.trans_inverse.transform_point((x, y)) - + dr = r - startr # Deal with r scale = r / startr self.set_rmax(p.rmax / scale) - + # These are a couple of aborted attempts to project a polar plot using # cubic bezier curves. - + # def transform_path(self, path): # twopi = 2.0 * npy.pi # halfpi = 0.5 * npy.pi - + # vertices = path.vertices # t0 = vertices[0:-1, 0] # t1 = vertices[1: , 0] @@ -469,7 +475,7 @@ # kappa = 4.0 * ((npy.sqrt(2.0) - 1.0) / 3.0) # kappa = 0.5 - + # p0 = vertices[0:-1] # p1 = vertices[1: ] @@ -497,17 +503,17 @@ # result[2::3, 0:1] = xk # result[2::3, 1: ] = yk - + # result[3::3] = p1 # print vertices[-2:] # print result[-2:] - + # return mpath.Path(result, codes) - + # twopi = 2.0 * npy.pi # halfpi = 0.5 * npy.pi - + # vertices = path.vertices # t0 = vertices[0:-1, 0] # t1 = vertices[1: , 0] @@ -518,7 +524,7 @@ # print "interpolate", interpolate # if interpolate > 1.0: # vertices = self.interpolate(vertices, interpolate) - + # result = npy.zeros((len(vertices) * 3 - 2, 2), npy.float_) # codes = mpath.Path.CURVE4 * npy.ones((len(vertices) * 3 - 2, ), mpath.Path.code_type) # result[0] = vertices[0] @@ -547,7 +553,7 @@ # result[2::3, 0] = t1 - (tkappa * td_scaled) # result[2::3, 1] = r1*hyp_kappa # # result[2::3, 1] = r1 / npy.cos(tkappa * td_scaled) # npy.sqrt(r1*r1 + ravg_kappa*ravg_kappa) - + # result[3::3, 0] = t1 # result[3::3, 1] = r1 @@ -556,4 +562,4 @@ # return mpath.Path(result, codes) # transform_path_non_affine = transform_path - + Modified: branches/transforms/lib/matplotlib/rcsetup.py =================================================================== --- branches/transforms/lib/matplotlib/rcsetup.py 2007-12-04 21:30:06 UTC (rev 4602) +++ branches/transforms/lib/matplotlib/rcsetup.py 2007-12-04 21:33:33 UTC (rev 4603) @@ -143,7 +143,7 @@ if len(s)==6 and s.isalnum(): # looks like hex return '#' + s - + if len(s)==7 and s.startswith('#') and s[1:].isalnum(): return s @@ -198,7 +198,7 @@ return float(s) except ValueError: raise ValueError('not a valid font size') - + def validate_font_properties(s): parse_fontconfig_pattern(s) return s @@ -369,7 +369,7 @@ 'mathtext.sf' : ['sans\-serif', validate_font_properties], 'mathtext.fontset' : ['cm', validate_fontset], 'mathtext.fallback_to_cm' : [True, validate_bool], - + 'image.aspect' : ['equal', validate_aspect], # equal, auto, a number 'image.interpolation' : ['bilinear', str], 'image.cmap' : ['jet', str], # one of gray, jet, etc @@ -440,12 +440,12 @@ 'figure.facecolor' : [ '0.75', validate_color], # facecolor; scalar gray 'figure.edgecolor' : [ 'w', validate_color], # edgecolor; white - 'figure.subplot.left' : [0.125, ValidateInterval(0, 1, closedmin=False, closedmax=False)], + 'figure.subplot.left' : [0.1, ValidateInterval(0, 1, closedmin=False, closedmax=False)], 'figure.subplot.right' : [0.9, ValidateInterval(0, 1, closedmin=False, closedmax=False)], 'figure.subplot.bottom' : [0.1, ValidateInterval(0, 1, closedmin=False, closedmax=False)], 'figure.subplot.top' : [0.9, ValidateInterval(0, 1, closedmin=False, closedmax=False)], - 'figure.subplot.wspace' : [0.2, ValidateInterval(0, 1, closedmin=False, closedmax=True)], - 'figure.subplot.hspace' : [0.2, ValidateInterval(0, 1, closedmin=False, closedmax=True)], + 'figure.subplot.wspace' : [0.1, ValidateInterval(0, 1, closedmin=False, closedmax=True)], + 'figure.subplot.hspace' : [0.1, ValidateInterval(0, 1, closedmin=False, closedmax=True)], 'savefig.dpi' : [100, validate_float], # DPI This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-12-05 15:36:50
|
Revision: 4615 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4615&view=rev Author: mdboom Date: 2007-12-05 07:36:48 -0800 (Wed, 05 Dec 2007) Log Message: ----------- Make new auto-layout stuff optional (so it can be experimented on without breaking too much.) Modified Paths: -------------- branches/transforms/examples/simple_plot.py branches/transforms/lib/matplotlib/figure.py branches/transforms/lib/matplotlib/rcsetup.py Modified: branches/transforms/examples/simple_plot.py =================================================================== --- branches/transforms/examples/simple_plot.py 2007-12-05 15:16:48 UTC (rev 4614) +++ branches/transforms/examples/simple_plot.py 2007-12-05 15:36:48 UTC (rev 4615) @@ -13,9 +13,6 @@ ylabel('voltage (mV)') title('About as simple as it gets, folks') grid(True) -axes().xaxis.set_label_position('top') -axes().xaxis.set_ticks_position('top') -axes().yaxis.set_label_position('right') #savefig('simple_plot.png') savefig('simple_plot') Modified: branches/transforms/lib/matplotlib/figure.py =================================================================== --- branches/transforms/lib/matplotlib/figure.py 2007-12-05 15:16:48 UTC (rev 4614) +++ branches/transforms/lib/matplotlib/figure.py 2007-12-05 15:36:48 UTC (rev 4615) @@ -151,6 +151,7 @@ self.clf() self._cachedRenderer = None + self._autoLayout = False def _get_dpi(self): return self._dpi @@ -159,6 +160,9 @@ self._dpi_scale_trans.clear().scale(dpi, dpi) dpi = property(_get_dpi, _set_dpi) + def enable_auto_layout(self, setting=True): + self._autoLayout = setting + def autofmt_xdate(self, bottom=0.2, rotation=30, ha='right'): """ A common use case is a number of subplots with shared xaxes @@ -628,8 +632,9 @@ # based on the tick and axis labels etc., and then makes sure # that any axes that began life aligned to another axes remains # aligned after these adjustments - if len(self.axes) > 1: + if self._autoLayout and len(self.axes) > 1: aligned_positions = [{}, {}, {}, {}] + sizes = [{}, {}] for a in self.axes: a.update_layout(renderer) orig_pos = a.get_position(True) @@ -642,6 +647,15 @@ pos[orig][1].add(curr) else: pos[orig] = [[a], set([curr])] + for size, orig, curr in zip(sizes, + orig_pos.size, + curr_pos.size): + orig = round(orig * 100.0) / 100.0 + if orig in size: + size[orig][0].append(a) + size[orig][1].add(curr) + else: + size[orig] = [[a], set([curr])] for i, pos in enumerate(aligned_positions): for axes, places in pos.values(): @@ -654,7 +668,19 @@ curr_pos = a.get_position().frozen() curr_pos.get_points()[i/2, i%2] = curr a.set_position(curr_pos, 'active') - else: + + for i, size in enumerate(sizes): + for axes, dims in size.values(): + new = min(dims) + for a in axes: + curr_pos = a.get_position().frozen() + curr = curr_pos.size[i] + if curr > new: + extra = (curr - new) * 0.5 + curr_pos.get_points()[0, i] += extra + curr_pos.get_points()[1, i] -= extra + a.set_position(curr_pos, 'active') + elif self._autoLayout: for a in self.axes: a.update_layout(renderer) # render the axes Modified: branches/transforms/lib/matplotlib/rcsetup.py =================================================================== --- branches/transforms/lib/matplotlib/rcsetup.py 2007-12-05 15:16:48 UTC (rev 4614) +++ branches/transforms/lib/matplotlib/rcsetup.py 2007-12-05 15:36:48 UTC (rev 4615) @@ -440,12 +440,12 @@ 'figure.facecolor' : [ '0.75', validate_color], # facecolor; scalar gray 'figure.edgecolor' : [ 'w', validate_color], # edgecolor; white - 'figure.subplot.left' : [0.1, ValidateInterval(0, 1, closedmin=False, closedmax=False)], + 'figure.subplot.left' : [0.125, ValidateInterval(0, 1, closedmin=False, closedmax=False)], 'figure.subplot.right' : [0.9, ValidateInterval(0, 1, closedmin=False, closedmax=False)], 'figure.subplot.bottom' : [0.1, ValidateInterval(0, 1, closedmin=False, closedmax=False)], 'figure.subplot.top' : [0.9, ValidateInterval(0, 1, closedmin=False, closedmax=False)], - 'figure.subplot.wspace' : [0.1, ValidateInterval(0, 1, closedmin=False, closedmax=True)], - 'figure.subplot.hspace' : [0.1, ValidateInterval(0, 1, closedmin=False, closedmax=True)], + 'figure.subplot.wspace' : [0.2, ValidateInterval(0, 1, closedmin=False, closedmax=True)], + 'figure.subplot.hspace' : [0.2, ValidateInterval(0, 1, closedmin=False, closedmax=True)], 'savefig.dpi' : [100, validate_float], # DPI This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-12-05 15:39:46
|
Revision: 4616 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4616&view=rev Author: mdboom Date: 2007-12-05 07:39:39 -0800 (Wed, 05 Dec 2007) Log Message: ----------- Merged revisions 4562-4615 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r4571 | jdh2358 | 2007-12-03 21:06:52 -0500 (Mon, 03 Dec 2007) | 1 line applied barrys cocoaagg patch ........ r4572 | jdh2358 | 2007-12-03 22:18:39 -0500 (Mon, 03 Dec 2007) | 1 line colormapped histogram ........ r4576 | jdh2358 | 2007-12-04 09:38:48 -0500 (Tue, 04 Dec 2007) | 2 lines added additional lines to MANIFEST.in ........ r4586 | mdboom | 2007-12-04 14:34:11 -0500 (Tue, 04 Dec 2007) | 2 lines Support '|' as a symbol in mathtext. ........ r4606 | jdh2358 | 2007-12-04 21:47:07 -0500 (Tue, 04 Dec 2007) | 1 line updated install doc ........ r4613 | dsdale | 2007-12-05 09:45:56 -0500 (Wed, 05 Dec 2007) | 2 lines removed .cvsignore files, they are not needed ........ r4614 | jdh2358 | 2007-12-05 10:16:48 -0500 (Wed, 05 Dec 2007) | 2 lines exposed default color cycle ........ Modified Paths: -------------- branches/transforms/API_CHANGES branches/transforms/CODING_GUIDE branches/transforms/INSTALL branches/transforms/MANIFEST.in branches/transforms/examples/poly_editor.py branches/transforms/lib/matplotlib/__init__.py branches/transforms/lib/matplotlib/_mathtext_data.py branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/backends/backend_cocoaagg.py branches/transforms/lib/matplotlib/image.py branches/transforms/lib/matplotlib/mathtext.py branches/transforms/matplotlibrc.template Added Paths: ----------- branches/transforms/examples/hist_colormapped.py Removed Paths: ------------- branches/transforms/.cvsignore branches/transforms/examples/.cvsignore branches/transforms/lib/matplotlib/.cvsignore branches/transforms/lib/matplotlib/backends/.cvsignore branches/transforms/lib/matplotlib/numerix/.cvsignore branches/transforms/lib/matplotlib/numerix/mlab/.cvsignore Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-4561 + /trunk/matplotlib:1-4615 Deleted: branches/transforms/.cvsignore =================================================================== --- branches/transforms/.cvsignore 2007-12-05 15:36:48 UTC (rev 4615) +++ branches/transforms/.cvsignore 2007-12-05 15:39:39 UTC (rev 4616) @@ -1,6 +0,0 @@ -build -dist -docs -*.pyc -.project -matplotlibrc Modified: branches/transforms/API_CHANGES =================================================================== --- branches/transforms/API_CHANGES 2007-12-05 15:36:48 UTC (rev 4615) +++ branches/transforms/API_CHANGES 2007-12-05 15:39:39 UTC (rev 4616) @@ -169,6 +169,8 @@ END OF TRANSFORMS REFACTORING + Removed, dead/experimental ExampleInfo, Namespace and Importer + code from matplotlib/__init__.py 0.91.1 Released 0.91.0 Released Modified: branches/transforms/CODING_GUIDE =================================================================== --- branches/transforms/CODING_GUIDE 2007-12-05 15:36:48 UTC (rev 4615) +++ branches/transforms/CODING_GUIDE 2007-12-05 15:39:39 UTC (rev 4616) @@ -39,8 +39,11 @@ * If you have altered extension code, do you pass unit/memleak_hawaii.py? + * if you have added new files or directories, or reorganized + existing ones, are the new files included in the match patterns in + MANIFEST.in. This file determines what goes into the src + distribution of the mpl build. - == Importing and name spaces == For numpy, use: Modified: branches/transforms/INSTALL =================================================================== --- branches/transforms/INSTALL 2007-12-05 15:36:48 UTC (rev 4615) +++ branches/transforms/INSTALL 2007-12-05 15:39:39 UTC (rev 4616) @@ -1,42 +1,42 @@ + INTRODUCTION - matplotlib requires at a minimum python 2.2+, Numeric or numarray - and freetype. To get the most out of matplotlib, you will want to - build some of the optional GUI and image extensions, discussed - below. Matplotlib is known to work on linux, unix, win32 and OS X + matplotlib requires at a minimum python 2.3, numpy, libpng and + freetype. To get the most out of matplotlib, you will want to build + some of the optional GUI and image extensions, discussed below. + Matplotlib is known to work on linux, unix, win32 and OS X platforms. There are two kinds of matplotlib backends: vector based and raster - based. The vector based backends, SVG and PS, produce ASCII text - output files *.svg and *.ps. The core raster based renderer is the - http://antigrain.com (agg) backend. This is a high quality 2D - library that supports fast antialiasing, alpha blending and much - more. If you want to produce PNGs or GUI images that support all of - matplotlib's features, you should compile matplotlib with agg - support and use one of the GUI agg backends: GTKAgg, WXAgg, TkAgg or - FLTKAgg. + based. The vector based backends, SVG, PDF and PS, produce ASCII + text output files *.svg, *.pdf and *.ps. The core raster based + renderer is the http://antigrain.com (agg) backend. This is a high + quality 2D library that supports fast antialiasing, alpha blending + and much more. If you want to produce PNGs or GUI images that + support all of matplotlib's features, you should compile matplotlib + with agg support and use one of the GUI agg backends: GTKAgg, WXAgg, + TkAgg or FLTKAgg. COMPILING - You will need to have recent versions of freetype (>= 2.1.7), libpng - and zlib installed on your system. If you are using a package - manager, also make sure the devel versions of these packages are - also installed (eg freetype-devel). + You will need to have recent versions of freetype, libpng and zlib + installed on your system. If you are using a package manager, also + make sure the devel versions of these packages are also installed + (eg freetype-devel). - The top of setup.py contains some flags controlling which backends - will be built. If you want to use a GUI backend, you will need - either Tkinter, pygtk or wxpython installed on your system, from src - or from a package manager including the devel packages. You can - choose which backends to enable by setting the flags in setup.py, - but the 'auto' flags will work in most cases, as matplotlib tries to - find a GUI and build the backend acccordingly. If you know you - don't want a particular backend or extension, you can set that flag - to False. + matplotlib ships with a setup.cfg.template which you can use to + customize the build process. Copy it to setup.cfg if you need to + customize something. See that files for details of the parameters + you can set. - As discussed above, most users will want to set 'BUILD_AGG = 1' and - one or more of the GUI backends to True. Exceptions to this are if - you know you don't need a GUI (eg a web server) or you only want to - produce vector graphics. + If you want to use a GUI backend, you will need either Tkinter, + pygtk or wxpython installed on your system, from src or from a + package manager including the devel packages. You can choose which + backends to enable by setting the flags in setup.py, but the default + is to automatically detect your installed GUIs and build support for + them. If you later find that you did not have a GUI toolkit like + pygtk installed when you built matplotlib, but now want it, you will + need to install the toolkit and rebuild matplotlib. If you have installed prerequisites to nonstandard places and need to inform matplotlib where they are, edit setupext.py an add the @@ -45,13 +45,6 @@ /some/path/include/somheader.h, put /some/path in the basedir list for your platform. - matplotlib works with with Numeric or numarray. At compile time, - setup.py will look for both packages and compile the appropriate - extensions into matplotlib. At runtime, the correct extension code - will be chosen based on your numerix setting in matplotlibrc. If - you want to be able to use either Numeric or numarray efficiently - with matplotlib, it is important that you have *both* present and in - your PYTHONPATH when you compile matplotlib. Once you have everything above set to your liking, just do the usual thing @@ -62,20 +55,19 @@ WINDOWS If you don't already have python installed, you may want to consider - using the enthought edition of python, which has (old) scipy, Numeric, and + using the enthought edition of python, which has scipy, numpy, and wxpython, plus a lot of other goodies, preinstalled - http://www.enthought.com/python . With the enthought edition of python + matplotlib installer, the following backends should work - out of the box: agg, wx, wxagg, tkagg, ps and svg. + out of the box: agg, wx, wxagg, tkagg, ps, pdf and svg. For standard python installations, you will also need to install - either numpy, Numeric or numarray in addition to the matplotlib installer. - With a standard python + Numeric/numarray + matplotlib, the - following backends should work on windows: agg, tkagg, ps, svg. If - you want others, eg a wx, wxagg, gtk or gtkagg, you'll need to - install the requisite GUI toolkits. This is fairly easy, as both - wxpython and pygtk come with windows friendly installers. The - latter includes an additional requirement of the GTK runtime. + either numpy, in addition to the matplotlib installer. On some + systems you will also need to download msvcp71.dll library, which + you can download from + http://www.dll-files.com/dllindex/dll-files.shtml?msvcp71 or other + sites. You will need to unzip the archive and drag the dll into + c:\windows\system32 All of the GUI backends run on windows, but TkAgg is probably the best for interactive use from the standard python shell or ipython. @@ -113,18 +105,9 @@ DEBIAN - Vittorio Palmisano <re...@em...> maintails the debian - packages at http://mentors.debian.net + matplotlib is part of debian (and ubuntu) so you shoule be able to + apt-get install it. - - * add this lines to your /etc/apt/sources.list: - deb http://anakonda.altervista.org/debian packages/ - deb-src http://anakonda.altervista.org/debian sources/ - - * then run: - # apt-get update - # apt-get install python-matplotlib python-matplotlib-doc - FREEBSD http://www.freshports.org/math/py-matplotlib/ Modified: branches/transforms/MANIFEST.in =================================================================== --- branches/transforms/MANIFEST.in 2007-12-05 15:36:48 UTC (rev 4615) +++ branches/transforms/MANIFEST.in 2007-12-05 15:39:39 UTC (rev 4616) @@ -5,8 +5,13 @@ include __init__.py setupext.py setup.py setupegg.py makeswig.py include examples/data/* include lib/matplotlib/toolkits +include lib/matplotlib/mpl-data/matplotlib.conf +include lib/matplotlib/mpl-data/matplotlib.conf.template +include lib/matplotlib/mpl-data/lineprops.glade +include lib/matplotlib/mpl-data/matplotlibrc include lib/matplotlib/mpl-data/images/* include lib/matplotlib/mpl-data/fonts/ttf/* +include lib/matplotlib/mpl-data/fonts/pdfcorefonts/* include lib/matplotlib/mpl-data/fonts/afm/* recursive-include license LICENSE* recursive-include examples README *.py Deleted: branches/transforms/examples/.cvsignore =================================================================== --- branches/transforms/examples/.cvsignore 2007-12-05 15:36:48 UTC (rev 4615) +++ branches/transforms/examples/.cvsignore 2007-12-05 15:39:39 UTC (rev 4616) @@ -1,8 +0,0 @@ -*.eps -*.jpeg -*.jpg -*.pdf -*.png -*.ps -*.pyc -*.svg Copied: branches/transforms/examples/hist_colormapped.py (from rev 4614, trunk/matplotlib/examples/hist_colormapped.py) =================================================================== --- branches/transforms/examples/hist_colormapped.py (rev 0) +++ branches/transforms/examples/hist_colormapped.py 2007-12-05 15:39:39 UTC (rev 4616) @@ -0,0 +1,24 @@ +import numpy as n +from pylab import figure, show +import matplotlib.cm as cm +import matplotlib.colors as colors + +fig = figure() +ax = fig.add_subplot(111) +Ntotal = 1000 +N, bins, patches = ax.hist(n.random.rand(Ntotal), 20) + +#I'll color code by height, but you could use any scalar + + +# we need to normalize the data to 0..1 for the full +# range of the colormap +fracs = N.astype(float)/N.max() +norm = colors.normalize(fracs.min(), fracs.max()) + +for thisfrac, thispatch in zip(fracs, patches): + color = cm.jet(norm(thisfrac)) + thispatch.set_facecolor(color) + + +show() Modified: branches/transforms/examples/poly_editor.py =================================================================== --- branches/transforms/examples/poly_editor.py 2007-12-05 15:36:48 UTC (rev 4615) +++ branches/transforms/examples/poly_editor.py 2007-12-05 15:39:39 UTC (rev 4616) @@ -9,8 +9,6 @@ from matplotlib.mlab import dist_point_to_segment - - class PolygonInteractor: """ An polygon editor. @@ -74,7 +72,7 @@ xyt = self.poly.get_transform().transform(xy) xt, yt = xyt[:, 0], xyt[:, 1] d = sqrt((xt-event.x)**2 + (yt-event.y)**2) - indseq = nonzero(equal(d, amin(d))) + indseq = nonzero(equal(d, amin(d)))[0] ind = indseq[0] if d[ind]>=self.epsilon: @@ -129,6 +127,7 @@ if event.inaxes is None: return if event.button != 1: return x,y = event.xdata, event.ydata + self.poly.xy[self._ind] = x,y self.line.set_data(zip(*self.poly.xy)) @@ -161,7 +160,7 @@ ax.add_patch(poly) p = PolygonInteractor( ax, poly) -ax.add_line(p.line) +#ax.add_line(p.line) ax.set_title('Click and drag a point to move it') ax.set_xlim((-2,2)) ax.set_ylim((-2,2)) Deleted: branches/transforms/lib/matplotlib/.cvsignore =================================================================== --- branches/transforms/lib/matplotlib/.cvsignore 2007-12-05 15:36:48 UTC (rev 4615) +++ branches/transforms/lib/matplotlib/.cvsignore 2007-12-05 15:39:39 UTC (rev 4616) @@ -1,2 +0,0 @@ -*.pyc -.cvsignore \ No newline at end of file Modified: branches/transforms/lib/matplotlib/__init__.py =================================================================== --- branches/transforms/lib/matplotlib/__init__.py 2007-12-05 15:36:48 UTC (rev 4615) +++ branches/transforms/lib/matplotlib/__init__.py 2007-12-05 15:39:39 UTC (rev 4616) @@ -55,7 +55,7 @@ """ from __future__ import generators -__version__ = '0.91.1' +__version__ = '0.91.2svn' __revision__ = '$Revision$' __date__ = '$Date$' @@ -784,60 +784,3 @@ verbose.report('platform is %s'%sys.platform) verbose.report('loaded modules: %s'%sys.modules.keys(), 'debug') -class ExampleInfo: - pass - -class ExampleManager: - baseurl = 'http://matplotlib.sf.net' - urls = ['%s/%s'%(baseurl, subdir) for subdir in - ( 'examples', 'examples/widgets')] - - def get_examples(self): - import urllib, re - rgx = re.compile('.*<A HREF="([^.]+\.py)">.*') - examples = [] - for url in urls: - lines = urllib.urlopen(url).readlines() - for line in lines: - m = rgx.match(line) - if m is not None: - examples.append('%s/%s'%(url, m.group(1))) - return examples - - def get_info(self, s): - """ - return an ExampleInfo instance from s, the string content of - an example - """ - pass - -class Namespace: - """ - A class which takes a list of modules and creates an object with - the module naems at attrs - """ - def __init__(self, namespace): - for k,v in namespace.items(): - modname = getattr(v, '__name__', None) - if modname is None: continue - if modname.startswith('matplotlib.'): - self.__dict__[modname.replace('matplotlib.', '')] = v - - -class Importer: - def __init__(self, modstr): - """ - import a bunch of matplotlib modules listed in modstr into a - single namespace. Eg, - - mpl = Importer('artist, cbook, lines, patches') - print mpl.cbook.iterable(1) - """ - for name in modstr.split(','): - name = name.strip() - wholename = '.'.join(['matplotlib', name]) - basemod = __import__(wholename) - mod = getattr(basemod, name) - setattr(self, name, mod) - - Modified: branches/transforms/lib/matplotlib/_mathtext_data.py =================================================================== --- branches/transforms/lib/matplotlib/_mathtext_data.py 2007-12-05 15:36:48 UTC (rev 4615) +++ branches/transforms/lib/matplotlib/_mathtext_data.py 2007-12-05 15:39:39 UTC (rev 4616) @@ -88,7 +88,8 @@ r'\phi' : ('cmmi10', 42), r'\chi' : ('cmmi10', 17), r'\psi' : ('cmmi10', 31), - + r'|' : ('cmsy10', 47), + r'\|' : ('cmsy10', 47), r'(' : ('cmr10', 119), r'\leftparen' : ('cmr10', 119), r'\rightparen' : ('cmr10', 68), @@ -1771,6 +1772,7 @@ 'succnsim': 8937, 'gimel': 8503, 'vert': 124, +'|': 124, 'varrho': 1009, 'P': 182, 'approxident': 8779, Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-12-05 15:36:48 UTC (rev 4615) +++ branches/transforms/lib/matplotlib/axes.py 2007-12-05 15:39:39 UTC (rev 4616) @@ -150,13 +150,14 @@ an arbitrary number of x, y, fmt are allowed """ + defaultColors = ['b','g','r','c','m','y','k'] def __init__(self, axes, command='plot'): self.axes = axes self.command = command self._clear_color_cycle() def _clear_color_cycle(self): - self.colors = ['b','g','r','c','m','y','k'] + self.colors = _process_plot_var_args.defaultColors[:] # if the default line color is a color format string, move it up # in the que try: ind = self.colors.index(rcParams['lines.color']) Deleted: branches/transforms/lib/matplotlib/backends/.cvsignore =================================================================== --- branches/transforms/lib/matplotlib/backends/.cvsignore 2007-12-05 15:36:48 UTC (rev 4615) +++ branches/transforms/lib/matplotlib/backends/.cvsignore 2007-12-05 15:39:39 UTC (rev 4616) @@ -1,2 +0,0 @@ -*.pyc -.cvsignore \ No newline at end of file Modified: branches/transforms/lib/matplotlib/backends/backend_cocoaagg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_cocoaagg.py 2007-12-05 15:36:48 UTC (rev 4615) +++ branches/transforms/lib/matplotlib/backends/backend_cocoaagg.py 2007-12-05 15:39:39 UTC (rev 4616) @@ -78,8 +78,8 @@ self.plotWindow.setDelegate_(self)#.plotView) self.plotView.setImageFrameStyle_(NSImageFrameGroove) - self.plotView.image = NSImage.alloc().initWithSize_((0,0)) - self.plotView.setImage_(self.plotView.image) + self.plotView.image_ = NSImage.alloc().initWithSize_((0,0)) + self.plotView.setImage_(self.plotView.image_) # Make imageview first responder for key events self.plotWindow.makeFirstResponder_(self.plotView) @@ -112,10 +112,10 @@ w,h = self.canvas.get_width_height() # Remove all previous images - for i in xrange(self.image.representations().count()): - self.image.removeRepresentation_(self.image.representations().objectAtIndex_(i)) + for i in xrange(self.image_.representations().count()): + self.image_.removeRepresentation_(self.image_.representations().objectAtIndex_(i)) - self.image.setSize_((w,h)) + self.image_.setSize_((w,h)) brep = NSBitmapImageRep.alloc().initWithBitmapDataPlanes_pixelsWide_pixelsHigh_bitsPerSample_samplesPerPixel_hasAlpha_isPlanar_colorSpaceName_bytesPerRow_bitsPerPixel_( (self.canvas.buffer_rgba(0,0),'','','',''), # Image data @@ -129,7 +129,7 @@ w*4, # row bytes 32) # bits per pixel - self.image.addRepresentation_(brep) + self.image_.addRepresentation_(brep) self.setNeedsDisplay_(True) def windowDidResize_(self, sender): Modified: branches/transforms/lib/matplotlib/image.py =================================================================== --- branches/transforms/lib/matplotlib/image.py 2007-12-05 15:36:48 UTC (rev 4615) +++ branches/transforms/lib/matplotlib/image.py 2007-12-05 15:39:39 UTC (rev 4616) @@ -239,6 +239,8 @@ self.set_data(A) + + def set_extent(self, extent): """extent is data axes (left, right, bottom, top) for making image plots """ Modified: branches/transforms/lib/matplotlib/mathtext.py =================================================================== --- branches/transforms/lib/matplotlib/mathtext.py 2007-12-05 15:36:48 UTC (rev 4615) +++ branches/transforms/lib/matplotlib/mathtext.py 2007-12-05 15:39:39 UTC (rev 4616) @@ -2019,7 +2019,7 @@ ).setParseAction(self.customspace).setName('customspace') unicode_range = u"\U00000080-\U0001ffff" - symbol =(Regex(UR"([a-zA-Z0-9 +\-*/<>=:,.;!'@()%s])|(\\[%%${}\[\]_])" % unicode_range) + symbol =(Regex(UR"([a-zA-Z0-9 +\-*/<>=:,.;!'@()|%s])|(\\[%%${}\[\]_|])" % unicode_range) | Combine( bslash + oneOf(tex2uni.keys()) Deleted: branches/transforms/lib/matplotlib/numerix/.cvsignore =================================================================== --- branches/transforms/lib/matplotlib/numerix/.cvsignore 2007-12-05 15:36:48 UTC (rev 4615) +++ branches/transforms/lib/matplotlib/numerix/.cvsignore 2007-12-05 15:39:39 UTC (rev 4616) @@ -1,2 +0,0 @@ -*.pyc -.cvsignore \ No newline at end of file Deleted: branches/transforms/lib/matplotlib/numerix/mlab/.cvsignore =================================================================== --- branches/transforms/lib/matplotlib/numerix/mlab/.cvsignore 2007-12-05 15:36:48 UTC (rev 4615) +++ branches/transforms/lib/matplotlib/numerix/mlab/.cvsignore 2007-12-05 15:39:39 UTC (rev 4616) @@ -1 +0,0 @@ -*.pyc Modified: branches/transforms/matplotlibrc.template =================================================================== --- branches/transforms/matplotlibrc.template 2007-12-05 15:36:48 UTC (rev 4615) +++ branches/transforms/matplotlibrc.template 2007-12-05 15:39:39 UTC (rev 4616) @@ -25,7 +25,7 @@ #### CONFIGURATION BEGINS HERE # the default backend; one of GTK GTKAgg GTKCairo FltkAgg QtAgg TkAgg -# Agg Cairo GD GDK Paint PS PDF SVG Template +# WX WXAgg Agg Cairo GD GDK Paint PS PDF SVG Template backend : %(backend)s numerix : %(numerix)s # numpy, Numeric or numarray #maskedarray : False # True to use external maskedarray module This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-12-05 16:28:14
|
Revision: 4619 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4619&view=rev Author: mdboom Date: 2007-12-05 08:28:05 -0800 (Wed, 05 Dec 2007) Log Message: ----------- Merged revisions 4616-4618 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r4618 | mdboom | 2007-12-05 11:20:54 -0500 (Wed, 05 Dec 2007) | 2 lines Support arbitrary rotation of usetex text. ........ Modified Paths: -------------- branches/transforms/lib/matplotlib/backends/backend_agg.py branches/transforms/lib/matplotlib/texmanager.py branches/transforms/src/_backend_agg.cpp branches/transforms/src/_image.cpp Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-4615 + /trunk/matplotlib:1-4618 Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-12-05 16:20:54 UTC (rev 4618) +++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-12-05 16:28:05 UTC (rev 4619) @@ -71,7 +71,7 @@ self.tostring_rgba_minimized = self._renderer.tostring_rgba_minimized self.mathtext_parser = MathTextParser('Agg') self._fontd = {} - + self.bbox = Bbox.from_bounds(0, 0, self.width, self.height) if __debug__: verbose.report('RendererAgg.__init__ done', 'debug-annoying') @@ -84,7 +84,7 @@ 'debug-annoying') ox, oy, width, height, descent, font_image, used_characters = \ self.mathtext_parser.parse(s, self.dpi, prop) - + x = int(x) + ox y = int(y) - oy self._renderer.draw_text_image(font_image, x, y + 1, angle, gc) @@ -112,7 +112,7 @@ self._renderer.draw_text_image(font.get_image(), int(x), int(y) + 1, angle, gc) - def get_text_width_height_descent(self, s, prop, ismath, rgb=(0,0,0)): + def get_text_width_height_descent(self, s, prop, ismath): """ get the width and height in display coords of the string s with FontPropertry prop @@ -125,8 +125,8 @@ # todo: handle props size = prop.get_size_in_points() texmanager = self.get_texmanager() - Z = texmanager.get_rgba(s, size, self.dpi, rgb) - m,n,tmp = Z.shape + Z = texmanager.get_grey(s, size, self.dpi) + m,n = Z.shape # TODO: descent of TeX text (I am imitating backend_ps here -JKS) return n, m, 0 @@ -145,45 +145,18 @@ def draw_tex(self, gc, x, y, s, prop, angle): # todo, handle props, angle, origins - rgb = gc.get_rgb() size = prop.get_size_in_points() dpi = self.dpi - flip = angle==90 - w,h,d = self.get_text_width_height_descent(s, prop, 'TeX', rgb) - if flip: - w,h = h,w - x -= w - texmanager = self.get_texmanager() - key = s, size, dpi, rgb, angle, texmanager.get_font_config() + key = s, size, dpi, angle, texmanager.get_font_config() im = self.texd.get(key) if im is None: - Z = texmanager.get_rgba(s, size, dpi, rgb) - if flip: - r = Z[:,:,0] - g = Z[:,:,1] - b = Z[:,:,2] - a = Z[:,:,3] - m,n,tmp = Z.shape + Z = texmanager.get_grey(s, size, dpi) + Z = npy.array(Z * 255.0, npy.uint8) - def func(x): - return npy.transpose(npy.fliplr(x)) + self._renderer.draw_text_image(Z, x, y, angle, gc) - Z = npy.zeros((n,m,4), float) - Z[:,:,0] = func(r) - Z[:,:,1] = func(g) - Z[:,:,2] = func(b) - Z[:,:,3] = func(a) - im = fromarray(Z, 1) - im.flipud_out() - self.texd[key] = im - - cliprect = gc.get_clip_rectangle() - if cliprect is None: bbox = None - else: bbox = Bbox.from_bounds(*cliprect) - self.draw_image(x, self.height-y, im, bbox) - def get_canvas_width_height(self): 'return the canvas width and height in display coords' return self.width, self.height @@ -217,7 +190,7 @@ if __debug__: verbose.report('RendererAgg.points_to_pixels', 'debug-annoying') return points*self.dpi/72.0 - + def tostring_rgb(self): if __debug__: verbose.report('RendererAgg.tostring_rgb', 'debug-annoying') @@ -314,8 +287,8 @@ FigureCanvasAgg.draw(self) self.get_renderer()._renderer.write_rgba(str(filename)) print_rgba = print_raw - + def print_png(self, filename, *args, **kwargs): FigureCanvasAgg.draw(self) self.get_renderer()._renderer.write_png(filename, self.figure.dpi) - + Modified: branches/transforms/lib/matplotlib/texmanager.py =================================================================== --- branches/transforms/lib/matplotlib/texmanager.py 2007-12-05 16:20:54 UTC (rev 4618) +++ branches/transforms/lib/matplotlib/texmanager.py 2007-12-05 16:28:05 UTC (rev 4619) @@ -79,7 +79,8 @@ dvipngVersion = get_dvipng_version() # mappable cache of - arrayd = {} + rgba_arrayd = {} + grey_arrayd = {} postscriptd = {} pscnt = 0 @@ -131,7 +132,7 @@ found_font = self.font_info[font.lower()] setattr(self, font_family_attr, self.font_info[font.lower()]) - if DEBUG: + if DEBUG: print 'family: %s, font: %s, info: %s'%(font_family, font, self.font_info[font.lower()]) break @@ -323,6 +324,24 @@ return [int(val) for val in line.split()[1:]] raise RuntimeError('Could not parse %s'%psfile) + def get_grey(self, tex, fontsize=None, dpi=None): + key = tex, self.get_font_config(), fontsize, dpi + alpha = self.grey_arrayd.get(key) + + if alpha is None: + pngfile = self.make_png(tex, fontsize, dpi) + X = readpng(os.path.join(self.texcache, pngfile)) + + if (self.dvipngVersion < '1.6') or rcParams['text.dvipnghack']: + # hack the alpha channel as described in comment above + alpha = npy.sqrt(1-X[:,:,0]) + else: + alpha = X[:,:,-1] + + self.grey_arrayd[key] = alpha + return alpha + + def get_rgba(self, tex, fontsize=None, dpi=None, rgb=(0,0,0)): """ Return tex string as an rgba array @@ -351,23 +370,16 @@ if not dpi: dpi = rcParams['savefig.dpi'] r,g,b = rgb key = tex, self.get_font_config(), fontsize, dpi, tuple(rgb) - Z = self.arrayd.get(key) + Z = self.rgba_arrayd.get(key) if Z is None: - pngfile = self.make_png(tex, fontsize, dpi) - X = readpng(os.path.join(self.texcache, pngfile)) + alpha = self.get_grey(tex, fontsize, dpi) - if (self.dvipngVersion < '1.6') or rcParams['text.dvipnghack']: - # hack the alpha channel as described in comment above - alpha = npy.sqrt(1-X[:,:,0]) - else: - alpha = X[:,:,-1] - - Z = npy.zeros(X.shape, npy.float) + Z = npy.zeros((X.shape[0], X.shape[1], 4), npy.float) Z[:,:,0] = r Z[:,:,1] = g Z[:,:,2] = b Z[:,:,3] = alpha - self.arrayd[key] = Z + self.rgba_arrayd[key] = Z return Z Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-12-05 16:20:54 UTC (rev 4618) +++ branches/transforms/src/_backend_agg.cpp 2007-12-05 16:28:05 UTC (rev 4619) @@ -658,9 +658,25 @@ args.verify_length(5); - FT2Image *image = static_cast<FT2Image*>(args[0].ptr()); - if (!image->get_buffer()) - return Py::Object(); + const unsigned char* buffer = NULL; + int width, height; + Py::Object image_obj = args[0]; + if (PyArray_Check(image_obj.ptr())) { + PyArrayObject* image_array = NULL; + image_array = (PyArrayObject*)PyArray_FromObject(image_obj.ptr(), PyArray_UBYTE, 2, 2); + if (!image_array) + throw Py::ValueError("First argument to draw_text_image must be a FT2Font.Image object or a Nx2 uint8 numpy array."); + buffer = (unsigned char *)PyArray_DATA(image_array); + width = PyArray_DIM(image_array, 1); + height = PyArray_DIM(image_array, 0); + } else { + FT2Image *image = static_cast<FT2Image*>(args[0].ptr()); + if (!image->get_buffer()) + throw Py::ValueError("First argument to draw_text_image must be a FT2Font.Image object or a Nx2 uint8 numpy array."); + buffer = image->get_buffer(); + width = image->get_width(); + height = image->get_height(); + } int x(0),y(0); try { @@ -680,22 +696,19 @@ rendererBase->reset_clipping(true); set_clipbox(gc.cliprect, theRasterizer); - const unsigned char* const buffer = image->get_buffer(); - agg::rendering_buffer srcbuf - ((agg::int8u*)buffer, image->get_width(), - image->get_height(), image->get_width()); + agg::rendering_buffer srcbuf((agg::int8u*)buffer, width, height, width); agg::pixfmt_gray8 pixf_img(srcbuf); agg::trans_affine mtx; - mtx *= agg::trans_affine_translation(0, -(int)image->get_height()); + mtx *= agg::trans_affine_translation(0, -height); mtx *= agg::trans_affine_rotation(-angle * agg::pi / 180.0); mtx *= agg::trans_affine_translation(x, y); agg::path_storage rect; rect.move_to(0, 0); - rect.line_to(image->get_width(), 0); - rect.line_to(image->get_width(), image->get_height()); - rect.line_to(0, image->get_height()); + rect.line_to(width, 0); + rect.line_to(width, height); + rect.line_to(0, height); rect.line_to(0, 0); agg::conv_transform<agg::path_storage> rect2(rect, mtx); Modified: branches/transforms/src/_image.cpp =================================================================== --- branches/transforms/src/_image.cpp 2007-12-05 16:20:54 UTC (rev 4618) +++ branches/transforms/src/_image.cpp 2007-12-05 16:28:05 UTC (rev 4619) @@ -805,7 +805,7 @@ char _image_module_readpng__doc__[] = "readpng(fname)\n" "\n" -"Load an image from png file into a numerix array of MxNx4 uint8"; +"Load an image from png file into a numerix array of MxNx4 float"; Py::Object _image_module::readpng(const Py::Tuple& args) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-12-05 16:38:03
|
Revision: 4621 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4621&view=rev Author: mdboom Date: 2007-12-05 08:38:01 -0800 (Wed, 05 Dec 2007) Log Message: ----------- Merged revisions 4619-4620 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r4620 | mdboom | 2007-12-05 11:35:26 -0500 (Wed, 05 Dec 2007) | 2 lines Fix reference leak in draw_text_image. ........ Modified Paths: -------------- branches/transforms/src/_backend_agg.cpp Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-4618 + /trunk/matplotlib:1-4620 Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-12-05 16:35:26 UTC (rev 4620) +++ branches/transforms/src/_backend_agg.cpp 2007-12-05 16:38:01 UTC (rev 4621) @@ -661,8 +661,8 @@ const unsigned char* buffer = NULL; int width, height; Py::Object image_obj = args[0]; + PyArrayObject* image_array = NULL; if (PyArray_Check(image_obj.ptr())) { - PyArrayObject* image_array = NULL; image_array = (PyArrayObject*)PyArray_FromObject(image_obj.ptr(), PyArray_UBYTE, 2, 2); if (!image_array) throw Py::ValueError("First argument to draw_text_image must be a FT2Font.Image object or a Nx2 uint8 numpy array."); @@ -685,6 +685,7 @@ } catch (Py::TypeError) { //x,y out of range; todo issue warning? + Py_XDECREF(image_array); return Py::Object(); } @@ -727,6 +728,8 @@ theRasterizer->add_path(rect2); agg::render_scanlines(*theRasterizer, *slineP8, ri); + Py_XDECREF(image_array); + return Py::Object(); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-12-05 18:14:40
|
Revision: 4624 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4624&view=rev Author: mdboom Date: 2007-12-05 10:14:38 -0800 (Wed, 05 Dec 2007) Log Message: ----------- Make autolayout a configuration option. Modified Paths: -------------- branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/config/mplconfig.py branches/transforms/lib/matplotlib/config/rcsetup.py branches/transforms/lib/matplotlib/figure.py branches/transforms/lib/matplotlib/rcsetup.py branches/transforms/matplotlibrc.template Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-12-05 17:25:34 UTC (rev 4623) +++ branches/transforms/lib/matplotlib/axes.py 2007-12-05 18:14:38 UTC (rev 4624) @@ -802,7 +802,7 @@ self.xaxis.set_clip_path(self.axesPatch) self.yaxis.set_clip_path(self.axesPatch) - self.titleOffsetTrans.clear() + self.titleOffsetTrans.clear().translate(0.0, 10.0) def clear(self): 'clear the axes' Modified: branches/transforms/lib/matplotlib/config/mplconfig.py =================================================================== --- branches/transforms/lib/matplotlib/config/mplconfig.py 2007-12-05 17:25:34 UTC (rev 4623) +++ branches/transforms/lib/matplotlib/config/mplconfig.py 2007-12-05 18:14:38 UTC (rev 4624) @@ -238,6 +238,7 @@ dpi = T.Float(80) facecolor = T.Trait('0.75', mplT.ColorHandler()) edgecolor = T.Trait('white', mplT.ColorHandler()) + autolayout = T.false class subplot(TConfig): """The figure subplot parameters. All dimensions are fraction @@ -415,6 +416,7 @@ 'figure.subplot.wspace' : (self.tconfig.figure.subplot, 'wspace'), 'figure.subplot.hspace' : (self.tconfig.figure.subplot, 'hspace'), + 'figure.autolayout' : (self.tconfig.figure, 'autolayout'), 'savefig.dpi' : (self.tconfig.savefig, 'dpi'), 'savefig.facecolor' : (self.tconfig.savefig, 'facecolor'), Modified: branches/transforms/lib/matplotlib/config/rcsetup.py =================================================================== --- branches/transforms/lib/matplotlib/config/rcsetup.py 2007-12-05 17:25:34 UTC (rev 4623) +++ branches/transforms/lib/matplotlib/config/rcsetup.py 2007-12-05 18:14:38 UTC (rev 4624) @@ -447,6 +447,7 @@ 'figure.subplot.wspace' : [0.2, ValidateInterval(0, 1, closedmin=False, closedmax=True)], 'figure.subplot.hspace' : [0.2, ValidateInterval(0, 1, closedmin=False, closedmax=True)], + 'figure.autolayout' : [False, validate_bool], # autolayout 'savefig.dpi' : [100, validate_float], # DPI 'savefig.facecolor' : ['w', validate_color], # facecolor; white Modified: branches/transforms/lib/matplotlib/figure.py =================================================================== --- branches/transforms/lib/matplotlib/figure.py 2007-12-05 17:25:34 UTC (rev 4623) +++ branches/transforms/lib/matplotlib/figure.py 2007-12-05 18:14:38 UTC (rev 4624) @@ -151,7 +151,7 @@ self.clf() self._cachedRenderer = None - self._autoLayout = False + self._autoLayout = rcParams['figure.autolayout'] def _get_dpi(self): return self._dpi @@ -185,7 +185,8 @@ else: for label in ax.get_xticklabels(): label.set_visible(False) - #self.subplots_adjust(bottom=bottom) + if not self._autoLayout: + self.subplots_adjust(bottom=bottom) def get_children(self): 'get a list of artists contained in the figure' Modified: branches/transforms/lib/matplotlib/rcsetup.py =================================================================== --- branches/transforms/lib/matplotlib/rcsetup.py 2007-12-05 17:25:34 UTC (rev 4623) +++ branches/transforms/lib/matplotlib/rcsetup.py 2007-12-05 18:14:38 UTC (rev 4624) @@ -447,6 +447,7 @@ 'figure.subplot.wspace' : [0.2, ValidateInterval(0, 1, closedmin=False, closedmax=True)], 'figure.subplot.hspace' : [0.2, ValidateInterval(0, 1, closedmin=False, closedmax=True)], + 'figure.autolayout' : [False, validate_bool], 'savefig.dpi' : [100, validate_float], # DPI 'savefig.facecolor' : ['w', validate_color], # facecolor; white Modified: branches/transforms/matplotlibrc.template =================================================================== --- branches/transforms/matplotlibrc.template 2007-12-05 17:25:34 UTC (rev 4623) +++ branches/transforms/matplotlibrc.template 2007-12-05 18:14:38 UTC (rev 4624) @@ -156,7 +156,7 @@ # 'tex': As TeX-like text. Text between $'s will be # formatted as a TeX math expression. # This setting has no effect when text.usetex is True. - # In that case, all text will be sent to TeX for + # In that case, all text will be sent to TeX for # processing. # The following settings allow you to select the fonts in math mode. @@ -171,7 +171,7 @@ #mathtext.fontset : cm # Should be 'cm' (Computer Modern), 'stix', # 'stixsans' or 'custom' #mathtext.fallback_to_cm : True # When True, use symbols from the Computer Modern - # fonts when a symbol can not be found in one of + # fonts when a symbol can not be found in one of # the custom math fonts. ### AXES @@ -247,6 +247,7 @@ #figure.subplot.wspace : 0.2 # the amount of width reserved for blank space between subplots #figure.subplot.hspace : 0.2 # the amount of height reserved for white space between subplots +#figure.autolayout : False # when True, adjust the axes so that text doesn't overlap ### IMAGES #image.aspect : equal # equal | auto | a number This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-12-05 21:13:59
|
Revision: 4634 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4634&view=rev Author: mdboom Date: 2007-12-05 13:13:46 -0800 (Wed, 05 Dec 2007) Log Message: ----------- Merged revisions 4621-4633 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r4622 | jdh2358 | 2007-12-05 12:11:28 -0500 (Wed, 05 Dec 2007) | 2 lines updated autofmt_xdate to work in more cases. it no longer raises if axes aren't subplots ........ r4629 | jdh2358 | 2007-12-05 14:27:14 -0500 (Wed, 05 Dec 2007) | 2 lines minor rec2excel enhancements ........ r4632 | pkienzle | 2007-12-05 14:36:36 -0500 (Wed, 05 Dec 2007) | 1 line docu update: coord reporting works in wx ........ r4633 | mdboom | 2007-12-05 15:28:28 -0500 (Wed, 05 Dec 2007) | 2 lines Fix bug where font files were opened many more times than they need to be. ........ Modified Paths: -------------- branches/transforms/examples/coords_report.py branches/transforms/examples/loadrec.py branches/transforms/lib/matplotlib/backends/backend_agg.py branches/transforms/lib/matplotlib/backends/backend_pdf.py branches/transforms/lib/matplotlib/backends/backend_ps.py branches/transforms/lib/matplotlib/backends/backend_svg.py branches/transforms/lib/matplotlib/figure.py branches/transforms/lib/matplotlib/font_manager.py branches/transforms/lib/matplotlib/mlab.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-4620 + /trunk/matplotlib:1-4633 Modified: branches/transforms/examples/coords_report.py =================================================================== --- branches/transforms/examples/coords_report.py 2007-12-05 20:28:28 UTC (rev 4633) +++ branches/transforms/examples/coords_report.py 2007-12-05 21:13:46 UTC (rev 4634) @@ -1,7 +1,6 @@ #!/usr/bin/env python -# override the default reporting of coords (coords reporting not -# implemented yet on wx*) +# override the default reporting of coords from pylab import * Modified: branches/transforms/examples/loadrec.py =================================================================== --- branches/transforms/examples/loadrec.py 2007-12-05 20:28:28 UTC (rev 4633) +++ branches/transforms/examples/loadrec.py 2007-12-05 21:13:46 UTC (rev 4634) @@ -9,4 +9,6 @@ ax = fig.add_subplot(111) ax.plot(a.date, a.adj_close, '-') fig.autofmt_xdate() + +mlab.rec2excel(a, 'test.xls', colnum=4) show() Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-12-05 20:28:28 UTC (rev 4633) +++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-12-05 21:13:46 UTC (rev 4634) @@ -31,7 +31,8 @@ from matplotlib._pylab_helpers import Gcf from matplotlib.backend_bases import RendererBase,\ GraphicsContextBase, FigureManagerBase, FigureCanvasBase -from matplotlib.cbook import enumerate, is_string_like, exception_to_str +from matplotlib.cbook import enumerate, is_string_like, exception_to_str, \ + maxdict from matplotlib.figure import Figure from matplotlib.font_manager import findfont from matplotlib.ft2font import FT2Font, LOAD_FORCE_AUTOHINT @@ -49,7 +50,8 @@ context instance that controls the colors/styles """ debug=1 - texd = {} # a cache of tex image rasters + texd = maxdict(50) # a cache of tex image rasters + _fontd = maxdict(50) def __init__(self, width, height, dpi): if __debug__: verbose.report('RendererAgg.__init__', 'debug-annoying') RendererBase.__init__(self) @@ -70,7 +72,6 @@ self.restore_region = self._renderer.restore_region self.tostring_rgba_minimized = self._renderer.tostring_rgba_minimized self.mathtext_parser = MathTextParser('Agg') - self._fontd = {} self.bbox = Bbox.from_bounds(0, 0, self.width, self.height) if __debug__: verbose.report('RendererAgg.__init__ done', @@ -172,7 +173,10 @@ if font is None: fname = findfont(prop) - font = FT2Font(str(fname)) + font = self._fontd.get(fname) + if font is None: + font = FT2Font(str(fname)) + self._fontd[fname] = font self._fontd[key] = font font.clear() Modified: branches/transforms/lib/matplotlib/backends/backend_pdf.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-12-05 20:28:28 UTC (rev 4633) +++ branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-12-05 21:13:46 UTC (rev 4634) @@ -26,7 +26,7 @@ FigureManagerBase, FigureCanvasBase from matplotlib.backends.backend_mixed import MixedModeRenderer from matplotlib.cbook import Bunch, enumerate, is_string_like, reverse_dict, \ - get_realpath_and_stat, is_writable_file_like + get_realpath_and_stat, is_writable_file_like, maxdict from matplotlib.figure import Figure from matplotlib.font_manager import findfont, is_opentype_cff_font from matplotlib.afm import AFM @@ -1162,13 +1162,13 @@ self.write("\nstartxref\n%d\n%%%%EOF\n" % self.startxref) class RendererPdf(RendererBase): + truetype_font_cache = maxdict(50) + afm_font_cache = maxdict(50) def __init__(self, file, dpi): RendererBase.__init__(self) self.file = file self.gc = self.new_gc() - self.truetype_font_cache = {} - self.afm_font_cache = {} self.file.used_characters = self.used_characters = {} self.mathtext_parser = MathTextParser("Pdf") self.dpi = dpi @@ -1176,8 +1176,6 @@ def finalize(self): self.gc.finalize() - del self.truetype_font_cache - del self.afm_font_cache def check_gc(self, gc, fillcolor=None): orig_fill = gc._fillcolor @@ -1589,9 +1587,12 @@ font = self.afm_font_cache.get(key) if font is None: filename = findfont(prop, fontext='afm') - fh = file(filename) - font = AFM(fh) - fh.close() + font = self.afm_font_cache.get(filename) + if font is None: + fh = file(filename) + font = AFM(fh) + self.afm_font_cache[filename] = font + fh.close() self.afm_font_cache[key] = font return font @@ -1600,7 +1601,10 @@ font = self.truetype_font_cache.get(key) if font is None: filename = findfont(prop) - font = FT2Font(str(filename)) + font = self.truetype_font_cache.get(filename) + if font is None: + font = FT2Font(str(filename)) + self.truetype_font_cache[filename] = font self.truetype_font_cache[key] = font font.clear() font.set_size(prop.get_size_in_points(), self.dpi) Modified: branches/transforms/lib/matplotlib/backends/backend_ps.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-12-05 20:28:28 UTC (rev 4633) +++ branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-12-05 21:13:46 UTC (rev 4634) @@ -15,7 +15,7 @@ FigureManagerBase, FigureCanvasBase from matplotlib.cbook import is_string_like, izip, get_realpath_and_stat, \ - is_writable_file_like + is_writable_file_like, maxdict from matplotlib.figure import Figure from matplotlib.font_manager import findfont, is_opentype_cff_font @@ -122,6 +122,9 @@ context instance that controls the colors/styles. """ + fontd = maxdict(50) + afmfontd = maxdict(50) + def __init__(self, width, height, pswriter, dpi=72): RendererBase.__init__(self) self.width = width @@ -144,8 +147,6 @@ self._clip_paths = {} self._path_collection_id = 0 - self.fontd = {} - self.afmfontd = {} self.used_characters = {} self.mathtext_parser = MathTextParser("PS") @@ -316,7 +317,11 @@ key = hash(prop) font = self.afmfontd.get(key) if font is None: - font = AFM(file(findfont(prop, fontext='afm'))) + fname = findfont(prop, fontext='afm') + font = self.afmfontd.get(fname) + if font is None: + font = AFM(file(findfont(prop, fontext='afm'))) + self.afmfontd[fname] = font self.afmfontd[key] = font return font @@ -325,7 +330,10 @@ font = self.fontd.get(key) if font is None: fname = findfont(prop) - font = FT2Font(str(fname)) + font = self.fontd.get(fname) + if font is None: + font = FT2Font(str(fname)) + self.fontd[fname] = font self.fontd[key] = font font.clear() size = prop.get_size_in_points() Modified: branches/transforms/lib/matplotlib/backends/backend_svg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_svg.py 2007-12-05 20:28:28 UTC (rev 4633) +++ branches/transforms/lib/matplotlib/backends/backend_svg.py 2007-12-05 21:13:46 UTC (rev 4634) @@ -6,7 +6,7 @@ from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\ FigureManagerBase, FigureCanvasBase from matplotlib.backends.backend_mixed import MixedModeRenderer -from matplotlib.cbook import is_string_like, is_writable_file_like +from matplotlib.cbook import is_string_like, is_writable_file_like, maxdict from matplotlib.colors import rgb2hex from matplotlib.figure import Figure from matplotlib.font_manager import findfont, FontProperties @@ -30,6 +30,7 @@ _capstyle_d = {'projecting' : 'square', 'butt' : 'butt', 'round': 'round',} class RendererSVG(RendererBase): FONT_SCALE = 100.0 + fontd = maxdict(50) def __init__(self, width, height, svgwriter, basename=None): self.width=width @@ -46,7 +47,6 @@ self._markers = {} self._path_collection_id = 0 self.mathtext_parser = MathTextParser('SVG') - self.fontd = {} svgwriter.write(svgProlog%(width,height,width,height)) def _draw_svg_element(self, element, details, gc, rgbFace): @@ -59,13 +59,16 @@ style = self._get_style(gc, rgbFace) self._svgwriter.write ('<%s style="%s" %s %s/>\n' % ( element, style, clippath, details)) - + def _get_font(self, prop): key = hash(prop) font = self.fontd.get(key) if font is None: fname = findfont(prop) - font = FT2Font(str(fname)) + font = self.fontd.get(fname) + if font is None: + font = FT2Font(str(fname)) + self.fontd[fname] = font self.fontd[key] = font font.clear() size = prop.get_size_in_points() @@ -119,7 +122,7 @@ path = '<rect x="%(x)s" y="%(y)s" width="%(w)s" height="%(h)s"/>' % locals() else: return None - + id = self._clipd.get(path) if id is None: id = 'p%x' % len(self._clipd) @@ -154,7 +157,7 @@ Affine2D() .scale(1.0, -1.0) .translate(0.0, self.height)) - + def _convert_path(self, path, transform): tpath = transform.transform_path(path) @@ -174,7 +177,7 @@ appender(segment) currpos += len(segment) return ''.join(path_data) - + def draw_path(self, gc, path, transform, rgbFace=None): trans_and_flip = self._make_flip_transform(transform) path_data = self._convert_path(path, trans_and_flip) @@ -182,7 +185,7 @@ def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): write = self._svgwriter.write - + key = self._convert_path(marker_path, marker_trans + Affine2D().scale(1.0, -1.0)) name = self._markers.get(key) if name is None: @@ -201,7 +204,7 @@ offsetTrans, facecolors, edgecolors, linewidths, linestyles, antialiaseds): write = self._svgwriter.write - + path_codes = [] write('<defs>\n') for i, (path, transform) in enumerate(self._iter_collection_raw_paths( @@ -212,7 +215,7 @@ write('<path id="%s" d="%s"/>\n' % (name, d)) path_codes.append(name) write('</defs>\n') - + for xo, yo, path_id, gc, rgbFace in self._iter_collection( path_codes, cliprect, clippath, clippath_trans, offsets, offsetTrans, facecolors, edgecolors, @@ -221,7 +224,7 @@ self._draw_svg_element('use', details, gc, rgbFace) self._path_collection_id += 1 - + def draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None): # MGDTODO: Support clippath here trans = [1,0,0,1,0,0] @@ -288,7 +291,7 @@ font = self._get_font(prop) font.set_text(s, 0.0, flags=LOAD_NO_HINTING) y -= font.get_descent() / 64.0 - + fontsize = prop.get_size_in_points() color = rgb2hex(gc.get_rgb()[:3]) @@ -429,7 +432,7 @@ for font, fontsize, thetext, new_x, new_y_mtc, metrics in svg_glyphs: new_y = - new_y_mtc style = "font-size: %f; font-family: %s" % (fontsize, font.family_name) - + svg.append('<tspan style="%s"' % style) xadvance = metrics.advance svg.append(' textLength="%s"' % xadvance) @@ -503,14 +506,20 @@ 'svgz': 'Scalable Vector Graphics'} def print_svg(self, filename, *args, **kwargs): - svgwriter = codecs.open(filename, 'w', 'utf-8') - return self._print_svg(filename, svgwriter) + if is_string_like(filename): + fh_to_close = svgwriter = codecs.open(filename, 'w', 'utf-8') + elif is_writable_file_like(filename): + svgwriter = codecs.EncodedFile(filename, 'utf-8') + fh_to_close = None + else: + raise ValueError("filename must be a path or a file-like object") + return self._print_svg(filename, svgwriter, fh_to_close) def print_svgz(self, filename, *args, **kwargs): gzipwriter = gzip.GzipFile(filename, 'w') svgwriter = codecs.EncodedFile(gzipwriter, 'utf-8') return self._print_svg(filename, svgwriter) - + def _print_svg(self, filename, svgwriter, fh_to_close=None): self.figure.set_dpi(72.0) width, height = self.figure.get_size_inches() @@ -522,10 +531,10 @@ renderer.finalize() if fh_to_close is not None: svgwriter.close() - + def get_default_filetype(self): return 'svg' - + class FigureManagerSVG(FigureManagerBase): pass Modified: branches/transforms/lib/matplotlib/figure.py =================================================================== --- branches/transforms/lib/matplotlib/figure.py 2007-12-05 20:28:28 UTC (rev 4633) +++ branches/transforms/lib/matplotlib/figure.py 2007-12-05 21:13:46 UTC (rev 4634) @@ -165,27 +165,36 @@ def autofmt_xdate(self, bottom=0.2, rotation=30, ha='right'): """ - A common use case is a number of subplots with shared xaxes - where the x-axis is date data. The ticklabels are often - long,and it helps to rotate them on the bottom subplot and - turn them off on other subplots. This function will raise a - RuntimeError if any of the Axes are not Subplots. + Date ticklabels often overlap, so it is useful to rotate them + and right align them. Also, a common use case is a number of + subplots with shared xaxes where the x-axis is date data. The + ticklabels are often long, and it helps to rotate them on the + bottom subplot and turn them off on other subplots, as well as + turn off xlabels. + bottom : the bottom of the subplots for subplots_adjust rotation: the rotation of the xtick labels ha : the horizontal alignment of the xticklabels """ - for ax in self.get_axes(): - if not hasattr(ax, 'is_last_row'): - raise RuntimeError('Axes must be subplot instances; found %s'%type(ax)) - if ax.is_last_row(): - for label in ax.get_xticklabels(): - label.set_ha(ha) - label.set_rotation(rotation) - else: - for label in ax.get_xticklabels(): - label.set_visible(False) - if not self._autoLayout: + allsubplots = npy.alltrue([hasattr(ax, 'is_last_row') for ax in self.axes]) + if len(self.axes)==1: + for label in ax.get_xticklabels(): + label.set_ha(ha) + label.set_rotation(rotation) + else: + if allsubplots: + for ax in self.get_axes(): + if ax.is_last_row(): + for label in ax.get_xticklabels(): + label.set_ha(ha) + label.set_rotation(rotation) + else: + for label in ax.get_xticklabels(): + label.set_visible(False) + ax.set_xlabel('') + + if allsubplots and not self._autoLayout: self.subplots_adjust(bottom=bottom) def get_children(self): Modified: branches/transforms/lib/matplotlib/font_manager.py =================================================================== --- branches/transforms/lib/matplotlib/font_manager.py 2007-12-05 20:28:28 UTC (rev 4633) +++ branches/transforms/lib/matplotlib/font_manager.py 2007-12-05 21:13:46 UTC (rev 4634) @@ -36,7 +36,7 @@ import os, sys, glob from sets import Set import matplotlib -from matplotlib import afm +from matplotlib import afm from matplotlib import ft2font from matplotlib import rcParams, get_configdir from matplotlib.cbook import is_string_like @@ -49,7 +49,7 @@ import pickle USE_FONTCONFIG = False - + verbose = matplotlib.verbose font_scalings = {'xx-small': 0.579, 'x-small': 0.694, 'small': 0.833, @@ -98,7 +98,7 @@ def get_fontext_synonyms(fontext): return {'ttf': ('ttf', 'otf'), 'afm': ('afm',)}[fontext] - + def win32FontDirectory(): """Return the user-specified font directory for Win32.""" @@ -126,7 +126,7 @@ directory = win32FontDirectory() fontext = get_fontext_synonyms(fontext) - + key, items = None, {} for fontdir in MSFontDirectories: try: @@ -178,7 +178,7 @@ directory = OSXFontDirectory() fontext = get_fontext_synonyms(fontext) - + files = [] for path in directory: if fontext is None: @@ -214,7 +214,7 @@ return {} fontext = get_fontext_synonyms(fontext) - + fontfiles = {} status, output = commands.getstatusoutput("fc-list file") if status == 0: @@ -236,7 +236,7 @@ """ fontfiles = {} fontexts = get_fontext_synonyms(fontext) - + if fontpaths is None: if sys.platform == 'win32': fontdir = win32FontDirectory() @@ -635,7 +635,7 @@ stretch = [rcParams['font.stretch']] size = [rcParams['font.size']] file = None - + def __init__(self, family = None, style = None, @@ -653,7 +653,7 @@ if _init is not None: self.__props.__dict__.update(_init) return - + if is_string_like(family): # Treat family as a fontconfig pattern if it is the only # parameter provided. @@ -674,16 +674,16 @@ self.set_stretch(stretch) self.set_file(fname) self.set_size(size) - + def _parse_fontconfig_pattern(self, pattern): return parse_fontconfig_pattern(pattern) def __hash__(self): - return hash(repr(self.__props)) + return hash(repr(self.__props.__dict__)) def __str__(self): return self.get_fontconfig_pattern() - + def get_family(self): """Return a list of font names that comprise the font family. """ @@ -727,7 +727,7 @@ def get_fontconfig_pattern(self): return generate_fontconfig_pattern(self.__props.__dict__) - + def set_family(self, family): """ Change the font family. May be either an alias (generic name @@ -741,7 +741,7 @@ family = [family] self.__props.family = family set_name = set_family - + def set_style(self, style): """Set the font style. Values are: normal, italic or oblique.""" if style is None: @@ -812,7 +812,7 @@ def add_property_pair(self, key, val): self.__props.setdefault(key, []).append(val) - + def copy(self): """Return a deep copy of self""" return FontProperties(_init = self.__props.__dict__) @@ -862,7 +862,7 @@ def __init__(self, size=None, weight='normal'): self.__default_weight = weight self.default_size = size - + paths = [os.path.join(rcParams['datapath'],'fonts','ttf'), os.path.join(rcParams['datapath'],'fonts','afm')] @@ -1076,8 +1076,8 @@ _is_opentype_cff_font_cache[filename] = result return result return False - - + + if USE_FONTCONFIG and sys.platform != 'win32': import re @@ -1095,7 +1095,7 @@ _fc_match_regex = re.compile(r'\sfile:\s+"([^"]*)"') _fc_match_cache = {} - + def findfont(prop, fontext='ttf'): if not is_string_like(prop): prop = prop.get_fontconfig_pattern() Modified: branches/transforms/lib/matplotlib/mlab.py =================================================================== --- branches/transforms/lib/matplotlib/mlab.py 2007-12-05 20:28:28 UTC (rev 4633) +++ branches/transforms/lib/matplotlib/mlab.py 2007-12-05 21:13:46 UTC (rev 4634) @@ -2367,7 +2367,7 @@ xlstyle.num_format_str = '#,##;[RED]-#,##' elif isinstance(format, FormatPercent): zeros = ''.join(['0']*format.precision) - xlstyle.num_format_str = '0.%s%;[RED]-0.%s%'%(zeros, zeros) + xlstyle.num_format_str = '0.%s%%;[RED]-0.%s%%'%(zeros, zeros) format.scale = 1. else: xlstyle = None @@ -2376,12 +2376,14 @@ return format - def rec2excel(r, ws, formatd=None, rownum=0): + def rec2excel(r, ws, formatd=None, rownum=0, colnum=0): """ save record array r to excel pyExcelerator worksheet ws starting at rownum. if ws is string like, assume it is a filename and save to it + start writing at rownum, colnum + formatd is a dictionary mapping dtype name -> FormatXL instances The next rownum after writing is returned @@ -2399,6 +2401,12 @@ formatd = dict() formats = [] + font = excel.Font() + font.bold = True + + stylehdr = excel.XFStyle() + stylehdr.font = font + for i, name in enumerate(r.dtype.names): dt = r.dtype[name] format = formatd.get(name) @@ -2406,7 +2414,7 @@ format = defaultformatd.get(dt.type, FormatObj()) format = xlformat_factory(format) - ws.write(rownum, i, name) + ws.write(rownum, colnum+i, name, stylehdr) formats.append(format) rownum+=1 @@ -2419,12 +2427,12 @@ format = formats[i] val = format.toval(val) if format.xlstyle is None: - ws.write(rownum, i, val) + ws.write(rownum, colnum+i, val) else: if safe_isnan(val): - ws.write(rownum, i, 'NaN') + ws.write(rownum, colnum+i, 'NaN') else: - ws.write(rownum, i, val, format.xlstyle) + ws.write(rownum, colnum+i, val, format.xlstyle) rownum += 1 if autosave: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-12-07 19:09:54
|
Revision: 4668 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4668&view=rev Author: mdboom Date: 2007-12-07 11:09:52 -0800 (Fri, 07 Dec 2007) Log Message: ----------- Merged revisions 4634-4652 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r4636 | jrevans | 2007-12-05 19:04:49 -0500 (Wed, 05 Dec 2007) | 2 lines Added a 'data offset' coordinate to the Annotation class. ........ r4637 | jrevans | 2007-12-05 19:09:49 -0500 (Wed, 05 Dec 2007) | 2 lines Submitted the wrong version. This is the correct one. ........ r4638 | jdh2358 | 2007-12-05 21:36:05 -0500 (Wed, 05 Dec 2007) | 1 line changed offset naming for annotations ........ r4640 | mdboom | 2007-12-06 07:48:16 -0500 (Thu, 06 Dec 2007) | 2 lines Import numpy. ........ r4643 | mdboom | 2007-12-06 10:10:15 -0500 (Thu, 06 Dec 2007) | 2 lines Fixing display of float images. ........ r4644 | jrevans | 2007-12-06 11:11:17 -0500 (Thu, 06 Dec 2007) | 2 lines Updated to demonstrate 'offset points' ........ r4645 | dsdale | 2007-12-06 11:23:58 -0500 (Thu, 06 Dec 2007) | 3 lines modified svn:ignore properties to ignore generated files not under revision control ........ r4647 | dsdale | 2007-12-06 12:47:46 -0500 (Thu, 06 Dec 2007) | 2 lines fixed a bug in rcsetup, see bug 1845057 ........ r4648 | dsdale | 2007-12-06 13:08:21 -0500 (Thu, 06 Dec 2007) | 3 lines changed the default backend in rcsetup from WXAgg, which is not certain to be present, to Agg. ........ r4649 | dsdale | 2007-12-06 13:32:44 -0500 (Thu, 06 Dec 2007) | 4 lines fixed a bug in savefig, saving to a nonexistent directory would result in a crash in some circumstances. Closes bug 1699614 ........ r4650 | dsdale | 2007-12-06 13:38:55 -0500 (Thu, 06 Dec 2007) | 2 lines undo that last change, mdboom had a different solution that I overlooked ........ r4651 | mdboom | 2007-12-06 13:47:50 -0500 (Thu, 06 Dec 2007) | 2 lines Fix saving to a file-like object. ........ Modified Paths: -------------- branches/transforms/CHANGELOG branches/transforms/examples/annotation_demo.py branches/transforms/lib/matplotlib/__init__.py branches/transforms/lib/matplotlib/cbook.py branches/transforms/lib/matplotlib/cm.py branches/transforms/lib/matplotlib/rcsetup.py branches/transforms/lib/matplotlib/text.py branches/transforms/src/_backend_agg.cpp Property Changed: ---------------- branches/transforms/ branches/transforms/examples/ branches/transforms/lib/ branches/transforms/lib/matplotlib/mpl-data/ branches/transforms/unit/ Property changes on: branches/transforms ___________________________________________________________________ Name: svn:ignore - build dist docs *.pyc .project matplotlibrc win32_static + build dist docs *.pyc .project matplotlibrc win32_static setup.cfg Name: svnmerge-integrated - /trunk/matplotlib:1-4633 + /trunk/matplotlib:1-4652 Modified: branches/transforms/CHANGELOG =================================================================== --- branches/transforms/CHANGELOG 2007-12-07 19:05:11 UTC (rev 4667) +++ branches/transforms/CHANGELOG 2007-12-07 19:09:52 UTC (rev 4668) @@ -1,3 +1,5 @@ +2007-12-06 fixed a bug in rcsetup, see bug 1845057 - DSD + =============================================================== 2007-11-27 Released 0.91.1 at revision 4517 Property changes on: branches/transforms/examples ___________________________________________________________________ Name: svn:ignore - *.eps *.jpeg *.jpg *.pdf *.png *.ps *.pyc *.svg + matplotlibrc matplotlib.conf *.eps *.jpeg *.jpg *.pdf *.png *.ps *.pyc *.svg Modified: branches/transforms/examples/annotation_demo.py =================================================================== --- branches/transforms/examples/annotation_demo.py 2007-12-07 19:05:11 UTC (rev 4667) +++ branches/transforms/examples/annotation_demo.py 2007-12-07 19:09:52 UTC (rev 4668) @@ -10,6 +10,7 @@ 'axes points' : points from lower left corner of axes 'axes pixels' : pixels from lower left corner of axes 'axes fraction' : 0,1 is lower left of axes and 1,1 is upper right + 'offset points' : Specify an offset (in points) from the xy value 'data' : use the axes data coordinate system Optionally, you can specify arrow properties which draws and arrow @@ -54,6 +55,12 @@ ax.annotate('points', xy=(100, 300), xycoords='figure points') + ax.annotate('offset', xy=(1, 1), xycoords='data', + xytext=(-15, 10), textcoords='offset points', + arrowprops=dict(facecolor='black', shrink=0.05), + horizontalalignment='right', verticalalignment='bottom', + ) + ax.annotate('local max', xy=(3, 1), xycoords='data', xytext=(0.8, 0.95), textcoords='axes fraction', arrowprops=dict(facecolor='black', shrink=0.05), Property changes on: branches/transforms/lib ___________________________________________________________________ Name: svn:ignore + matplotlib.egg-info Modified: branches/transforms/lib/matplotlib/__init__.py =================================================================== --- branches/transforms/lib/matplotlib/__init__.py 2007-12-07 19:05:11 UTC (rev 4667) +++ branches/transforms/lib/matplotlib/__init__.py 2007-12-07 19:09:52 UTC (rev 4668) @@ -615,6 +615,15 @@ if ret['datapath'] is None: ret['datapath'] = get_data_path() + if not ret['text.latex.preamble'] == ['']: + verbose.report(""" +***************************************************************** +You have the following UNSUPPORTED LaTeX preamble customizations: +%s +Please do not ask for support with these customizations active. +***************************************************************** +"""% '\n'.join(ret['text.latex.preamble']), 'helpful') + verbose.report('loaded rc file %s'%fname) return ret Modified: branches/transforms/lib/matplotlib/cbook.py =================================================================== --- branches/transforms/lib/matplotlib/cbook.py 2007-12-07 19:05:11 UTC (rev 4667) +++ branches/transforms/lib/matplotlib/cbook.py 2007-12-07 19:09:52 UTC (rev 4668) @@ -215,7 +215,7 @@ return 1 def is_writable_file_like(obj): - return hasattr(filename, 'write') and callable(filename.write) + return hasattr(obj, 'write') and callable(obj.write) def is_scalar(obj): return is_string_like(obj) or not iterable(obj) @@ -892,7 +892,7 @@ return x, self._mem[i0:self._n:isub] def plot(self, i0=0, isub=1, fig=None): - if fig is None: + if fig is None: from pylab import figure, show fig = figure() Modified: branches/transforms/lib/matplotlib/cm.py =================================================================== --- branches/transforms/lib/matplotlib/cm.py 2007-12-07 19:05:11 UTC (rev 4667) +++ branches/transforms/lib/matplotlib/cm.py 2007-12-07 19:09:52 UTC (rev 4668) @@ -2,6 +2,7 @@ This module contains the instantiations of color mapping classes """ +import numpy as npy import matplotlib as mpl import matplotlib.colors as colors import matplotlib.numerix.npyma as ma @@ -57,7 +58,7 @@ if x.shape[2] == 3: if x.dtype == npy.uint8: alpha = npy.array(alpha*255, npy.uint8) - m, n = npy.shape[:2] + m, n = x.shape[:2] xx = npy.empty(shape=(m,n,4), dtype = x.dtype) xx[:,:,:3] = x xx[:,:,3] = alpha Property changes on: branches/transforms/lib/matplotlib/mpl-data ___________________________________________________________________ Name: svn:ignore + matplotlibrc matplotlib.conf Modified: branches/transforms/lib/matplotlib/rcsetup.py =================================================================== --- branches/transforms/lib/matplotlib/rcsetup.py 2007-12-07 19:05:11 UTC (rev 4667) +++ branches/transforms/lib/matplotlib/rcsetup.py 2007-12-07 19:09:52 UTC (rev 4668) @@ -165,21 +165,6 @@ 'landscape', 'portrait', ]) -def validate_latex_preamble(s): - 'return a list' - preamble_list = validate_stringlist(s) - if not preamble_list == ['']: - verbose.report(""" -***************************************************************** -You have the following UNSUPPORTED LaTeX preamble customizations: -%s -Please do not ask for support with these customizations active. -***************************************************************** -"""% '\n'.join(preamble_list), 'helpful') - return preamble_list - - - def validate_aspect(s): if s in ('auto', 'equal'): return s @@ -290,7 +275,7 @@ # a map from key -> value, converter defaultParams = { - 'backend' : ['WXAgg', validate_backend], + 'backend' : ['Agg', validate_backend], # agg is certainly present 'numerix' : ['numpy', validate_numerix], 'maskedarray' : [False, validate_bool], 'toolbar' : ['toolbar2', validate_toolbar], @@ -353,7 +338,7 @@ 'text.color' : ['k', validate_color], # black 'text.usetex' : [False, validate_bool], 'text.latex.unicode' : [False, validate_bool], - 'text.latex.preamble' : [[''], validate_latex_preamble], + 'text.latex.preamble' : [[''], validate_stringlist], 'text.dvipnghack' : [False, validate_bool], 'text.fontstyle' : ['normal', str], 'text.fontangle' : ['normal', str], Modified: branches/transforms/lib/matplotlib/text.py =================================================================== --- branches/transforms/lib/matplotlib/text.py 2007-12-07 19:05:11 UTC (rev 4667) +++ branches/transforms/lib/matplotlib/text.py 2007-12-07 19:09:52 UTC (rev 4668) @@ -182,6 +182,7 @@ whs = npy.zeros((len(lines), 2)) horizLayout = npy.zeros((len(lines), 4)) + # Find full vertical extent of font, # including ascenders and descenders: tmp, heightt, bl = renderer.get_text_width_height_descent( @@ -986,6 +987,7 @@ 'axes pixels' : pixels from lower left corner of axes 'axes fraction' : 0,1 is lower left of axes and 1,1 is upper right 'data' : use the coordinate system of the object being annotated (default) + 'offset points' : Specify an offset (in points) from the xy value 'polar' : you can specify theta, r for the annotation, even in cartesian plots. Note that if you are using a polar axes, you do not need @@ -1041,6 +1043,26 @@ x = float(self.convert_xunits(x)) y = float(self.convert_yunits(y)) return trans.transform_point((x, y)) + elif s=='offset points': + # convert the data point + dx, dy = self.xy + + # prevent recursion + if self.xycoords == 'offset points': + return self._get_xy(dx, dy, 'data') + + dx, dy = self._get_xy(dx, dy, self.xycoords) + + # convert the offset + dpi = self.figure.dpi.get() + x *= dpi/72. + y *= dpi/72. + + # add the offset to the data point + x += dx + y += dy + + return x, y elif s=='polar': theta, r = x, y x = r*npy.cos(theta) Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-12-07 19:05:11 UTC (rev 4667) +++ branches/transforms/src/_backend_agg.cpp 2007-12-07 19:09:52 UTC (rev 4668) @@ -593,7 +593,6 @@ delete[] strokeCache; return Py::Object(); - } /** @@ -1324,11 +1323,9 @@ throw Py::RuntimeError( Printf("Could not open file %s", file_name).str() ); } else { - if ((fp = PyFile_AsFile(py_fileobj.ptr())) == NULL) { - PyObject* write_method = PyObject_GetAttrString(py_fileobj.ptr(), "write"); - if (!(write_method && PyCallable_Check(write_method))) - throw Py::TypeError("Object does not appear to be a path or a Python file-like object"); - } + PyObject* write_method = PyObject_GetAttrString(py_fileobj.ptr(), "write"); + if (!(write_method && PyCallable_Check(write_method))) + throw Py::TypeError("Object does not appear to be a path or a Python file-like object"); } png_bytep *row_pointers = NULL; Property changes on: branches/transforms/unit ___________________________________________________________________ Name: svn:ignore + *.png This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-12-07 19:18:07
|
Revision: 4669 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4669&view=rev Author: mdboom Date: 2007-12-07 11:18:02 -0800 (Fri, 07 Dec 2007) Log Message: ----------- Merged revisions 4653-4668 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r4653 | mdboom | 2007-12-06 14:10:12 -0500 (Thu, 06 Dec 2007) | 2 lines [ 1841933 ] font_manager.win32FontDirectory() fails as Vista service ........ r4654 | dsdale | 2007-12-06 14:18:49 -0500 (Thu, 06 Dec 2007) | 2 lines updated references to mpl data directories for py2exe ........ r4658 | dsdale | 2007-12-06 17:28:27 -0500 (Thu, 06 Dec 2007) | 4 lines let widgets.Cursor initialize to the lower x and y bounds rather than 0,0, which can cause havoc for dates and other transforms ........ r4665 | efiring | 2007-12-07 02:12:33 -0500 (Fri, 07 Dec 2007) | 2 lines Clarify docstrings on Subplot classes; closes 1659419 ........ r4667 | mdboom | 2007-12-07 14:05:11 -0500 (Fri, 07 Dec 2007) | 4 lines [ 1697287 ] imshow on log axes broken if axes limits != image extent Adds a warning when an image is used on non-linear axes. Doesn't really address the problem (see bug report for the reason.) ........ Modified Paths: -------------- branches/transforms/CHANGELOG branches/transforms/lib/matplotlib/__init__.py branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/config/cutils.py branches/transforms/lib/matplotlib/figure.py branches/transforms/lib/matplotlib/font_manager.py branches/transforms/lib/matplotlib/image.py branches/transforms/lib/matplotlib/widgets.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-4652 + /trunk/matplotlib:1-4668 Modified: branches/transforms/CHANGELOG =================================================================== --- branches/transforms/CHANGELOG 2007-12-07 19:09:52 UTC (rev 4668) +++ branches/transforms/CHANGELOG 2007-12-07 19:18:02 UTC (rev 4669) @@ -1,3 +1,9 @@ +2007-12-06 let widgets.Cursor initialize to the lower x and y bounds + rather than 0,0, which can cause havoc for dates and other + transforms - DSD + +2007-12-06 updated references to mpl data directories for py2exe - DSD + 2007-12-06 fixed a bug in rcsetup, see bug 1845057 - DSD =============================================================== @@ -11,8 +17,8 @@ object in place of a file path. - MGD 2007-11-13 Improved the default backend selection at build time: - SVG -> Agg -> TkAgg -> WXAgg -> GTK -> GTKAgg. The last usable - backend in this progression will be chosen in the default + SVG -> Agg -> TkAgg -> WXAgg -> GTK -> GTKAgg. The last usable + backend in this progression will be chosen in the default config file. If a backend is defined in setup.cfg, that will be the default backend - DSD @@ -22,41 +28,41 @@ 2007-11-12 Exposed all the build options in setup.cfg. These options are read into a dict called "options" by setupext.py. Also, added "-mpl" tags to the version strings for packages provided by - matplotlib. Versions provided by mpl will be identified and + matplotlib. Versions provided by mpl will be identified and updated on subsequent installs - DSD 2007-11-12 Added support for STIX fonts. A new rcParam, - mathtext.fontset, can be used to choose between: - + mathtext.fontset, can be used to choose between: + 'cm': - The TeX/LaTeX Computer Modern fonts + The TeX/LaTeX Computer Modern fonts - 'stix': + 'stix': The STIX fonts (see stixfonts.org) - 'stixsans': - The STIX fonts, using sans-serif glyphs by default + 'stixsans': + The STIX fonts, using sans-serif glyphs by default - 'custom': + 'custom': A generic Unicode font, in which case the mathtext font must be specified using mathtext.bf, mathtext.it, mathtext.sf etc. - + Added a new example, stix_fonts_demo.py to show how to access different fonts and unusual symbols. - + - MGD -2007-11-12 Options to disable building backend extension modules moved +2007-11-12 Options to disable building backend extension modules moved from setup.py to setup.cfg - DSD 2007-11-09 Applied Martin Teichmann's patch 1828813: a QPainter is used in - paintEvent, which has to be destroyed using the method end(). If - matplotlib raises an exception before the call to end - and it - does if you feed it with bad data - this method end() is never + paintEvent, which has to be destroyed using the method end(). If + matplotlib raises an exception before the call to end - and it + does if you feed it with bad data - this method end() is never called and Qt4 will start spitting error messages -2007-11-09 Moved pyparsing back into matplotlib namespace. Don't use +2007-11-09 Moved pyparsing back into matplotlib namespace. Don't use system pyparsing, API is too variable from one release to the next - DSD @@ -101,7 +107,7 @@ The transformation framework was completely rewritten in Python (with Numpy). This will make it easier to add news - kinds of transformations without writing C/C++ code. + kinds of transformations without writing C/C++ code. Transforms are composed into a 'transform tree', made of transforms whose value depends on other transforms (their @@ -133,7 +139,7 @@ the backends more consistent in terms of functionality. User visible changes: - + - POLAR PLOTS: Polar plots are now interactively zoomable, and the r-axis labels can be interactively rotated. Straight line segments are now interpolated to follow the @@ -141,21 +147,21 @@ - Non-rectangular clipping works in more backends and with more types of objects. - + - Sharing an axis across figures is now done in exactly the same way as sharing an axis between two axes in the same figure: - + fig1 = figure() fig2 = figure() ax1 = fig1.add_subplot(111) ax2 = fig2.add_subplot(111, sharex=ax1, sharey=ax1) - + - linestyles now include steps-pre, steps-post and steps-mid. The old step still works and is equivalent to step-pre. - + - Multiple line styles may be provided to a collection. See API_CHANGES for more low-level information about this Modified: branches/transforms/lib/matplotlib/__init__.py =================================================================== --- branches/transforms/lib/matplotlib/__init__.py 2007-12-07 19:09:52 UTC (rev 4668) +++ branches/transforms/lib/matplotlib/__init__.py 2007-12-07 19:18:02 UTC (rev 4669) @@ -428,11 +428,16 @@ # py2exe zips pure python, so still need special check if getattr(sys,'frozen',None): - path = os.path.join(os.path.split(sys.path[0])[0], 'matplotlibdata') + path = os.path.join(os.path.split(sys.path[0])[0], 'mpl-data') if os.path.isdir(path): return path else: + # Try again assuming we need to step up one more directory + path = os.path.join(os.path.split(os.path.split(sys.path[0])[0])[0], + 'mpl-data') + if os.path.isdir(path): return path + else: # Try again assuming sys.path[0] is a dir not a exe - path = os.path.join(sys.path[0], 'matplotlibdata') + path = os.path.join(sys.path[0], 'mpl-data') if os.path.isdir(path): return path raise RuntimeError('Could not find the matplotlib data files') @@ -442,7 +447,8 @@ defaultParams['datapath'][0] = _get_data_path() return defaultParams['datapath'][0] -get_data_path = verbose.wrap('matplotlib data path %s', _get_data_path_cached, always=False) +get_data_path = verbose.wrap('matplotlib data path %s', _get_data_path_cached, + always=False) def get_py2exe_datafiles(): datapath = get_data_path() @@ -454,8 +460,8 @@ if 'Matplotlib.nib' in files: files.remove('Matplotlib.nib') files = [os.path.join(root, filename) for filename in files] - root = root.replace(tail, 'matplotlibdata') - root = root[root.index('matplotlibdata'):] + root = root.replace(tail, 'mpl-data') + root = root[root.index('mpl-data'):] d[root] = files return d.items() Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-12-07 19:09:52 UTC (rev 4668) +++ branches/transforms/lib/matplotlib/axes.py 2007-12-07 19:18:02 UTC (rev 4669) @@ -5511,25 +5511,23 @@ class SubplotBase: """ - Emulate matlab's(TM) subplot command, creating axes with - - Subplot(numRows, numCols, plotNum) - - where plotNum=1 is the first plot number and increasing plotNums - fill rows first. max(plotNum)==numRows*numCols - - You can leave out the commas if numRows<=numCols<=plotNum<10, as - in - - Subplot(211) # 2 rows, 1 column, first (upper) plot + Base class for subplots, which are Axes instances with additional + methods to facilitate generating and manipulating a set of Axes + within a figure. """ def __init__(self, fig, *args, **kwargs): """ fig is a figure instance - args is a varargs to specify the subplot + args is numRows, numCols, plotNum + where the array of subplots in the figure has dimensions + numRows, numCols, and where plotNum is the number of the + subplot being created. plotNum starts at 1 in the upper + right corner and increases to the right. + If numRows<=numCols<=plotNum<10, args can be the decimal + integer numRows*100 + numCols*10 + plotNum. """ self.figure = fig @@ -5650,7 +5648,6 @@ def subplot_class_factory(axes_class=None): # This makes a new class that inherits from SubclassBase and the # given axes_class (which is assumed to be a subclass of Axes). - # This is perhaps a little bit roundabout to make a new class on # the fly like this, but it means that a new Subplot class does # not have to be created for every type of Axes. Modified: branches/transforms/lib/matplotlib/config/cutils.py =================================================================== --- branches/transforms/lib/matplotlib/config/cutils.py 2007-12-07 19:09:52 UTC (rev 4668) +++ branches/transforms/lib/matplotlib/config/cutils.py 2007-12-07 19:18:02 UTC (rev 4669) @@ -77,7 +77,7 @@ if os.path.exists(p): if not is_writable_dir(p): raise RuntimeError("""\ -'%s' is not a writable dir; you must set %s/.matplotlib to be a writable dir. +'%s' is not a writable dir; you must set %s/.matplotlib to be a writable dir. You can also set environment variable MPLCONFIGDIR to any writable directory where you want matplotlib data stored """%h) else: @@ -110,11 +110,16 @@ # py2exe zips pure python, so still need special check if getattr(sys,'frozen',None): - path = os.path.join(os.path.split(sys.path[0])[0], 'matplotlibdata') + path = os.path.join(os.path.split(sys.path[0])[0], 'mpl-data') if os.path.isdir(path): return path else: + # Try again assuming we need to step up one more directory + path = os.path.join(os.path.split(os.path.split(sys.path[0])[0])[0], + 'mpl-data') + if os.path.isdir(path): return path + else: # Try again assuming sys.path[0] is a dir not a exe - path = os.path.join(sys.path[0], 'matplotlibdata') + path = os.path.join(sys.path[0], 'mpl-data') if os.path.isdir(path): return path raise RuntimeError('Could not find the matplotlib data files') @@ -136,8 +141,8 @@ if 'Matplotlib.nib' in files: files.remove('Matplotlib.nib') files = [os.path.join(root, filename) for filename in files] - root = root.replace(tail, 'matplotlibdata') - root = root[root.index('matplotlibdata'):] + root = root.replace(tail, 'mpl-data') + root = root[root.index('mpl-data'):] d[root] = files return d.items() Modified: branches/transforms/lib/matplotlib/figure.py =================================================================== --- branches/transforms/lib/matplotlib/figure.py 2007-12-07 19:09:52 UTC (rev 4668) +++ branches/transforms/lib/matplotlib/figure.py 2007-12-07 19:18:02 UTC (rev 4669) @@ -526,6 +526,7 @@ Add a subplot. Examples add_subplot(111) + add_subplot(1,1,1) # equivalent but more general add_subplot(212, axisbg='r') # add subplot with red background add_subplot(111, polar=True) # add a polar subplot add_subplot(sub) # add Subplot instance sub Modified: branches/transforms/lib/matplotlib/font_manager.py =================================================================== --- branches/transforms/lib/matplotlib/font_manager.py 2007-12-07 19:09:52 UTC (rev 4668) +++ branches/transforms/lib/matplotlib/font_manager.py 2007-12-07 19:18:02 UTC (rev 4669) @@ -105,14 +105,16 @@ try: import _winreg except ImportError: - return os.path.join(os.environ['WINDIR'], 'Fonts') + pass # Fall through to default else: user = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, MSFolders) try: return _winreg.QueryValueEx(user, 'Fonts')[0] + except OSError: + pass # Fall through to default finally: _winreg.CloseKey(user) - return None + return os.path.join(os.environ['WINDIR'], 'Fonts') def win32InstalledFonts(directory=None, fontext='ttf'): """ Modified: branches/transforms/lib/matplotlib/image.py =================================================================== --- branches/transforms/lib/matplotlib/image.py 2007-12-07 19:09:52 UTC (rev 4668) +++ branches/transforms/lib/matplotlib/image.py 2007-12-07 19:18:02 UTC (rev 4669) @@ -4,7 +4,7 @@ """ from __future__ import division -import os +import os, warnings import numpy as npy @@ -180,6 +180,9 @@ def draw(self, renderer, *args, **kwargs): if not self.get_visible(): return + if (self.axes.get_xscale() != 'linear' or + self.axes.get_yscale() != 'linear'): + warnings.warn("Images are not supported on non-linear axes.") im = self.make_image(renderer.get_image_magnification()) l, b, widthDisplay, heightDisplay = self.axes.bbox.bounds renderer.draw_image(l, b, im, self.axes.bbox.frozen(), Modified: branches/transforms/lib/matplotlib/widgets.py =================================================================== --- branches/transforms/lib/matplotlib/widgets.py 2007-12-07 19:09:52 UTC (rev 4668) +++ branches/transforms/lib/matplotlib/widgets.py 2007-12-07 19:18:02 UTC (rev 4669) @@ -664,8 +664,8 @@ self.vertOn = True self.useblit = useblit - self.lineh = ax.axhline(0, visible=False, **lineprops) - self.linev = ax.axvline(0, visible=False, **lineprops) + self.lineh = ax.axhline(ax.get_ybound()[0], visible=False, **lineprops) + self.linev = ax.axvline(ax.get_xbound()[0], visible=False, **lineprops) self.background = None self.needclear = False @@ -1072,11 +1072,11 @@ # If RectangleSelector is not active : if not self.active: return True - + # If canvas was locked if not self.canvas.widgetlock.available(self): return True - + # If no button was pressed yet ignore the event if it was out # of the axes if self.eventpress == None: @@ -1176,7 +1176,7 @@ def get_active(self): """ to get status of active mode (boolean variable)""" - return self.active + return self.active class Lasso(Widget): def __init__(self, ax, xy, callback=None, useblit=True): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-12-10 16:17:46
|
Revision: 4688 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4688&view=rev Author: mdboom Date: 2007-12-10 08:17:42 -0800 (Mon, 10 Dec 2007) Log Message: ----------- Merged revisions 4669-4682 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r4670 | mdboom | 2007-12-07 14:18:58 -0500 (Fri, 07 Dec 2007) | 2 lines Updating CHANGELOG. ........ r4679 | mdboom | 2007-12-10 09:50:40 -0500 (Mon, 10 Dec 2007) | 2 lines Use an 8-spline approximation of an ellipse instead of a 4-spline one. ........ Modified Paths: -------------- branches/transforms/CHANGELOG branches/transforms/lib/matplotlib/backends/backend_ps.py branches/transforms/lib/matplotlib/patches.py Added Paths: ----------- branches/transforms/unit/ellipse_large.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-4668 + /trunk/matplotlib:1-4682 Modified: branches/transforms/CHANGELOG =================================================================== --- branches/transforms/CHANGELOG 2007-12-10 16:17:16 UTC (rev 4687) +++ branches/transforms/CHANGELOG 2007-12-10 16:17:42 UTC (rev 4688) @@ -1,3 +1,5 @@ +2007-12-07 Issue a warning when drawing an image on a non-linear axis. - MGD + 2007-12-06 let widgets.Cursor initialize to the lower x and y bounds rather than 0,0, which can cause havoc for dates and other transforms - DSD @@ -6,6 +8,10 @@ 2007-12-06 fixed a bug in rcsetup, see bug 1845057 - DSD +2007-12-05 Fix how fonts are cached to avoid loading the same one multiple times. + (This was a regression since 0.90 caused by the refactoring of + font_manager.py) - MGD + =============================================================== 2007-11-27 Released 0.91.1 at revision 4517 Modified: branches/transforms/lib/matplotlib/backends/backend_ps.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-12-10 16:17:16 UTC (rev 4687) +++ branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-12-10 16:17:42 UTC (rev 4688) @@ -1430,4 +1430,31 @@ clip newpath } bind def""", +<<<<<<< .working +======= + # angle1 angle2 rx ry x y *ellipse* - + """/ellipse { + newpath + matrix currentmatrix 7 1 roll + translate + scale + 0 0 1 5 3 roll arc + setmatrix + closepath + } bind def""", + """/unitcircle { + newpath +0. -1. moveto +0.2652031 -1.0 0.519579870785 -0.894633691588 0.707106781187 -0.707106781187 curveto +0.894633691588 -0.519579870785 1.0 -0.2652031 1.0 0.0 curveto +1.0 0.2652031 0.894633691588 0.519579870785 0.707106781187 0.707106781187 curveto +0.519579870785 0.894633691588 0.2652031 1.0 0.0 1.0 curveto +-0.2652031 1.0 -0.519579870785 0.894633691588 -0.707106781187 0.707106781187 curveto +-0.894633691588 0.519579870785 -1.0 0.2652031 -1.0 0.0 curveto +-1.0 -0.2652031 -0.894633691588 -0.519579870785 -0.707106781187 -0.707106781187 curveto +-0.519579870785 -0.894633691588 -0.2652031 -1.0 0.0 -1.0 curveto +closepath + } bind def""", + +>>>>>>> .merge-right.r4679 ] Modified: branches/transforms/lib/matplotlib/patches.py =================================================================== --- branches/transforms/lib/matplotlib/patches.py 2007-12-10 16:17:16 UTC (rev 4687) +++ branches/transforms/lib/matplotlib/patches.py 2007-12-10 16:17:42 UTC (rev 4688) @@ -820,6 +820,49 @@ """ A scale-free ellipse """ +<<<<<<< .working +======= + MAGIC = 0.2652031 + SQRT2 = npy.sqrt(0.5) + MAGIC45 = npy.sqrt((MAGIC*MAGIC) / 2.0) + + circle = npy.array( + [[0.0, -1.0], + + [MAGIC, -1.0], + [SQRT2-MAGIC45, -SQRT2-MAGIC45], + [SQRT2, -SQRT2], + + [SQRT2+MAGIC45, -SQRT2+MAGIC45], + [1.0, -MAGIC], + [1.0, 0.0], + + [1.0, MAGIC], + [SQRT2+MAGIC45, SQRT2-MAGIC45], + [SQRT2, SQRT2], + + [SQRT2-MAGIC45, SQRT2+MAGIC45], + [MAGIC, 1.0], + [0.0, 1.0], + + [-MAGIC, 1.0], + [-SQRT2+MAGIC45, SQRT2+MAGIC45], + [-SQRT2, SQRT2], + + [-SQRT2-MAGIC45, SQRT2-MAGIC45], + [-1.0, MAGIC], + [-1.0, 0.0], + + [-1.0, -MAGIC], + [-SQRT2-MAGIC45, -SQRT2+MAGIC45], + [-SQRT2, -SQRT2], + + [-SQRT2+MAGIC45, -SQRT2-MAGIC45], + [-MAGIC, -1.0], + [0.0, -1.0]], + npy.float_) + +>>>>>>> .merge-right.r4679 def __str__(self): return "Ellipse(%d,%d;%dx%d)"%(self.center[0],self.center[1],self.width,self.height) @@ -855,10 +898,17 @@ def get_patch_transform(self): return self._patch_transform +<<<<<<< .working def contains(self,ev): if ev.x is None or ev.y is None: return False,{} x, y = self.get_transform().inverted().transform_point((ev.x, ev.y)) return (x*x + y*y) <= 1.0, {} +======= + xcenter = self.convert_xunits(xcenter) + width = self.convert_xunits(width) + ycenter = self.convert_yunits(ycenter) + height = self.convert_xunits(height) +>>>>>>> .merge-right.r4679 def _get_center(self): return self._center @@ -882,6 +932,105 @@ angle = property(_get_angle, _set_angle) +<<<<<<< .working +======= + rtheta = angle*npy.pi/180. + R = npy.array([ + [npy.cos(rtheta), -npy.sin(rtheta)], + [npy.sin(rtheta), npy.cos(rtheta)], + ]) + + + x, y = npy.dot(R, npy.array([x, y])) + x += xcenter + y += ycenter + + return zip(x, y) + + def draw(self, renderer): + if not self.get_visible(): return + #renderer.open_group('patch') + gc = renderer.new_gc() + gc.set_foreground(self._edgecolor) + gc.set_linewidth(self._linewidth) + gc.set_alpha(self._alpha) + gc.set_antialiased(self._antialiased) + self._set_gc_clip(gc) + + gc.set_capstyle('projecting') + + if not self.fill or self._facecolor is None: rgbFace = None + else: rgbFace = colors.colorConverter.to_rgb(self._facecolor) + + if self._hatch: + gc.set_hatch(self._hatch ) + + + if not hasattr(renderer, 'draw_path'): + mpl.verbose.report('patches.Ellipse renderer does not support path drawing; falling back on vertex approximation for nonlinear transformation') + renderer.draw_polygon(gc, rgbFace, self.get_verts()) + return + + + x, y = self.center + x = self.convert_xunits(x) + y = self.convert_yunits(y) + w = self.convert_xunits(self.width)/2. + h = self.convert_yunits(self.height)/2. + + theta = self.angle * npy.pi/180. + T = npy.array([ + [1, 0, x], + [0, 1, y], + [0, 0, 1]]) + + + + + S = npy.array([ + [w, 0, 0], + [0, h, 0], + [0, 0, 1]]) + + + + # rotate by theta + R = npy.array([ + [npy.cos(theta), -npy.sin(theta), 0], + [npy.sin(theta), npy.cos(theta), 0], + [0, 0, 1]]) + + # transform unit circle into ellipse + E = npy.dot(T, npy.dot(R, S)) + + + # Apply the display affine + sx, b, c, sy, tx, ty = self.get_transform().as_vec6_val() + + # display coords + D = npy.array([ + [sx, b, tx], + [c, sy, ty], + [0, 0, 1]], npy.float_) + + M = npy.dot(D,E) + + C = npy.ones((3, len(self.circle))) + C[0:2,:] = self.circle.T + + ellipse = npy.dot(M, C).T[:,:2] + + path = agg.path_storage() + path.move_to(*ellipse[0]) + for i in range(1, 25, 3): + path.curve4(*ellipse[i:i+3].flat) + path.close_polygon() + + renderer.draw_path(gc, rgbFace, path) + + +>>>>>>> .merge-right.r4679 + class Circle(Ellipse): """ A circle patch Copied: branches/transforms/unit/ellipse_large.py (from rev 4679, trunk/matplotlib/unit/ellipse_large.py) =================================================================== --- branches/transforms/unit/ellipse_large.py (rev 0) +++ branches/transforms/unit/ellipse_large.py 2007-12-10 16:17:42 UTC (rev 4688) @@ -0,0 +1,107 @@ + +# This example can be boiled down to a more simplistic example +# to show the problem, but bu including the upper and lower +# bound ellipses, it demonstrates how significant this error +# is to our plots. + +import math +from pylab import * +from matplotlib.patches import Ellipse + +# given a point x, y +x = 2692.440 +y = 6720.850 + +# get is the radius of a circle through this point +r = math.sqrt( x*x+y*y ) + +# show some comparative circles +delta = 6 + + +################################################## +def custom_ellipse( ax, x, y, major, minor, theta, numpoints = 750, **kwargs ): + xs = [] + ys = [] + incr = 2.0*math.pi / numpoints + incrTheta = 0.0 + while incrTheta <= (2.0*math.pi): + a = major * math.cos( incrTheta ) + b = minor * math.sin( incrTheta ) + l = math.sqrt( ( a**2 ) + ( b**2 ) ) + phi = math.atan2( b, a ) + incrTheta += incr + + xs.append( x + ( l * math.cos( theta + phi ) ) ) + ys.append( y + ( l * math.sin( theta + phi ) ) ) + # end while + + incrTheta = 2.0*math.pi + a = major * math.cos( incrTheta ) + b = minor * math.sin( incrTheta ) + l = sqrt( ( a**2 ) + ( b**2 ) ) + phi = math.atan2( b, a ) + xs.append( x + ( l * math.cos( theta + phi ) ) ) + ys.append( y + ( l * math.sin( theta + phi ) ) ) + + ellipseLine = ax.plot( xs, ys, **kwargs ) + + +################################################## +# make the axes +ax = subplot( 211, aspect='equal' ) +ax.set_aspect( 'equal', 'datalim' ) + +# make the lower-bound ellipse +diam = (r - delta) * 2.0 +lower_ellipse = Ellipse( (0.0, 0.0), diam, diam, 0.0, fill=False, edgecolor="darkgreen" ) +ax.add_patch( lower_ellipse ) + +# make the target ellipse +diam = r * 2.0 +target_ellipse = Ellipse( (0.0, 0.0), diam, diam, 0.0, fill=False, edgecolor="darkred" ) +ax.add_patch( target_ellipse ) + +# make the upper-bound ellipse +diam = (r + delta) * 2.0 +upper_ellipse = Ellipse( (0.0, 0.0), diam, diam, 0.0, fill=False, edgecolor="darkblue" ) +ax.add_patch( upper_ellipse ) + +# make the target +diam = delta * 2.0 +target = Ellipse( (x, y), diam, diam, 0.0, fill=False, edgecolor="#DD1208" ) +ax.add_patch( target ) + +# give it a big marker +ax.plot( [x], [y], marker='x', linestyle='None', mfc='red', mec='red', markersize=10 ) + +################################################## +# now lets do the same thing again using a custom ellipse function + +# make the axes +ax = subplot( 212, aspect='equal', sharex=ax, sharey=ax ) +ax.set_aspect( 'equal', 'datalim' ) + +# make the lower-bound ellipse +custom_ellipse( ax, 0.0, 0.0, r-delta, r-delta, 0.0, color="darkgreen" ) + +# make the target ellipse +custom_ellipse( ax, 0.0, 0.0, r, r, 0.0, color="darkred" ) + +# make the upper-bound ellipse +custom_ellipse( ax, 0.0, 0.0, r+delta, r+delta, 0.0, color="darkblue" ) + +# make the target +custom_ellipse( ax, x, y, delta, delta, 0.0, color="#BB1208" ) + +# give it a big marker +ax.plot( [x], [y], marker='x', linestyle='None', mfc='red', mec='red', markersize=10 ) + +################################################## +# lets zoom in to see the area of interest + +ax.set_xlim(2650, 2735) +ax.set_ylim(6705, 6735) +show() + +savefig("ellipse") This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-12-10 16:21:40
|
Revision: 4689 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4689&view=rev Author: mdboom Date: 2007-12-10 08:21:36 -0800 (Mon, 10 Dec 2007) Log Message: ----------- Merged revisions 4683-4688 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r4684 | mdboom | 2007-12-10 10:23:08 -0500 (Mon, 10 Dec 2007) | 2 lines Fix variable name. ........ r4685 | mdboom | 2007-12-10 10:34:29 -0500 (Mon, 10 Dec 2007) | 2 lines Fix syntax for pre-Python 2.5 ........ r4686 | mdboom | 2007-12-10 11:15:30 -0500 (Mon, 10 Dec 2007) | 4 lines Support draw_path (importantly for ellipses) in Pdf, Svg and Cairo backends. Fix SVG text rendering bug. ........ Modified Paths: -------------- branches/transforms/CHANGELOG branches/transforms/lib/matplotlib/backends/backend_cairo.py branches/transforms/lib/matplotlib/backends/backend_pdf.py branches/transforms/lib/matplotlib/backends/backend_svg.py branches/transforms/lib/matplotlib/font_manager.py branches/transforms/lib/matplotlib/patches.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-4682 + /trunk/matplotlib:1-4688 Modified: branches/transforms/CHANGELOG =================================================================== --- branches/transforms/CHANGELOG 2007-12-10 16:17:42 UTC (rev 4688) +++ branches/transforms/CHANGELOG 2007-12-10 16:21:36 UTC (rev 4689) @@ -1,3 +1,9 @@ +2007-12-10 Fix SVG text rendering bug. + +2007-12-10 Increase accuracy of circle and ellipse drawing by using an 8-piece + bezier approximation, rather than a 4-piece one. Fix PDF, SVG and + Cairo backends so they can draw paths (meaning ellipses as well). + 2007-12-07 Issue a warning when drawing an image on a non-linear axis. - MGD 2007-12-06 let widgets.Cursor initialize to the lower x and y bounds Modified: branches/transforms/lib/matplotlib/backends/backend_cairo.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_cairo.py 2007-12-10 16:17:42 UTC (rev 4688) +++ branches/transforms/lib/matplotlib/backends/backend_cairo.py 2007-12-10 16:21:36 UTC (rev 4689) @@ -34,6 +34,7 @@ backend_version = cairo.version del _version_required +from matplotlib import agg from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\ FigureManagerBase, FigureCanvasBase from matplotlib.cbook import enumerate, izip, is_string_like @@ -117,6 +118,7 @@ ctx.stroke() +<<<<<<< .working #@staticmethod def convert_path(ctx, tpath): for points, code in tpath.iter_segments(): @@ -133,12 +135,48 @@ elif code == Path.CLOSEPOLY: ctx.close_path() convert_path = staticmethod(convert_path) +======= + def draw_path(self, gc, rgbFace, path): + ctx = gc.ctx + ctx.new_path() +>>>>>>> .merge-right.r4686 +<<<<<<< .working def draw_path(self, gc, path, transform, rgbFace=None): if len(path.vertices) > 18980: raise ValueError("The Cairo backend can not draw paths longer than 18980 points.") +======= + while 1: + code, xp, yp = path.vertex() + yp = self.height - yp + + if code == agg.path_cmd_stop: + ctx.close_path() + break + elif code == agg.path_cmd_move_to: + ctx.move_to(xp, yp) + elif code == agg.path_cmd_line_to: + ctx.line_to(xp, yp) + elif code == agg.path_cmd_curve3: + _, xp1, yp1 = path.vertex() + yp1 = self.height - yp1 + ctx.curve_to(xp, yp, xp, yp, xp1, yp1) + elif code == agg.path_cmd_curve4: + _, xp1, yp1 = path.vertex() + yp1 = self.height - yp1 + _, xp2, yp2 = path.vertex() + yp2 = self.height - yp2 + ctx.curve_to(xp, yp, xp1, yp1, xp2, yp2) + elif code == agg.path_cmd_end_poly: + ctx.close_path() + self._fill_and_stroke(ctx, rgbFace) + + def draw_arc(self, gc, rgbFace, x, y, width, height, angle1, angle2, + rotation): + if _debug: print '%s.%s()' % (self.__class__.__name__, _fn_name()) +>>>>>>> .merge-right.r4686 ctx = gc.ctx transform = transform + \ Affine2D().scale(1.0, -1.0).translate(0, self.height) Modified: branches/transforms/lib/matplotlib/backends/backend_pdf.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-12-10 16:17:42 UTC (rev 4688) +++ branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-12-10 16:21:36 UTC (rev 4689) @@ -1211,7 +1211,97 @@ stat_key, (realpath, Set())) used_characters[1].update(set) +<<<<<<< .working def draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None): +======= + def draw_arc(self, gcEdge, rgbFace, x, y, width, height, + angle1, angle2, rotation): + """ + Draw an arc using GraphicsContext instance gcEdge, centered at x,y, + with width and height and angles from 0.0 to 360.0 + 0 degrees is at 3-o'clock, rotated by `rotation` degrees + positive angles are anti-clockwise + + If the color rgbFace is not None, fill the arc with it. + """ + # source: agg_bezier_arc.cpp in agg23 + + def arc_to_bezier(cx, cy, rx, ry, angle1, sweep, rotation): + halfsweep = sweep / 2.0 + x0, y0 = cos(halfsweep), sin(halfsweep) + tx = (1.0 - x0) * 4.0/3.0; + ty = y0 - tx * x0 / y0; + px = x0, x0+tx, x0+tx, x0 + py = -y0, -ty, ty, y0 + sn, cs = sin(angle1 + halfsweep), cos(angle1 + halfsweep) + result = [ (rx * (pxi * cs - pyi * sn), + ry * (pxi * sn + pyi * cs)) + for pxi, pyi in zip(px, py) ] + result = [ (cx + cos(rotation)*x - sin(rotation)*y, + cy + sin(rotation)*x + cos(rotation)*y) + for x, y in result ] + return reduce(lambda x, y: x + y, result) + + epsilon = 0.01 + angle1 *= pi/180.0 + angle2 *= pi/180.0 + rotation *= pi/180.0 + sweep = angle2 - angle1 + angle1 = angle1 % (2*pi) + sweep = min(max(-2*pi, sweep), 2*pi) + + if sweep < 0.0: + sweep, angle1, angle2 = -sweep, angle2, angle1 + bp = [ pi/2.0 * i + for i in range(4) + if pi/2.0 * i < sweep-epsilon ] + bp.append(sweep) + subarcs = [ arc_to_bezier(x, y, width/2.0, height/2.0, + bp[i], bp[i+1]-bp[i], rotation) + for i in range(len(bp)-1) ] + + self.check_gc(gcEdge, rgbFace) + self.file.output(subarcs[0][0], subarcs[0][1], Op.moveto) + for arc in subarcs: + self.file.output(*(arc[2:] + (Op.curveto,))) + + self.file.output(self.gc.close_and_paint()) + + def draw_path(self, gc, rgbFace, path): + self.check_gc(gc, rgbFace) + + cmds = [] + + while 1: + code, xp, yp = path.vertex() + + if code == agg.path_cmd_stop: + cmds.append(Op.closepath) + break + elif code == agg.path_cmd_move_to: + cmds.extend([xp, yp, Op.moveto]) + elif code == agg.path_cmd_line_to: + cmds.extend([xp, yp, Op.lineto]) + elif code == agg.path_cmd_curve3: + cmds.extend([xp, yp]) + cmds.extend([xp, yp]) + cmds.extend(path.vertex()[1:]) + cmds.append(Op.curveto) + elif code == agg.path_cmd_curve4: + cmds.extend([xp, yp]) + cmds.extend(path.vertex()[1:]) + cmds.extend(path.vertex()[1:]) + cmds.append(Op.curveto) + elif code == agg.path_cmd_end_poly: + cmds.append(Op.closepath) + self.file.output(*cmds) + self.file.output(self.gc.paint()) + + def get_image_magnification(self): + return self.image_magnification + + def draw_image(self, x, y, im, bbox): +>>>>>>> .merge-right.r4686 #print >>sys.stderr, "draw_image called" # MGDTODO: Support clippath here Modified: branches/transforms/lib/matplotlib/backends/backend_svg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_svg.py 2007-12-10 16:17:42 UTC (rev 4688) +++ branches/transforms/lib/matplotlib/backends/backend_svg.py 2007-12-10 16:21:36 UTC (rev 4689) @@ -2,6 +2,7 @@ import os, codecs, base64, tempfile, urllib, gzip +from matplotlib import agg from matplotlib import verbose, __version__, rcParams from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\ FigureManagerBase, FigureCanvasBase @@ -139,6 +140,49 @@ def close_group(self, s): self._svgwriter.write('</g>\n') +<<<<<<< .working +======= + def draw_path(self, gc, rgbFace, path): + cmd = [] + + while 1: + code, xp, yp = path.vertex() + yp = self.height - yp + + if code == agg.path_cmd_stop: + cmd.append('z') # Hack, path_cmd_end_poly not found + break + elif code == agg.path_cmd_move_to: + cmd.append('M%g %g' % (xp, yp)) + elif code == agg.path_cmd_line_to: + cmd.append('L%g %g' % (xp, yp)) + elif code == agg.path_cmd_curve3: + verts = [xp, yp] + verts.extent(path.vertex()[1:]) + verts[-1] = self.height - verts[-1] + cmd.append('Q%g %g %g %g' % tuple(verts)) + elif code == agg.path_cmd_curve4: + verts = [xp, yp] + verts.extend(path.vertex()[1:]) + verts[-1] = self.height - verts[-1] + verts.extend(path.vertex()[1:]) + verts[-1] = self.height - verts[-1] + cmd.append('C%g %g %g %g %g %g'%tuple(verts)) + elif code == agg.path_cmd_end_poly: + cmd.append('z') + + path_data = "".join(cmd) + self._draw_svg_element("path", 'd="%s"' % path_data, gc, rgbFace) + + def draw_arc(self, gc, rgbFace, x, y, width, height, angle1, angle2, rotation): + """ + Ignores angles for now + """ + details = 'cx="%s" cy="%s" rx="%s" ry="%s" transform="rotate(%1.1f %s %s)"' % \ + (x, self.height-y, width/2.0, height/2.0, -rotation, x, self.height-y) + self._draw_svg_element('ellipse', details, gc, rgbFace) + +>>>>>>> .merge-right.r4686 def option_image_nocomposite(self): """ if svg.image_noscale is True, compositing multiple images into one is prohibited @@ -327,7 +371,7 @@ svg.append(' x="%s"' % (currx * (self.FONT_SCALE / fontsize))) svg.append('/>\n') - currx += (glyph.linearHoriAdvance / 65536.0) + currx += (glyph.linearHoriAdvance / 65536.0) / (self.FONT_SCALE / fontsize) svg.append('</g>\n') svg = ''.join(svg) else: Modified: branches/transforms/lib/matplotlib/font_manager.py =================================================================== --- branches/transforms/lib/matplotlib/font_manager.py 2007-12-10 16:17:42 UTC (rev 4688) +++ branches/transforms/lib/matplotlib/font_manager.py 2007-12-10 16:21:36 UTC (rev 4689) @@ -109,9 +109,10 @@ else: user = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, MSFolders) try: - return _winreg.QueryValueEx(user, 'Fonts')[0] - except OSError: - pass # Fall through to default + try: + return _winreg.QueryValueEx(user, 'Fonts')[0] + except OSError: + pass # Fall through to default finally: _winreg.CloseKey(user) return os.path.join(os.environ['WINDIR'], 'Fonts') Modified: branches/transforms/lib/matplotlib/patches.py =================================================================== --- branches/transforms/lib/matplotlib/patches.py 2007-12-10 16:17:42 UTC (rev 4688) +++ branches/transforms/lib/matplotlib/patches.py 2007-12-10 16:21:36 UTC (rev 4689) @@ -820,49 +820,6 @@ """ A scale-free ellipse """ -<<<<<<< .working -======= - MAGIC = 0.2652031 - SQRT2 = npy.sqrt(0.5) - MAGIC45 = npy.sqrt((MAGIC*MAGIC) / 2.0) - - circle = npy.array( - [[0.0, -1.0], - - [MAGIC, -1.0], - [SQRT2-MAGIC45, -SQRT2-MAGIC45], - [SQRT2, -SQRT2], - - [SQRT2+MAGIC45, -SQRT2+MAGIC45], - [1.0, -MAGIC], - [1.0, 0.0], - - [1.0, MAGIC], - [SQRT2+MAGIC45, SQRT2-MAGIC45], - [SQRT2, SQRT2], - - [SQRT2-MAGIC45, SQRT2+MAGIC45], - [MAGIC, 1.0], - [0.0, 1.0], - - [-MAGIC, 1.0], - [-SQRT2+MAGIC45, SQRT2+MAGIC45], - [-SQRT2, SQRT2], - - [-SQRT2-MAGIC45, SQRT2-MAGIC45], - [-1.0, MAGIC], - [-1.0, 0.0], - - [-1.0, -MAGIC], - [-SQRT2-MAGIC45, -SQRT2+MAGIC45], - [-SQRT2, -SQRT2], - - [-SQRT2+MAGIC45, -SQRT2-MAGIC45], - [-MAGIC, -1.0], - [0.0, -1.0]], - npy.float_) - ->>>>>>> .merge-right.r4679 def __str__(self): return "Ellipse(%d,%d;%dx%d)"%(self.center[0],self.center[1],self.width,self.height) @@ -898,17 +855,10 @@ def get_patch_transform(self): return self._patch_transform -<<<<<<< .working def contains(self,ev): if ev.x is None or ev.y is None: return False,{} x, y = self.get_transform().inverted().transform_point((ev.x, ev.y)) return (x*x + y*y) <= 1.0, {} -======= - xcenter = self.convert_xunits(xcenter) - width = self.convert_xunits(width) - ycenter = self.convert_yunits(ycenter) - height = self.convert_xunits(height) ->>>>>>> .merge-right.r4679 def _get_center(self): return self._center @@ -932,105 +882,6 @@ angle = property(_get_angle, _set_angle) -<<<<<<< .working -======= - rtheta = angle*npy.pi/180. - R = npy.array([ - [npy.cos(rtheta), -npy.sin(rtheta)], - [npy.sin(rtheta), npy.cos(rtheta)], - ]) - - - x, y = npy.dot(R, npy.array([x, y])) - x += xcenter - y += ycenter - - return zip(x, y) - - def draw(self, renderer): - if not self.get_visible(): return - #renderer.open_group('patch') - gc = renderer.new_gc() - gc.set_foreground(self._edgecolor) - gc.set_linewidth(self._linewidth) - gc.set_alpha(self._alpha) - gc.set_antialiased(self._antialiased) - self._set_gc_clip(gc) - - gc.set_capstyle('projecting') - - if not self.fill or self._facecolor is None: rgbFace = None - else: rgbFace = colors.colorConverter.to_rgb(self._facecolor) - - if self._hatch: - gc.set_hatch(self._hatch ) - - - if not hasattr(renderer, 'draw_path'): - mpl.verbose.report('patches.Ellipse renderer does not support path drawing; falling back on vertex approximation for nonlinear transformation') - renderer.draw_polygon(gc, rgbFace, self.get_verts()) - return - - - x, y = self.center - x = self.convert_xunits(x) - y = self.convert_yunits(y) - w = self.convert_xunits(self.width)/2. - h = self.convert_yunits(self.height)/2. - - theta = self.angle * npy.pi/180. - T = npy.array([ - [1, 0, x], - [0, 1, y], - [0, 0, 1]]) - - - - - S = npy.array([ - [w, 0, 0], - [0, h, 0], - [0, 0, 1]]) - - - - # rotate by theta - R = npy.array([ - [npy.cos(theta), -npy.sin(theta), 0], - [npy.sin(theta), npy.cos(theta), 0], - [0, 0, 1]]) - - # transform unit circle into ellipse - E = npy.dot(T, npy.dot(R, S)) - - - # Apply the display affine - sx, b, c, sy, tx, ty = self.get_transform().as_vec6_val() - - # display coords - D = npy.array([ - [sx, b, tx], - [c, sy, ty], - [0, 0, 1]], npy.float_) - - M = npy.dot(D,E) - - C = npy.ones((3, len(self.circle))) - C[0:2,:] = self.circle.T - - ellipse = npy.dot(M, C).T[:,:2] - - path = agg.path_storage() - path.move_to(*ellipse[0]) - for i in range(1, 25, 3): - path.curve4(*ellipse[i:i+3].flat) - path.close_polygon() - - renderer.draw_path(gc, rgbFace, path) - - ->>>>>>> .merge-right.r4679 - class Circle(Ellipse): """ A circle patch This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-12-12 00:15:30
|
Revision: 4700 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4700&view=rev Author: mdboom Date: 2007-12-11 16:15:23 -0800 (Tue, 11 Dec 2007) Log Message: ----------- Added (experimental) support for large arcs Modified Paths: -------------- branches/transforms/lib/matplotlib/patches.py branches/transforms/lib/matplotlib/path.py branches/transforms/src/_path.cpp branches/transforms/unit/ellipse_compare.py branches/transforms/unit/ellipse_large.py Modified: branches/transforms/lib/matplotlib/patches.py =================================================================== --- branches/transforms/lib/matplotlib/patches.py 2007-12-11 22:03:58 UTC (rev 4699) +++ branches/transforms/lib/matplotlib/patches.py 2007-12-12 00:15:23 UTC (rev 4700) @@ -839,6 +839,7 @@ self._width, self._height = width, height self._angle = angle self._recompute_transform() + self._path = Path.unit_circle() def _recompute_transform(self): self._patch_transform = transforms.Affine2D() \ @@ -850,7 +851,7 @@ """ Return the vertices of the rectangle """ - return Path.unit_circle() + return self._path def get_patch_transform(self): return self._patch_transform @@ -881,7 +882,6 @@ self._recompute_transform() angle = property(_get_angle, _set_angle) - class Circle(Ellipse): """ A circle patch @@ -908,7 +908,180 @@ Ellipse.__init__(self, xy, radius*2, radius*2, **kwargs) __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd +class Arc(Ellipse): + """ + An elliptical arc. Because it performs various optimizations, it may not be + filled. + """ + def __str__(self): + return "Arc(%d,%d;%dx%d)"%(self.center[0],self.center[1],self.width,self.height) + def __init__(self, xy, width, height, angle=0.0, theta1=0.0, theta2=360.0, **kwargs): + """ + xy - center of ellipse + width - length of horizontal axis + height - length of vertical axis + angle - rotation in degrees (anti-clockwise) + theta1 - starting angle of the arc in degrees + theta2 - ending angle of the arc in degrees + + If theta1 and theta2 are not provided, the arc will form a + complete ellipse. + + Valid kwargs are: + %(Patch)s + """ + fill = kwargs.pop('fill') + if fill: + raise ValueError("Arc objects can not be filled") + kwargs['fill'] = False + + Ellipse.__init__(self, xy, width, height, angle, **kwargs) + + self._theta1 = theta1 + self._theta2 = theta2 + + def draw(self, renderer): + """ + Ellipses are normally drawn using an approximation that uses + eight cubic bezier splines. The error of this approximation + is 1.89818e-6, according to this unverified source: + + Lancaster, Don. Approximating a Circle or an Ellipse Using + Four Bezier Cubic Splines. + + http://www.tinaja.com/glib/ellipse4.pdf + + There is a use case where very large ellipses must be drawn + with very high accuracy, and it is too expensive to render the + entire ellipse with enough segments (either splines or line + segments). Therefore, in the case where either radius of the + ellipse is large enough that the error of the spline + approximation will be visible (greater than one pixel offset + from the ideal), a different technique is used. + + In that case, only the visible parts of the ellipse are drawn, + with each visible arc using a fixed number of spline segments + (8). The algorithm proceeds as follows: + + 1. The points where the ellipse intersects the axes bounding + box are located. (This is done be performing an inverse + transformation on the axes bbox such that it is relative to + the unit circle -- this makes the intersection calculation + much easier than doing rotated ellipse intersection + directly). + + This uses the "line intersecting a circle" algorithm from: + + Vince, John. Geometry for Computer Graphics: Formulae, + Examples & Proofs. London: Springer-Verlag, 2005. + + 2. The angles of each of the intersection points are + calculated. + + 3. Proceeding counterclockwise starting in the positive + x-direction, each of the visible arc-segments between the + pairs of vertices are drawn using the bezier arc + approximation technique implemented in Path.arc(). + """ + # Get the width and height in pixels + width, height = self.get_transform().transform_point( + (self._width, self._height)) + inv_error = (1.0 / 1.89818e-6) + + if width < inv_error and height < inv_error and False: + self._path = Path.arc(self._theta1, self._theta2) + return Patch.draw(self, renderer) + + # Transforms the axes box_path so that it is relative to the unit + # circle in the same way that it is relative to the desired + # ellipse. + box_path = Path.unit_rectangle() + box_path_transform = transforms.BboxTransformTo(self.axes.bbox) + \ + self.get_transform().inverted() + box_path = box_path.transformed(box_path_transform) + vertices = [] + + def iter_circle_intersect_on_line(x0, y0, x1, y1): + dx = x1 - x0 + dy = y1 - y0 + dr2 = dx*dx + dy*dy + dr = npy.sqrt(dr2) + D = x0*y1 - x1*y0 + D2 = D*D + discrim = dr2 - D2 + + # Single (tangential) intersection + if discrim == 0.0: + x = (D*dy) / dr2 + y = (-D*dx) / dr2 + yield x, y + elif discrim > 0.0: + if dy < 0: + sign_dy = -1.0 + else: + sign_dy = 1.0 + sqrt_discrim = npy.sqrt(discrim) + for sign in (1., -1.): + x = (D*dy + sign * sign_dy * dx * sqrt_discrim) / dr2 + y = (-D*dx + sign * npy.abs(dy) * sqrt_discrim) / dr2 + yield x, y + + def iter_circle_intersect_on_line_seg(x0, y0, x1, y1): + epsilon = 1e-9 + if x1 < x0: + x0e, x1e = x1, x0 + else: + x0e, x1e = x0, x1 + if y1 < y0: + y0e, y1e = y1, y0 + else: + y0e, y1e = y0, y1 + x0e -= epsilon + y0e -= epsilon + x1e += epsilon + y1e += epsilon + for x, y in iter_circle_intersect_on_line(x0, y0, x1, y1): + if x >= x0e and x <= x1e and y >= y0e and y <= y1e: + yield x, y + + PI = npy.pi + TWOPI = PI * 2.0 + RAD2DEG = 180.0 / PI + DEG2RAD = PI / 180.0 + theta1 = self._theta1 + theta2 = self._theta2 + thetas = {} + # For each of the point pairs, there is a line segment + for p0, p1 in zip(box_path.vertices[:-1], box_path.vertices[1:]): + x0, y0 = p0 + x1, y1 = p1 + for x, y in iter_circle_intersect_on_line_seg(x0, y0, x1, y1): + # Convert radians to angles + theta = npy.arccos(x) + if y < 0: + theta = TWOPI - theta + theta *= RAD2DEG + if theta > theta1 and theta < theta2: + thetas[theta] = None + + thetas = thetas.keys() + thetas.sort() + thetas.append(theta2) + + last_theta = theta1 + theta1_rad = theta1 * DEG2RAD + inside = box_path.contains_point((npy.cos(theta1_rad), npy.sin(theta1_rad))) + + for theta in thetas: + if inside: + self._path = Path.arc(last_theta, theta, 8) + Patch.draw(self, renderer) + inside = False + else: + inside = True + last_theta = theta + def bbox_artist(artist, renderer, props=None, fill=True): """ This is a debug function to draw a rectangle around the bounding Modified: branches/transforms/lib/matplotlib/path.py =================================================================== --- branches/transforms/lib/matplotlib/path.py 2007-12-11 22:03:58 UTC (rev 4699) +++ branches/transforms/lib/matplotlib/path.py 2007-12-12 00:15:23 UTC (rev 4700) @@ -408,7 +408,7 @@ unit_circle = classmethod(unit_circle) #@classmethod - def arc(cls, theta1, theta2, is_wedge=False, n=None): + def arc(cls, theta1, theta2, n=None, is_wedge=False): """ Returns an arc on the unit circle from angle theta1 to angle theta2 (in degrees). @@ -486,12 +486,12 @@ arc = classmethod(arc) #@classmethod - def wedge(cls, theta1, theta2): + def wedge(cls, theta1, theta2, n=None): """ Returns a wedge of the unit circle from angle theta1 to angle theta2 (in degrees). """ - return cls.arc(theta1, theta2, True) + return cls.arc(theta1, theta2, True, n) wedge = classmethod(wedge) _get_path_collection_extents = get_path_collection_extents Modified: branches/transforms/src/_path.cpp =================================================================== --- branches/transforms/src/_path.cpp 2007-12-11 22:03:58 UTC (rev 4699) +++ branches/transforms/src/_path.cpp 2007-12-12 00:15:23 UTC (rev 4700) @@ -109,7 +109,7 @@ // Input 2D polygon _pgon_ with _numverts_ number of vertices and test point // _point_, returns 1 if inside, 0 if outside. template<class T> -bool point_in_path_impl(double tx, double ty, T& path) +bool point_in_path_impl(const double tx, const double ty, T& path) { int yflag0, yflag1, inside_flag; double vtx0, vty0, vtx1, vty1, sx, sy; @@ -132,7 +132,7 @@ yflag0 = (vty0 >= ty); vtx1 = x; - vty1 = x; + vty1 = y; inside_flag = 0; do @@ -141,7 +141,7 @@ // The following cases denote the beginning on a new subpath if (code == agg::path_cmd_stop || - (code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) + (code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) { x = sx; y = sy; @@ -169,7 +169,7 @@ // by Joseph Samosky's and Mark Haigh-Hutchinson's different // polygon inclusion tests. if ( ((vty1-ty) * (vtx0-vtx1) >= - (vtx1-tx) * (vty0-vty1)) == yflag1 ) + (vtx1-tx) * (vty0-vty1)) == yflag1 ) { inside_flag ^= 1; } @@ -184,7 +184,7 @@ vty1 = y; } while (code != agg::path_cmd_stop && - (code & agg::path_cmd_end_poly) != agg::path_cmd_end_poly); + (code & agg::path_cmd_end_poly) != agg::path_cmd_end_poly); yflag1 = (vty1 >= ty); if (yflag0 != yflag1) Modified: branches/transforms/unit/ellipse_compare.py =================================================================== --- branches/transforms/unit/ellipse_compare.py 2007-12-11 22:03:58 UTC (rev 4699) +++ branches/transforms/unit/ellipse_compare.py 2007-12-12 00:15:23 UTC (rev 4700) @@ -1,5 +1,5 @@ """ -Compare the ellipse generated with arcs versus a polygonal approximation +Compare the ellipse generated with arcs versus a polygonal approximation """ import numpy as npy from matplotlib import patches @@ -29,7 +29,7 @@ ax = fig.add_subplot(211, aspect='auto') ax.fill(x, y, alpha=0.2, facecolor='yellow', edgecolor='yellow', linewidth=1, zorder=1) -e1 = patches.Ellipse((xcenter, ycenter), width, height, +e1 = patches.Arc((xcenter, ycenter), width, height, angle=angle, linewidth=2, fill=False, zorder=2) ax.add_patch(e1) Modified: branches/transforms/unit/ellipse_large.py =================================================================== --- branches/transforms/unit/ellipse_large.py 2007-12-11 22:03:58 UTC (rev 4699) +++ branches/transforms/unit/ellipse_large.py 2007-12-12 00:15:23 UTC (rev 4700) @@ -6,7 +6,7 @@ import math from pylab import * -from matplotlib.patches import Ellipse +from matplotlib.patches import Arc # given a point x, y x = 2692.440 @@ -54,22 +54,22 @@ # make the lower-bound ellipse diam = (r - delta) * 2.0 -lower_ellipse = Ellipse( (0.0, 0.0), diam, diam, 0.0, fill=False, edgecolor="darkgreen" ) +lower_ellipse = Arc( (0.0, 0.0), diam, diam, 0.0, fill=False, edgecolor="darkgreen" ) ax.add_patch( lower_ellipse ) # make the target ellipse diam = r * 2.0 -target_ellipse = Ellipse( (0.0, 0.0), diam, diam, 0.0, fill=False, edgecolor="darkred" ) +target_ellipse = Arc( (0.0, 0.0), diam, diam, 0.0, fill=False, edgecolor="darkred" ) ax.add_patch( target_ellipse ) # make the upper-bound ellipse diam = (r + delta) * 2.0 -upper_ellipse = Ellipse( (0.0, 0.0), diam, diam, 0.0, fill=False, edgecolor="darkblue" ) +upper_ellipse = Arc( (0.0, 0.0), diam, diam, 0.0, fill=False, edgecolor="darkblue" ) ax.add_patch( upper_ellipse ) # make the target diam = delta * 2.0 -target = Ellipse( (x, y), diam, diam, 0.0, fill=False, edgecolor="#DD1208" ) +target = Arc( (x, y), diam, diam, 0.0, fill=False, edgecolor="#DD1208" ) ax.add_patch( target ) # give it a big marker @@ -104,4 +104,4 @@ ax.set_ylim(6705, 6735) show() -savefig("ellipse") +# savefig("ellipse") This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |